initial import
[roojs1] / Roo / UpdateManager.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11
12  
13 /**
14  * @class Roo.UpdateManager
15  * @extends Roo.util.Observable
16  * Provides AJAX-style update for Element object.<br><br>
17  * Usage:<br>
18  * <pre><code>
19  * // Get it from a Roo.Element object
20  * var el = Roo.get("foo");
21  * var mgr = el.getUpdateManager();
22  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
23  * ...
24  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
25  * <br>
26  * // or directly (returns the same UpdateManager instance)
27  * var mgr = new Roo.UpdateManager("myElementId");
28  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
29  * mgr.on("update", myFcnNeedsToKnow);
30  * <br>
31    // short handed call directly from the element object
32    Roo.get("foo").load({
33         url: "bar.php",
34         scripts:true,
35         params: "for=bar",
36         text: "Loading Foo..."
37    });
38  * </code></pre>
39  * @constructor
40  * Create new UpdateManager directly.
41  * @param {String/HTMLElement/Roo.Element} el The element to update
42  * @param {Boolean} forceNew (optional) By default the constructor checks to see if the passed element already has an UpdateManager and if it does it returns the same instance. This will skip that check (useful for extending this class).
43  */
44 Roo.UpdateManager = function(el, forceNew){
45     el = Roo.get(el);
46     if(!forceNew && el.updateManager){
47         return el.updateManager;
48     }
49     /**
50      * The Element object
51      * @type Roo.Element
52      */
53     this.el = el;
54     /**
55      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
56      * @type String
57      */
58     this.defaultUrl = null;
59
60     this.addEvents({
61         /**
62          * @event beforeupdate
63          * Fired before an update is made, return false from your handler and the update is cancelled.
64          * @param {Roo.Element} el
65          * @param {String/Object/Function} url
66          * @param {String/Object} params
67          */
68         "beforeupdate": true,
69         /**
70          * @event update
71          * Fired after successful update is made.
72          * @param {Roo.Element} el
73          * @param {Object} oResponseObject The response Object
74          */
75         "update": true,
76         /**
77          * @event failure
78          * Fired on update failure.
79          * @param {Roo.Element} el
80          * @param {Object} oResponseObject The response Object
81          */
82         "failure": true
83     });
84     var d = Roo.UpdateManager.defaults;
85     /**
86      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
87      * @type String
88      */
89     this.sslBlankUrl = d.sslBlankUrl;
90     /**
91      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
92      * @type Boolean
93      */
94     this.disableCaching = d.disableCaching;
95     /**
96      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
97      * @type String
98      */
99     this.indicatorText = d.indicatorText;
100     /**
101      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
102      * @type String
103      */
104     this.showLoadIndicator = d.showLoadIndicator;
105     /**
106      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
107      * @type Number
108      */
109     this.timeout = d.timeout;
110
111     /**
112      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
113      * @type Boolean
114      */
115     this.loadScripts = d.loadScripts;
116
117     /**
118      * Transaction object of current executing transaction
119      */
120     this.transaction = null;
121
122     /**
123      * @private
124      */
125     this.autoRefreshProcId = null;
126     /**
127      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
128      * @type Function
129      */
130     this.refreshDelegate = this.refresh.createDelegate(this);
131     /**
132      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
133      * @type Function
134      */
135     this.updateDelegate = this.update.createDelegate(this);
136     /**
137      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
138      * @type Function
139      */
140     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
141     /**
142      * @private
143      */
144     this.successDelegate = this.processSuccess.createDelegate(this);
145     /**
146      * @private
147      */
148     this.failureDelegate = this.processFailure.createDelegate(this);
149
150     if(!this.renderer){
151      /**
152       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
153       */
154     this.renderer = new Roo.UpdateManager.BasicRenderer();
155     }
156     
157     Roo.UpdateManager.superclass.constructor.call(this);
158 };
159
160 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
161     /**
162      * Get the Element this UpdateManager is bound to
163      * @return {Roo.Element} The element
164      */
165     getEl : function(){
166         return this.el;
167     },
168     /**
169      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
170      * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
171 <pre><code>
172 um.update({<br/>
173     url: "your-url.php",<br/>
174     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
175     callback: yourFunction,<br/>
176     scope: yourObject, //(optional scope)  <br/>
177     discardUrl: false, <br/>
178     nocache: false,<br/>
179     text: "Loading...",<br/>
180     timeout: 30,<br/>
181     scripts: false<br/>
182 });
183 </code></pre>
184      * The only required property is url. The optional properties nocache, text and scripts
185      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
186      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "param1=1&amp;param2=2" or an object {param1: 1, param2: 2}
187      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
188      * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used url. If true, it will not store the url.
189      */
190     update : function(url, params, callback, discardUrl){
191         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
192             var method = this.method, cfg;
193             if(typeof url == "object"){ // must be config object
194                 cfg = url;
195                 url = cfg.url;
196                 params = params || cfg.params;
197                 callback = callback || cfg.callback;
198                 discardUrl = discardUrl || cfg.discardUrl;
199                 if(callback && cfg.scope){
200                     callback = callback.createDelegate(cfg.scope);
201                 }
202                 if(typeof cfg.method != "undefined"){method = cfg.method;};
203                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
204                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
205                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
206                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
207             }
208             this.showLoading();
209             if(!discardUrl){
210                 this.defaultUrl = url;
211             }
212             if(typeof url == "function"){
213                 url = url.call(this);
214             }
215
216             method = method || (params ? "POST" : "GET");
217             if(method == "GET"){
218                 url = this.prepareUrl(url);
219             }
220
221             var o = Roo.apply(cfg ||{}, {
222                 url : url,
223                 params: params,
224                 success: this.successDelegate,
225                 failure: this.failureDelegate,
226                 callback: undefined,
227                 timeout: (this.timeout*1000),
228                 argument: {"url": url, "form": null, "callback": callback, "params": params}
229             });
230
231             this.transaction = Roo.Ajax.request(o);
232         }
233     },
234
235     /**
236      * Performs an async form post, updating this element with the response. If the form has the attribute enctype="multipart/form-data", it assumes it's a file upload.
237      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
238      * @param {String/HTMLElement} form The form Id or form element
239      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
240      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
241      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
242      */
243     formUpdate : function(form, url, reset, callback){
244         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
245             if(typeof url == "function"){
246                 url = url.call(this);
247             }
248             form = Roo.getDom(form);
249             this.transaction = Roo.Ajax.request({
250                 form: form,
251                 url:url,
252                 success: this.successDelegate,
253                 failure: this.failureDelegate,
254                 timeout: (this.timeout*1000),
255                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
256             });
257             this.showLoading.defer(1, this);
258         }
259     },
260
261     /**
262      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
263      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
264      */
265     refresh : function(callback){
266         if(this.defaultUrl == null){
267             return;
268         }
269         this.update(this.defaultUrl, null, callback, true);
270     },
271
272     /**
273      * Set this element to auto refresh.
274      * @param {Number} interval How often to update (in seconds).
275      * @param {String/Function} url (optional) The url for this request or a function to call to get the url (Defaults to the last used url)
276      * @param {String/Object} params (optional) The parameters to pass as either a url encoded string "&param1=1&param2=2" or as an object {param1: 1, param2: 2}
277      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
278      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
279      */
280     startAutoRefresh : function(interval, url, params, callback, refreshNow){
281         if(refreshNow){
282             this.update(url || this.defaultUrl, params, callback, true);
283         }
284         if(this.autoRefreshProcId){
285             clearInterval(this.autoRefreshProcId);
286         }
287         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
288     },
289
290     /**
291      * Stop auto refresh on this element.
292      */
293      stopAutoRefresh : function(){
294         if(this.autoRefreshProcId){
295             clearInterval(this.autoRefreshProcId);
296             delete this.autoRefreshProcId;
297         }
298     },
299
300     isAutoRefreshing : function(){
301        return this.autoRefreshProcId ? true : false;
302     },
303     /**
304      * Called to update the element to "Loading" state. Override to perform custom action.
305      */
306     showLoading : function(){
307         if(this.showLoadIndicator){
308             this.el.update(this.indicatorText);
309         }
310     },
311
312     /**
313      * Adds unique parameter to query string if disableCaching = true
314      * @private
315      */
316     prepareUrl : function(url){
317         if(this.disableCaching){
318             var append = "_dc=" + (new Date().getTime());
319             if(url.indexOf("?") !== -1){
320                 url += "&" + append;
321             }else{
322                 url += "?" + append;
323             }
324         }
325         return url;
326     },
327
328     /**
329      * @private
330      */
331     processSuccess : function(response){
332         this.transaction = null;
333         if(response.argument.form && response.argument.reset){
334             try{ // put in try/catch since some older FF releases had problems with this
335                 response.argument.form.reset();
336             }catch(e){}
337         }
338         if(this.loadScripts){
339             this.renderer.render(this.el, response, this,
340                 this.updateComplete.createDelegate(this, [response]));
341         }else{
342             this.renderer.render(this.el, response, this);
343             this.updateComplete(response);
344         }
345     },
346
347     updateComplete : function(response){
348         this.fireEvent("update", this.el, response);
349         if(typeof response.argument.callback == "function"){
350             response.argument.callback(this.el, true, response);
351         }
352     },
353
354     /**
355      * @private
356      */
357     processFailure : function(response){
358         this.transaction = null;
359         this.fireEvent("failure", this.el, response);
360         if(typeof response.argument.callback == "function"){
361             response.argument.callback(this.el, false, response);
362         }
363     },
364
365     /**
366      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
367      * @param {Object} renderer The object implementing the render() method
368      */
369     setRenderer : function(renderer){
370         this.renderer = renderer;
371     },
372
373     getRenderer : function(){
374        return this.renderer;
375     },
376
377     /**
378      * Set the defaultUrl used for updates
379      * @param {String/Function} defaultUrl The url or a function to call to get the url
380      */
381     setDefaultUrl : function(defaultUrl){
382         this.defaultUrl = defaultUrl;
383     },
384
385     /**
386      * Aborts the executing transaction
387      */
388     abort : function(){
389         if(this.transaction){
390             Roo.Ajax.abort(this.transaction);
391         }
392     },
393
394     /**
395      * Returns true if an update is in progress
396      * @return {Boolean}
397      */
398     isUpdating : function(){
399         if(this.transaction){
400             return Roo.Ajax.isLoading(this.transaction);
401         }
402         return false;
403     }
404 });
405
406 /**
407  * @class Roo.UpdateManager.defaults
408  * @static (not really - but it helps the doc tool)
409  * The defaults collection enables customizing the default properties of UpdateManager
410  */
411    Roo.UpdateManager.defaults = {
412        /**
413          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
414          * @type Number
415          */
416          timeout : 30,
417
418          /**
419          * True to process scripts by default (Defaults to false).
420          * @type Boolean
421          */
422         loadScripts : false,
423
424         /**
425         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
426         * @type String
427         */
428         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
429         /**
430          * Whether to append unique parameter on get request to disable caching (Defaults to false).
431          * @type Boolean
432          */
433         disableCaching : false,
434         /**
435          * Whether to show indicatorText when loading (Defaults to true).
436          * @type Boolean
437          */
438         showLoadIndicator : true,
439         /**
440          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
441          * @type String
442          */
443         indicatorText : '<div class="loading-indicator">Loading...</div>'
444    };
445
446 /**
447  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
448  *Usage:
449  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
450  * @param {String/HTMLElement/Roo.Element} el The element to update
451  * @param {String} url The url
452  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
453  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
454  * @static
455  * @deprecated
456  * @member Roo.UpdateManager
457  */
458 Roo.UpdateManager.updateElement = function(el, url, params, options){
459     var um = Roo.get(el, true).getUpdateManager();
460     Roo.apply(um, options);
461     um.update(url, params, options ? options.callback : null);
462 };
463 // alias for backwards compat
464 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
465 /**
466  * @class Roo.UpdateManager.BasicRenderer
467  * Default Content renderer. Updates the elements innerHTML with the responseText.
468  */
469 Roo.UpdateManager.BasicRenderer = function(){};
470
471 Roo.UpdateManager.BasicRenderer.prototype = {
472     /**
473      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
474      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
475      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
476      * @param {Roo.Element} el The element being rendered
477      * @param {Object} response The YUI Connect response object
478      * @param {UpdateManager} updateManager The calling update manager
479      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
480      */
481      render : function(el, response, updateManager, callback){
482         el.update(response.responseText, updateManager.loadScripts, callback);
483     }
484 };