1 <!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.NodeInterface'>/**
2 </span> * @class Ext.data.NodeInterface
3 * This class is meant to be used as a set of methods that are applied to the prototype of a
4 * Record to decorate it with a Node API. This means that models used in conjunction with a tree
5 * will have all of the tree related methods available on the model. In general this class will
6 * not be used directly by the developer.
8 Ext.define('Ext.data.NodeInterface', {
9 requires: ['Ext.data.Field'],
12 <span id='Ext-data.NodeInterface-method-decorate'> /**
13 </span> * This method allows you to decorate a Record's prototype to implement the NodeInterface.
14 * This adds a set of methods, new events, new properties and new fields on every Record
15 * with the same Model as the passed Record.
16 * @param {Ext.data.Record} record The Record you want to decorate the prototype of.
19 decorate: function(record) {
21 // Apply the methods and fields to the prototype
22 // @TODO: clean this up to use proper class system stuff
23 var mgr = Ext.ModelManager,
24 modelName = record.modelName,
25 modelClass = mgr.getModel(modelName),
26 idName = modelClass.prototype.idProperty,
27 instances = Ext.Array.filter(mgr.all.getArray(), function(item) {
28 return item.modelName == modelName;
30 iln = instances.length,
32 i, instance, jln, j, newField;
34 // Start by adding the NodeInterface methods to the Model's prototype
35 modelClass.override(this.getPrototypeBody());
36 newFields = this.applyFields(modelClass, [
37 {name: idName, type: 'string', defaultValue: null},
38 {name: 'parentId', type: 'string', defaultValue: null},
39 {name: 'index', type: 'int', defaultValue: null},
40 {name: 'depth', type: 'int', defaultValue: 0},
41 {name: 'expanded', type: 'bool', defaultValue: false, persist: false},
42 {name: 'checked', type: 'auto', defaultValue: null},
43 {name: 'leaf', type: 'bool', defaultValue: false, persist: false},
44 {name: 'cls', type: 'string', defaultValue: null, persist: false},
45 {name: 'iconCls', type: 'string', defaultValue: null, persist: false},
46 {name: 'root', type: 'boolean', defaultValue: false, persist: false},
47 {name: 'isLast', type: 'boolean', defaultValue: false, persist: false},
48 {name: 'isFirst', type: 'boolean', defaultValue: false, persist: false},
49 {name: 'allowDrop', type: 'boolean', defaultValue: true, persist: false},
50 {name: 'allowDrag', type: 'boolean', defaultValue: true, persist: false},
51 {name: 'loaded', type: 'boolean', defaultValue: false, persist: false},
52 {name: 'loading', type: 'boolean', defaultValue: false, persist: false},
53 {name: 'href', type: 'string', defaultValue: null, persist: false},
54 {name: 'hrefTarget',type: 'string', defaultValue: null, persist: false},
55 {name: 'qtip', type: 'string', defaultValue: null, persist: false},
56 {name: 'qtitle', type: 'string', defaultValue: null, persist: false}
59 jln = newFields.length;
60 // Set default values to all instances already out there
61 for (i = 0; i < iln; i++) {
62 instance = instances[i];
63 for (j = 0; j < jln; j++) {
64 newField = newFields[j];
65 if (instance.get(newField.name) === undefined) {
66 instance.data[newField.name] = newField.defaultValue;
76 previousSibling: null,
80 // Commit any fields so the record doesn't show as dirty initially
84 <span id='Ext-data.NodeInterface-event-append'> /**
85 </span> * @event append
86 * Fires when a new child node is appended
87 * @param {Node} this This node
88 * @param {Node} node The newly appended node
89 * @param {Number} index The index of the newly appended node
93 <span id='Ext-data.NodeInterface-event-remove'> /**
94 </span> * @event remove
95 * Fires when a child node is removed
96 * @param {Node} this This node
97 * @param {Node} node The removed node
101 <span id='Ext-data.NodeInterface-event-move'> /**
102 </span> * @event move
103 * Fires when this node is moved to a new location in the tree
104 * @param {Node} this This node
105 * @param {Node} oldParent The old parent of this node
106 * @param {Node} newParent The new parent of this node
107 * @param {Number} index The index it was moved to
111 <span id='Ext-data.NodeInterface-event-insert'> /**
112 </span> * @event insert
113 * Fires when a new child node is inserted.
114 * @param {Node} this This node
115 * @param {Node} node The child node inserted
116 * @param {Node} refNode The child node the node was inserted before
120 <span id='Ext-data.NodeInterface-event-beforeappend'> /**
121 </span> * @event beforeappend
122 * Fires before a new child is appended, return false to cancel the append.
123 * @param {Node} this This node
124 * @param {Node} node The child node to be appended
126 "beforeappend",
128 <span id='Ext-data.NodeInterface-event-beforeremove'> /**
129 </span> * @event beforeremove
130 * Fires before a child is removed, return false to cancel the remove.
131 * @param {Node} this This node
132 * @param {Node} node The child node to be removed
134 "beforeremove",
136 <span id='Ext-data.NodeInterface-event-beforemove'> /**
137 </span> * @event beforemove
138 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
139 * @param {Node} this This node
140 * @param {Node} oldParent The parent of this node
141 * @param {Node} newParent The new parent this node is moving to
142 * @param {Number} index The index it is being moved to
144 "beforemove",
146 <span id='Ext-data.NodeInterface-event-beforeinsert'> /**
147 </span> * @event beforeinsert
148 * Fires before a new child is inserted, return false to cancel the insert.
149 * @param {Node} this This node
150 * @param {Node} node The child node to be inserted
151 * @param {Node} refNode The child node the node is being inserted before
153 "beforeinsert",
155 <span id='Ext-data.NodeInterface-event-expand'> /**
156 </span> * @event expand
157 * Fires when this node is expanded.
158 * @param {Node} this The expanding node
162 <span id='Ext-data.NodeInterface-event-collapse'> /**
163 </span> * @event collapse
164 * Fires when this node is collapsed.
165 * @param {Node} this The collapsing node
167 "collapse",
169 <span id='Ext-data.NodeInterface-event-beforeexpand'> /**
170 </span> * @event beforeexpand
171 * Fires before this node is expanded.
172 * @param {Node} this The expanding node
174 "beforeexpand",
176 <span id='Ext-data.NodeInterface-event-beforecollapse'> /**
177 </span> * @event beforecollapse
178 * Fires before this node is collapsed.
179 * @param {Node} this The collapsing node
181 "beforecollapse",
183 <span id='Ext-data.NodeInterface-event-beforecollapse'> /**
184 </span> * @event beforecollapse
185 * Fires before this node is collapsed.
186 * @param {Node} this The collapsing node
194 applyFields: function(modelClass, addFields) {
195 var modelPrototype = modelClass.prototype,
196 fields = modelPrototype.fields,
198 ln = addFields.length,
202 for (i = 0; i < ln; i++) {
203 addField = addFields[i];
204 if (!Ext.Array.contains(keys, addField.name)) {
205 addField = Ext.create('data.field', addField);
207 newFields.push(addField);
208 fields.add(addField);
215 getPrototypeBody: function() {
219 <span id='Ext-data.NodeInterface-method-createNode'> /**
220 </span> * Ensures that the passed object is an instance of a Record with the NodeInterface applied
223 createNode: function(node) {
224 if (Ext.isObject(node) && !node.isModel) {
225 node = Ext.ModelManager.create(node, this.modelName);
227 // Make sure the node implements the node interface
228 return Ext.data.NodeInterface.decorate(node);
231 <span id='Ext-data.NodeInterface-method-isLeaf'> /**
232 </span> * Returns true if this node is a leaf
235 isLeaf : function() {
236 return this.get('leaf') === true;
239 <span id='Ext-data.NodeInterface-method-setFirstChild'> /**
240 </span> * Sets the first child of this node
242 * @param {Ext.data.NodeInterface} node
244 setFirstChild : function(node) {
245 this.firstChild = node;
248 <span id='Ext-data.NodeInterface-method-setLastChild'> /**
249 </span> * Sets the last child of this node
251 * @param {Ext.data.NodeInterface} node
253 setLastChild : function(node) {
254 this.lastChild = node;
257 <span id='Ext-data.NodeInterface-method-updateInfo'> /**
258 </span> * Updates general data of this node like isFirst, isLast, depth. This
259 * method is internally called after a node is moved. This shouldn't
260 * have to be called by the developer unless they are creating custom
264 updateInfo: function(silent) {
266 isRoot = me.isRoot(),
267 parentNode = me.parentNode,
268 isFirst = (!parentNode ? true : parentNode.firstChild == me),
269 isLast = (!parentNode ? true : parentNode.lastChild == me),
272 children = me.childNodes,
273 len = children.length,
276 while (parent.parentNode) {
278 parent = parent.parentNode;
286 index: parentNode ? parentNode.indexOf(me) : 0,
287 parentId: parentNode ? parentNode.getId() : null
294 for (i = 0; i < len; i++) {
295 children[i].updateInfo(silent);
299 <span id='Ext-data.NodeInterface-method-isLast'> /**
300 </span> * Returns true if this node is the last child of its parent
303 isLast : function() {
304 return this.get('isLast');
307 <span id='Ext-data.NodeInterface-method-isFirst'> /**
308 </span> * Returns true if this node is the first child of its parent
311 isFirst : function() {
312 return this.get('isFirst');
315 <span id='Ext-data.NodeInterface-method-hasChildNodes'> /**
316 </span> * Returns true if this node has one or more child nodes, else false.
319 hasChildNodes : function() {
320 return !this.isLeaf() && this.childNodes.length > 0;
323 <span id='Ext-data.NodeInterface-method-isExpandable'> /**
324 </span> * Returns true if this node has one or more child nodes, or if the <tt>expandable</tt>
325 * node attribute is explicitly specified as true (see {@link #attributes}), otherwise returns false.
328 isExpandable : function() {
329 return this.get('expandable') || this.hasChildNodes();
332 <span id='Ext-data.NodeInterface-method-appendChild'> /**
333 </span> * <p>Insert node(s) as the last child node of this node.</p>
334 * <p>If the node was previously a child node of another parent node, it will be removed from that node first.</p>
335 * @param {Node/Array} node The node or Array of nodes to append
336 * @return {Node} The appended node if single append, or null if an array was passed
338 appendChild : function(node, suppressEvents, suppressNodeUpdate) {
345 // if passed an array or multiple args do them one by one
346 if (Ext.isArray(node)) {
347 for (i = 0, ln = node.length; i < ln; i++) {
348 me.appendChild(node[i]);
351 // Make sure it is a record
352 node = me.createNode(node);
354 if (suppressEvents !== true && me.fireEvent("beforeappend", me, node) === false) {
358 index = me.childNodes.length;
359 oldParent = node.parentNode;
361 // it's a move, make sure we move it cleanly
363 if (suppressEvents !== true && node.fireEvent("beforemove", node, oldParent, me, index) === false) {
366 oldParent.removeChild(node, null, false, true);
369 index = me.childNodes.length;
371 me.setFirstChild(node);
374 me.childNodes.push(node);
375 node.parentNode = me;
376 node.nextSibling = null;
378 me.setLastChild(node);
380 ps = me.childNodes[index - 1];
382 node.previousSibling = ps;
383 ps.nextSibling = node;
384 ps.updateInfo(suppressNodeUpdate);
386 node.previousSibling = null;
389 node.updateInfo(suppressNodeUpdate);
391 // As soon as we append a child to this node, we are loaded
392 if (!me.isLoaded()) {
393 me.set('loaded', true);
395 // If this node didnt have any childnodes before, update myself
396 else if (me.childNodes.length === 1) {
397 me.set('loaded', me.isLoaded());
400 if (suppressEvents !== true) {
401 me.fireEvent("append", me, node, index);
404 node.fireEvent("move", node, oldParent, me, index);
412 <span id='Ext-data.NodeInterface-method-getBubbleTarget'> /**
413 </span> * Returns the bubble target for this node
415 * @return {Object} The bubble target
417 getBubbleTarget: function() {
418 return this.parentNode;
421 <span id='Ext-data.NodeInterface-method-removeChild'> /**
422 </span> * Removes a child node from this node.
423 * @param {Node} node The node to remove
424 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
425 * @return {Node} The removed node
427 removeChild : function(node, destroy, suppressEvents, suppressNodeUpdate) {
429 index = me.indexOf(node);
431 if (index == -1 || (suppressEvents !== true && me.fireEvent("beforeremove", me, node) === false)) {
435 // remove it from childNodes collection
436 me.childNodes.splice(index, 1);
439 if (me.firstChild == node) {
440 me.setFirstChild(node.nextSibling);
442 if (me.lastChild == node) {
443 me.setLastChild(node.previousSibling);
447 if (node.previousSibling) {
448 node.previousSibling.nextSibling = node.nextSibling;
449 node.previousSibling.updateInfo(suppressNodeUpdate);
451 if (node.nextSibling) {
452 node.nextSibling.previousSibling = node.previousSibling;
453 node.nextSibling.updateInfo(suppressNodeUpdate);
456 if (suppressEvents !== true) {
457 me.fireEvent("remove", me, node);
461 // If this node suddenly doesnt have childnodes anymore, update myself
462 if (!me.childNodes.length) {
463 me.set('loaded', me.isLoaded());
475 <span id='Ext-data.NodeInterface-method-copy'> /**
476 </span> * Creates a copy (clone) of this Node.
477 * @param {String} id (optional) A new id, defaults to this Node's id. See <code>{@link #id}</code>.
478 * @param {Boolean} deep (optional) <p>If passed as <code>true</code>, all child Nodes are recursively copied into the new Node.</p>
479 * <p>If omitted or false, the copy will have no child Nodes.</p>
480 * @return {Node} A copy of this Node.
482 copy: function(newId, deep) {
484 result = me.callOverridden(arguments),
485 len = me.childNodes ? me.childNodes.length : 0,
488 // Move child nodes across to the copy if required
490 for (i = 0; i < len; i++) {
491 result.appendChild(me.childNodes[i].copy(true));
497 <span id='Ext-data.NodeInterface-method-clear'> /**
498 </span> * Clear the node.
500 * @param {Boolean} destroy True to destroy the node.
502 clear : function(destroy) {
505 // clear any references from the node
506 me.parentNode = me.previousSibling = me.nextSibling = null;
508 me.firstChild = me.lastChild = null;
512 <span id='Ext-data.NodeInterface-method-destroy'> /**
513 </span> * Destroys the node.
515 destroy : function(silent) {
517 * Silent is to be used in a number of cases
518 * 1) When setRoot is called.
519 * 2) When destroy on the tree is called
520 * 3) For destroying child nodes on a node
524 if (silent === true) {
526 Ext.each(me.childNodes, function(n) {
529 me.childNodes = null;
537 <span id='Ext-data.NodeInterface-method-insertBefore'> /**
538 </span> * Inserts the first node before the second node in this nodes childNodes collection.
539 * @param {Node} node The node to insert
540 * @param {Node} refNode The node to insert before (if null the node is appended)
541 * @return {Node} The inserted node
543 insertBefore : function(node, refNode, suppressEvents) {
545 index = me.indexOf(refNode),
546 oldParent = node.parentNode,
550 if (!refNode) { // like standard Dom, refNode can be null for append
551 return me.appendChild(node);
555 if (node == refNode) {
559 // Make sure it is a record with the NodeInterface
560 node = me.createNode(node);
562 if (suppressEvents !== true && me.fireEvent("beforeinsert", me, node, refNode) === false) {
566 // when moving internally, indexes will change after remove
567 if (oldParent == me && me.indexOf(node) < index) {
571 // it's a move, make sure we move it cleanly
573 if (suppressEvents !== true && node.fireEvent("beforemove", node, oldParent, me, index, refNode) === false) {
576 oldParent.removeChild(node);
579 if (refIndex === 0) {
580 me.setFirstChild(node);
583 me.childNodes.splice(refIndex, 0, node);
584 node.parentNode = me;
586 node.nextSibling = refNode;
587 refNode.previousSibling = node;
589 ps = me.childNodes[refIndex - 1];
591 node.previousSibling = ps;
592 ps.nextSibling = node;
595 node.previousSibling = null;
600 if (!me.isLoaded()) {
601 me.set('loaded', true);
603 // If this node didnt have any childnodes before, update myself
604 else if (me.childNodes.length === 1) {
605 me.set('loaded', me.isLoaded());
608 if (suppressEvents !== true) {
609 me.fireEvent("insert", me, node, refNode);
612 node.fireEvent("move", node, oldParent, me, refIndex, refNode);
619 <span id='Ext-data.NodeInterface-method-insertChild'> /**
620 </span> * Insert a node into this node
621 * @param {Number} index The zero-based index to insert the node at
622 * @param {Ext.data.Model} node The node to insert
623 * @return {Ext.data.Record} The record you just inserted
625 insertChild: function(index, node) {
626 var sibling = this.childNodes[index];
628 return this.insertBefore(node, sibling);
631 return this.appendChild(node);
635 <span id='Ext-data.NodeInterface-method-remove'> /**
636 </span> * Removes this node from its parent
637 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
638 * @return {Node} this
640 remove : function(destroy, suppressEvents) {
641 var parentNode = this.parentNode;
644 parentNode.removeChild(this, destroy, suppressEvents, true);
649 <span id='Ext-data.NodeInterface-method-removeAll'> /**
650 </span> * Removes all child nodes from this node.
651 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
652 * @return {Node} this
654 removeAll : function(destroy, suppressEvents) {
655 var cn = this.childNodes,
658 while ((n = cn[0])) {
659 this.removeChild(n, destroy, suppressEvents);
664 <span id='Ext-data.NodeInterface-method-getChildAt'> /**
665 </span> * Returns the child node at the specified index.
666 * @param {Number} index
669 getChildAt : function(index) {
670 return this.childNodes[index];
673 <span id='Ext-data.NodeInterface-method-replaceChild'> /**
674 </span> * Replaces one child node in this node with another.
675 * @param {Node} newChild The replacement node
676 * @param {Node} oldChild The node to replace
677 * @return {Node} The replaced node
679 replaceChild : function(newChild, oldChild, suppressEvents) {
680 var s = oldChild ? oldChild.nextSibling : null;
682 this.removeChild(oldChild, suppressEvents);
683 this.insertBefore(newChild, s, suppressEvents);
687 <span id='Ext-data.NodeInterface-method-indexOf'> /**
688 </span> * Returns the index of a child node
690 * @return {Number} The index of the node or -1 if it was not found
692 indexOf : function(child) {
693 return Ext.Array.indexOf(this.childNodes, child);
696 <span id='Ext-data.NodeInterface-method-getDepth'> /**
697 </span> * Returns depth of this node (the root node has a depth of 0)
700 getDepth : function() {
701 return this.get('depth');
704 <span id='Ext-data.NodeInterface-method-bubble'> /**
705 </span> * Bubbles up the tree from this node, calling the specified function with each node. The arguments to the function
706 * will be the args provided or the current node. If the function returns false at any point,
707 * the bubble is stopped.
708 * @param {Function} fn The function to call
709 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node.
710 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
712 bubble : function(fn, scope, args) {
715 if (fn.apply(scope || p, args || [p]) === false) {
722 //<deprecated since=0.99>
723 cascade: function() {
724 if (Ext.isDefined(Ext.global.console)) {
725 Ext.global.console.warn('Ext.data.Node: cascade has been deprecated. Please use cascadeBy instead.');
727 return this.cascadeBy.apply(this, arguments);
729 //</deprecated>
731 <span id='Ext-data.NodeInterface-method-cascadeBy'> /**
732 </span> * Cascades down the tree from this node, calling the specified function with each node. The arguments to the function
733 * will be the args provided or the current node. If the function returns false at any point,
734 * the cascade is stopped on that branch.
735 * @param {Function} fn The function to call
736 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node.
737 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
739 cascadeBy : function(fn, scope, args) {
740 if (fn.apply(scope || this, args || [this]) !== false) {
741 var childNodes = this.childNodes,
742 length = childNodes.length,
745 for (i = 0; i < length; i++) {
746 childNodes[i].cascadeBy(fn, scope, args);
751 <span id='Ext-data.NodeInterface-method-eachChild'> /**
752 </span> * Interates the child nodes of this node, calling the specified function with each node. The arguments to the function
753 * will be the args provided or the current node. If the function returns false at any point,
754 * the iteration stops.
755 * @param {Function} fn The function to call
756 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node in the iteration.
757 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
759 eachChild : function(fn, scope, args) {
760 var childNodes = this.childNodes,
761 length = childNodes.length,
764 for (i = 0; i < length; i++) {
765 if (fn.apply(scope || this, args || [childNodes[i]]) === false) {
771 <span id='Ext-data.NodeInterface-method-findChild'> /**
772 </span> * Finds the first child that has the attribute with the specified value.
773 * @param {String} attribute The attribute name
774 * @param {Mixed} value The value to search for
775 * @param {Boolean} deep (Optional) True to search through nodes deeper than the immediate children
776 * @return {Node} The found child or null if none was found
778 findChild : function(attribute, value, deep) {
779 return this.findChildBy(function() {
780 return this.get(attribute) == value;
784 <span id='Ext-data.NodeInterface-method-findChildBy'> /**
785 </span> * Finds the first child by a custom function. The child matches if the function passed returns <code>true</code>.
786 * @param {Function} fn A function which must return <code>true</code> if the passed Node is the required Node.
787 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Node being tested.
788 * @param {Boolean} deep (Optional) True to search through nodes deeper than the immediate children
789 * @return {Node} The found child or null if none was found
791 findChildBy : function(fn, scope, deep) {
792 var cs = this.childNodes,
796 for (; i < len; i++) {
798 if (fn.call(scope || n, n) === true) {
802 res = n.findChildBy(fn, scope, deep);
812 <span id='Ext-data.NodeInterface-method-contains'> /**
813 </span> * Returns true if this node is an ancestor (at any point) of the passed node.
817 contains : function(node) {
818 return node.isAncestor(this);
821 <span id='Ext-data.NodeInterface-method-isAncestor'> /**
822 </span> * Returns true if the passed node is an ancestor (at any point) of this node.
826 isAncestor : function(node) {
827 var p = this.parentNode;
837 <span id='Ext-data.NodeInterface-method-sort'> /**
838 </span> * Sorts this nodes children using the supplied sort function.
839 * @param {Function} fn A function which, when passed two Nodes, returns -1, 0 or 1 depending upon required sort order.
840 * @param {Boolean} recursive Whether or not to apply this sort recursively
841 * @param {Boolean} suppressEvent Set to true to not fire a sort event.
843 sort : function(sortFn, recursive, suppressEvent) {
844 var cs = this.childNodes,
849 Ext.Array.sort(cs, sortFn);
850 for (i = 0; i < ln; i++) {
852 n.previousSibling = cs[i-1];
853 n.nextSibling = cs[i+1];
856 this.setFirstChild(n);
860 this.setLastChild(n);
863 if (recursive && !n.isLeaf()) {
864 n.sort(sortFn, true, true);
868 if (suppressEvent !== true) {
869 this.fireEvent('sort', this, cs);
874 <span id='Ext-data.NodeInterface-method-isExpanded'> /**
875 </span> * Returns true if this node is expaned
878 isExpanded: function() {
879 return this.get('expanded');
882 <span id='Ext-data.NodeInterface-method-isLoaded'> /**
883 </span> * Returns true if this node is loaded
886 isLoaded: function() {
887 return this.get('loaded');
890 <span id='Ext-data.NodeInterface-method-isLoading'> /**
891 </span> * Returns true if this node is loading
894 isLoading: function() {
895 return this.get('loading');
898 <span id='Ext-data.NodeInterface-method-isRoot'> /**
899 </span> * Returns true if this node is the root node
903 return !this.parentNode;
906 <span id='Ext-data.NodeInterface-method-isVisible'> /**
907 </span> * Returns true if this node is visible
910 isVisible: function() {
911 var parent = this.parentNode;
913 if (!parent.isExpanded()) {
916 parent = parent.parentNode;
921 <span id='Ext-data.NodeInterface-method-expand'> /**
922 </span> * Expand this node.
923 * @param {Function} recursive (Optional) True to recursively expand all the children
924 * @param {Function} callback (Optional) The function to execute once the expand completes
925 * @param {Object} scope (Optional) The scope to run the callback in
927 expand: function(recursive, callback, scope) {
930 // all paths must call the callback (eventually) or things like
933 // First we start by checking if this node is a parent
935 // Now we check if this record is already expanding or expanded
936 if (!me.isLoading() && !me.isExpanded()) {
937 // The TreeStore actually listens for the beforeexpand method and checks
938 // whether we have to asynchronously load the children from the server
939 // first. Thats why we pass a callback function to the event that the
940 // store can call once it has loaded and parsed all the children.
941 me.fireEvent('beforeexpand', me, function(records) {
942 me.set('expanded', true);
943 me.fireEvent('expand', me, me.childNodes, false);
945 // Call the expandChildren method if recursive was set to true
947 me.expandChildren(true, callback, scope);
950 Ext.callback(callback, scope || me, [me.childNodes]);
954 // If it is is already expanded but we want to recursively expand then call expandChildren
955 else if (recursive) {
956 me.expandChildren(true, callback, scope);
959 Ext.callback(callback, scope || me, [me.childNodes]);
962 // TODO - if the node isLoading, we probably need to defer the
963 // callback until it is loaded (e.g., selectPath would need us
964 // to not make the callback until the childNodes exist).
966 // If it's not then we fire the callback right away
968 Ext.callback(callback, scope || me); // leaf = no childNodes
972 <span id='Ext-data.NodeInterface-method-expandChildren'> /**
973 </span> * Expand all the children of this node.
974 * @param {Function} recursive (Optional) True to recursively expand all the children
975 * @param {Function} callback (Optional) The function to execute once all the children are expanded
976 * @param {Object} scope (Optional) The scope to run the callback in
978 expandChildren: function(recursive, callback, scope) {
981 nodes = me.childNodes,
986 for (; i < ln; ++i) {
988 if (!node.isLeaf() && !node.isExpanded()) {
990 nodes[i].expand(recursive, function () {
992 if (callback && !expanding) {
993 Ext.callback(callback, scope || me, me.childNodes);
999 if (!expanding && callback) {
1000 Ext.callback(callback, scope || me, me.childNodes);
1004 <span id='Ext-data.NodeInterface-method-collapse'> /**
1005 </span> * Collapse this node.
1006 * @param {Function} recursive (Optional) True to recursively collapse all the children
1007 * @param {Function} callback (Optional) The function to execute once the collapse completes
1008 * @param {Object} scope (Optional) The scope to run the callback in
1010 collapse: function(recursive, callback, scope) {
1013 // First we start by checking if this node is a parent
1015 // Now we check if this record is already collapsing or collapsed
1016 if (!me.collapsing && me.isExpanded()) {
1017 me.fireEvent('beforecollapse', me, function(records) {
1018 me.set('expanded', false);
1019 me.fireEvent('collapse', me, me.childNodes, false);
1021 // Call the collapseChildren method if recursive was set to true
1023 me.collapseChildren(true, callback, scope);
1026 Ext.callback(callback, scope || me, [me.childNodes]);
1030 // If it is is already collapsed but we want to recursively collapse then call collapseChildren
1031 else if (recursive) {
1032 me.collapseChildren(true, callback, scope);
1035 // If it's not then we fire the callback right away
1037 Ext.callback(callback, scope || me, me.childNodes);
1041 <span id='Ext-data.NodeInterface-method-collapseChildren'> /**
1042 </span> * Collapse all the children of this node.
1043 * @param {Function} recursive (Optional) True to recursively collapse all the children
1044 * @param {Function} callback (Optional) The function to execute once all the children are collapsed
1045 * @param {Object} scope (Optional) The scope to run the callback in
1047 collapseChildren: function(recursive, callback, scope) {
1050 nodes = me.childNodes,
1055 for (; i < ln; ++i) {
1057 if (!node.isLeaf() && node.isExpanded()) {
1059 nodes[i].collapse(recursive, function () {
1061 if (callback && !collapsing) {
1062 Ext.callback(callback, scope || me, me.childNodes);
1068 if (!collapsing && callback) {
1069 Ext.callback(callback, scope || me, me.childNodes);
1075 });</pre></pre></body></html>