source: trunk/web/addons/job_monarch/lib/extjs-30/src/data/core/Connection.js @ 625

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

lib/extjs-30:

  • new ExtJS 3.0
File size: 26.5 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(function(){
8    var BEFOREREQUEST = "beforerequest",
9        REQUESTCOMPLETE = "requestcomplete",
10        REQUESTEXCEPTION = "requestexception",
11        UNDEFINED = undefined,
12        LOAD = 'load',
13        POST = 'POST',
14        GET = 'GET',
15        WINDOW = window;
16   
17    /**
18     * @class Ext.data.Connection
19     * @extends Ext.util.Observable
20     * <p>The class encapsulates a connection to the page's originating domain, allowing requests to be made
21     * either to a configured URL, or to a URL specified at request time.</p>
22     * <p>Requests made by this class are asynchronous, and will return immediately. No data from
23     * the server will be available to the statement immediately following the {@link #request} call.
24     * To process returned data, use a
25     * <a href="#request-option-success" ext:member="request-option-success" ext:cls="Ext.data.Connection">success callback</a>
26     * in the request options object,
27     * or an {@link #requestcomplete event listener}.</p>
28     * <p><h3>File Uploads</h3><a href="#request-option-isUpload" ext:member="request-option-isUpload" ext:cls="Ext.data.Connection">File uploads</a> are not performed using normal "Ajax" techniques, that
29     * is they are <b>not</b> performed using XMLHttpRequests. Instead the form is submitted in the standard
30     * manner with the DOM <tt>&lt;form></tt> element temporarily modified to have its
31     * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
32     * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
33     * but removed after the return data has been gathered.</p>
34     * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
35     * server is using JSON to send the return object, then the
36     * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
37     * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
38     * <p>Characters which are significant to an HTML parser must be sent as HTML entities, so encode
39     * "&lt;" as "&amp;lt;", "&amp;" as "&amp;amp;" etc.</p>
40     * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
41     * is created containing a <tt>responseText</tt> property in order to conform to the
42     * requirements of event handlers and callbacks.</p>
43     * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
44     * and some server technologies (notably JEE) may require some custom processing in order to
45     * retrieve parameter names and parameter values from the packet content.</p>
46     * @constructor
47     * @param {Object} config a configuration object.
48     */
49    Ext.data.Connection = function(config){   
50        Ext.apply(this, config);
51        this.addEvents(
52            /**
53             * @event beforerequest
54             * Fires before a network request is made to retrieve a data object.
55             * @param {Connection} conn This Connection object.
56             * @param {Object} options The options config object passed to the {@link #request} method.
57             */
58            BEFOREREQUEST,
59            /**
60             * @event requestcomplete
61             * Fires if the request was successfully completed.
62             * @param {Connection} conn This Connection object.
63             * @param {Object} response The XHR object containing the response data.
64             * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
65             * for details.
66             * @param {Object} options The options config object passed to the {@link #request} method.
67             */
68            REQUESTCOMPLETE,
69            /**
70             * @event requestexception
71             * Fires if an error HTTP status was returned from the server.
72             * See <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html">HTTP Status Code Definitions</a>
73             * for details of HTTP status codes.
74             * @param {Connection} conn This Connection object.
75             * @param {Object} response The XHR object containing the response data.
76             * See <a href="http://www.w3.org/TR/XMLHttpRequest/">The XMLHttpRequest Object</a>
77             * for details.
78             * @param {Object} options The options config object passed to the {@link #request} method.
79             */
80            REQUESTEXCEPTION
81        );
82        Ext.data.Connection.superclass.constructor.call(this);
83    };
84
85    // private
86    function handleResponse(response){
87        this.transId = false;
88        var options = response.argument.options;
89        response.argument = options ? options.argument : null;
90        this.fireEvent(REQUESTCOMPLETE, this, response, options);
91        if(options.success){
92            options.success.call(options.scope, response, options);
93        }
94        if(options.callback){
95            options.callback.call(options.scope, options, true, response);
96        }
97    }
98
99    // private
100    function handleFailure(response, e){
101        this.transId = false;
102        var options = response.argument.options;
103        response.argument = options ? options.argument : null;
104        this.fireEvent(REQUESTEXCEPTION, this, response, options, e);
105        if(options.failure){
106            options.failure.call(options.scope, response, options);
107        }
108        if(options.callback){
109            options.callback.call(options.scope, options, false, response);
110        }
111    }
112
113    // private
114    function doFormUpload(o, ps, url){
115        var id = Ext.id(),
116            doc = document,
117            frame = doc.createElement('iframe'),
118            form = Ext.getDom(o.form),
119            hiddens = [],
120            hd,
121            encoding = 'multipart/form-data',
122            buf = {
123                target: form.target,
124                method: form.method,
125                encoding: form.encoding,
126                enctype: form.enctype,
127                action: form.action
128            };
129           
130        Ext.apply(frame, {
131            id: id,
132            name: id,
133            className: 'x-hidden',
134            src: Ext.SSL_SECURE_URL // for IE
135        });     
136        doc.body.appendChild(frame);
137       
138        // This is required so that IE doesn't pop the response up in a new window.
139        if(Ext.isIE){
140           document.frames[id].name = id;
141        }
142       
143        Ext.apply(form, {
144            target: id,
145            method: POST,
146            enctype: encoding,
147            encoding: encoding,
148            action: url || buf.action
149        });
150       
151        // add dynamic params           
152        ps = Ext.urlDecode(ps, false);
153        for(var k in ps){
154            if(ps.hasOwnProperty(k)){
155                hd = doc.createElement('input');
156                hd.type = 'hidden';                   
157                hd.value = ps[hd.name = k];
158                form.appendChild(hd);
159                hiddens.push(hd);
160            }
161        }       
162
163        function cb(){
164            var me = this,
165                // bogus response object
166                r = {responseText : '',
167                     responseXML : null,
168                     argument : o.argument},
169                doc,
170                firstChild;
171
172            try{ 
173                doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
174                if(doc){
175                    if(doc.body){
176                        if(/textarea/i.test((firstChild = doc.body.firstChild || {}).tagName)){ // json response wrapped in textarea                       
177                            r.responseText = firstChild.value;
178                        }else{
179                            r.responseText = doc.body.innerHTML;
180                        }
181                    }
182                    //in IE the document may still have a body even if returns XML.
183                    r.responseXML = doc.XMLDocument || doc;
184                }
185            }
186            catch(e) {}
187
188            Ext.EventManager.removeListener(frame, LOAD, cb, me);
189
190            me.fireEvent(REQUESTCOMPLETE, me, r, o);
191           
192            function runCallback(fn, scope, args){
193                if(Ext.isFunction(fn)){
194                    fn.apply(scope, args);
195                }
196            }
197
198            runCallback(o.success, o.scope, [r, o]);
199            runCallback(o.callback, o.scope, [o, true, r]);
200
201            if(!me.debugUploads){
202                setTimeout(function(){Ext.removeNode(frame);}, 100);
203            }
204        }
205
206        Ext.EventManager.on(frame, LOAD, cb, this);
207        form.submit();
208       
209        Ext.apply(form, buf);
210        Ext.each(hiddens, function(h) {
211            Ext.removeNode(h);
212        });
213    }
214
215    Ext.extend(Ext.data.Connection, Ext.util.Observable, {
216        /**
217         * @cfg {String} url (Optional) <p>The default URL to be used for requests to the server. Defaults to undefined.</p>
218         * <p>The <code>url</code> config may be a function which <i>returns</i> the URL to use for the Ajax request. The scope
219         * (<code><b>this</b></code> reference) of the function is the <code>scope</code> option passed to the {@link #request} method.</p>
220         */
221        /**
222         * @cfg {Object} extraParams (Optional) An object containing properties which are used as
223         * extra parameters to each request made by this object. (defaults to undefined)
224         */
225        /**
226         * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
227         *  to each request made by this object. (defaults to undefined)
228         */
229        /**
230         * @cfg {String} method (Optional) The default HTTP method to be used for requests.
231         * (defaults to undefined; if not set, but {@link #request} params are present, POST will be used;
232         * otherwise, GET will be used.)
233         */
234        /**
235         * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
236         */
237        timeout : 30000,
238        /**
239         * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
240         * @type Boolean
241         */
242        autoAbort:false,
243   
244        /**
245         * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
246         * @type Boolean
247         */
248        disableCaching: true,
249       
250        /**
251         * @cfg {String} disableCachingParam (Optional) Change the parameter which is sent went disabling caching
252         * through a cache buster. Defaults to '_dc'
253         * @type String
254         */
255        disableCachingParam: '_dc',
256       
257        /**
258         * <p>Sends an HTTP request to a remote server.</p>
259         * <p><b>Important:</b> Ajax server requests are asynchronous, and this call will
260         * return before the response has been received. Process any returned data
261         * in a callback function.</p>
262         * <pre><code>
263Ext.Ajax.request({
264   url: 'ajax_demo/sample.json',
265   success: function(response, opts) {
266      var obj = Ext.decode(response.responseText);
267      console.dir(obj);
268   },
269   failure: function(response, opts) {
270      console.log('server-side failure with status code ' + response.status);
271   }
272});
273         * </code></pre>
274         * <p>To execute a callback function in the correct scope, use the <tt>scope</tt> option.</p>
275         * @param {Object} options An object which may contain the following properties:<ul>
276         * <li><b>url</b> : String/Function (Optional)<div class="sub-desc">The URL to
277         * which to send the request, or a function to call which returns a URL string. The scope of the
278         * function is specified by the <tt>scope</tt> option. Defaults to the configured
279         * <tt>{@link #url}</tt>.</div></li>
280         * <li><b>params</b> : Object/String/Function (Optional)<div class="sub-desc">
281         * An object containing properties which are used as parameters to the
282         * request, a url encoded string or a function to call to get either. The scope of the function
283         * is specified by the <tt>scope</tt> option.</div></li>
284         * <li><b>method</b> : String (Optional)<div class="sub-desc">The HTTP method to use
285         * for the request. Defaults to the configured method, or if no method was configured,
286         * "GET" if no parameters are being sent, and "POST" if parameters are being sent.  Note that
287         * the method name is case-sensitive and should be all caps.</div></li>
288         * <li><b>callback</b> : Function (Optional)<div class="sub-desc">The
289         * function to be called upon receipt of the HTTP response. The callback is
290         * called regardless of success or failure and is passed the following
291         * parameters:<ul>
292         * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
293         * <li><b>success</b> : Boolean<div class="sub-desc">True if the request succeeded.</div></li>
294         * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.
295         * See <a href="http://www.w3.org/TR/XMLHttpRequest/">http://www.w3.org/TR/XMLHttpRequest/</a> for details about
296         * accessing elements of the response.</div></li>
297         * </ul></div></li>
298         * <li><a id="request-option-success"></a><b>success</b> : Function (Optional)<div class="sub-desc">The function
299         * to be called upon success of the request. The callback is passed the following
300         * parameters:<ul>
301         * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
302         * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
303         * </ul></div></li>
304         * <li><b>failure</b> : Function (Optional)<div class="sub-desc">The function
305         * to be called upon failure of the request. The callback is passed the
306         * following parameters:<ul>
307         * <li><b>response</b> : Object<div class="sub-desc">The XMLHttpRequest object containing the response data.</div></li>
308         * <li><b>options</b> : Object<div class="sub-desc">The parameter to the request call.</div></li>
309         * </ul></div></li>
310         * <li><b>scope</b> : Object (Optional)<div class="sub-desc">The scope in
311         * which to execute the callbacks: The "this" object for the callback function. If the <tt>url</tt>, or <tt>params</tt> options were
312         * specified as functions from which to draw values, then this also serves as the scope for those function calls.
313         * Defaults to the browser window.</div></li>
314         * <li><b>timeout</b> : Number (Optional)<div class="sub-desc">The timeout in milliseconds to be used for this request. Defaults to 30 seconds.</div></li>
315         * <li><b>form</b> : Element/HTMLElement/String (Optional)<div class="sub-desc">The <tt>&lt;form&gt;</tt>
316         * Element or the id of the <tt>&lt;form&gt;</tt> to pull parameters from.</div></li>
317         * <li><a id="request-option-isUpload"></a><b>isUpload</b> : Boolean (Optional)<div class="sub-desc"><b>Only meaningful when used
318         * with the <tt>form</tt> option</b>.
319         * <p>True if the form object is a file upload (will be set automatically if the form was
320         * configured with <b><tt>enctype</tt></b> "multipart/form-data").</p>
321         * <p>File uploads are not performed using normal "Ajax" techniques, that is they are <b>not</b>
322         * performed using XMLHttpRequests. Instead the form is submitted in the standard manner with the
323         * DOM <tt>&lt;form></tt> element temporarily modified to have its
324         * <a href="http://www.w3.org/TR/REC-html40/present/frames.html#adef-target">target</a> set to refer
325         * to a dynamically generated, hidden <tt>&lt;iframe></tt> which is inserted into the document
326         * but removed after the return data has been gathered.</p>
327         * <p>The server response is parsed by the browser to create the document for the IFRAME. If the
328         * server is using JSON to send the return object, then the
329         * <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17">Content-Type</a> header
330         * must be set to "text/html" in order to tell the browser to insert the text unchanged into the document body.</p>
331         * <p>The response text is retrieved from the document, and a fake XMLHttpRequest object
332         * is created containing a <tt>responseText</tt> property in order to conform to the
333         * requirements of event handlers and callbacks.</p>
334         * <p>Be aware that file upload packets are sent with the content type <a href="http://www.faqs.org/rfcs/rfc2388.html">multipart/form</a>
335         * and some server technologies (notably JEE) may require some custom processing in order to
336         * retrieve parameter names and parameter values from the packet content.</p>
337         * </div></li>
338         * <li><b>headers</b> : Object (Optional)<div class="sub-desc">Request
339         * headers to set for the request.</div></li>
340         * <li><b>xmlData</b> : Object (Optional)<div class="sub-desc">XML document
341         * to use for the post. Note: This will be used instead of params for the post
342         * data. Any params will be appended to the URL.</div></li>
343         * <li><b>jsonData</b> : Object/String (Optional)<div class="sub-desc">JSON
344         * data to use as the post. Note: This will be used instead of params for the post
345         * data. Any params will be appended to the URL.</div></li>
346         * <li><b>disableCaching</b> : Boolean (Optional)<div class="sub-desc">True
347         * to add a unique cache-buster param to GET requests.</div></li>
348         * </ul></p>
349         * <p>The options object may also contain any other property which might be needed to perform
350         * postprocessing in a callback because it is passed to callback functions.</p>
351         * @return {Number} transactionId The id of the server transaction. This may be used
352         * to cancel the request.
353         */
354        request : function(o){
355            var me = this;
356            if(me.fireEvent(BEFOREREQUEST, me, o)){
357                if (o.el) {
358                    if(!Ext.isEmpty(o.indicatorText)){
359                        me.indicatorText = '<div class="loading-indicator">'+o.indicatorText+"</div>";
360                    }
361                    if(me.indicatorText) {
362                        Ext.getDom(o.el).innerHTML = me.indicatorText;                       
363                    }
364                    o.success = (Ext.isFunction(o.success) ? o.success : function(){}).createInterceptor(function(response) {
365                        Ext.getDom(o.el).innerHTML = response.responseText;
366                    });
367                }
368               
369                var p = o.params,
370                    url = o.url || me.url,               
371                    method,
372                    cb = {success: handleResponse,
373                          failure: handleFailure,
374                          scope: me,
375                          argument: {options: o},
376                          timeout : o.timeout || me.timeout
377                    },
378                    form,                   
379                    serForm;                   
380                 
381                     
382                if (Ext.isFunction(p)) {
383                    p = p.call(o.scope||WINDOW, o);
384                }
385                                                           
386                p = Ext.urlEncode(me.extraParams, Ext.isObject(p) ? Ext.urlEncode(p) : p);   
387               
388                if (Ext.isFunction(url)) {
389                    url = url.call(o.scope || WINDOW, o);
390                }
391   
392                if((form = Ext.getDom(o.form))){
393                    url = url || form.action;
394                     if(o.isUpload || /multipart\/form-data/i.test(form.getAttribute("enctype"))) { 
395                         return doFormUpload.call(me, o, p, url);
396                     }
397                    serForm = Ext.lib.Ajax.serializeForm(form);                   
398                    p = p ? (p + '&' + serForm) : serForm;
399                }
400               
401                method = o.method || me.method || ((p || o.xmlData || o.jsonData) ? POST : GET);
402               
403                if(method === GET && (me.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
404                    var dcp = o.disableCachingParam || me.disableCachingParam;
405                    url = Ext.urlAppend(url, dcp + '=' + (new Date().getTime()));
406                }
407               
408                o.headers = Ext.apply(o.headers || {}, me.defaultHeaders || {});
409               
410                if(o.autoAbort === true || me.autoAbort) {
411                    me.abort();
412                }
413                 
414                if((method == GET || o.xmlData || o.jsonData) && p){
415                    url = Ext.urlAppend(url, p); 
416                    p = '';
417                }
418                return (me.transId = Ext.lib.Ajax.request(method, url, cb, p, o));
419            }else{               
420                return o.callback ? o.callback.apply(o.scope, [o,UNDEFINED,UNDEFINED]) : null;
421            }
422        },
423   
424        /**
425         * Determine whether this object has a request outstanding.
426         * @param {Number} transactionId (Optional) defaults to the last transaction
427         * @return {Boolean} True if there is an outstanding request.
428         */
429        isLoading : function(transId){
430            return transId ? Ext.lib.Ajax.isCallInProgress(transId) : !! this.transId;           
431        },
432   
433        /**
434         * Aborts any outstanding request.
435         * @param {Number} transactionId (Optional) defaults to the last transaction
436         */
437        abort : function(transId){
438            if(transId || this.isLoading()){
439                Ext.lib.Ajax.abort(transId || this.transId);
440            }
441        }
442    });
443})();
444
445/**
446 * @class Ext.Ajax
447 * @extends Ext.data.Connection
448 * <p>The global Ajax request class that provides a simple way to make Ajax requests
449 * with maximum flexibility.</p>
450 * <p>Since Ext.Ajax is a singleton, you can set common properties/events for it once
451 * and override them at the request function level only if necessary.</p>
452 * <p>Common <b>Properties</b> you may want to set are:<div class="mdetail-params"><ul>
453 * <li><b><tt>{@link #method}</tt></b><p class="sub-desc"></p></li>
454 * <li><b><tt>{@link #extraParams}</tt></b><p class="sub-desc"></p></li>
455 * <li><b><tt>{@link #url}</tt></b><p class="sub-desc"></p></li>
456 * </ul></div>
457 * <pre><code>
458// Default headers to pass in every request
459Ext.Ajax.defaultHeaders = {
460    'Powered-By': 'Ext'
461};
462 * </code></pre>
463 * </p>
464 * <p>Common <b>Events</b> you may want to set are:<div class="mdetail-params"><ul>
465 * <li><b><tt>{@link Ext.data.Connection#beforerequest beforerequest}</tt></b><p class="sub-desc"></p></li>
466 * <li><b><tt>{@link Ext.data.Connection#requestcomplete requestcomplete}</tt></b><p class="sub-desc"></p></li>
467 * <li><b><tt>{@link Ext.data.Connection#requestexception requestexception}</tt></b><p class="sub-desc"></p></li>
468 * </ul></div>
469 * <pre><code>
470// Example: show a spinner during all Ajax requests
471Ext.Ajax.on('beforerequest', this.showSpinner, this);
472Ext.Ajax.on('requestcomplete', this.hideSpinner, this);
473Ext.Ajax.on('requestexception', this.hideSpinner, this);
474 * </code></pre>
475 * </p>
476 * <p>An example request:</p>
477 * <pre><code>
478// Basic request
479Ext.Ajax.{@link Ext.data.Connection#request request}({
480   url: 'foo.php',
481   success: someFn,
482   failure: otherFn,
483   headers: {
484       'my-header': 'foo'
485   },
486   params: { foo: 'bar' }
487});
488
489// Simple ajax form submission
490Ext.Ajax.{@link Ext.data.Connection#request request}({
491    form: 'some-form',
492    params: 'foo=bar'
493});
494 * </code></pre>
495 * </p>
496 * @singleton
497 */
498Ext.Ajax = new Ext.data.Connection({
499    /**
500     * @cfg {String} url @hide
501     */
502    /**
503     * @cfg {Object} extraParams @hide
504     */
505    /**
506     * @cfg {Object} defaultHeaders @hide
507     */
508    /**
509     * @cfg {String} method (Optional) @hide
510     */
511    /**
512     * @cfg {Number} timeout (Optional) @hide
513     */
514    /**
515     * @cfg {Boolean} autoAbort (Optional) @hide
516     */
517
518    /**
519     * @cfg {Boolean} disableCaching (Optional) @hide
520     */
521
522    /**
523     * @property  disableCaching
524     * True to add a unique cache-buster param to GET requests. (defaults to true)
525     * @type Boolean
526     */
527    /**
528     * @property  url
529     * The default URL to be used for requests to the server. (defaults to undefined)
530     * If the server receives all requests through one URL, setting this once is easier than
531     * entering it on every request.
532     * @type String
533     */
534    /**
535     * @property  extraParams
536     * An object containing properties which are used as extra parameters to each request made
537     * by this object (defaults to undefined). Session information and other data that you need
538     * to pass with each request are commonly put here.
539     * @type Object
540     */
541    /**
542     * @property  defaultHeaders
543     * An object containing request headers which are added to each request made by this object
544     * (defaults to undefined).
545     * @type Object
546     */
547    /**
548     * @property  method
549     * The default HTTP method to be used for requests. Note that this is case-sensitive and
550     * should be all caps (defaults to undefined; if not set but params are present will use
551     * <tt>"POST"</tt>, otherwise will use <tt>"GET"</tt>.)
552     * @type String
553     */
554    /**
555     * @property  timeout
556     * The timeout in milliseconds to be used for requests. (defaults to 30000)
557     * @type Number
558     */
559
560    /**
561     * @property  autoAbort
562     * Whether a new request should abort any pending requests. (defaults to false)
563     * @type Boolean
564     */
565    autoAbort : false,
566
567    /**
568     * Serialize the passed form into a url encoded string
569     * @param {String/HTMLElement} form
570     * @return {String}
571     */
572    serializeForm : function(form){
573        return Ext.lib.Ajax.serializeForm(form);
574    }
575});
Note: See TracBrowser for help on using the repository browser.