/ext-4.1.0_b3/src/data/Tree.js
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});