4 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5 <title>The source code</title>
6 <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7 <script type="text/javascript" src="../prettify/prettify.js"></script>
8 <style type="text/css">
9 .highlight { display: block; background-color: #ddd; }
11 <script type="text/javascript">
12 function highlight() {
13 document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
17 <body onload="prettyPrint(); highlight();">
18 <pre class="prettyprint lang-js"><span id='Ext-data-NodeInterface'>/**
19 </span> * @class Ext.data.NodeInterface
20 * This class is meant to be used as a set of methods that are applied to the prototype of a
21 * Record to decorate it with a Node API. This means that models used in conjunction with a tree
22 * will have all of the tree related methods available on the model. In general this class will
23 * not be used directly by the developer.
25 Ext.define('Ext.data.NodeInterface', {
26 requires: ['Ext.data.Field'],
29 <span id='Ext-data-NodeInterface-method-decorate'> /**
30 </span> * This method allows you to decorate a Record's prototype to implement the NodeInterface.
31 * This adds a set of methods, new events, new properties and new fields on every Record
32 * with the same Model as the passed Record.
33 * @param {Ext.data.Record} record The Record you want to decorate the prototype of.
36 decorate: function(record) {
38 // Apply the methods and fields to the prototype
39 // @TODO: clean this up to use proper class system stuff
40 var mgr = Ext.ModelManager,
41 modelName = record.modelName,
42 modelClass = mgr.getModel(modelName),
43 idName = modelClass.prototype.idProperty,
47 // Start by adding the NodeInterface methods to the Model's prototype
48 modelClass.override(this.getPrototypeBody());
49 newFields = this.applyFields(modelClass, [
50 {name: idName, type: 'string', defaultValue: null},
51 {name: 'parentId', type: 'string', defaultValue: null},
52 {name: 'index', type: 'int', defaultValue: null},
53 {name: 'depth', type: 'int', defaultValue: 0},
54 {name: 'expanded', type: 'bool', defaultValue: false, persist: false},
55 {name: 'expandable', type: 'bool', defaultValue: true, persist: false},
56 {name: 'checked', type: 'auto', defaultValue: null},
57 {name: 'leaf', type: 'bool', defaultValue: false, persist: false},
58 {name: 'cls', type: 'string', defaultValue: null, persist: false},
59 {name: 'iconCls', type: 'string', defaultValue: null, persist: false},
60 {name: 'root', type: 'boolean', defaultValue: false, persist: false},
61 {name: 'isLast', type: 'boolean', defaultValue: false, persist: false},
62 {name: 'isFirst', type: 'boolean', defaultValue: false, persist: false},
63 {name: 'allowDrop', type: 'boolean', defaultValue: true, persist: false},
64 {name: 'allowDrag', type: 'boolean', defaultValue: true, persist: false},
65 {name: 'loaded', type: 'boolean', defaultValue: false, persist: false},
66 {name: 'loading', type: 'boolean', defaultValue: false, persist: false},
67 {name: 'href', type: 'string', defaultValue: null, persist: false},
68 {name: 'hrefTarget', type: 'string', defaultValue: null, persist: false},
69 {name: 'qtip', type: 'string', defaultValue: null, persist: false},
70 {name: 'qtitle', type: 'string', defaultValue: null, persist: false}
73 len = newFields.length;
75 for (i = 0; i < len; ++i) {
76 newField = newFields[i];
77 if (record.get(newField.name) === undefined) {
78 record.data[newField.name] = newField.defaultValue;
87 previousSibling: null,
91 // Commit any fields so the record doesn't show as dirty initially
95 <span id='Ext-data-NodeInterface-event-append'> /**
96 </span> * @event append
97 * Fires when a new child node is appended
98 * @param {Node} this This node
99 * @param {Node} node The newly appended node
100 * @param {Number} index The index of the newly appended node
104 <span id='Ext-data-NodeInterface-event-remove'> /**
105 </span> * @event remove
106 * Fires when a child node is removed
107 * @param {Node} this This node
108 * @param {Node} node The removed node
112 <span id='Ext-data-NodeInterface-event-move'> /**
113 </span> * @event move
114 * Fires when this node is moved to a new location in the tree
115 * @param {Node} this This node
116 * @param {Node} oldParent The old parent of this node
117 * @param {Node} newParent The new parent of this node
118 * @param {Number} index The index it was moved to
122 <span id='Ext-data-NodeInterface-event-insert'> /**
123 </span> * @event insert
124 * Fires when a new child node is inserted.
125 * @param {Node} this This node
126 * @param {Node} node The child node inserted
127 * @param {Node} refNode The child node the node was inserted before
131 <span id='Ext-data-NodeInterface-event-beforeappend'> /**
132 </span> * @event beforeappend
133 * Fires before a new child is appended, return false to cancel the append.
134 * @param {Node} this This node
135 * @param {Node} node The child node to be appended
137 "beforeappend",
139 <span id='Ext-data-NodeInterface-event-beforeremove'> /**
140 </span> * @event beforeremove
141 * Fires before a child is removed, return false to cancel the remove.
142 * @param {Node} this This node
143 * @param {Node} node The child node to be removed
145 "beforeremove",
147 <span id='Ext-data-NodeInterface-event-beforemove'> /**
148 </span> * @event beforemove
149 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
150 * @param {Node} this This node
151 * @param {Node} oldParent The parent of this node
152 * @param {Node} newParent The new parent this node is moving to
153 * @param {Number} index The index it is being moved to
155 "beforemove",
157 <span id='Ext-data-NodeInterface-event-beforeinsert'> /**
158 </span> * @event beforeinsert
159 * Fires before a new child is inserted, return false to cancel the insert.
160 * @param {Node} this This node
161 * @param {Node} node The child node to be inserted
162 * @param {Node} refNode The child node the node is being inserted before
164 "beforeinsert",
166 <span id='Ext-data-NodeInterface-event-expand'> /**
167 </span> * @event expand
168 * Fires when this node is expanded.
169 * @param {Node} this The expanding node
173 <span id='Ext-data-NodeInterface-event-collapse'> /**
174 </span> * @event collapse
175 * Fires when this node is collapsed.
176 * @param {Node} this The collapsing node
178 "collapse",
180 <span id='Ext-data-NodeInterface-event-beforeexpand'> /**
181 </span> * @event beforeexpand
182 * Fires before this node is expanded.
183 * @param {Node} this The expanding node
185 "beforeexpand",
187 <span id='Ext-data-NodeInterface-event-beforecollapse'> /**
188 </span> * @event beforecollapse
189 * Fires before this node is collapsed.
190 * @param {Node} this The collapsing node
192 "beforecollapse",
194 <span id='Ext-data-NodeInterface-event-sort'> /**
195 </span> * @event sort
196 * Fires when this node's childNodes are sorted.
197 * @param {Node} this This node.
198 * @param {Array} The childNodes of this node.
206 applyFields: function(modelClass, addFields) {
207 var modelPrototype = modelClass.prototype,
208 fields = modelPrototype.fields,
210 ln = addFields.length,
214 for (i = 0; i < ln; i++) {
215 addField = addFields[i];
216 if (!Ext.Array.contains(keys, addField.name)) {
217 addField = Ext.create('data.field', addField);
219 newFields.push(addField);
220 fields.add(addField);
227 getPrototypeBody: function() {
231 <span id='Ext-data-NodeInterface-method-createNode'> /**
232 </span> * Ensures that the passed object is an instance of a Record with the NodeInterface applied
235 createNode: function(node) {
236 if (Ext.isObject(node) && !node.isModel) {
237 node = Ext.ModelManager.create(node, this.modelName);
239 // Make sure the node implements the node interface
240 return Ext.data.NodeInterface.decorate(node);
243 <span id='Ext-data-NodeInterface-method-isLeaf'> /**
244 </span> * Returns true if this node is a leaf
247 isLeaf : function() {
248 return this.get('leaf') === true;
251 <span id='Ext-data-NodeInterface-method-setFirstChild'> /**
252 </span> * Sets the first child of this node
254 * @param {Ext.data.NodeInterface} node
256 setFirstChild : function(node) {
257 this.firstChild = node;
260 <span id='Ext-data-NodeInterface-method-setLastChild'> /**
261 </span> * Sets the last child of this node
263 * @param {Ext.data.NodeInterface} node
265 setLastChild : function(node) {
266 this.lastChild = node;
269 <span id='Ext-data-NodeInterface-method-updateInfo'> /**
270 </span> * Updates general data of this node like isFirst, isLast, depth. This
271 * method is internally called after a node is moved. This shouldn't
272 * have to be called by the developer unless they are creating custom
276 updateInfo: function(silent) {
278 isRoot = me.isRoot(),
279 parentNode = me.parentNode,
280 isFirst = (!parentNode ? true : parentNode.firstChild == me),
281 isLast = (!parentNode ? true : parentNode.lastChild == me),
284 children = me.childNodes,
285 len = children.length,
288 while (parent.parentNode) {
290 parent = parent.parentNode;
298 index: parentNode ? parentNode.indexOf(me) : 0,
299 parentId: parentNode ? parentNode.getId() : null
306 for (i = 0; i < len; i++) {
307 children[i].updateInfo(silent);
311 <span id='Ext-data-NodeInterface-method-isLast'> /**
312 </span> * Returns true if this node is the last child of its parent
315 isLast : function() {
316 return this.get('isLast');
319 <span id='Ext-data-NodeInterface-method-isFirst'> /**
320 </span> * Returns true if this node is the first child of its parent
323 isFirst : function() {
324 return this.get('isFirst');
327 <span id='Ext-data-NodeInterface-method-hasChildNodes'> /**
328 </span> * Returns true if this node has one or more child nodes, else false.
331 hasChildNodes : function() {
332 return !this.isLeaf() && this.childNodes.length > 0;
335 <span id='Ext-data-NodeInterface-method-isExpandable'> /**
336 </span> * Returns true if this node has one or more child nodes, or if the <tt>expandable</tt>
337 * node attribute is explicitly specified as true (see {@link #attributes}), otherwise returns false.
340 isExpandable : function() {
343 if (me.get('expandable')) {
344 return !(me.isLeaf() || (me.isLoaded() && !me.hasChildNodes()));
349 <span id='Ext-data-NodeInterface-method-appendChild'> /**
350 </span> * <p>Insert node(s) as the last child node of this node.</p>
351 * <p>If the node was previously a child node of another parent node, it will be removed from that node first.</p>
352 * @param {Node/Array} node The node or Array of nodes to append
353 * @return {Node} The appended node if single append, or null if an array was passed
355 appendChild : function(node, suppressEvents, suppressNodeUpdate) {
362 // if passed an array or multiple args do them one by one
363 if (Ext.isArray(node)) {
364 for (i = 0, ln = node.length; i < ln; i++) {
365 me.appendChild(node[i]);
368 // Make sure it is a record
369 node = me.createNode(node);
371 if (suppressEvents !== true && me.fireEvent("beforeappend", me, node) === false) {
375 index = me.childNodes.length;
376 oldParent = node.parentNode;
378 // it's a move, make sure we move it cleanly
380 if (suppressEvents !== true && node.fireEvent("beforemove", node, oldParent, me, index) === false) {
383 oldParent.removeChild(node, null, false, true);
386 index = me.childNodes.length;
388 me.setFirstChild(node);
391 me.childNodes.push(node);
392 node.parentNode = me;
393 node.nextSibling = null;
395 me.setLastChild(node);
397 ps = me.childNodes[index - 1];
399 node.previousSibling = ps;
400 ps.nextSibling = node;
401 ps.updateInfo(suppressNodeUpdate);
403 node.previousSibling = null;
406 node.updateInfo(suppressNodeUpdate);
408 // As soon as we append a child to this node, we are loaded
409 if (!me.isLoaded()) {
410 me.set('loaded', true);
412 // If this node didnt have any childnodes before, update myself
413 else if (me.childNodes.length === 1) {
414 me.set('loaded', me.isLoaded());
417 if (suppressEvents !== true) {
418 me.fireEvent("append", me, node, index);
421 node.fireEvent("move", node, oldParent, me, index);
429 <span id='Ext-data-NodeInterface-method-getBubbleTarget'> /**
430 </span> * Returns the bubble target for this node
432 * @return {Object} The bubble target
434 getBubbleTarget: function() {
435 return this.parentNode;
438 <span id='Ext-data-NodeInterface-method-removeChild'> /**
439 </span> * Removes a child node from this node.
440 * @param {Node} node The node to remove
441 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
442 * @return {Node} The removed node
444 removeChild : function(node, destroy, suppressEvents, suppressNodeUpdate) {
446 index = me.indexOf(node);
448 if (index == -1 || (suppressEvents !== true && me.fireEvent("beforeremove", me, node) === false)) {
452 // remove it from childNodes collection
453 Ext.Array.erase(me.childNodes, index, 1);
456 if (me.firstChild == node) {
457 me.setFirstChild(node.nextSibling);
459 if (me.lastChild == node) {
460 me.setLastChild(node.previousSibling);
464 if (node.previousSibling) {
465 node.previousSibling.nextSibling = node.nextSibling;
466 node.previousSibling.updateInfo(suppressNodeUpdate);
468 if (node.nextSibling) {
469 node.nextSibling.previousSibling = node.previousSibling;
470 node.nextSibling.updateInfo(suppressNodeUpdate);
473 if (suppressEvents !== true) {
474 me.fireEvent("remove", me, node);
478 // If this node suddenly doesnt have childnodes anymore, update myself
479 if (!me.childNodes.length) {
480 me.set('loaded', me.isLoaded());
492 <span id='Ext-data-NodeInterface-method-copy'> /**
493 </span> * Creates a copy (clone) of this Node.
494 * @param {String} id (optional) A new id, defaults to this Node's id. See <code>{@link #id}</code>.
495 * @param {Boolean} deep (optional) <p>If passed as <code>true</code>, all child Nodes are recursively copied into the new Node.</p>
496 * <p>If omitted or false, the copy will have no child Nodes.</p>
497 * @return {Node} A copy of this Node.
499 copy: function(newId, deep) {
501 result = me.callOverridden(arguments),
502 len = me.childNodes ? me.childNodes.length : 0,
505 // Move child nodes across to the copy if required
507 for (i = 0; i < len; i++) {
508 result.appendChild(me.childNodes[i].copy(true));
514 <span id='Ext-data-NodeInterface-method-clear'> /**
515 </span> * Clear the node.
517 * @param {Boolean} destroy True to destroy the node.
519 clear : function(destroy) {
522 // clear any references from the node
523 me.parentNode = me.previousSibling = me.nextSibling = null;
525 me.firstChild = me.lastChild = null;
529 <span id='Ext-data-NodeInterface-method-destroy'> /**
530 </span> * Destroys the node.
532 destroy : function(silent) {
534 * Silent is to be used in a number of cases
535 * 1) When setRoot is called.
536 * 2) When destroy on the tree is called
537 * 3) For destroying child nodes on a node
540 options = me.destroyOptions;
542 if (silent === true) {
544 Ext.each(me.childNodes, function(n) {
547 me.childNodes = null;
548 delete me.destroyOptions;
549 me.callOverridden([options]);
551 me.destroyOptions = silent;
552 // overridden method will be called, since remove will end up calling destroy(true);
557 <span id='Ext-data-NodeInterface-method-insertBefore'> /**
558 </span> * Inserts the first node before the second node in this nodes childNodes collection.
559 * @param {Node} node The node to insert
560 * @param {Node} refNode The node to insert before (if null the node is appended)
561 * @return {Node} The inserted node
563 insertBefore : function(node, refNode, suppressEvents) {
565 index = me.indexOf(refNode),
566 oldParent = node.parentNode,
570 if (!refNode) { // like standard Dom, refNode can be null for append
571 return me.appendChild(node);
575 if (node == refNode) {
579 // Make sure it is a record with the NodeInterface
580 node = me.createNode(node);
582 if (suppressEvents !== true && me.fireEvent("beforeinsert", me, node, refNode) === false) {
586 // when moving internally, indexes will change after remove
587 if (oldParent == me && me.indexOf(node) < index) {
591 // it's a move, make sure we move it cleanly
593 if (suppressEvents !== true && node.fireEvent("beforemove", node, oldParent, me, index, refNode) === false) {
596 oldParent.removeChild(node);
599 if (refIndex === 0) {
600 me.setFirstChild(node);
603 Ext.Array.splice(me.childNodes, refIndex, 0, node);
604 node.parentNode = me;
606 node.nextSibling = refNode;
607 refNode.previousSibling = node;
609 ps = me.childNodes[refIndex - 1];
611 node.previousSibling = ps;
612 ps.nextSibling = node;
615 node.previousSibling = null;
620 if (!me.isLoaded()) {
621 me.set('loaded', true);
623 // If this node didnt have any childnodes before, update myself
624 else if (me.childNodes.length === 1) {
625 me.set('loaded', me.isLoaded());
628 if (suppressEvents !== true) {
629 me.fireEvent("insert", me, node, refNode);
632 node.fireEvent("move", node, oldParent, me, refIndex, refNode);
639 <span id='Ext-data-NodeInterface-method-insertChild'> /**
640 </span> * Insert a node into this node
641 * @param {Number} index The zero-based index to insert the node at
642 * @param {Ext.data.Model} node The node to insert
643 * @return {Ext.data.Record} The record you just inserted
645 insertChild: function(index, node) {
646 var sibling = this.childNodes[index];
648 return this.insertBefore(node, sibling);
651 return this.appendChild(node);
655 <span id='Ext-data-NodeInterface-method-remove'> /**
656 </span> * Removes this node from its parent
657 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
658 * @return {Node} this
660 remove : function(destroy, suppressEvents) {
661 var parentNode = this.parentNode;
664 parentNode.removeChild(this, destroy, suppressEvents, true);
669 <span id='Ext-data-NodeInterface-method-removeAll'> /**
670 </span> * Removes all child nodes from this node.
671 * @param {Boolean} destroy <tt>true</tt> to destroy the node upon removal. Defaults to <tt>false</tt>.
672 * @return {Node} this
674 removeAll : function(destroy, suppressEvents) {
675 var cn = this.childNodes,
678 while ((n = cn[0])) {
679 this.removeChild(n, destroy, suppressEvents);
684 <span id='Ext-data-NodeInterface-method-getChildAt'> /**
685 </span> * Returns the child node at the specified index.
686 * @param {Number} index
689 getChildAt : function(index) {
690 return this.childNodes[index];
693 <span id='Ext-data-NodeInterface-method-replaceChild'> /**
694 </span> * Replaces one child node in this node with another.
695 * @param {Node} newChild The replacement node
696 * @param {Node} oldChild The node to replace
697 * @return {Node} The replaced node
699 replaceChild : function(newChild, oldChild, suppressEvents) {
700 var s = oldChild ? oldChild.nextSibling : null;
702 this.removeChild(oldChild, suppressEvents);
703 this.insertBefore(newChild, s, suppressEvents);
707 <span id='Ext-data-NodeInterface-method-indexOf'> /**
708 </span> * Returns the index of a child node
710 * @return {Number} The index of the node or -1 if it was not found
712 indexOf : function(child) {
713 return Ext.Array.indexOf(this.childNodes, child);
716 <span id='Ext-data-NodeInterface-method-getDepth'> /**
717 </span> * Returns depth of this node (the root node has a depth of 0)
720 getDepth : function() {
721 return this.get('depth');
724 <span id='Ext-data-NodeInterface-method-bubble'> /**
725 </span> * Bubbles up the tree from this node, calling the specified function with each node. The arguments to the function
726 * will be the args provided or the current node. If the function returns false at any point,
727 * the bubble is stopped.
728 * @param {Function} fn The function to call
729 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node.
730 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
732 bubble : function(fn, scope, args) {
735 if (fn.apply(scope || p, args || [p]) === false) {
742 //<deprecated since=0.99>
743 cascade: function() {
744 if (Ext.isDefined(Ext.global.console)) {
745 Ext.global.console.warn('Ext.data.Node: cascade has been deprecated. Please use cascadeBy instead.');
747 return this.cascadeBy.apply(this, arguments);
749 //</deprecated>
751 <span id='Ext-data-NodeInterface-method-cascadeBy'> /**
752 </span> * Cascades down the tree from 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 cascade is stopped on that branch.
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.
757 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
759 cascadeBy : function(fn, scope, args) {
760 if (fn.apply(scope || this, args || [this]) !== false) {
761 var childNodes = this.childNodes,
762 length = childNodes.length,
765 for (i = 0; i < length; i++) {
766 childNodes[i].cascadeBy(fn, scope, args);
771 <span id='Ext-data-NodeInterface-method-eachChild'> /**
772 </span> * Interates the child nodes of this node, calling the specified function with each node. The arguments to the function
773 * will be the args provided or the current node. If the function returns false at any point,
774 * the iteration stops.
775 * @param {Function} fn The function to call
776 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the current Node in the iteration.
777 * @param {Array} args (optional) The args to call the function with (default to passing the current Node)
779 eachChild : function(fn, scope, args) {
780 var childNodes = this.childNodes,
781 length = childNodes.length,
784 for (i = 0; i < length; i++) {
785 if (fn.apply(scope || this, args || [childNodes[i]]) === false) {
791 <span id='Ext-data-NodeInterface-method-findChild'> /**
792 </span> * Finds the first child that has the attribute with the specified value.
793 * @param {String} attribute The attribute name
794 * @param {Mixed} value The value to search for
795 * @param {Boolean} deep (Optional) True to search through nodes deeper than the immediate children
796 * @return {Node} The found child or null if none was found
798 findChild : function(attribute, value, deep) {
799 return this.findChildBy(function() {
800 return this.get(attribute) == value;
804 <span id='Ext-data-NodeInterface-method-findChildBy'> /**
805 </span> * Finds the first child by a custom function. The child matches if the function passed returns <code>true</code>.
806 * @param {Function} fn A function which must return <code>true</code> if the passed Node is the required Node.
807 * @param {Object} scope (optional) The scope (<code>this</code> reference) in which the function is executed. Defaults to the Node being tested.
808 * @param {Boolean} deep (Optional) True to search through nodes deeper than the immediate children
809 * @return {Node} The found child or null if none was found
811 findChildBy : function(fn, scope, deep) {
812 var cs = this.childNodes,
816 for (; i < len; i++) {
818 if (fn.call(scope || n, n) === true) {
822 res = n.findChildBy(fn, scope, deep);
832 <span id='Ext-data-NodeInterface-method-contains'> /**
833 </span> * Returns true if this node is an ancestor (at any point) of the passed node.
837 contains : function(node) {
838 return node.isAncestor(this);
841 <span id='Ext-data-NodeInterface-method-isAncestor'> /**
842 </span> * Returns true if the passed node is an ancestor (at any point) of this node.
846 isAncestor : function(node) {
847 var p = this.parentNode;
857 <span id='Ext-data-NodeInterface-method-sort'> /**
858 </span> * Sorts this nodes children using the supplied sort function.
859 * @param {Function} fn A function which, when passed two Nodes, returns -1, 0 or 1 depending upon required sort order.
860 * @param {Boolean} recursive Whether or not to apply this sort recursively
861 * @param {Boolean} suppressEvent Set to true to not fire a sort event.
863 sort : function(sortFn, recursive, suppressEvent) {
864 var cs = this.childNodes,
869 Ext.Array.sort(cs, sortFn);
870 for (i = 0; i < ln; i++) {
872 n.previousSibling = cs[i-1];
873 n.nextSibling = cs[i+1];
876 this.setFirstChild(n);
880 this.setLastChild(n);
883 if (recursive && !n.isLeaf()) {
884 n.sort(sortFn, true, true);
888 if (suppressEvent !== true) {
889 this.fireEvent('sort', this, cs);
894 <span id='Ext-data-NodeInterface-method-isExpanded'> /**
895 </span> * Returns true if this node is expaned
898 isExpanded: function() {
899 return this.get('expanded');
902 <span id='Ext-data-NodeInterface-method-isLoaded'> /**
903 </span> * Returns true if this node is loaded
906 isLoaded: function() {
907 return this.get('loaded');
910 <span id='Ext-data-NodeInterface-method-isLoading'> /**
911 </span> * Returns true if this node is loading
914 isLoading: function() {
915 return this.get('loading');
918 <span id='Ext-data-NodeInterface-method-isRoot'> /**
919 </span> * Returns true if this node is the root node
923 return !this.parentNode;
926 <span id='Ext-data-NodeInterface-method-isVisible'> /**
927 </span> * Returns true if this node is visible
930 isVisible: function() {
931 var parent = this.parentNode;
933 if (!parent.isExpanded()) {
936 parent = parent.parentNode;
941 <span id='Ext-data-NodeInterface-method-expand'> /**
942 </span> * Expand this node.
943 * @param {Function} recursive (Optional) True to recursively expand all the children
944 * @param {Function} callback (Optional) The function to execute once the expand completes
945 * @param {Object} scope (Optional) The scope to run the callback in
947 expand: function(recursive, callback, scope) {
950 // all paths must call the callback (eventually) or things like
953 // First we start by checking if this node is a parent
955 // Now we check if this record is already expanding or expanded
956 if (!me.isLoading() && !me.isExpanded()) {
957 // The TreeStore actually listens for the beforeexpand method and checks
958 // whether we have to asynchronously load the children from the server
959 // first. Thats why we pass a callback function to the event that the
960 // store can call once it has loaded and parsed all the children.
961 me.fireEvent('beforeexpand', me, function() {
962 me.set('expanded', true);
963 me.fireEvent('expand', me, me.childNodes, false);
965 // Call the expandChildren method if recursive was set to true
967 me.expandChildren(true, callback, scope);
970 Ext.callback(callback, scope || me, [me.childNodes]);
974 // If it is is already expanded but we want to recursively expand then call expandChildren
975 else if (recursive) {
976 me.expandChildren(true, callback, scope);
979 Ext.callback(callback, scope || me, [me.childNodes]);
982 // TODO - if the node isLoading, we probably need to defer the
983 // callback until it is loaded (e.g., selectPath would need us
984 // to not make the callback until the childNodes exist).
986 // If it's not then we fire the callback right away
988 Ext.callback(callback, scope || me); // leaf = no childNodes
992 <span id='Ext-data-NodeInterface-method-expandChildren'> /**
993 </span> * Expand all the children of this node.
994 * @param {Function} recursive (Optional) True to recursively expand all the children
995 * @param {Function} callback (Optional) The function to execute once all the children are expanded
996 * @param {Object} scope (Optional) The scope to run the callback in
998 expandChildren: function(recursive, callback, scope) {
1001 nodes = me.childNodes,
1006 for (; i < ln; ++i) {
1008 if (!node.isLeaf() && !node.isExpanded()) {
1010 nodes[i].expand(recursive, function () {
1012 if (callback && !expanding) {
1013 Ext.callback(callback, scope || me, [me.childNodes]);
1019 if (!expanding && callback) {
1020 Ext.callback(callback, scope || me, [me.childNodes]); }
1023 <span id='Ext-data-NodeInterface-method-collapse'> /**
1024 </span> * Collapse this node.
1025 * @param {Function} recursive (Optional) True to recursively collapse all the children
1026 * @param {Function} callback (Optional) The function to execute once the collapse completes
1027 * @param {Object} scope (Optional) The scope to run the callback in
1029 collapse: function(recursive, callback, scope) {
1032 // First we start by checking if this node is a parent
1034 // Now we check if this record is already collapsing or collapsed
1035 if (!me.collapsing && me.isExpanded()) {
1036 me.fireEvent('beforecollapse', me, function() {
1037 me.set('expanded', false);
1038 me.fireEvent('collapse', me, me.childNodes, false);
1040 // Call the collapseChildren method if recursive was set to true
1042 me.collapseChildren(true, callback, scope);
1045 Ext.callback(callback, scope || me, [me.childNodes]);
1049 // If it is is already collapsed but we want to recursively collapse then call collapseChildren
1050 else if (recursive) {
1051 me.collapseChildren(true, callback, scope);
1054 // If it's not then we fire the callback right away
1056 Ext.callback(callback, scope || me, [me.childNodes]);
1060 <span id='Ext-data-NodeInterface-method-collapseChildren'> /**
1061 </span> * Collapse all the children of this node.
1062 * @param {Function} recursive (Optional) True to recursively collapse all the children
1063 * @param {Function} callback (Optional) The function to execute once all the children are collapsed
1064 * @param {Object} scope (Optional) The scope to run the callback in
1066 collapseChildren: function(recursive, callback, scope) {
1069 nodes = me.childNodes,
1074 for (; i < ln; ++i) {
1076 if (!node.isLeaf() && node.isExpanded()) {
1078 nodes[i].collapse(recursive, function () {
1080 if (callback && !collapsing) {
1081 Ext.callback(callback, scope || me, [me.childNodes]);
1087 if (!collapsing && callback) {
1088 Ext.callback(callback, scope || me, [me.childNodes]);