--- /dev/null
+/*!
+ * Ext JS Library 3.0.0
+ * Copyright(c) 2006-2009 Ext JS, LLC
+ * licensing@extjs.com
+ * http://www.extjs.com/license
+ */
+/**\r
+ * @class Ext.tree.TreeLoader\r
+ * @extends Ext.util.Observable\r
+ * A TreeLoader provides for lazy loading of an {@link Ext.tree.TreeNode}'s child\r
+ * nodes from a specified URL. The response must be a JavaScript Array definition\r
+ * whose elements are node definition objects. e.g.:\r
+ * <pre><code>\r
+ [{\r
+ id: 1,\r
+ text: 'A leaf Node',\r
+ leaf: true\r
+ },{\r
+ id: 2,\r
+ text: 'A folder Node',\r
+ children: [{\r
+ id: 3,\r
+ text: 'A child Node',\r
+ leaf: true\r
+ }]\r
+ }]\r
+</code></pre>\r
+ * <br><br>\r
+ * A server request is sent, and child nodes are loaded only when a node is expanded.\r
+ * The loading node's id is passed to the server under the parameter name "node" to\r
+ * enable the server to produce the correct child nodes.\r
+ * <br><br>\r
+ * To pass extra parameters, an event handler may be attached to the "beforeload"\r
+ * event, and the parameters specified in the TreeLoader's baseParams property:\r
+ * <pre><code>\r
+ myTreeLoader.on("beforeload", function(treeLoader, node) {\r
+ this.baseParams.category = node.attributes.category;\r
+ }, this);\r
+</code></pre>\r
+ * This would pass an HTTP parameter called "category" to the server containing\r
+ * the value of the Node's "category" attribute.\r
+ * @constructor\r
+ * Creates a new Treeloader.\r
+ * @param {Object} config A config object containing config properties.\r
+ */\r
+Ext.tree.TreeLoader = function(config){\r
+ this.baseParams = {};\r
+ Ext.apply(this, config);\r
+\r
+ this.addEvents(\r
+ /**\r
+ * @event beforeload\r
+ * Fires before a network request is made to retrieve the Json text which specifies a node's children.\r
+ * @param {Object} This TreeLoader object.\r
+ * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.\r
+ * @param {Object} callback The callback function specified in the {@link #load} call.\r
+ */\r
+ "beforeload",\r
+ /**\r
+ * @event load\r
+ * Fires when the node has been successfuly loaded.\r
+ * @param {Object} This TreeLoader object.\r
+ * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.\r
+ * @param {Object} response The response object containing the data from the server.\r
+ */\r
+ "load",\r
+ /**\r
+ * @event loadexception\r
+ * Fires if the network request failed.\r
+ * @param {Object} This TreeLoader object.\r
+ * @param {Object} node The {@link Ext.tree.TreeNode} object being loaded.\r
+ * @param {Object} response The response object containing the data from the server.\r
+ */\r
+ "loadexception"\r
+ );\r
+ Ext.tree.TreeLoader.superclass.constructor.call(this);\r
+ if(typeof this.paramOrder == 'string'){\r
+ this.paramOrder = this.paramOrder.split(/[\s,|]/);\r
+ }\r
+};\r
+\r
+Ext.extend(Ext.tree.TreeLoader, Ext.util.Observable, {\r
+ /**\r
+ * @cfg {String} dataUrl The URL from which to request a Json string which\r
+ * specifies an array of node definition objects representing the child nodes\r
+ * to be loaded.\r
+ */\r
+ /**\r
+ * @cfg {String} requestMethod The HTTP request method for loading data (defaults to the value of {@link Ext.Ajax#method}).\r
+ */\r
+ /**\r
+ * @cfg {String} url Equivalent to {@link #dataUrl}.\r
+ */\r
+ /**\r
+ * @cfg {Boolean} preloadChildren If set to true, the loader recursively loads "children" attributes when doing the first load on nodes.\r
+ */\r
+ /**\r
+ * @cfg {Object} baseParams (optional) An object containing properties which\r
+ * specify HTTP parameters to be passed to each request for child nodes.\r
+ */\r
+ /**\r
+ * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes\r
+ * created by this loader. If the attributes sent by the server have an attribute in this object,\r
+ * they take priority.\r
+ */\r
+ /**\r
+ * @cfg {Object} uiProviders (optional) An object containing properties which\r
+ * specify custom {@link Ext.tree.TreeNodeUI} implementations. If the optional\r
+ * <i>uiProvider</i> attribute of a returned child node is a string rather\r
+ * than a reference to a TreeNodeUI implementation, then that string value\r
+ * is used as a property name in the uiProviders object.\r
+ */\r
+ uiProviders : {},\r
+\r
+ /**\r
+ * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing\r
+ * child nodes before loading.\r
+ */\r
+ clearOnLoad : true,\r
+\r
+ /**\r
+ * @cfg {Array/String} paramOrder Defaults to <tt>undefined</tt>. Only used when using directFn.\r
+ * A list of params to be executed\r
+ * server side. Specify the params in the order in which they must be executed on the server-side\r
+ * as either (1) an Array of String values, or (2) a String of params delimited by either whitespace,\r
+ * comma, or pipe. For example,\r
+ * any of the following would be acceptable:<pre><code>\r
+paramOrder: ['param1','param2','param3']\r
+paramOrder: 'param1 param2 param3'\r
+paramOrder: 'param1,param2,param3'\r
+paramOrder: 'param1|param2|param'\r
+ </code></pre>\r
+ */\r
+ paramOrder: undefined,\r
+\r
+ /**\r
+ * @cfg {Boolean} paramsAsHash Only used when using directFn.\r
+ * Send parameters as a collection of named arguments (defaults to <tt>false</tt>). Providing a\r
+ * <tt>{@link #paramOrder}</tt> nullifies this configuration.\r
+ */\r
+ paramsAsHash: false,\r
+\r
+ /**\r
+ * @cfg {Function} directFn\r
+ * Function to call when executing a request.\r
+ */\r
+ directFn : undefined,\r
+\r
+ /**\r
+ * Load an {@link Ext.tree.TreeNode} from the URL specified in the constructor.\r
+ * This is called automatically when a node is expanded, but may be used to reload\r
+ * a node (or append new children if the {@link #clearOnLoad} option is false.)\r
+ * @param {Ext.tree.TreeNode} node\r
+ * @param {Function} callback\r
+ * @param (Object) scope\r
+ */\r
+ load : function(node, callback, scope){\r
+ if(this.clearOnLoad){\r
+ while(node.firstChild){\r
+ node.removeChild(node.firstChild);\r
+ }\r
+ }\r
+ if(this.doPreload(node)){ // preloaded json children\r
+ this.runCallback(callback, scope || node, []);\r
+ }else if(this.directFn || this.dataUrl || this.url){\r
+ this.requestData(node, callback, scope || node);\r
+ }\r
+ },\r
+\r
+ doPreload : function(node){\r
+ if(node.attributes.children){\r
+ if(node.childNodes.length < 1){ // preloaded?\r
+ var cs = node.attributes.children;\r
+ node.beginUpdate();\r
+ for(var i = 0, len = cs.length; i < len; i++){\r
+ var cn = node.appendChild(this.createNode(cs[i]));\r
+ if(this.preloadChildren){\r
+ this.doPreload(cn);\r
+ }\r
+ }\r
+ node.endUpdate();\r
+ }\r
+ return true;\r
+ }\r
+ return false;\r
+ },\r
+\r
+ getParams: function(node){\r
+ var buf = [], bp = this.baseParams;\r
+ if(this.directFn){\r
+ buf.push(node.id);\r
+ if(bp){\r
+ if(this.paramOrder){\r
+ for(var i = 0, len = this.paramOrder.length; i < len; i++){\r
+ buf.push(bp[this.paramOrder[i]]);\r
+ }\r
+ }else if(this.paramsAsHash){\r
+ buf.push(bp);\r
+ }\r
+ }\r
+ return buf;\r
+ }else{\r
+ for(var key in bp){\r
+ if(!Ext.isFunction(bp[key])){\r
+ buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");\r
+ }\r
+ }\r
+ buf.push("node=", encodeURIComponent(node.id));\r
+ return buf.join("");\r
+ }\r
+ },\r
+\r
+ requestData : function(node, callback, scope){\r
+ if(this.fireEvent("beforeload", this, node, callback) !== false){\r
+ if(this.directFn){\r
+ var args = this.getParams(node);\r
+ args.push(this.processDirectResponse.createDelegate(this, [{callback: callback, node: node, scope: scope}], true));\r
+ this.directFn.apply(window, args);\r
+ }else{\r
+ this.transId = Ext.Ajax.request({\r
+ method:this.requestMethod,\r
+ url: this.dataUrl||this.url,\r
+ success: this.handleResponse,\r
+ failure: this.handleFailure,\r
+ scope: this,\r
+ argument: {callback: callback, node: node, scope: scope},\r
+ params: this.getParams(node)\r
+ });\r
+ }\r
+ }else{\r
+ // if the load is cancelled, make sure we notify\r
+ // the node that we are done\r
+ this.runCallback(callback, scope || node, []);\r
+ }\r
+ },\r
+\r
+ processDirectResponse: function(result, response, args){\r
+ if(response.status){\r
+ this.handleResponse({\r
+ responseData: Ext.isArray(result) ? result : null,\r
+ responseText: result,\r
+ argument: args\r
+ });\r
+ }else{\r
+ this.handleFailure({\r
+ argument: args\r
+ });\r
+ }\r
+ },\r
+\r
+ // private\r
+ runCallback: function(cb, scope, args){\r
+ if(Ext.isFunction(cb)){\r
+ cb.apply(scope, args);\r
+ }\r
+ },\r
+\r
+ isLoading : function(){\r
+ return !!this.transId;\r
+ },\r
+\r
+ abort : function(){\r
+ if(this.isLoading()){\r
+ Ext.Ajax.abort(this.transId);\r
+ }\r
+ },\r
+\r
+ /**\r
+ * <p>Override this function for custom TreeNode node implementation, or to\r
+ * modify the attributes at creation time.</p>\r
+ * Example:<pre><code>\r
+new Ext.tree.TreePanel({\r
+ ...\r
+ new Ext.tree.TreeLoader({\r
+ url: 'dataUrl',\r
+ createNode: function(attr) {\r
+// Allow consolidation consignments to have\r
+// consignments dropped into them.\r
+ if (attr.isConsolidation) {\r
+ attr.iconCls = 'x-consol',\r
+ attr.allowDrop = true;\r
+ }\r
+ return Ext.tree.TreeLoader.prototype.call(this, attr);\r
+ }\r
+ }),\r
+ ...\r
+});\r
+</code></pre>\r
+ * @param attr {Object} The attributes from which to create the new node.\r
+ */\r
+ createNode : function(attr){\r
+ // apply baseAttrs, nice idea Corey!\r
+ if(this.baseAttrs){\r
+ Ext.applyIf(attr, this.baseAttrs);\r
+ }\r
+ if(this.applyLoader !== false){\r
+ attr.loader = this;\r
+ }\r
+ if(typeof attr.uiProvider == 'string'){\r
+ attr.uiProvider = this.uiProviders[attr.uiProvider] || eval(attr.uiProvider);\r
+ }\r
+ if(attr.nodeType){\r
+ return new Ext.tree.TreePanel.nodeTypes[attr.nodeType](attr);\r
+ }else{\r
+ return attr.leaf ?\r
+ new Ext.tree.TreeNode(attr) :\r
+ new Ext.tree.AsyncTreeNode(attr);\r
+ }\r
+ },\r
+\r
+ processResponse : function(response, node, callback, scope){\r
+ var json = response.responseText;\r
+ try {\r
+ var o = response.responseData || Ext.decode(json);\r
+ node.beginUpdate();\r
+ for(var i = 0, len = o.length; i < len; i++){\r
+ var n = this.createNode(o[i]);\r
+ if(n){\r
+ node.appendChild(n);\r
+ }\r
+ }\r
+ node.endUpdate();\r
+ this.runCallback(callback, scope || node, [node]);\r
+ }catch(e){\r
+ this.handleFailure(response);\r
+ }\r
+ },\r
+\r
+ handleResponse : function(response){\r
+ this.transId = false;\r
+ var a = response.argument;\r
+ this.processResponse(response, a.node, a.callback, a.scope);\r
+ this.fireEvent("load", this, a.node, response);\r
+ },\r
+\r
+ handleFailure : function(response){\r
+ this.transId = false;\r
+ var a = response.argument;\r
+ this.fireEvent("loadexception", this, a.node, response);\r
+ this.runCallback(a.callback, a.scope || a.node, [a.node]);\r
+ }\r
+});
\ No newline at end of file