|
1 <!DOCTYPE html> |
|
2 <html lang="en"> |
|
3 <head> |
|
4 <meta charset="utf-8"> |
|
5 <title>Tree</title> |
|
6 <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=PT+Sans:400,700,400italic,700italic"> |
|
7 <link rel="stylesheet" href="../../build/cssgrids/cssgrids-min.css"> |
|
8 <link rel="stylesheet" href="../assets/css/main.css"> |
|
9 <link rel="stylesheet" href="../assets/vendor/prettify/prettify-min.css"> |
|
10 <link rel="shortcut icon" type="image/png" href="../assets/favicon.png"> |
|
11 <script src="../../build/yui/yui-min.js"></script> |
|
12 |
|
13 </head> |
|
14 <body> |
|
15 <!-- |
|
16 <a href="https://github.com/yui/yui3"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" alt="Fork me on GitHub"></a> |
|
17 --> |
|
18 <div id="doc"> |
|
19 <div id="hd"> |
|
20 <h1><img src="http://yuilibrary.com/img/yui-logo.png"></h1> |
|
21 </div> |
|
22 |
|
23 <a href="#toc" class="jump">Jump to Table of Contents</a> |
|
24 |
|
25 |
|
26 <h1>Tree</h1> |
|
27 <div class="yui3-g"> |
|
28 <div class="yui3-u-3-4"> |
|
29 <div id="main"> |
|
30 <div class="content"><div class="intro"> |
|
31 <p> |
|
32 The Tree component provides a generic tree data structure, which is good for efficiently representing hierarchical data. |
|
33 </p> |
|
34 |
|
35 <p> |
|
36 A tree has a root node, which may contain any number of child nodes, which may themselves contain child nodes, <i>ad infinitum</i>. Child nodes are lightweight function instances which delegate to the tree for all significant functionality, so trees remain performant and memory-efficient even when they contain thousands and thousands of nodes. |
|
37 </p> |
|
38 |
|
39 <p> |
|
40 The Tree component itself is purely a data structure and doesn't expose any UI, but it works well as a base class for a <a href="../view/index.html">View</a> or a <a href="../widget/index.html">Widget</a>. |
|
41 </p> |
|
42 </div> |
|
43 |
|
44 <h2 id="getting-started">Getting Started</h2> |
|
45 |
|
46 <p> |
|
47 To include the source files for Tree and its dependencies, first load |
|
48 the YUI seed file if you haven't already loaded it. |
|
49 </p> |
|
50 |
|
51 <pre class="code prettyprint"><script src="http://yui.yahooapis.com/3.10.3/build/yui/yui-min.js"></script></pre> |
|
52 |
|
53 |
|
54 <p> |
|
55 Next, create a new YUI instance for your application and populate it with the |
|
56 modules you need by specifying them as arguments to the <code>YUI().use()</code> method. |
|
57 YUI will automatically load any dependencies required by the modules you |
|
58 specify. |
|
59 </p> |
|
60 |
|
61 <pre class="code prettyprint"><script> |
|
62 // Create a new YUI instance and populate it with the required modules. |
|
63 YUI().use('tree', function (Y) { |
|
64 // Tree is available and ready for use. Add implementation |
|
65 // code here. |
|
66 }); |
|
67 </script></pre> |
|
68 |
|
69 |
|
70 <p> |
|
71 For more information on creating YUI instances and on the |
|
72 <a href="http://yuilibrary.com/yui/docs/api/classes/YUI.html#method_use"><code>use()</code> method</a>, see the |
|
73 documentation for the <a href="../yui/index.html">YUI Global Object</a>. |
|
74 </p> |
|
75 |
|
76 |
|
77 <h2 id="using-tree">Using Tree</h2> |
|
78 |
|
79 <h3 id="creating-a-tree">Creating a Tree</h3> |
|
80 |
|
81 <p> |
|
82 Create an empty Tree by instantiating <code>Y.Tree</code> without any options. |
|
83 </p> |
|
84 |
|
85 <pre class="code prettyprint lang-js">// Create a new empty Tree. |
|
86 var tree = new Y.Tree();</pre> |
|
87 |
|
88 |
|
89 <p> |
|
90 Trees always have a single root node, so an "empty" tree is really just a tree without any child nodes. |
|
91 </p> |
|
92 |
|
93 <p> |
|
94 To populate a tree with an initial set of nodes at instantiation time, pass an array of node configuration objects to Tree's constructor. |
|
95 </p> |
|
96 |
|
97 <pre class="code prettyprint lang-js">// Create a new tree with some child nodes. |
|
98 var tree = new Y.Tree({ |
|
99 nodes: [ |
|
100 {id: 'node 1'}, |
|
101 {id: 'node 2', children: [ |
|
102 {id: 'node 2.1'}, |
|
103 {id: 'node 2.2'} |
|
104 ]}, |
|
105 {id: 'node 3'} |
|
106 ] |
|
107 });</pre> |
|
108 |
|
109 |
|
110 <p> |
|
111 This creates a tree structure that looks like this: |
|
112 </p> |
|
113 |
|
114 <pre> |
|
115 root node |
|
116 / | \ |
|
117 node 1 node 2 node 3 |
|
118 / \ |
|
119 node 2.1 node 2.2 |
|
120 </pre> |
|
121 |
|
122 <p> |
|
123 The <code>id</code> property of node objects is optional. If not specified, a unique node id will be generated automatically. |
|
124 </p> |
|
125 |
|
126 <pre class="code prettyprint lang-js">// Use empty objects to create child nodes with auto-generated ids. |
|
127 var tree = new Y.Tree({ |
|
128 nodes: [{}, {children: [{}, {}]}, {}] |
|
129 });</pre> |
|
130 |
|
131 |
|
132 <p> |
|
133 If you do choose to provide custom node ids, be sure that they're unique. No two nodes in a tree may share the same id. |
|
134 </p> |
|
135 |
|
136 <h3 id="tree-properties">Tree Properties</h3> |
|
137 |
|
138 <table> |
|
139 <thead> |
|
140 <tr> |
|
141 <th>Property</th> |
|
142 <th>Type</th> |
|
143 <th>Description</th> |
|
144 </tr> |
|
145 </thead> |
|
146 |
|
147 <tbody> |
|
148 <tr> |
|
149 <td><code>children</code></td> |
|
150 <td>Array</td> |
|
151 <td> |
|
152 Reference to the <code>children</code> property of the Tree's <code>rootNode</code>. This is a convenience property to allow you to type <code>tree.children</code> instead of <code>tree.rootNode.children</code>. |
|
153 </td> |
|
154 </tr> |
|
155 |
|
156 <tr> |
|
157 <td><code>nodeClass</code></td> |
|
158 <td>String / Tree.Node</td> |
|
159 <td> |
|
160 The <code>Y.Tree.Node</code> class or subclass that should be used for nodes created by the tree. You may specify an actual class reference or a string that resolves to a class reference at runtime. By default this is a reference to <code>Y.Tree.Node</code>. |
|
161 </td> |
|
162 </tr> |
|
163 |
|
164 <tr> |
|
165 <td><code>nodeExtensions</code></td> |
|
166 <td>Array</td> |
|
167 <td> |
|
168 <p> |
|
169 Optional array containing one or more extension classes that should be mixed into the <code>nodeClass</code> when the Tree is instantiated. The resulting composed node class will be unique to the Tree instance and will not affect any other instances, nor will it modify the defined <code>nodeClass</code> itself. |
|
170 </p> |
|
171 |
|
172 <p> |
|
173 This provides a late-binding extension mechanism for nodes that doesn't require them to extend <code>Y.Base</code>, which would incur a significant performance hit. |
|
174 </p> |
|
175 </td> |
|
176 </tr> |
|
177 |
|
178 <tr> |
|
179 <td><code>rootNode</code></td> |
|
180 <td>Tree.Node</td> |
|
181 <td> |
|
182 The root node of the tree. |
|
183 </td> |
|
184 </tr> |
|
185 </tbody> |
|
186 </table> |
|
187 |
|
188 <h3 id="working-with-tree-nodes">Working with Tree Nodes</h3> |
|
189 |
|
190 <h4 id="tree-node-properties">Tree Node Properties</h4> |
|
191 |
|
192 <p>Tree nodes use properties exclusively rather than using attributes as many YUI classes do. This ensures that <code>Y.Tree.Node</code> instances are lightweight and extremely fast to create. Using attributes would require extending <a href="../attribute/index.html"><code>Y.Attribute</code></a>, which incurs significant instantiation and memory cost.</p> |
|
193 |
|
194 <p>All nodes have the following built-in properties:</p> |
|
195 |
|
196 <table> |
|
197 <thead> |
|
198 <tr> |
|
199 <th>Property</th> |
|
200 <th>Type</th> |
|
201 <th>Description</th> |
|
202 </tr> |
|
203 </thead> |
|
204 |
|
205 <tbody> |
|
206 <tr> |
|
207 <td>canHaveChildren</td> |
|
208 <td>Boolean</td> |
|
209 <td> |
|
210 <p>Whether or not the node can contain child nodes.</p> |
|
211 |
|
212 <p>This value is falsy by default unless child nodes are added at instantiation time, in which case it will be automatically set to <code>true</code>. You can also manually set it to <code>true</code> to indicate that a node <i>can</i> have children even though it might not currently have any children.</p> |
|
213 |
|
214 <p>Note that regardless of the value of this property, appending, prepending, or inserting a node into this node will cause <code>canHaveChildren</code> to be set to true automatically.</p> |
|
215 </td> |
|
216 </tr> |
|
217 |
|
218 <tr> |
|
219 <td>children</td> |
|
220 <td>Array</td> |
|
221 <td> |
|
222 Child nodes contained within this node. |
|
223 </td> |
|
224 </tr> |
|
225 |
|
226 <tr> |
|
227 <td>data</td> |
|
228 <td>Object</td> |
|
229 <td> |
|
230 Arbitrary serializable data related to the node. Use this property to store any data that should accompany a node when that node is serialized to JSON. |
|
231 </td> |
|
232 </tr> |
|
233 |
|
234 <tr> |
|
235 <td>id</td> |
|
236 <td>String</td> |
|
237 <td> |
|
238 Unique id for the node. If you don't specify a custom id when creating a node, one will be generated automatically. |
|
239 </td> |
|
240 </tr> |
|
241 |
|
242 <tr> |
|
243 <td>parent</td> |
|
244 <td>Tree.Node</td> |
|
245 <td> |
|
246 Parent node of the node, or <code>undefined</code> for an unattached node or the root node. |
|
247 </td> |
|
248 </tr> |
|
249 |
|
250 <tr> |
|
251 <td>state</td> |
|
252 <td>Object</td> |
|
253 <td> |
|
254 Arbitrary serializable state information related to the node. Use this property to store state-specific info — such as whether a node is "open", "selected", or any other arbitrary state — that should accompany a node when that node is serialized to JSON. |
|
255 </td> |
|
256 </tr> |
|
257 |
|
258 <tr> |
|
259 <td>tree</td> |
|
260 <td>Tree</td> |
|
261 <td> |
|
262 Reference to the Tree instance with which the node is associated. |
|
263 </td> |
|
264 </tr> |
|
265 </tbody> |
|
266 </table> |
|
267 |
|
268 <p>When creating a node, any properties you specify in the node's config object will be applied to the created <code>Y.Tree.Node</code> instance. These can be built-in <code>Y.Tree.Node</code> properties or arbitrary properties for your own use.</p> |
|
269 |
|
270 <pre class="code prettyprint lang-js">// Create a tree with some nodes containing arbitrary properties. |
|
271 var tree = new Y.Tree({ |
|
272 nodes: [ |
|
273 {foo: 'bar'}, |
|
274 {baz: 'quux'} |
|
275 ] |
|
276 }); |
|
277 |
|
278 console.log(tree.children[0].foo); // => 'bar' |
|
279 console.log(tree.children[1].baz); // => 'quux'</pre> |
|
280 |
|
281 |
|
282 <p>Note that arbitrary properties placed on the node itself won't be serialized if you call the node's <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.html#method_toJSON"><code>toJSON()</code></a> method or pass it to <code>JSON.stringify()</code>. If you want to store serializable data on a node, store it in the node's <code>data</code> property.</p> |
|
283 |
|
284 <h4 id="creating-unattached-nodes">Creating Unattached Nodes</h4> |
|
285 |
|
286 <p>An unattached node is a node that has been created, but hasn't yet been added to a tree. Unattached nodes can be created using a tree's <code>createNode()</code> method.</p> |
|
287 |
|
288 <pre class="code prettyprint lang-js">// Create an unattached node. |
|
289 var node = tree.createNode();</pre> |
|
290 |
|
291 |
|
292 <p>A node created using <code>createNode()</code> is associated with the tree that created it, so the node's <code>tree</code> property is a reference to that tree, but since it isn't yet a child of a node in that tree, its <code>parent</code> property will be <code>undefined</code>.</p> |
|
293 |
|
294 <pre class="code prettyprint lang-js">console.log(node.tree); // => the Y.Tree instance that created the node |
|
295 console.log(node.parent); // => undefined</pre> |
|
296 |
|
297 |
|
298 <p>An unattached node may have children. Children of an unattached node have a <code>parent</code>, but are still considered unattached because the top-most parent node is not the <code>rootNode</code> of a tree.</p> |
|
299 |
|
300 <pre class="code prettyprint lang-js">// Create an unattached node with children. |
|
301 var node = tree.createNode({ |
|
302 children: [ |
|
303 {id: 'unattached child 1'}, |
|
304 {id: 'unattached child 2'}, |
|
305 {id: 'unattached child 3'} |
|
306 ] |
|
307 });</pre> |
|
308 |
|
309 |
|
310 <p>To test whether a node is attached, call the node's <code>isInTree()</code> method.</p> |
|
311 |
|
312 <pre class="code prettyprint lang-js">var node = tree.createNode(); |
|
313 console.log(node.isInTree()); // => false |
|
314 |
|
315 tree.rootNode.append(node); |
|
316 console.log(node.isInTree()); // => true</pre> |
|
317 |
|
318 |
|
319 <p>An unattached node that was created in one tree can be moved to another tree by passing it to the second tree's <code>createNode()</code> method. The node and all its children will lose their association to the original tree and become associated with the second tree, but will remain unattached.</p> |
|
320 |
|
321 <pre class="code prettyprint lang-js">// Create two trees. |
|
322 var treeA = new Y.Tree(), |
|
323 treeB = new Y.Tree(); |
|
324 |
|
325 // Create an unattached node in Tree A. |
|
326 var node = treeA.createNode(); |
|
327 console.log(node.tree); // => treeA |
|
328 |
|
329 // Move the node to Tree B. |
|
330 treeB.createNode(node); |
|
331 console.log(node.tree); // => treeB</pre> |
|
332 |
|
333 |
|
334 <h4 id="adding-nodes-to-a-tree">Adding Nodes To a Tree</h4> |
|
335 |
|
336 <p>Use <code>Y.Tree.Node</code>'s <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.html#method_append"><code>append()</code></a>, <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.html#method_insert"><code>insert()</code></a>, and <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.html#method_prepend"><code>prepend()</code></a> methods to add nodes to other nodes as children. Each method accepts a <code>Y.Tree.Node</code> instance, a node config object, or an array of Node instances or config objects.</p> |
|
337 |
|
338 <p>After adding the node, each method returns the node that was added.</p> |
|
339 |
|
340 <pre class="code prettyprint lang-js">var tree = new Y.Tree(), |
|
341 parent = tree.rootNode; |
|
342 |
|
343 // Append a node (it becomes the parent's last child). |
|
344 parent.append({id: 'appended'}); |
|
345 |
|
346 // Prepend a node (it becomes the parent's first child). |
|
347 parent.prepend({id: 'prepended'}); |
|
348 |
|
349 // Insert a node at a specific zero-based index. |
|
350 parent.insert({id: 'inserted'}, {index: 1});</pre> |
|
351 |
|
352 |
|
353 <p>You may also pass a <code>Y.Tree.Node</code> instance instead of a config object.</p> |
|
354 |
|
355 <pre class="code prettyprint lang-js">// Append a previously created Tree.Node instance. |
|
356 var node = tree.createNode(); |
|
357 parent.append(node);</pre> |
|
358 |
|
359 |
|
360 <p>To add multiple nodes at once, pass an array of nodes or config objects.</p> |
|
361 |
|
362 <pre class="code prettyprint lang-js">// Append multiple nodes at once. |
|
363 parent.append([ |
|
364 {id: 'zero'}, |
|
365 {id: 'one'}, |
|
366 {id: 'two'} |
|
367 ]);</pre> |
|
368 |
|
369 |
|
370 <p> |
|
371 If you add an existing node that's already a child of another node, the node will be removed from its current parent and moved under the new parent. Similarly, if you add a node that's associated with another tree, the node will be removed from that tree and associated with the new tree. |
|
372 </p> |
|
373 |
|
374 <h4 id="getting-nodes-from-a-tree">Getting Nodes From a Tree</h4> |
|
375 |
|
376 <p>Use <code>Y.Tree</code>'s <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.html#method_getNodeById"><code>getNodeById()</code></a> method to look up any node in the tree (including <a href="#creating-unattached-nodes">unattached nodes</a>) by its <code>id</code>.</p> |
|
377 |
|
378 <pre class="code prettyprint lang-js">tree.rootNode.append({id: 'foo'}); |
|
379 |
|
380 // Look up a node by its id. |
|
381 var node = tree.getNodeById('foo'); // returns the previously added node</pre> |
|
382 |
|
383 |
|
384 <p>Use <code>Y.Tree.Node</code>'s <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.html#method_next"><code>next()</code></a> and <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.html#method_previous"><code>previous()</code></a> methods to get the next and previous siblings of a node, respectively.</p> |
|
385 |
|
386 <pre class="code prettyprint lang-js">tree.rootNode.append([ |
|
387 {id: 'zero'}, |
|
388 {id: 'one'}, |
|
389 {id: 'two'} |
|
390 ]); |
|
391 |
|
392 // Get the next/previous siblings of a node. |
|
393 tree.children[1].next(); // => node 'two' |
|
394 tree.children[1].previous(); // => node 'one'</pre> |
|
395 |
|
396 |
|
397 <p>If you know the numerical index of a node, you can retrieve it directly from the parent's <code>children</code> array.</p> |
|
398 |
|
399 <pre class="code prettyprint lang-js">// Look up a child node by numerical index. |
|
400 parent.children[0]; // returns the first child of `parent`</pre> |
|
401 |
|
402 |
|
403 <h4 id="removing-nodes-from-a-tree">Removing Nodes From a Tree</h4> |
|
404 |
|
405 <p>Use <code>Y.Tree.Node</code>'s <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.html#method_empty"><code>empty()</code></a> and <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.html#method_remove"><code>remove()</code></a> methods to remove nodes from a tree.</p> |
|
406 |
|
407 <pre class="code prettyprint lang-js">// Remove all of this node's children. |
|
408 node.empty(); // returns an array of removed child nodes |
|
409 |
|
410 // Remove this node (and its children, if any) from its parent node. |
|
411 node.remove(); // chainable</pre> |
|
412 |
|
413 |
|
414 <p>Removing a node causes it to become <a href="#creating-unattached-nodes">unattached</a>, but doesn't destroy it entirely. A removed node can still be re-added to the tree later.</p> |
|
415 |
|
416 <p>To both remove a node and ensure that it can't be reused (freeing up memory in the process), set the <code>destroy</code> option to <code>true</code> when calling <code>empty()</code> or <code>remove()</code>.</p> |
|
417 |
|
418 <pre class="code prettyprint lang-js">// Remove and destroy all of this node's children. |
|
419 node.empty({destroy: true}); |
|
420 |
|
421 // Remove and destroy this node and all of its children. |
|
422 node.remove({destroy: true});</pre> |
|
423 |
|
424 |
|
425 <p>Use <code>Y.Tree</code>'s <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.html#method_clear"><code>clear()</code></a> method to completely clear a tree by destroying all its nodes (including the root node) and then creating a new root node.</p> |
|
426 |
|
427 <pre class="code prettyprint lang-js">// Remove and destroy all the tree's nodes, including the root node. |
|
428 tree.clear();</pre> |
|
429 |
|
430 |
|
431 <p>Note that while it's possible to manually remove a tree's root node by calling its <code>remove()</code> method, this will just cause another root node to be created automatically, since a tree must always have a root node.</p> |
|
432 |
|
433 <h3 id="tree-events">Tree Events</h3> |
|
434 |
|
435 <p><code>Y.Tree</code> instances expose the following events:</p> |
|
436 |
|
437 <table> |
|
438 <thead> |
|
439 <tr> |
|
440 <th>Event</th> |
|
441 <th>When</th> |
|
442 <th>Payload</th> |
|
443 </tr> |
|
444 </thead> |
|
445 |
|
446 <tbody> |
|
447 <tr> |
|
448 <td><code>add</code></td> |
|
449 <td>A node is added to the tree.</td> |
|
450 <td> |
|
451 <dl> |
|
452 <dt>index (<em>Number</em>)</dt> |
|
453 <dd>Index at which the node will be added.</dd> |
|
454 |
|
455 <dt>node (<em>Tree.Node</em>)</dt> |
|
456 <dd>Node being added.</dd> |
|
457 |
|
458 <dt>parent (<em>Tree.Node</em>)</dt> |
|
459 <dd>Parent node to which the node will be added.</dd> |
|
460 |
|
461 <dt>src (<em>String</em>)</dt> |
|
462 <dd>Source of the event ("append", "prepend", "insert", etc.)</dd> |
|
463 </dl> |
|
464 </td> |
|
465 </tr> |
|
466 |
|
467 <tr> |
|
468 <td><code>clear</code></td> |
|
469 <td>The tree is cleared.</td> |
|
470 <td> |
|
471 <dl> |
|
472 <dt>rootNode (<em>Tree.Node</em>)</dt> |
|
473 <dd>The tree's new root node.</dd> |
|
474 </dl> |
|
475 </td> |
|
476 </tr> |
|
477 |
|
478 <tr> |
|
479 <td><code>remove</code></td> |
|
480 <td>A node is removed from the tree.</td> |
|
481 <td> |
|
482 <dl> |
|
483 <dt>destroy (<em>Boolean</em>)</dt> |
|
484 <dd>Whether or not the node will be destroyed after being removed.</dd> |
|
485 |
|
486 <dt>node (<em>Tree.Node</em>)</dt> |
|
487 <dd>Node being removed.</dd> |
|
488 |
|
489 <dt>parent (<em>Tree.Node</em>)</dt> |
|
490 <dd>Parent node from which the node will be removed.</dd> |
|
491 </dl> |
|
492 </td> |
|
493 </tr> |
|
494 </tbody> |
|
495 </table> |
|
496 |
|
497 <p>All events exposed by <code>Y.Tree</code> are preventable, which means that the "on" phase of the event occurs before the event's default action takes place. You can prevent the default action from taking place by calling the <code>preventDefault()</code> method on the event façade.</p> |
|
498 |
|
499 <p>If you're only interested in being notified of an event after its default action has occurred, subscribe to the event's "after" phase.</p> |
|
500 |
|
501 <h2 id="plugins-extensions">Plugins & Extensions</h2> |
|
502 |
|
503 <p>While the base functionality of Tree is kept intentionally simple and generic, extensions and plugins can be used to provide additional features. This makes it easy to adapt the Tree component to a variety of use cases.</p> |
|
504 |
|
505 <p>Each extension is described here individually, but a custom Tree class can mix in multiple extensions to compose a class with the perfect set of features to meet your needs.</p> |
|
506 |
|
507 <h3 id="labelable-extension">Labelable Extension</h3> |
|
508 |
|
509 <p>The Labelable extension adds support for a serializable <code>label</code> property on <code>Y.Tree.Node</code> instances. This can be useful when a tree is the backing data structure for a widget with labeled nodes, such as a treeview or menu.</p> |
|
510 |
|
511 <p>To use the Labelable extension, include the <a href="http://yuilibrary.com/yui/docs/api/modules/tree-labelable.html"><code>tree-labelable</code></a> module, then create a class that extends <code>Y.Tree</code> and mixes in <code>Y.Tree.Labelable</code>.</p> |
|
512 |
|
513 <pre class="code prettyprint lang-js">// Load the tree-labelable module. |
|
514 YUI().use('tree-labelable', function (Y) { |
|
515 // Create a custom Tree class that mixes in the Labelable extension. |
|
516 Y.PieTree = Y.Base.create('pieTree', Y.Tree, [Y.Tree.Labelable]); |
|
517 |
|
518 // ... additional implementation code here ... |
|
519 });</pre> |
|
520 |
|
521 |
|
522 <p>Tree nodes created by this custom class can now take advantage of the <code>label</code> property.</p> |
|
523 |
|
524 <pre class="code prettyprint lang-js">// Create a new tree with some labeled nodes. |
|
525 var tree = new Y.PieTree({ |
|
526 nodes: [ |
|
527 {label: 'fruit pies', children: [ |
|
528 {label: 'apple'}, |
|
529 {label: 'peach'}, |
|
530 {label: 'marionberry'} |
|
531 ]}, |
|
532 |
|
533 {label: 'custard pies', children: [ |
|
534 {label: 'maple custard'}, |
|
535 {label: 'pumpkin'} |
|
536 ]} |
|
537 ] |
|
538 });</pre> |
|
539 |
|
540 |
|
541 <h3 id="openable-extension">Openable Extension</h3> |
|
542 |
|
543 <p>The Openable extension adds the concept of an "open" and "closed" state for tree nodes, along with related methods and events.</p> |
|
544 |
|
545 <p>To use the Openable extension, include the <a href="http://yuilibrary.com/yui/docs/api/modules/tree-openable.html"><code>tree-openable</code></a> module, then create a class that extends <code>Y.Tree</code> and mixes in <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Openable.html"><code>Y.Tree.Openable</code></a>.</p> |
|
546 |
|
547 <pre class="code prettyprint lang-js">// Load the tree-openable module. |
|
548 YUI().use('tree-openable', function (Y) { |
|
549 // Create a custom Tree class that mixes in the Openable extension. |
|
550 Y.MenuTree = Y.Base.create('menuTree', Y.Tree, [Y.Tree.Openable]); |
|
551 |
|
552 // ... additional implementation code here ... |
|
553 });</pre> |
|
554 |
|
555 |
|
556 <p>Tree nodes created by this custom class are now considered closed by default, but can be opened either by setting the <code>state.open</code> property to <code>true</code> at creation time or by calling the node's <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.Openable.html#method_open"><code>open()</code></a> method.</p> |
|
557 |
|
558 <pre class="code prettyprint lang-js">// Create a new tree with some openable nodes. |
|
559 var tree = new Y.MenuTree({ |
|
560 nodes: [ |
|
561 {id: 'file', children: [ |
|
562 {id: 'new'}, |
|
563 {id: 'open'}, |
|
564 {id: 'save'} |
|
565 ]}, |
|
566 |
|
567 {id: 'edit', state: {open: true}, children: [ |
|
568 {id: 'copy'}, |
|
569 {id: 'cut'}, |
|
570 {id: 'paste'} |
|
571 ]} |
|
572 ] |
|
573 }); |
|
574 |
|
575 // Close the "edit" node. |
|
576 tree.getNodeById('edit').close(); |
|
577 |
|
578 // Open the "file" node. |
|
579 tree.getNodeById('file').open();</pre> |
|
580 |
|
581 |
|
582 <p>Tree instances that mix in the Openable extension receive two new events: <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Openable.html#event_open"><code>open</code></a> and <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Openable.html#event_close"><code>close</code></a>. These events fire when a node is opened or closed, respectively.</p> |
|
583 |
|
584 <p>See the <a href="http://yuilibrary.com/yui/docs/api/modules/tree-openable.html">API docs</a> for more details on the methods and events added by the Openable extension.</p> |
|
585 |
|
586 <h4 id="lazy-tree-plugin">Lazy Tree Plugin</h4> |
|
587 |
|
588 <p>The Lazy Tree plugin is a companion for the Openable extension that makes it easy to load and populate a node's children on demand the first time that node is opened. This can help improve performance in very large trees by avoiding populating the children of closed nodes until they're needed.</p> |
|
589 |
|
590 <p>To use the Lazy Tree plugin, include the <a href="http://yuilibrary.com/yui/docs/api/modules/tree-lazy.html"><code>tree-lazy</code></a> and <a href="http://yuilibrary.com/yui/docs/api/modules/tree-openable.html"><code>tree-openable</code></a> modules and create a custom tree class that mixes in the <a href="#openable-extension">Openable extension</a>, as described above.</p> |
|
591 |
|
592 <pre class="code prettyprint lang-js">// Load the tree-lazy and tree-openable modules. In this example we'll also |
|
593 // load the jsonp module to demonstrate how to load node data via JSONP. |
|
594 YUI().use('jsonp', 'tree-lazy', 'tree-openable', function (Y) { |
|
595 // Create a custom Tree class that mixes in the Openable extension. |
|
596 Y.LazyTree = Y.Base.create('lazyTree', Y.Tree, [Y.Tree.Openable]); |
|
597 |
|
598 // ... additional implementation code here ... |
|
599 });</pre> |
|
600 |
|
601 |
|
602 <p>Next, create an instance of your tree class, and plug <a href="http://yuilibrary.com/yui/docs/api/classes/Plugin.Tree.Lazy.html"><code>Y.Plugin.Tree.Lazy</code></a> into it. Provide a custom <code>load()</code> function that will be called the first time a node is opened. This callback is responsible for populating the node with children if necessary.</p> |
|
603 |
|
604 <pre class="code prettyprint lang-js">// Create a new tree instance. |
|
605 var tree = new Y.LazyTree(); |
|
606 |
|
607 // Plug in the Lazy Tree plugin and provide a load() callback that will |
|
608 // populate child nodes on demand. |
|
609 tree.plug(Y.Plugin.Tree.Lazy, { |
|
610 |
|
611 // Custom function that Y.Plugin.Tree.Lazy will call when it needs to |
|
612 // load the children for a node. |
|
613 load: function (node, callback) { |
|
614 // Request child nodes via JSONP. |
|
615 Y.jsonp('http://example.com/data?callback={callback}', function (data) { |
|
616 // If we didn't get any data back, treat this as an error. |
|
617 if (!data) { |
|
618 callback(new Error('No data!')); |
|
619 return; |
|
620 } |
|
621 |
|
622 // Append the loaded children to the node (for the sake of this |
|
623 // example, assume that data.children is an array of node config |
|
624 // objects). |
|
625 node.append(data.children); |
|
626 |
|
627 // Call the callback function to tell Y.Plugin.Tree.Lazy that |
|
628 // we're done loading data. |
|
629 callback(); |
|
630 }); |
|
631 }, |
|
632 |
|
633 // Handle events. |
|
634 on: { |
|
635 // Called before the load() function is executed for a node. |
|
636 beforeLoad: function () { /* ... */ }, |
|
637 |
|
638 // Called if the load() method passes an error to its callback. |
|
639 error: function () { /* ... */ }, |
|
640 |
|
641 // Called when the load() method executes its callback without an |
|
642 // error. |
|
643 load: function () { /* ... */ } |
|
644 } |
|
645 |
|
646 });</pre> |
|
647 |
|
648 |
|
649 <p>The first time any node with a truthy <code>canHaveChildren</code> property is opened, the Lazy Tree plugin will fire a <a href="http://yuilibrary.com/yui/docs/api/classes/Plugin.Tree.Lazy.html#event_beforeLoad"><code>beforeLoad</code></a> event and then call your custom <code>load()</code> function, passing in the node being opened and a callback that you should call once you've finished populating the node with children.</p> |
|
650 |
|
651 <p>How you load your node data is entirely up to you. You could use JSONP, XHR, pull it out of localStorage, or use any number of other techniques. All the Lazy Tree plugin cares about is that you populate the node and call the provided callback when you're done.</p> |
|
652 |
|
653 <p>If you pass an error to the callback, the plugin will fire an <a href="http://yuilibrary.com/yui/docs/api/classes/Plugin.Tree.Lazy.html#event_error"><code>error</code></a> event.</p> |
|
654 |
|
655 <p>If you call the callback without an error, the plugin will fire a <a href="http://yuilibrary.com/yui/docs/api/classes/Plugin.Tree.Lazy.html#event_load"><code>load</code></a> event to indicate that the node's children were loaded successfully.</p> |
|
656 |
|
657 <h3 id="selectable-extension">Selectable Extension</h3> |
|
658 |
|
659 <p>The Selectable extension adds the concept of a "selected" state for tree nodes, along with related methods, events, and tree attributes.</p> |
|
660 |
|
661 <p>To use the Selectable extension, include the <a href="http://yuilibrary.com/yui/docs/api/modules/tree-selectable.html"><code>tree-selectable</code></a> module, then create a class that extends <code>Y.Tree</code> and mixes in <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Selectable.html"><code>Y.Tree.Selectable</code></a>.</p> |
|
662 |
|
663 <pre class="code prettyprint lang-js">// Load the tree-selectable module. |
|
664 YUI().use('tree-selectable', function (Y) { |
|
665 // Create a custom Tree class that mixes in the Selectable extension. |
|
666 Y.OptionTree = Y.Base.create('optionTree', Y.Tree, [Y.Tree.Selectable]); |
|
667 |
|
668 // ... additional implementation code here ... |
|
669 });</pre> |
|
670 |
|
671 |
|
672 <p>Tree nodes created by this custom class are now considered unselected by default, but can be selected either by setting the <code>state.selected</code> property to <code>true</code> at creation time or by calling the node's <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.Selectable.html#method_select"><code>select()</code></a> method.</p> |
|
673 |
|
674 |
|
675 <pre class="code prettyprint lang-js">// Create a new tree with selectable nodes. |
|
676 var tree = new Y.OptionTree({ |
|
677 nodes: [ |
|
678 {id: 'kittens', children: [ |
|
679 {id: 'chartreux', state: {selected: true}}, |
|
680 {id: 'maine coon'}, |
|
681 {id: 'british shorthair'} |
|
682 ]}, |
|
683 |
|
684 {id: 'puppies', children: [ |
|
685 {id: 'pug'}, |
|
686 {id: 'dachshund'}, |
|
687 {id: 'miniature schnauzer'} |
|
688 ]} |
|
689 ] |
|
690 }); |
|
691 |
|
692 // Select a puppy. |
|
693 tree.getNodeById('pug').select();</pre> |
|
694 |
|
695 |
|
696 <p>By default, only one node in the tree may be selected at a time. Selecting a node when another node is already selected will cause the original node to be unselected. To allow multiple selection, set the tree's <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Selectable.html#attr_multiSelect"><code>multiSelect</code></a> attribute to <code>true</code>.</p> |
|
697 |
|
698 <p>When a node is selected, the Selectable extension fires a <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Selectable.html#event_select"><code>select</code></a> event. When a node is unselected, it fires an <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Selectable.html#event_unselect"><code>unselect</code></a> event.</p> |
|
699 |
|
700 <p>See the <a href="http://yuilibrary.com/yui/docs/api/modules/tree-selectable.html">API docs</a> for more details.</p> |
|
701 |
|
702 <h3 id="sortable-extension">Sortable Extension</h3> |
|
703 |
|
704 <p>The Sortable extension makes it possible to sort the children of any node using custom sorting logic, and also ensures that inserted nodes are added at the appropriate index to maintain the current sort order.</p> |
|
705 |
|
706 <p>To use the Sortable extension, include the <a href="http://yuilibrary.com/yui/docs/api/modules/tree-sortable.html"><code>tree-sortable</code></a> module, then create a class that extends <code>Y.Tree</code> and mixes in <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Sortable.html"><code>Y.Tree.Sortable</code></a>.</p> |
|
707 |
|
708 <pre class="code prettyprint lang-js">// Load the tree-sortable module. |
|
709 YUI().use('tree-sortable', function (Y) { |
|
710 // Create a custom Tree class that mixes in the Sortable extension. |
|
711 Y.SortableTree = Y.Base.create('sortableTree', Y.Tree, [Y.Tree.Sortable]); |
|
712 |
|
713 // ... additional implementation code here ... |
|
714 });</pre> |
|
715 |
|
716 |
|
717 <p>Nodes will now be sorted automatically as they're inserted in this tree, or you can manually re-sort all children of a specific node by calling that node's <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Node.Sortable.html#method_sort"><code>sort()</code></a> method.</p> |
|
718 |
|
719 <p>By default, nodes are sorted in insertion order, meaning that the first node you insert gets index 0, the second node inserted gets index 1, and so on. To customize the sort criteria, pass a custom <code>sortComparator</code> function to the tree's constructor, or set it on the tree's prototype. This function will receive a node as an argument, and should return a value by which that node should be sorted.</p> |
|
720 |
|
721 <p>Here's a <code>sortComparator</code> function that sorts nodes by id:</p> |
|
722 |
|
723 <pre class="code prettyprint lang-js">var tree = new Y.SortableTree({ |
|
724 sortComparator: function (node) { |
|
725 return node.id; |
|
726 } |
|
727 });</pre> |
|
728 |
|
729 |
|
730 <p>To sort nodes in descending order instead of ascending order, set the tree's <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Sortable.html#property_sortReverse"><code>sortReverse</code></a> property to <code>true</code>.</p> |
|
731 |
|
732 <p>Each node in a tree may optionally have its own custom <code>sortComparator</code> and/or <code>sortReverse</code> properties to govern the sort order of its children. This makes it possible to use different sort criteria for different nodes in the tree. Setting these properties on a node will override the tree's <code>sortComparator</code> and <code>sortReverse</code> properties for that node's children (but not for its children's children).</p> |
|
733 |
|
734 <p>Tree instances that mix in the Sortable extension receive a <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.Sortable.html#event_sort"><code>sort</code></a> event that fires when a node's children are manually re-sorted by calling the <code>sort()</code> method.</p> |
|
735 |
|
736 <p>See the <a href="http://yuilibrary.com/yui/docs/api/modules/tree-sortable.html">API docs</a> for more details on the methods and events added by the Sortable extension.</p> |
|
737 |
|
738 <h2 id="creating-custom-tree-extensions">Creating Custom Tree Extensions</h2> |
|
739 |
|
740 <p><code>Y.Tree</code> extends <a href="../base/index.html"><code>Y.Base</code></a>, so a Tree extension begins just like any other Base extension class. However, since <code>Y.Tree.Node</code> doesn't extend <code>Y.Base</code> for performance reasons, a special composition mechanism is used to allow for lightweight <code>Y.Tree.Node</code> extensions.</p> |
|
741 |
|
742 <p>For a simple example, let's look at the implementation of the <a href="#labelable-extension">Labelable extension</a>.</p> |
|
743 |
|
744 <p>The <code>Y.Tree.Labelable</code> class, which will be mixed into a Tree as a Base extension, looks like this:</p> |
|
745 |
|
746 <pre class="code prettyprint lang-js">// Y.Tree.Labelable extension class. |
|
747 function Labelable() {} |
|
748 |
|
749 Labelable.prototype = { |
|
750 initializer: function () { |
|
751 this.nodeExtensions = this.nodeExtensions.concat(Y.Tree.Node.Labelable); |
|
752 } |
|
753 }; |
|
754 |
|
755 Y.Tree.Labelable = Labelable;</pre> |
|
756 |
|
757 |
|
758 <p>In the <code>initializer()</code> method, the Labelable extension creates a copy of the tree's <a href="http://yuilibrary.com/yui/docs/api/classes/Tree.html#property_nodeExtensions"><code>nodeExtensions</code></a> array, then adds the <code>Y.Tree.Node.Labelable</code> class to it.</p> |
|
759 |
|
760 <p>The <code>Y.Tree.Node.Labelable</code> class looks like this:</p> |
|
761 |
|
762 <pre class="code prettyprint lang-js">// Y.Tree.Node.Labelable class. |
|
763 function NodeLabelable(tree, config) { |
|
764 this._serializable = this._serializable.concat('label'); |
|
765 |
|
766 if ('label' in config) { |
|
767 this.label = config.label; |
|
768 } |
|
769 } |
|
770 |
|
771 NodeLabelable.prototype = { |
|
772 label: '' |
|
773 }; |
|
774 |
|
775 Y.Tree.Node.Labelable = NodeLabelable;</pre> |
|
776 |
|
777 |
|
778 <p>The specific implementation here isn't important, but it illustrates how node extensions work.</p> |
|
779 |
|
780 <p>When a Tree instance is created, <code>Y.Tree</code> extensions have a chance to add their custom <code>Y.Tree.Node</code> extension classes to the <code>nodeExtensions</code> array. Once all the tree extension initializers have run, a "composed" Tree Node class is created.</p> |
|
781 |
|
782 <p>This composed Tree Node class mixes in all the prototype properties of every class in <code>nodeExtensions</code> and automatically chains their constructor functions. This is similar in some ways to how <code>Y.Base</code> extensions work, but much lighter and faster, so composed nodes remain very efficient.</p> |
|
783 |
|
784 <p>For more detailed examples of Tree and Tree Node extensions, take a look at the <a href="https://github.com/yui/yui3/tree/dev-3.x/src/tree/js/extensions">source code</a> for the Openable and Selectable extensions.</p> |
|
785 </div> |
|
786 </div> |
|
787 </div> |
|
788 |
|
789 <div class="yui3-u-1-4"> |
|
790 <div class="sidebar"> |
|
791 |
|
792 <div id="toc" class="sidebox"> |
|
793 <div class="hd"> |
|
794 <h2 class="no-toc">Table of Contents</h2> |
|
795 </div> |
|
796 |
|
797 <div class="bd"> |
|
798 <ul class="toc"> |
|
799 <li> |
|
800 <a href="#getting-started">Getting Started</a> |
|
801 </li> |
|
802 <li> |
|
803 <a href="#using-tree">Using Tree</a> |
|
804 <ul class="toc"> |
|
805 <li> |
|
806 <a href="#creating-a-tree">Creating a Tree</a> |
|
807 </li> |
|
808 <li> |
|
809 <a href="#tree-properties">Tree Properties</a> |
|
810 </li> |
|
811 <li> |
|
812 <a href="#working-with-tree-nodes">Working with Tree Nodes</a> |
|
813 <ul class="toc"> |
|
814 <li> |
|
815 <a href="#tree-node-properties">Tree Node Properties</a> |
|
816 </li> |
|
817 <li> |
|
818 <a href="#creating-unattached-nodes">Creating Unattached Nodes</a> |
|
819 </li> |
|
820 <li> |
|
821 <a href="#adding-nodes-to-a-tree">Adding Nodes To a Tree</a> |
|
822 </li> |
|
823 <li> |
|
824 <a href="#getting-nodes-from-a-tree">Getting Nodes From a Tree</a> |
|
825 </li> |
|
826 <li> |
|
827 <a href="#removing-nodes-from-a-tree">Removing Nodes From a Tree</a> |
|
828 </li> |
|
829 </ul> |
|
830 </li> |
|
831 <li> |
|
832 <a href="#tree-events">Tree Events</a> |
|
833 </li> |
|
834 </ul> |
|
835 </li> |
|
836 <li> |
|
837 <a href="#plugins-extensions">Plugins & Extensions</a> |
|
838 <ul class="toc"> |
|
839 <li> |
|
840 <a href="#labelable-extension">Labelable Extension</a> |
|
841 </li> |
|
842 <li> |
|
843 <a href="#openable-extension">Openable Extension</a> |
|
844 <ul class="toc"> |
|
845 <li> |
|
846 <a href="#lazy-tree-plugin">Lazy Tree Plugin</a> |
|
847 </li> |
|
848 </ul> |
|
849 </li> |
|
850 <li> |
|
851 <a href="#selectable-extension">Selectable Extension</a> |
|
852 </li> |
|
853 <li> |
|
854 <a href="#sortable-extension">Sortable Extension</a> |
|
855 </li> |
|
856 </ul> |
|
857 </li> |
|
858 <li> |
|
859 <a href="#creating-custom-tree-extensions">Creating Custom Tree Extensions</a> |
|
860 </li> |
|
861 </ul> |
|
862 </div> |
|
863 </div> |
|
864 |
|
865 |
|
866 |
|
867 |
|
868 |
|
869 </div> |
|
870 </div> |
|
871 </div> |
|
872 </div> |
|
873 |
|
874 <script src="../assets/vendor/prettify/prettify-min.js"></script> |
|
875 <script>prettyPrint();</script> |
|
876 |
|
877 <script> |
|
878 YUI.Env.Tests = { |
|
879 examples: [], |
|
880 project: '../assets', |
|
881 assets: '../assets/tree', |
|
882 name: 'tree', |
|
883 title: 'Tree', |
|
884 newWindow: '', |
|
885 auto: false |
|
886 }; |
|
887 |
|
888 </script> |
|
889 <script src="../assets/yui/test-runner.js"></script> |
|
890 |
|
891 |
|
892 |
|
893 </body> |
|
894 </html> |