--- /dev/null
+<!DOCTYPE html><html><head><title>Sencha Documentation Project</title><link rel="stylesheet" href="../reset.css" type="text/css"><link rel="stylesheet" href="../prettify.css" type="text/css"><link rel="stylesheet" href="../prettify_sa.css" type="text/css"><script type="text/javascript" src="../prettify.js"></script></head><body onload="prettyPrint()"><pre class="prettyprint"><pre><span id='Ext-data.TreeStore'>/**
+</span> * @class Ext.data.TreeStore
+ * @extends Ext.data.AbstractStore
+ *
+ * The TreeStore is a store implementation that is backed by by an {@link Ext.data.Tree}.
+ * It provides convenience methods for loading nodes, as well as the ability to use
+ * the hierarchical tree structure combined with a store. This class is generally used
+ * in conjunction with {@link Ext.tree.Panel}. This class also relays many events from
+ * the Tree for convenience.
+ *
+ * ## Using Models
+ * If no Model is specified, an implicit model will be created that implements {@link Ext.data.NodeInterface}.
+ * The standard Tree fields will also be copied onto the Model for maintaining their state.
+ *
+ * ## Reading Nested Data
+ * For the tree to read nested data, the {@link Ext.data.Reader} must be configured with a root property,
+ * so the reader can find nested data for each node. If a root is not specified, it will default to
+ * 'children'.
+ */
+Ext.define('Ext.data.TreeStore', {
+ extend: 'Ext.data.AbstractStore',
+ alias: 'store.tree',
+ requires: ['Ext.data.Tree', 'Ext.data.NodeInterface', 'Ext.data.NodeStore'],
+
+<span id='Ext-data.TreeStore-cfg-clearOnLoad'> /**
+</span> * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
+ * child nodes before loading.
+ */
+ clearOnLoad : true,
+
+<span id='Ext-data.TreeStore-cfg-nodeParam'> /**
+</span> * @cfg {String} nodeParam The name of the parameter sent to the server which contains
+ * the identifier of the node. Defaults to <tt>'node'</tt>.
+ */
+ nodeParam: 'node',
+
+<span id='Ext-data.TreeStore-cfg-defaultRootId'> /**
+</span> * @cfg {String} defaultRootId
+ * The default root id. Defaults to 'root'
+ */
+ defaultRootId: 'root',
+
+<span id='Ext-data.TreeStore-cfg-defaultRootProperty'> /**
+</span> * @cfg {String} defaultRootProperty
+ * The root property to specify on the reader if one is not explicitly defined.
+ */
+ defaultRootProperty: 'children',
+
+<span id='Ext-data.TreeStore-cfg-folderSort'> /**
+</span> * @cfg {Boolean} folderSort Set to true to automatically prepend a leaf sorter (defaults to <tt>undefined</tt>)
+ */
+ folderSort: false,
+
+ constructor: function(config) {
+ var me = this,
+ root,
+ fields;
+
+
+ config = Ext.apply({}, config);
+
+<span id='Ext-data.TreeStore-property-fields'> /**
+</span> * If we have no fields declare for the store, add some defaults.
+ * These will be ignored if a model is explicitly specified.
+ */
+ fields = config.fields || me.fields;
+ if (!fields) {
+ config.fields = [{name: 'text', type: 'string'}];
+ }
+
+ me.callParent([config]);
+
+ // We create our data tree.
+ me.tree = Ext.create('Ext.data.Tree');
+
+ me.tree.on({
+ scope: me,
+ remove: me.onNodeRemove,
+ beforeexpand: me.onBeforeNodeExpand,
+ beforecollapse: me.onBeforeNodeCollapse,
+ append: me.onNodeAdded,
+ insert: me.onNodeAdded
+ });
+
+ me.onBeforeSort();
+
+ root = me.root;
+ if (root) {
+ delete me.root;
+ me.setRootNode(root);
+ }
+
+ me.relayEvents(me.tree, [
+<span id='Ext-data.TreeStore-event-append'> /**
+</span> * @event append
+ * Fires when a new child node is appended to a node in this store's tree.
+ * @param {Tree} tree The owner tree
+ * @param {Node} parent The parent node
+ * @param {Node} node The newly appended node
+ * @param {Number} index The index of the newly appended node
+ */
+ "append",
+
+<span id='Ext-data.TreeStore-event-remove'> /**
+</span> * @event remove
+ * Fires when a child node is removed from a node in this store's tree.
+ * @param {Tree} tree The owner tree
+ * @param {Node} parent The parent node
+ * @param {Node} node The child node removed
+ */
+ "remove",
+
+<span id='Ext-data.TreeStore-event-move'> /**
+</span> * @event move
+ * Fires when a node is moved to a new location in the store's tree
+ * @param {Tree} tree The owner tree
+ * @param {Node} node The node moved
+ * @param {Node} oldParent The old parent of this node
+ * @param {Node} newParent The new parent of this node
+ * @param {Number} index The index it was moved to
+ */
+ "move",
+
+<span id='Ext-data.TreeStore-event-insert'> /**
+</span> * @event insert
+ * Fires when a new child node is inserted in a node in this store's tree.
+ * @param {Tree} tree The owner tree
+ * @param {Node} parent The parent node
+ * @param {Node} node The child node inserted
+ * @param {Node} refNode The child node the node was inserted before
+ */
+ "insert",
+
+<span id='Ext-data.TreeStore-event-beforeappend'> /**
+</span> * @event beforeappend
+ * Fires before a new child is appended to a node in this store's tree, return false to cancel the append.
+ * @param {Tree} tree The owner tree
+ * @param {Node} parent The parent node
+ * @param {Node} node The child node to be appended
+ */
+ "beforeappend",
+
+<span id='Ext-data.TreeStore-event-beforeremove'> /**
+</span> * @event beforeremove
+ * Fires before a child is removed from a node in this store's tree, return false to cancel the remove.
+ * @param {Tree} tree The owner tree
+ * @param {Node} parent The parent node
+ * @param {Node} node The child node to be removed
+ */
+ "beforeremove",
+
+<span id='Ext-data.TreeStore-event-beforemove'> /**
+</span> * @event beforemove
+ * Fires before a node is moved to a new location in the store's tree. Return false to cancel the move.
+ * @param {Tree} tree The owner tree
+ * @param {Node} node The node being moved
+ * @param {Node} oldParent The parent of the node
+ * @param {Node} newParent The new parent the node is moving to
+ * @param {Number} index The index it is being moved to
+ */
+ "beforemove",
+
+<span id='Ext-data.TreeStore-event-beforeinsert'> /**
+</span> * @event beforeinsert
+ * Fires before a new child is inserted in a node in this store's tree, return false to cancel the insert.
+ * @param {Tree} tree The owner tree
+ * @param {Node} parent The parent node
+ * @param {Node} node The child node to be inserted
+ * @param {Node} refNode The child node the node is being inserted before
+ */
+ "beforeinsert",
+
+<span id='Ext-data.TreeStore-event-expand'> /**
+</span> * @event expand
+ * Fires when this node is expanded.
+ * @param {Node} this The expanding node
+ */
+ "expand",
+
+<span id='Ext-data.TreeStore-event-collapse'> /**
+</span> * @event collapse
+ * Fires when this node is collapsed.
+ * @param {Node} this The collapsing node
+ */
+ "collapse",
+
+<span id='Ext-data.TreeStore-event-beforeexpand'> /**
+</span> * @event beforeexpand
+ * Fires before this node is expanded.
+ * @param {Node} this The expanding node
+ */
+ "beforeexpand",
+
+<span id='Ext-data.TreeStore-event-beforecollapse'> /**
+</span> * @event beforecollapse
+ * Fires before this node is collapsed.
+ * @param {Node} this The collapsing node
+ */
+ "beforecollapse",
+
+<span id='Ext-data.TreeStore-event-sort'> /**
+</span> * @event sort
+ * Fires when this TreeStore is sorted.
+ * @param {Node} node The node that is sorted.
+ */
+ "sort",
+
+<span id='Ext-data.TreeStore-event-rootchange'> /**
+</span> * @event rootchange
+ * Fires whenever the root node is changed in the tree.
+ * @param {Ext.data.Model} root The new root
+ */
+ "rootchange"
+ ]);
+
+ me.addEvents(
+<span id='Ext-data.TreeStore-event-rootchange'> /**
+</span> * @event rootchange
+ * Fires when the root node on this TreeStore is changed.
+ * @param {Ext.data.TreeStore} store This TreeStore
+ * @param {Node} The new root node.
+ */
+ 'rootchange'
+ );
+
+ //<deprecated since=0.99>
+ if (Ext.isDefined(me.nodeParameter)) {
+ if (Ext.isDefined(Ext.global.console)) {
+ Ext.global.console.warn('Ext.data.TreeStore: nodeParameter has been deprecated. Please use nodeParam instead.');
+ }
+ me.nodeParam = me.nodeParameter;
+ delete me.nodeParameter;
+ }
+ //</deprecated>
+ },
+
+ // inherit docs
+ setProxy: function(proxy) {
+ var reader,
+ needsRoot;
+
+ if (proxy instanceof Ext.data.proxy.Proxy) {
+ // proxy instance, check if a root was set
+ needsRoot = Ext.isEmpty(proxy.getReader().root);
+ } else if (Ext.isString(proxy)) {
+ // string type, means a reader can't be set
+ needsRoot = true;
+ } else {
+ // object, check if a reader and a root were specified.
+ reader = proxy.reader;
+ needsRoot = !(reader && !Ext.isEmpty(reader.root));
+ }
+ proxy = this.callParent(arguments);
+ if (needsRoot) {
+ reader = proxy.getReader();
+ reader.root = this.defaultRootProperty;
+ // force rebuild
+ reader.buildExtractors(true);
+ }
+ },
+
+ // inherit docs
+ onBeforeSort: function() {
+ if (this.folderSort) {
+ this.sort({
+ property: 'leaf',
+ direction: 'ASC'
+ }, 'prepend', false);
+ }
+ },
+
+<span id='Ext-data.TreeStore-method-onBeforeNodeExpand'> /**
+</span> * Called before a node is expanded.
+ * @private
+ * @param {Ext.data.NodeInterface} node The node being expanded.
+ * @param {Function} callback The function to run after the expand finishes
+ * @param {Object} scope The scope in which to run the callback function
+ */
+ onBeforeNodeExpand: function(node, callback, scope) {
+ if (node.isLoaded()) {
+ Ext.callback(callback, scope || node, [node.childNodes]);
+ }
+ else if (node.isLoading()) {
+ this.on('load', function() {
+ Ext.callback(callback, scope || node, [node.childNodes]);
+ }, this, {single: true});
+ }
+ else {
+ this.read({
+ node: node,
+ callback: function() {
+ Ext.callback(callback, scope || node, [node.childNodes]);
+ }
+ });
+ }
+ },
+
+ //inherit docs
+ getNewRecords: function() {
+ return Ext.Array.filter(this.tree.flatten(), this.filterNew);
+ },
+
+ //inherit docs
+ getUpdatedRecords: function() {
+ return Ext.Array.filter(this.tree.flatten(), this.filterUpdated);
+ },
+
+<span id='Ext-data.TreeStore-method-onBeforeNodeCollapse'> /**
+</span> * Called before a node is collapsed.
+ * @private
+ * @param {Ext.data.NodeInterface} node The node being collapsed.
+ * @param {Function} callback The function to run after the collapse finishes
+ * @param {Object} scope The scope in which to run the callback function
+ */
+ onBeforeNodeCollapse: function(node, callback, scope) {
+ callback.call(scope || node, node.childNodes);
+ },
+
+ onNodeRemove: function(parent, node) {
+ var removed = this.removed;
+
+ if (!node.isReplace && Ext.Array.indexOf(removed, node) == -1) {
+ removed.push(node);
+ }
+ },
+
+ onNodeAdded: function(parent, node) {
+ var proxy = this.getProxy(),
+ reader = proxy.getReader(),
+ data = node.raw || node.data,
+ dataRoot, children;
+
+ Ext.Array.remove(this.removed, node);
+
+ if (!node.isLeaf() && !node.isLoaded()) {
+ dataRoot = reader.getRoot(data);
+ if (dataRoot) {
+ this.fillNode(node, reader.extractData(dataRoot));
+ delete data[reader.root];
+ }
+ }
+ },
+
+<span id='Ext-data.TreeStore-method-setRootNode'> /**
+</span> * Sets the root node for this store
+ * @param {Ext.data.Model/Ext.data.NodeInterface} root
+ * @return {Ext.data.NodeInterface} The new root
+ */
+ setRootNode: function(root) {
+ var me = this;
+
+ root = root || {};
+ if (!root.isNode) {
+ // create a default rootNode and create internal data struct.
+ Ext.applyIf(root, {
+ id: me.defaultRootId,
+ text: 'Root',
+ allowDrag: false
+ });
+ root = Ext.ModelManager.create(root, me.model);
+ }
+ Ext.data.NodeInterface.decorate(root);
+
+ // Because we have decorated the model with new fields,
+ // we need to build new extactor functions on the reader.
+ me.getProxy().getReader().buildExtractors(true);
+
+ // When we add the root to the tree, it will automaticaly get the NodeInterface
+ me.tree.setRootNode(root);
+
+ // If the user has set expanded: true on the root, we want to call the expand function
+ if (!root.isLoaded() && root.isExpanded()) {
+ me.load({
+ node: root
+ });
+ }
+
+ return root;
+ },
+
+<span id='Ext-data.TreeStore-method-getRootNode'> /**
+</span> * Returns the root node for this tree.
+ * @return {Ext.data.NodeInterface}
+ */
+ getRootNode: function() {
+ return this.tree.getRootNode();
+ },
+
+<span id='Ext-data.TreeStore-method-getNodeById'> /**
+</span> * Returns the record node by id
+ * @return {Ext.data.NodeInterface}
+ */
+ getNodeById: function(id) {
+ return this.tree.getNodeById(id);
+ },
+
+<span id='Ext-data.TreeStore-method-load'> /**
+</span> * Loads the Store using its configured {@link #proxy}.
+ * @param {Object} options Optional config object. This is passed into the {@link Ext.data.Operation Operation}
+ * object that is created and then sent to the proxy's {@link Ext.data.proxy.Proxy#read} function.
+ * The options can also contain a node, which indicates which node is to be loaded. If not specified, it will
+ * default to the root node.
+ */
+ load: function(options) {
+ options = options || {};
+ options.params = options.params || {};
+
+ var me = this,
+ node = options.node || me.tree.getRootNode(),
+ root;
+
+ // If there is not a node it means the user hasnt defined a rootnode yet. In this case lets just
+ // create one for them.
+ if (!node) {
+ node = me.setRootNode({
+ expanded: true
+ });
+ }
+
+ if (me.clearOnLoad) {
+ node.removeAll();
+ }
+
+ Ext.applyIf(options, {
+ node: node
+ });
+ options.params[me.nodeParam] = node ? node.getId() : 'root';
+
+ if (node) {
+ node.set('loading', true);
+ }
+
+ return me.callParent([options]);
+ },
+
+
+<span id='Ext-data.TreeStore-method-fillNode'> /**
+</span> * Fills a node with a series of child records.
+ * @private
+ * @param {Ext.data.NodeInterface} node The node to fill
+ * @param {Array} records The records to add
+ */
+ fillNode: function(node, records) {
+ var me = this,
+ ln = records ? records.length : 0,
+ i = 0, sortCollection;
+
+ if (ln && me.sortOnLoad && !me.remoteSort && me.sorters && me.sorters.items) {
+ sortCollection = Ext.create('Ext.util.MixedCollection');
+ sortCollection.addAll(records);
+ sortCollection.sort(me.sorters.items);
+ records = sortCollection.items;
+ }
+
+ node.set('loaded', true);
+ for (; i < ln; i++) {
+ node.appendChild(records[i], undefined, true);
+ }
+
+ return records;
+ },
+
+ // inherit docs
+ onProxyLoad: function(operation) {
+ var me = this,
+ successful = operation.wasSuccessful(),
+ records = operation.getRecords(),
+ node = operation.node;
+
+ node.set('loading', false);
+ if (successful) {
+ records = me.fillNode(node, records);
+ }
+ // deprecate read?
+ me.fireEvent('read', me, operation.node, records, successful);
+ me.fireEvent('load', me, operation.node, records, successful);
+ //this is a callback that would have been passed to the 'read' function and is optional
+ Ext.callback(operation.callback, operation.scope || me, [records, operation, successful]);
+ },
+
+<span id='Ext-data.TreeStore-method-onCreateRecords'> /**
+</span> * Create any new records when a write is returned from the server.
+ * @private
+ * @param {Array} records The array of new records
+ * @param {Ext.data.Operation} operation The operation that just completed
+ * @param {Boolean} success True if the operation was successful
+ */
+ onCreateRecords: function(records, operation, success) {
+ if (success) {
+ var i = 0,
+ length = records.length,
+ originalRecords = operation.records,
+ parentNode,
+ record,
+ original,
+ index;
+
+<span id='Ext-data.TreeStore-property-'> /**
+</span> * Loop over each record returned from the server. Assume they are
+ * returned in order of how they were sent. If we find a matching
+ * record, replace it with the newly created one.
+ */
+ for (; i < length; ++i) {
+ record = records[i];
+ original = originalRecords[i];
+ if (original) {
+ parentNode = original.parentNode;
+ if (parentNode) {
+ // prevent being added to the removed cache
+ original.isReplace = true;
+ parentNode.replaceChild(record, original);
+ delete original.isReplace;
+ }
+ record.phantom = false;
+ }
+ }
+ }
+ },
+
+<span id='Ext-data.TreeStore-method-onUpdateRecords'> /**
+</span> * Update any records when a write is returned from the server.
+ * @private
+ * @param {Array} records The array of updated records
+ * @param {Ext.data.Operation} operation The operation that just completed
+ * @param {Boolean} success True if the operation was successful
+ */
+ onUpdateRecords: function(records, operation, success){
+ if (success) {
+ var me = this,
+ i = 0,
+ length = records.length,
+ data = me.data,
+ original,
+ parentNode,
+ record;
+
+ for (; i < length; ++i) {
+ record = records[i];
+ original = me.tree.getNodeById(record.getId());
+ parentNode = original.parentNode;
+ if (parentNode) {
+ // prevent being added to the removed cache
+ original.isReplace = true;
+ parentNode.replaceChild(record, original);
+ original.isReplace = false;
+ }
+ }
+ }
+ },
+
+<span id='Ext-data.TreeStore-method-onDestroyRecords'> /**
+</span> * Remove any records when a write is returned from the server.
+ * @private
+ * @param {Array} records The array of removed records
+ * @param {Ext.data.Operation} operation The operation that just completed
+ * @param {Boolean} success True if the operation was successful
+ */
+ onDestroyRecords: function(records, operation, success){
+ if (success) {
+ this.removed = [];
+ }
+ },
+
+ // inherit docs
+ removeAll: function() {
+ this.getRootNode().destroy();
+ this.fireEvent('clear', this);
+ },
+
+ // inherit docs
+ doSort: function(sorterFn) {
+ var me = this;
+ if (me.remoteSort) {
+ //the load function will pick up the new sorters and request the sorted data from the proxy
+ me.load();
+ } else {
+ me.tree.sort(sorterFn, true);
+ me.fireEvent('datachanged', me);
+ }
+ me.fireEvent('sort', me);
+ }
+});</pre></pre></body></html>
\ No newline at end of file