PageRenderTime 71ms CodeModel.GetById 20ms app.highlight 19ms RepoModel.GetById 12ms app.codeStats 0ms

/ext-4.1.0_b3/src/data/Tree.js

https://bitbucket.org/srogerf/javascript
JavaScript | 290 lines | 105 code | 39 blank | 146 comment | 9 complexity | e425521e463b8a73ef42830015f7428f MD5 | raw file
  1/**
  2 * @class Ext.data.Tree
  3 *
  4 * This class is used as a container for a series of nodes. The nodes themselves maintain
  5 * the relationship between parent/child. The tree itself acts as a manager. It gives functionality
  6 * to retrieve a node by its identifier: {@link #getNodeById}.
  7 *
  8 * The tree also relays events from any of it's child nodes, allowing them to be handled in a
  9 * centralized fashion. In general this class is not used directly, rather used internally
 10 * by other parts of the framework.
 11 *
 12 */
 13Ext.define('Ext.data.Tree', {
 14    alias: 'data.tree',
 15
 16    mixins: {
 17        observable: "Ext.util.Observable"
 18    },
 19
 20    /**
 21     * @property {Ext.data.NodeInterface}
 22     * The root node for this tree
 23     */
 24    root: null,
 25
 26    /**
 27     * Creates new Tree object.
 28     * @param {Ext.data.NodeInterface} root (optional) The root node
 29     */
 30    constructor: function(root) {
 31        var me = this;
 32
 33        me.mixins.observable.constructor.call(me);
 34
 35        if (root) {
 36            me.setRootNode(root);
 37        }
 38    },
 39
 40    /**
 41     * Returns the root node for this tree.
 42     * @return {Ext.data.NodeInterface}
 43     */
 44    getRootNode : function() {
 45        return this.root;
 46    },
 47
 48    /**
 49     * Sets the root node for this tree.
 50     * @param {Ext.data.NodeInterface} node
 51     * @return {Ext.data.NodeInterface} The root node
 52     */
 53    setRootNode : function(node) {
 54        var me = this;
 55
 56        me.root = node;
 57
 58        if (me.fireEvent('beforeappend', null, node) !== false) {
 59            node.set('root', true);
 60            node.updateInfo();
 61            // root node should never be phantom or dirty, so commit it
 62            node.commit();
 63
 64            node.on({
 65                scope: me,
 66                insert: me.onNodeInsert,
 67                append: me.onNodeAppend,
 68                remove: me.onNodeRemove
 69            });
 70
 71            me.relayEvents(node, [
 72                /**
 73                 * @event append
 74                 * @inheritdoc Ext.data.NodeInterface#append
 75                 */
 76                "append",
 77
 78                /**
 79                 * @event remove
 80                 * @inheritdoc Ext.data.NodeInterface#remove
 81                 */
 82                "remove",
 83
 84                /**
 85                 * @event move
 86                 * @inheritdoc Ext.data.NodeInterface#move
 87                 */
 88                "move",
 89
 90                /**
 91                 * @event insert
 92                 * @inheritdoc Ext.data.NodeInterface#insert
 93                 */
 94                "insert",
 95
 96                /**
 97                 * @event beforeappend
 98                 * @inheritdoc Ext.data.NodeInterface#beforeappend
 99                 */
100                "beforeappend",
101
102                /**
103                 * @event beforeremove
104                 * @inheritdoc Ext.data.NodeInterface#beforeremove
105                 */
106                "beforeremove",
107
108                /**
109                 * @event beforemove
110                 * @inheritdoc Ext.data.NodeInterface#beforemove
111                 */
112                "beforemove",
113
114                /**
115                 * @event beforeinsert
116                 * @inheritdoc Ext.data.NodeInterface#beforeinsert
117                 */
118                "beforeinsert",
119
120                /**
121                 * @event expand
122                 * @inheritdoc Ext.data.NodeInterface#expand
123                 */
124                "expand",
125
126                /**
127                 * @event collapse
128                 * @inheritdoc Ext.data.NodeInterface#collapse
129                 */
130                "collapse",
131
132                /**
133                 * @event beforeexpand
134                 * @inheritdoc Ext.data.NodeInterface#beforeexpand
135                 */
136                "beforeexpand",
137
138                /**
139                 * @event beforecollapse
140                 * @inheritdoc Ext.data.NodeInterface#beforecollapse
141                 */
142                "beforecollapse" ,
143
144                /**
145                 * @event sort
146                 * @inheritdoc Ext.data.NodeInterface#event-sort
147                 */
148                "sort",
149
150                /**
151                 * @event rootchange
152                 * Fires whenever the root node is changed in the tree.
153                 * @param {Ext.data.Model} root The new root
154                 */
155                "rootchange"
156            ]);
157
158            me.nodeHash = {};
159            me.registerNode(node);
160            me.fireEvent('append', null, node);
161            me.fireEvent('rootchange', node);
162        }
163
164        return node;
165    },
166
167    /**
168     * Flattens all the nodes in the tree into an array.
169     * @private
170     * @return {Ext.data.NodeInterface[]} The flattened nodes.
171     */
172    flatten: function(){
173        var nodes = [],
174            hash = this.nodeHash,
175            key;
176
177        for (key in hash) {
178            if (hash.hasOwnProperty(key)) {
179                nodes.push(hash[key]);
180            }
181        }
182        return nodes;
183    },
184
185    /**
186     * Fired when a node is inserted into the root or one of it's children
187     * @private
188     * @param {Ext.data.NodeInterface} parent The parent node
189     * @param {Ext.data.NodeInterface} node The inserted node
190     */
191    onNodeInsert: function(parent, node) {
192        this.registerNode(node, true);
193    },
194
195    /**
196     * Fired when a node is appended into the root or one of it's children
197     * @private
198     * @param {Ext.data.NodeInterface} parent The parent node
199     * @param {Ext.data.NodeInterface} node The appended node
200     */
201    onNodeAppend: function(parent, node) {
202        this.registerNode(node, true);
203    },
204
205    /**
206     * Fired when a node is removed from the root or one of it's children
207     * @private
208     * @param {Ext.data.NodeInterface} parent The parent node
209     * @param {Ext.data.NodeInterface} node The removed node
210     */
211    onNodeRemove: function(parent, node) {
212        this.unregisterNode(node, true);
213    },
214
215    /**
216     * Fired when a node's id changes.  Updates the node's id in the node hash.
217     * @private
218     * @param {Ext.data.NodeInterface} node 
219     * @param {Number} oldId The old id
220     * @param {Number} newId The new id
221     */
222    onNodeIdChanged: function(node, oldId, newId) {
223        var nodeHash = this.nodeHash;
224    
225        nodeHash[newId] = node;
226        delete nodeHash[oldId || node.internalId];
227    },
228
229    /**
230     * Gets a node in this tree by its id.
231     * @param {String} id
232     * @return {Ext.data.NodeInterface} The match node.
233     */
234    getNodeById : function(id) {
235        return this.nodeHash[id];
236    },
237
238    /**
239     * Registers a node with the tree
240     * @private
241     * @param {Ext.data.NodeInterface} The node to register
242     * @param {Boolean} [includeChildren] True to unregister any child nodes
243     */
244    registerNode : function(node, includeChildren) {
245        var me = this;
246
247        me.nodeHash[node.getId() || node.internalId] = node;
248        node.on('idchanged', me.onNodeIdChanged, me);
249        if (includeChildren === true) {
250            node.eachChild(function(child){
251                me.registerNode(child, true);
252            });
253        }
254    },
255
256    /**
257     * Unregisters a node with the tree
258     * @private
259     * @param {Ext.data.NodeInterface} The node to unregister
260     * @param {Boolean} [includeChildren] True to unregister any child nodes
261     */
262    unregisterNode : function(node, includeChildren) {
263        delete this.nodeHash[node.getId() || node.internalId];
264        if (includeChildren === true) {
265            node.eachChild(function(child){
266                this.unregisterNode(child, true);
267            }, this);
268        }
269    },
270
271    /**
272     * Sorts this tree
273     * @private
274     * @param {Function} sorterFn The function to use for sorting
275     * @param {Boolean} recursive True to perform recursive sorting
276     */
277    sort: function(sorterFn, recursive) {
278        this.getRootNode().sort(sorterFn, recursive);
279    },
280
281     /**
282     * Filters this tree
283     * @private
284     * @param {Function} sorterFn The function to use for filtering
285     * @param {Boolean} recursive True to perform recursive filtering
286     */
287    filter: function(filters, recursive) {
288        this.getRootNode().filter(filters, recursive);
289    }
290});