Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / src / ElementLoader.js
1 /*
2
3 This file is part of Ext JS 4
4
5 Copyright (c) 2011 Sencha Inc
6
7 Contact:  http://www.sencha.com/contact
8
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file.  Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
11
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
13
14 */
15 /**
16  * @class Ext.ElementLoader
17  * A class used to load remote content to an Element. Sample usage:
18  * <pre><code>
19 Ext.get('el').load({
20     url: 'myPage.php',
21     scripts: true,
22     params: {
23         id: 1
24     }
25 });
26  * </code></pre>
27  * <p>
28  * In general this class will not be instanced directly, rather the {@link Ext.core.Element#load} method
29  * will be used.
30  * </p>
31  */
32 Ext.define('Ext.ElementLoader', {
33
34     /* Begin Definitions */
35
36     mixins: {
37         observable: 'Ext.util.Observable'
38     },
39
40     uses: [
41         'Ext.data.Connection',
42         'Ext.Ajax'
43     ],
44     
45     statics: {
46         Renderer: {
47             Html: function(loader, response, active){
48                 loader.getTarget().update(response.responseText, active.scripts === true);
49                 return true;
50             }
51         }     
52     },
53
54     /* End Definitions */
55
56     /**
57      * @cfg {String} url The url to retrieve the content from. Defaults to <tt>null</tt>.
58      */
59     url: null,
60
61     /**
62      * @cfg {Object} params Any params to be attached to the Ajax request. These parameters will
63      * be overridden by any params in the load options. Defaults to <tt>null</tt>.
64      */
65     params: null,
66
67     /**
68      * @cfg {Object} baseParams Params that will be attached to every request. These parameters
69      * will not be overridden by any params in the load options. Defaults to <tt>null</tt>.
70      */
71     baseParams: null,
72
73     /**
74      * @cfg {Boolean/Object} autoLoad True to have the loader make a request as soon as it is created. Defaults to <tt>false</tt>.
75      * This argument can also be a set of options that will be passed to {@link #load} is called.
76      */
77     autoLoad: false,
78
79     /**
80      * @cfg {Mixed} target The target element for the loader. It can be the DOM element, the id or an Ext.Element.
81      */
82     target: null,
83
84     /**
85      * @cfg {Mixed} loadMask True or a string to show when the element is loading.
86      */
87     loadMask: false,
88
89     /**
90      * @cfg {Object} ajaxOptions Any additional options to be passed to the request, for example timeout or headers. Defaults to <tt>null</tt>.
91      */
92     ajaxOptions: null,
93     
94     /**
95      * @cfg {Boolean} scripts True to parse any inline script tags in the response.
96      */
97     scripts: false,
98
99     /**
100      * @cfg {Function} success A function to be called when a load request is successful.
101      */
102
103     /**
104      * @cfg {Function} failure A function to be called when a load request fails.
105      */
106
107     /**
108      * @cfg {Object} scope The scope to execute the {@link #success} and {@link #failure} functions in.
109      */
110     
111     /**
112      * @cfg {Function} renderer A custom function to render the content to the element. The passed parameters
113      * are
114      * <ul>
115      * <li>The loader</li>
116      * <li>The response</li>
117      * <li>The active request</li>
118      * </ul>
119      */
120
121     isLoader: true,
122
123     constructor: function(config) {
124         var me = this,
125             autoLoad;
126         
127         config = config || {};
128         Ext.apply(me, config);
129         me.setTarget(me.target);
130         me.addEvents(
131             /**
132              * @event beforeload
133              * Fires before a load request is made to the server.
134              * Returning false from an event listener can prevent the load
135              * from occurring.
136              * @param {Ext.ElementLoader} this
137              * @param {Object} options The options passed to the request
138              */
139             'beforeload',
140
141             /**
142              * @event exception
143              * Fires after an unsuccessful load.
144              * @param {Ext.ElementLoader} this
145              * @param {Object} response The response from the server
146              * @param {Object} options The options passed to the request
147              */
148             'exception',
149
150             /**
151              * @event exception
152              * Fires after a successful load.
153              * @param {Ext.ElementLoader} this
154              * @param {Object} response The response from the server
155              * @param {Object} options The options passed to the request
156              */
157             'load'
158         );
159
160         // don't pass config because we have already applied it.
161         me.mixins.observable.constructor.call(me);
162
163         if (me.autoLoad) {
164             autoLoad = me.autoLoad;
165             if (autoLoad === true) {
166                 autoLoad = {};
167             }
168             me.load(autoLoad);
169         }
170     },
171
172     /**
173      * Set an {Ext.Element} as the target of this loader. Note that if the target is changed,
174      * any active requests will be aborted.
175      * @param {Mixed} target The element
176      */
177     setTarget: function(target){
178         var me = this;
179         target = Ext.get(target);
180         if (me.target && me.target != target) {
181             me.abort();
182         }
183         me.target = target;
184     },
185
186     /**
187      * Get the target of this loader.
188      * @return {Ext.Component} target The target, null if none exists.
189      */
190     getTarget: function(){
191         return this.target || null;
192     },
193
194     /**
195      * Aborts the active load request
196      */
197     abort: function(){
198         var active = this.active;
199         if (active !== undefined) {
200             Ext.Ajax.abort(active.request);
201             if (active.mask) {
202                 this.removeMask();
203             }
204             delete this.active;
205         }
206     },
207     
208     /**
209      * Remove the mask on the target
210      * @private
211      */
212     removeMask: function(){
213         this.target.unmask();
214     },
215     
216     /**
217      * Add the mask on the target
218      * @private
219      * @param {Mixed} mask The mask configuration
220      */
221     addMask: function(mask){
222         this.target.mask(mask === true ? null : mask);
223     },
224
225     /**
226      * Load new data from the server.
227      * @param {Object} options The options for the request. They can be any configuration option that can be specified for
228      * the class, with the exception of the target option. Note that any options passed to the method will override any
229      * class defaults.
230      */
231     load: function(options) {
232         //<debug>
233         if (!this.target) {
234             Ext.Error.raise('A valid target is required when loading content');
235         }
236         //</debug>
237
238         options = Ext.apply({}, options);
239
240         var me = this,
241             target = me.target,
242             mask = Ext.isDefined(options.loadMask) ? options.loadMask : me.loadMask,
243             params = Ext.apply({}, options.params),
244             ajaxOptions = Ext.apply({}, options.ajaxOptions),
245             callback = options.callback || me.callback,
246             scope = options.scope || me.scope || me,
247             request;
248
249         Ext.applyIf(ajaxOptions, me.ajaxOptions);
250         Ext.applyIf(options, ajaxOptions);
251
252         Ext.applyIf(params, me.params);
253         Ext.apply(params, me.baseParams);
254
255         Ext.applyIf(options, {
256             url: me.url
257         });
258
259         //<debug>
260         if (!options.url) {
261             Ext.Error.raise('You must specify the URL from which content should be loaded');
262         }
263         //</debug>
264
265         Ext.apply(options, {
266             scope: me,
267             params: params,
268             callback: me.onComplete
269         });
270
271         if (me.fireEvent('beforeload', me, options) === false) {
272             return;
273         }
274
275         if (mask) {
276             me.addMask(mask);
277         }
278
279         request = Ext.Ajax.request(options);
280         me.active = {
281             request: request,
282             options: options,
283             mask: mask,
284             scope: scope,
285             callback: callback,
286             success: options.success || me.success,
287             failure: options.failure || me.failure,
288             renderer: options.renderer || me.renderer,
289             scripts: Ext.isDefined(options.scripts) ? options.scripts : me.scripts
290         };
291         me.setOptions(me.active, options);
292     },
293     
294     /**
295      * Set any additional options on the active request
296      * @private
297      * @param {Object} active The active request
298      * @param {Object} options The initial options
299      */
300     setOptions: Ext.emptyFn,
301
302     /**
303      * Parse the response after the request completes
304      * @private
305      * @param {Object} options Ajax options
306      * @param {Boolean} success Success status of the request
307      * @param {Object} response The response object
308      */
309     onComplete: function(options, success, response) {
310         var me = this,
311             active = me.active,
312             scope = active.scope,
313             renderer = me.getRenderer(active.renderer);
314
315
316         if (success) {
317             success = renderer.call(me, me, response, active);
318         }
319
320         if (success) {
321             Ext.callback(active.success, scope, [me, response, options]);
322             me.fireEvent('load', me, response, options);
323         } else {
324             Ext.callback(active.failure, scope, [me, response, options]);
325             me.fireEvent('exception', me, response, options);
326         }
327         Ext.callback(active.callback, scope, [me, success, response, options]);
328
329         if (active.mask) {
330             me.removeMask();
331         }
332
333         delete me.active;
334     },
335
336     /**
337      * Gets the renderer to use
338      * @private
339      * @param {String/Function} renderer The renderer to use
340      * @return {Function} A rendering function to use.
341      */
342     getRenderer: function(renderer){
343         if (Ext.isFunction(renderer)) {
344             return renderer;
345         }
346         return this.statics().Renderer.Html;
347     },
348     
349     /**
350      * Automatically refreshes the content over a specified period.
351      * @param {Number} interval The interval to refresh in ms.
352      * @param {Object} options (optional) The options to pass to the load method. See {@link #load}
353      */
354     startAutoRefresh: function(interval, options){
355         var me = this;
356         me.stopAutoRefresh();
357         me.autoRefresh = setInterval(function(){
358             me.load(options);
359         }, interval);
360     },
361     
362     /**
363      * Clears any auto refresh. See {@link #startAutoRefresh}.
364      */
365     stopAutoRefresh: function(){
366         clearInterval(this.autoRefresh);
367         delete this.autoRefresh;
368     },
369     
370     /**
371      * Checks whether the loader is automatically refreshing. See {@link #startAutoRefresh}.
372      * @return {Boolean} True if the loader is automatically refreshing
373      */
374     isAutoRefreshing: function(){
375         return Ext.isDefined(this.autoRefresh);
376     },
377
378     /**
379      * Destroys the loader. Any active requests will be aborted.
380      */
381     destroy: function(){
382         var me = this;
383         me.stopAutoRefresh();
384         delete me.target;
385         me.abort();
386         me.clearListeners();
387     }
388 });
389