[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
1 /* 2 YUI 3.17.2 (build 9c3c78e) 3 Copyright 2014 Yahoo! Inc. All rights reserved. 4 Licensed under the BSD License. 5 http://yuilibrary.com/license/ 6 */ 7 8 YUI.add('tree-node', function (Y, NAME) { 9 10 /*jshint expr:true, onevar:false */ 11 12 /** 13 Provides the `Tree.Node` class, which represents a tree node contained in a 14 `Tree` data structure. 15 16 @module tree 17 @submodule tree-node 18 **/ 19 20 /** 21 Represents a tree node in a `Tree` data structure. 22 23 @class Tree.Node 24 @param {Tree} tree `Tree` instance with which this node should be associated. 25 @param {Object} [config] Configuration hash for this node. 26 27 @param {Boolean} [config.canHaveChildren=false] Whether or not this node can 28 contain child nodes. Will be automatically set to `true` if not 29 specified and `config.children` contains one or more children. 30 31 @param {Tree.Node[]} [config.children] Array of `Tree.Node` instances 32 for child nodes of this node. 33 34 @param {Object} [config.data] Implementation-specific data related to this 35 node. You may add arbitrary properties to this hash for your own use. 36 37 @param {String} [config.id] Unique id for this node. This id must be unique 38 among all tree nodes on the entire page, and will also be used as this 39 node's DOM id when it's rendered by a TreeView. A unique id will be 40 automatically generated unless you specify a custom value. 41 42 @param {Object} [config.state] State hash for this node. You may add 43 arbitrary state properties to this hash for your own use. See the 44 docs for `Tree.Node`'s `state` property for details on state values used 45 internally by `Tree.Node`. 46 47 @constructor 48 **/ 49 50 function TreeNode(tree, config) { 51 config || (config = {}); 52 53 this.id = this._yuid = config.id || this.id || Y.guid('treeNode-'); 54 this.tree = tree; 55 56 this.children = config.children || []; 57 this.data = config.data || {}; 58 this.state = config.state || {}; 59 60 if (config.canHaveChildren) { 61 this.canHaveChildren = config.canHaveChildren; 62 } else if (this.children.length) { 63 this.canHaveChildren = true; 64 } 65 66 // Mix in arbitrary properties on the config object, but don't overwrite any 67 // existing properties of this node. 68 Y.mix(this, config); 69 70 // If this node has children, loop through them and ensure their parent 71 // references are all set to this node. 72 for (var i = 0, len = this.children.length; i < len; i++) { 73 this.children[i].parent = this; 74 } 75 } 76 77 TreeNode.prototype = { 78 // -- Public Properties ---------------------------------------------------- 79 80 /** 81 Whether or not this node can contain child nodes. 82 83 This value is falsy by default unless child nodes are added at instantiation 84 time, in which case it will be automatically set to `true`. You can also 85 manually set it to `true` to indicate that a node can have children even 86 though it might not currently have any children. 87 88 Note that regardless of the value of this property, appending, prepending, 89 or inserting a node into this node will cause `canHaveChildren` to be set to 90 true automatically. 91 92 @property {Boolean} canHaveChildren 93 **/ 94 95 /** 96 Child nodes contained within this node. 97 98 @property {Tree.Node[]} children 99 @default [] 100 @readOnly 101 **/ 102 103 /** 104 Arbitrary serializable data related to this node. 105 106 Use this property to store any data that should accompany this node when it 107 is serialized to JSON. 108 109 @property {Object} data 110 @default {} 111 **/ 112 113 /** 114 Unique id for this node. 115 116 @property {String} id 117 @readOnly 118 **/ 119 120 /** 121 Parent node of this node, or `undefined` if this is an unattached node or 122 the root node. 123 124 @property {Tree.Node} parent 125 @readOnly 126 **/ 127 128 /** 129 Current state of this node. 130 131 Use this property to store state-specific info -- such as whether this node 132 is "open", "selected", or any other arbitrary state -- that should accompany 133 this node when it is serialized to JSON. 134 135 @property {Object} state 136 **/ 137 138 /** 139 The Tree instance with which this node is associated. 140 141 @property {Tree} tree 142 @readOnly 143 **/ 144 145 // -- Protected Properties ------------------------------------------------- 146 147 /** 148 Mapping of child node ids to indices. 149 150 @property {Object} _indexMap 151 @protected 152 **/ 153 154 /** 155 Flag indicating whether the `_indexMap` is stale and needs to be rebuilt. 156 157 @property {Boolean} _isIndexStale 158 @default true 159 @protected 160 **/ 161 _isIndexStale: true, 162 163 /** 164 Simple way to type-check that this is an instance of Tree.Node. 165 166 @property {Boolean} _isYUITreeNode 167 @default true 168 @protected 169 **/ 170 _isYUITreeNode: true, 171 172 /** 173 Array of property names on this node that should be serialized to JSON when 174 `toJSON()` is called. 175 176 Note that the `children` property is a special case that is managed 177 separately. 178 179 @property {String[]} _serializable 180 @protected 181 **/ 182 _serializable: ['canHaveChildren', 'data', 'id', 'state'], 183 184 // -- Public Methods ------------------------------------------------------- 185 186 /** 187 Appends the given tree node or array of nodes to the end of this node's 188 children. 189 190 @method append 191 @param {Object|Object[]|Tree.Node|Tree.Node[]} node Child node, node config 192 object, array of child nodes, or array of node config objects to append 193 to the given parent. Node config objects will automatically be converted 194 into node instances. 195 @param {Object} [options] Options. 196 @param {Boolean} [options.silent=false] If `true`, the `add` event will 197 be suppressed. 198 @return {Tree.Node|Tree.Node[]} Node or array of nodes that were appended. 199 **/ 200 append: function (node, options) { 201 return this.tree.appendNode(this, node, options); 202 }, 203 204 /** 205 Returns this node's depth. 206 207 The root node of a tree always has a depth of 0. A child of the root has a 208 depth of 1, a child of that child will have a depth of 2, and so on. 209 210 @method depth 211 @return {Number} This node's depth. 212 @since 3.11.0 213 **/ 214 depth: function () { 215 if (this.isRoot()) { 216 return 0; 217 } 218 219 var depth = 0, 220 parent = this.parent; 221 222 while (parent) { 223 depth += 1; 224 parent = parent.parent; 225 } 226 227 return depth; 228 }, 229 230 /** 231 Removes all children from this node. The removed children will still be 232 reusable unless the `destroy` option is truthy. 233 234 @method empty 235 @param {Object} [options] Options. 236 @param {Boolean} [options.destroy=false] If `true`, the children will 237 also be destroyed, which makes them available for garbage collection 238 and means they can't be reused. 239 @param {Boolean} [options.silent=false] If `true`, `remove` events will 240 be suppressed. 241 @param {String} [options.src] Source of the change, to be passed along 242 to the event facade of the resulting event. This can be used to 243 distinguish between changes triggered by a user and changes 244 triggered programmatically, for example. 245 @return {Tree.Node[]} Array of removed child nodes. 246 **/ 247 empty: function (options) { 248 return this.tree.emptyNode(this, options); 249 }, 250 251 /** 252 Performs a depth-first traversal of this node, passing it and each of its 253 descendants to the specified _callback_, and returning the first node for 254 which the callback returns a truthy value. 255 256 Traversal will stop as soon as a truthy value is returned from the callback. 257 258 See `Tree#traverseNode()` for more details on how depth-first traversal 259 works. 260 261 @method find 262 @param {Object} [options] Options. 263 @param {Number} [options.depth] Depth limit. If specified, descendants 264 will only be traversed to this depth before backtracking and moving 265 on. 266 @param {Function} callback Callback function to call with the traversed 267 node and each of its descendants. If this function returns a truthy 268 value, traversal will be stopped and the current node will be returned. 269 270 @param {Tree.Node} callback.node Node being traversed. 271 272 @param {Object} [thisObj] `this` object to use when executing _callback_. 273 @return {Tree.Node|null} Returns the first node for which the _callback_ 274 returns a truthy value, or `null` if the callback never returns a truthy 275 value. 276 **/ 277 find: function (options, callback, thisObj) { 278 return this.tree.findNode(this, options, callback, thisObj); 279 }, 280 281 /** 282 Returns `true` if this node has one or more child nodes. 283 284 @method hasChildren 285 @return {Boolean} `true` if this node has one or more child nodes, `false` 286 otherwise. 287 **/ 288 hasChildren: function () { 289 return !!this.children.length; 290 }, 291 292 /** 293 Returns the numerical index of this node within its parent node, or `-1` if 294 this node doesn't have a parent node. 295 296 @method index 297 @return {Number} Index of this node within its parent node, or `-1` if this 298 node doesn't have a parent node. 299 **/ 300 index: function () { 301 return this.parent ? this.parent.indexOf(this) : -1; 302 }, 303 304 /** 305 Returns the numerical index of the given child node, or `-1` if the node is 306 not a child of this node. 307 308 @method indexOf 309 @param {Tree.Node} node Child node. 310 @return {Number} Index of the child, or `-1` if the node is not a child of 311 this node. 312 **/ 313 indexOf: function (node) { 314 var index; 315 316 if (this._isIndexStale) { 317 this._reindex(); 318 } 319 320 index = this._indexMap[node.id]; 321 322 return typeof index === 'undefined' ? -1 : index; 323 }, 324 325 /** 326 Inserts a node or array of nodes at the specified index under this node, or 327 appends them to this node if no index is specified. 328 329 If a node being inserted is from another tree, it and all its children will 330 be removed from that tree and moved to this one. 331 332 @method insert 333 @param {Object|Object[]|Tree.Node|Tree.Node[]} node Child node, node config 334 object, array of child nodes, or array of node config objects to insert 335 under the given parent. Node config objects will automatically be 336 converted into node instances. 337 338 @param {Object} [options] Options. 339 @param {Number} [options.index] Index at which to insert the child node. 340 If not specified, the node will be appended as the last child of the 341 parent. 342 @param {Boolean} [options.silent=false] If `true`, the `add` event will 343 be suppressed. 344 @param {String} [options.src='insert'] Source of the change, to be 345 passed along to the event facade of the resulting event. This can be 346 used to distinguish between changes triggered by a user and changes 347 triggered programmatically, for example. 348 349 @return {Tree.Node[]} Node or array of nodes that were inserted. 350 **/ 351 insert: function (node, options) { 352 return this.tree.insertNode(this, node, options); 353 }, 354 355 /** 356 Returns `true` if this node has been inserted into a tree, `false` if it is 357 merely associated with a tree and has not yet been inserted. 358 359 @method isInTree 360 @return {Boolean} `true` if this node has been inserted into a tree, `false` 361 otherwise. 362 **/ 363 isInTree: function () { 364 if (this.tree && this.tree.rootNode === this) { 365 return true; 366 } 367 368 return !!(this.parent && this.parent.isInTree()); 369 }, 370 371 /** 372 Returns `true` if this node is the root of the tree. 373 374 @method isRoot 375 @return {Boolean} `true` if this node is the root of the tree, `false` 376 otherwise. 377 **/ 378 isRoot: function () { 379 return !!(this.tree && this.tree.rootNode === this); 380 }, 381 382 /** 383 Returns this node's next sibling, or `undefined` if this node is the last 384 child. 385 386 @method next 387 @return {Tree.Node} This node's next sibling, or `undefined` if this node is 388 the last child. 389 **/ 390 next: function () { 391 if (this.parent) { 392 return this.parent.children[this.index() + 1]; 393 } 394 }, 395 396 /** 397 Prepends a node or array of nodes at the beginning of this node's children. 398 399 If a node being prepended is from another tree, it and all its children will 400 be removed from that tree and moved to this one. 401 402 @method prepend 403 @param {Object|Object[]|Tree.Node|Tree.Node[]} node Child node, node config 404 object, array of child nodes, or array of node config objects to prepend 405 to this node. Node config objects will automatically be converted into 406 node instances. 407 @param {Object} [options] Options. 408 @param {Boolean} [options.silent=false] If `true`, the `add` event will 409 be suppressed. 410 @return {Tree.Node|Tree.Node[]} Node or array of nodes that were prepended. 411 **/ 412 prepend: function (node, options) { 413 return this.tree.prependNode(this, node, options); 414 }, 415 416 /** 417 Returns this node's previous sibling, or `undefined` if this node is the 418 first child 419 420 @method previous 421 @return {Tree.Node} This node's previous sibling, or `undefined` if this 422 node is the first child. 423 **/ 424 previous: function () { 425 if (this.parent) { 426 return this.parent.children[this.index() - 1]; 427 } 428 }, 429 430 /** 431 Removes this node from its parent node. 432 433 @method remove 434 @param {Object} [options] Options. 435 @param {Boolean} [options.destroy=false] If `true`, this node and all 436 its children will also be destroyed, which makes them available for 437 garbage collection and means they can't be reused. 438 @param {Boolean} [options.silent=false] If `true`, the `remove` event 439 will be suppressed. 440 @param {String} [options.src] Source of the change, to be passed along 441 to the event facade of the resulting event. This can be used to 442 distinguish between changes triggered by a user and changes 443 triggered programmatically, for example. 444 @chainable 445 **/ 446 remove: function (options) { 447 return this.tree.removeNode(this, options); 448 }, 449 450 /** 451 Returns the total number of nodes contained within this node, including all 452 descendants of this node's children. 453 454 @method size 455 @return {Number} Total number of nodes contained within this node, including 456 all descendants. 457 **/ 458 size: function () { 459 var children = this.children, 460 len = children.length, 461 total = len; 462 463 for (var i = 0; i < len; i++) { 464 total += children[i].size(); 465 } 466 467 return total; 468 }, 469 470 /** 471 Serializes this node to an object suitable for use in JSON. 472 473 @method toJSON 474 @return {Object} Serialized node object. 475 **/ 476 toJSON: function () { 477 var obj = {}, 478 state = this.state, 479 i, key, len; 480 481 // Do nothing if this node is marked as destroyed. 482 if (state.destroyed) { 483 return null; 484 } 485 486 // Serialize properties explicitly marked as serializable. 487 for (i = 0, len = this._serializable.length; i < len; i++) { 488 key = this._serializable[i]; 489 490 if (key in this) { 491 obj[key] = this[key]; 492 } 493 } 494 495 // Serialize child nodes. 496 if (this.canHaveChildren) { 497 obj.children = []; 498 499 for (i = 0, len = this.children.length; i < len; i++) { 500 obj.children.push(this.children[i].toJSON()); 501 } 502 } 503 504 return obj; 505 }, 506 507 /** 508 Performs a depth-first traversal of this node, passing it and each of its 509 descendants to the specified _callback_. 510 511 If the callback function returns `Tree.STOP_TRAVERSAL`, traversal will be 512 stopped immediately. Otherwise, it will continue until the deepest 513 descendant of _node_ has been traversed, or until each branch has been 514 traversed to the optional maximum depth limit. 515 516 Since traversal is depth-first, that means nodes are traversed like this: 517 518 1 519 / | \ 520 2 8 9 521 / \ \ 522 3 7 10 523 / | \ / \ 524 4 5 6 11 12 525 526 @method traverse 527 @param {Object} [options] Options. 528 @param {Number} [options.depth] Depth limit. If specified, descendants 529 will only be traversed to this depth before backtracking and moving 530 on. 531 @param {Function} callback Callback function to call with the traversed 532 node and each of its descendants. 533 534 @param {Tree.Node} callback.node Node being traversed. 535 536 @param {Object} [thisObj] `this` object to use when executing _callback_. 537 @return {Mixed} Returns `Tree.STOP_TRAVERSAL` if traversal was stopped; 538 otherwise returns `undefined`. 539 **/ 540 traverse: function (options, callback, thisObj) { 541 return this.tree.traverseNode(this, options, callback, thisObj); 542 }, 543 544 // -- Protected Methods ---------------------------------------------------- 545 _reindex: function () { 546 var children = this.children, 547 indexMap = {}, 548 i, len; 549 550 for (i = 0, len = children.length; i < len; i++) { 551 indexMap[children[i].id] = i; 552 } 553 554 this._indexMap = indexMap; 555 this._isIndexStale = false; 556 } 557 }; 558 559 Y.namespace('Tree').Node = TreeNode; 560 561 562 }, '3.17.2');
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |