3 * Copyright(c) 2006-2010 Ext JS, Inc.
5 * http://www.extjs.com/license
8 * @class Ext.tree.TreeLoader
9 * @extends Ext.util.Observable
10 * A TreeLoader provides for lazy loading of an {@link Ext.tree.TreeNode}'s child
11 * nodes from a specified URL. The response must be a JavaScript Array definition
12 * whose elements are node definition objects. e.g.:
20 text: 'A folder Node',
29 * A server request is sent, and child nodes are loaded only when a node is expanded.
30 * The loading node's id is passed to the server under the parameter name "node" to
31 * enable the server to produce the correct child nodes.
33 * To pass extra parameters, an event handler may be attached to the "beforeload"
34 * event, and the parameters specified in the TreeLoader's baseParams property:
36 myTreeLoader.on("beforeload", function(treeLoader, node) {
37 this.baseParams.category = node.attributes.category;
40 * This would pass an HTTP parameter called "category" to the server containing
41 * the value of the Node's "category" attribute.
43 * Creates a new Treeloader.
44 * @param {Object} config A config object containing config properties.
46 Ext.tree.TreeLoader = function(config){
48 Ext.apply(this, config);
53 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
54 * @param {Object} This TreeLoader object.
55 * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
56 * @param {Object} callback The callback function specified in the {@link #load} call.
61 * Fires when the node has been successfuly loaded.
62 * @param {Object} This TreeLoader object.
63 * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
64 * @param {Object} response The response object containing the data from the server.
68 * @event loadexception
69 * Fires if the network request failed.
70 * @param {Object} This TreeLoader object.
71 * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.
72 * @param {Object} response The response object containing the data from the server.
76 Ext.tree.TreeLoader.superclass.constructor.call(this);
77 if(Ext.isString(this.paramOrder)){
78 this.paramOrder = this.paramOrder.split(/[\s,|]/);
82 Ext.extend(Ext.tree.TreeLoader, Ext.util.Observable, {
84 * @cfg {String} dataUrl The URL from which to request a Json string which
85 * specifies an array of node definition objects representing the child nodes
89 * @cfg {String} requestMethod The HTTP request method for loading data (defaults to the value of {@link Ext.Ajax#method}).
92 * @cfg {String} url Equivalent to {@link #dataUrl}.
95 * @cfg {Boolean} preloadChildren If set to true, the loader recursively loads "children" attributes when doing the first load on nodes.
98 * @cfg {Object} baseParams (optional) An object containing properties which
99 * specify HTTP parameters to be passed to each request for child nodes.
102 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
103 * created by this loader. If the attributes sent by the server have an attribute in this object,
104 * they take priority.
107 * @cfg {Object} uiProviders (optional) An object containing properties which
108 * specify custom {@link Ext.tree.TreeNodeUI} implementations. If the optional
109 * <i>uiProvider</i> attribute of a returned child node is a string rather
110 * than a reference to a TreeNodeUI implementation, then that string value
111 * is used as a property name in the uiProviders object.
116 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
117 * child nodes before loading.
122 * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. Only used when using directFn.
123 * Specifies the params in the order in which they must be passed to the server-side Direct method
124 * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,
125 * comma, or pipe. For example,
126 * any of the following would be acceptable:<pre><code>
127 nodeParameter: 'node',
128 paramOrder: ['param1','param2','param3']
129 paramOrder: 'node param1 param2 param3'
130 paramOrder: 'param1,node,param2,param3'
131 paramOrder: 'param1|param2|param|node'
134 paramOrder: undefined,
137 * @cfg {Boolean} paramsAsHash Only used when using directFn.
138 * Send parameters as a collection of named arguments (defaults to <tt>false</tt>). Providing a
139 * <tt>{@link #paramOrder}</tt> nullifies this configuration.
144 * @cfg {String} nodeParameter The name of the parameter sent to the server which contains
145 * the identifier of the node. Defaults to <tt>'node'</tt>.
147 nodeParameter: 'node',
150 * @cfg {Function} directFn
151 * Function to call when executing a request.
153 directFn : undefined,
156 * Load an {@link Ext.tree.TreeNode} from the URL specified in the constructor.
157 * This is called automatically when a node is expanded, but may be used to reload
158 * a node (or append new children if the {@link #clearOnLoad} option is false.)
159 * @param {Ext.tree.TreeNode} node
160 * @param {Function} callback Function to call after the node has been loaded. The
161 * function is passed the TreeNode which was requested to be loaded.
162 * @param {Object} scope The scope (<code>this</code> reference) in which the callback is executed.
163 * defaults to the loaded TreeNode.
165 load : function(node, callback, scope){
166 if(this.clearOnLoad){
167 while(node.firstChild){
168 node.removeChild(node.firstChild);
171 if(this.doPreload(node)){ // preloaded json children
172 this.runCallback(callback, scope || node, [node]);
173 }else if(this.directFn || this.dataUrl || this.url){
174 this.requestData(node, callback, scope || node);
178 doPreload : function(node){
179 if(node.attributes.children){
180 if(node.childNodes.length < 1){ // preloaded?
181 var cs = node.attributes.children;
183 for(var i = 0, len = cs.length; i < len; i++){
184 var cn = node.appendChild(this.createNode(cs[i]));
185 if(this.preloadChildren){
196 getParams: function(node){
197 var bp = Ext.apply({}, this.baseParams),
198 np = this.nodeParameter,
199 po = this.paramOrder;
201 np && (bp[ np ] = node.id);
206 // reset 'buf' if the nodeParameter was included in paramOrder
207 if(np && po.indexOf(np) > -1){
211 for(var i = 0, len = po.length; i < len; i++){
212 buf.push(bp[ po[i] ]);
214 }else if(this.paramsAsHash){
223 requestData : function(node, callback, scope){
224 if(this.fireEvent("beforeload", this, node, callback) !== false){
226 var args = this.getParams(node);
227 args.push(this.processDirectResponse.createDelegate(this, [{callback: callback, node: node, scope: scope}], true));
228 this.directFn.apply(window, args);
230 this.transId = Ext.Ajax.request({
231 method:this.requestMethod,
232 url: this.dataUrl||this.url,
233 success: this.handleResponse,
234 failure: this.handleFailure,
236 argument: {callback: callback, node: node, scope: scope},
237 params: this.getParams(node)
241 // if the load is cancelled, make sure we notify
242 // the node that we are done
243 this.runCallback(callback, scope || node, []);
247 processDirectResponse: function(result, response, args){
249 this.handleResponse({
250 responseData: Ext.isArray(result) ? result : null,
251 responseText: result,
262 runCallback: function(cb, scope, args){
263 if(Ext.isFunction(cb)){
264 cb.apply(scope, args);
268 isLoading : function(){
269 return !!this.transId;
273 if(this.isLoading()){
274 Ext.Ajax.abort(this.transId);
279 * <p>Override this function for custom TreeNode node implementation, or to
280 * modify the attributes at creation time.</p>
281 * Example:<pre><code>
282 new Ext.tree.TreePanel({
284 loader: new Ext.tree.TreeLoader({
286 createNode: function(attr) {
287 // Allow consolidation consignments to have
288 // consignments dropped into them.
289 if (attr.isConsolidation) {
290 attr.iconCls = 'x-consol',
291 attr.allowDrop = true;
293 return Ext.tree.TreeLoader.prototype.createNode.call(this, attr);
299 * @param attr {Object} The attributes from which to create the new node.
301 createNode : function(attr){
302 // apply baseAttrs, nice idea Corey!
304 Ext.applyIf(attr, this.baseAttrs);
306 if(this.applyLoader !== false && !attr.loader){
309 if(Ext.isString(attr.uiProvider)){
310 attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);
313 return new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr);
316 new Ext.tree.TreeNode(attr) :
317 new Ext.tree.AsyncTreeNode(attr);
321 processResponse : function(response, node, callback, scope){
322 var json = response.responseText;
324 var o = response.responseData || Ext.decode(json);
326 for(var i = 0, len = o.length; i < len; i++){
327 var n = this.createNode(o[i]);
333 this.runCallback(callback, scope || node, [node]);
335 this.handleFailure(response);
339 handleResponse : function(response){
340 this.transId = false;
341 var a = response.argument;
342 this.processResponse(response, a.node, a.callback, a.scope);
343 this.fireEvent("load", this, a.node, response);
346 handleFailure : function(response){
347 this.transId = false;
348 var a = response.argument;
349 this.fireEvent("loadexception", this, a.node, response);
350 this.runCallback(a.callback, a.scope || a.node, [a.node]);
353 destroy : function(){
355 this.purgeListeners();