| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336 | <!DOCTYPE html><html><head>  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />  <title>The source code</title>  <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />  <script type="text/javascript" src="../resources/prettify/prettify.js"></script>  <style type="text/css">    .highlight { display: block; background-color: #ddd; }  </style>  <script type="text/javascript">    function highlight() {      document.getElementById(location.hash.replace(/#/, "")).className = "highlight";    }  </script></head><body onload="prettyPrint(); highlight();">  <pre class="prettyprint lang-js"><span id='Ext-data-NodeInterface'>/**</span> * This class is used as a set of methods that are applied to the prototype of a * Model to decorate it with a Node API. This means that models used in conjunction with a tree * will have all of the tree related methods available on the model. In general this class will * not be used directly by the developer. This class also creates extra fields on the model if * they do not exist, to help maintain the tree state and UI. These fields are documented as * config options. */Ext.define('Ext.data.NodeInterface', {    requires: ['Ext.data.Field'],<span id='Ext-data-NodeInterface-cfg-parentId'>    /**</span>     * @cfg {String} parentId     * ID of parent node.     */<span id='Ext-data-NodeInterface-cfg-index'>    /**</span>     * @cfg {Number} index     * The position of the node inside its parent. When parent has 4 children and the node is third amongst them,     * index will be 2.     */<span id='Ext-data-NodeInterface-cfg-depth'>    /**</span>     * @cfg {Number} depth     * The number of parents this node has. A root node has depth 0, a child of it depth 1, and so on...     */<span id='Ext-data-NodeInterface-cfg-expanded'>    /**</span>     * @cfg {Boolean} [expanded=false]     * True if the node is expanded.     */<span id='Ext-data-NodeInterface-cfg-expandable'>    /**</span>     * @cfg {Boolean} [expandable=false]     * Set to true to allow for expanding/collapsing of this node.     */<span id='Ext-data-NodeInterface-cfg-checked'>    /**</span>     * @cfg {Boolean} [checked=null]     * Set to true or false to show a checkbox alongside this node.     */<span id='Ext-data-NodeInterface-cfg-leaf'>    /**</span>     * @cfg {Boolean} [leaf=false]     * Set to true to indicate that this child can have no children. The expand icon/arrow will then not be     * rendered for this node.     */<span id='Ext-data-NodeInterface-cfg-cls'>    /**</span>     * @cfg {String} cls     * CSS class to apply for this node.     */<span id='Ext-data-NodeInterface-cfg-iconCls'>    /**</span>     * @cfg {String} iconCls     * CSS class to apply for this node's icon.     */<span id='Ext-data-NodeInterface-cfg-icon'>    /**</span>     * @cfg {String} icon     * URL for this node's icon.     */<span id='Ext-data-NodeInterface-cfg-root'>    /**</span>     * @cfg {Boolean} root     * True if this is the root node.     */<span id='Ext-data-NodeInterface-cfg-isLast'>    /**</span>     * @cfg {Boolean} isLast     * True if this is the last node.     */<span id='Ext-data-NodeInterface-cfg-isFirst'>    /**</span>     * @cfg {Boolean} isFirst     * True if this is the first node.     */<span id='Ext-data-NodeInterface-cfg-allowDrop'>    /**</span>     * @cfg {Boolean} [allowDrop=true]     * Set to false to deny dropping on this node.     */<span id='Ext-data-NodeInterface-cfg-allowDrag'>    /**</span>     * @cfg {Boolean} [allowDrag=true]     * Set to false to deny dragging of this node.     */<span id='Ext-data-NodeInterface-cfg-loaded'>    /**</span>     * @cfg {Boolean} [loaded=false]     * True if the node has finished loading.     */<span id='Ext-data-NodeInterface-cfg-loading'>    /**</span>     * @cfg {Boolean} [loading=false]     * True if the node is currently loading.     */<span id='Ext-data-NodeInterface-cfg-href'>    /**</span>     * @cfg {String} href     * An URL for a link that's created when this config is specified.     */<span id='Ext-data-NodeInterface-cfg-hrefTarget'>    /**</span>     * @cfg {String} hrefTarget     * Target for link. Only applicable when {@link #href} also specified.     */<span id='Ext-data-NodeInterface-cfg-qtip'>    /**</span>     * @cfg {String} qtip     * Tooltip text to show on this node.     */<span id='Ext-data-NodeInterface-cfg-qtitle'>    /**</span>     * @cfg {String} qtitle     * Tooltip title.     */<span id='Ext-data-NodeInterface-cfg-text'>    /**</span>     * @cfg {String} text     * The text for to show on node label.     */<span id='Ext-data-NodeInterface-cfg-children'>    /**</span>     * @cfg {Ext.data.NodeInterface[]} children     * Array of child nodes.     */<span id='Ext-data-NodeInterface-property-nextSibling'>    /**</span>     * @property nextSibling     * A reference to this node's next sibling node. `null` if this node does not have a next sibling.     */<span id='Ext-data-NodeInterface-property-previousSibling'>    /**</span>     * @property previousSibling     * A reference to this node's previous sibling node. `null` if this node does not have a previous sibling.     */<span id='Ext-data-NodeInterface-property-parentNode'>    /**</span>     * @property parentNode     * A reference to this node's parent node. `null` if this node is the root node.     */<span id='Ext-data-NodeInterface-property-lastChild'>    /**</span>     * @property lastChild     * A reference to this node's last child node. `null` if this node has no children.     */<span id='Ext-data-NodeInterface-property-firstChild'>    /**</span>     * @property firstChild     * A reference to this node's first child node. `null` if this node has no children.     */<span id='Ext-data-NodeInterface-property-childNodes'>    /**</span>     * @property childNodes     * An array of this nodes children.  Array will be empty if this node has no chidren.     */    statics: {<span id='Ext-data-NodeInterface-static-method-decorate'>        /**</span>         * This method allows you to decorate a Model's class to implement the NodeInterface.         * This adds a set of methods, new events, new properties and new fields on every Record.         * @param {Ext.Class/Ext.data.Model} modelClass The Model class or an instance of the Model class you want to         * decorate the prototype of.         * @static         */        decorate: function(modelClass) {            var idName, idType;                        // get the reference to the model class, in case the argument was a string or a record            if (typeof modelClass == 'string') {                modelClass = Ext.ModelManager.getModel(modelClass);            } else if (modelClass.isModel) {                modelClass = Ext.ModelManager.getModel(modelClass.modelName);            }                        // avoid unnecessary work in case the model was already decorated            if (modelClass.prototype.isNode) {                return;            }            idName = modelClass.prototype.idProperty;            idField = modelClass.prototype.fields.get(idName);            idType = modelClass.prototype.fields.get(idName).type.type;            modelClass.override(this.getPrototypeBody());            this.applyFields(modelClass, [                {name: 'parentId',   type: idType,    defaultValue: null, useNull: idField.useNull},                {name: 'index',      type: 'int',     defaultValue: null, persist: false},                {name: 'depth',      type: 'int',     defaultValue: 0, persist: false},                {name: 'expanded',   type: 'bool',    defaultValue: false, persist: false},                {name: 'expandable', type: 'bool',    defaultValue: true, persist: false},                {name: 'checked',    type: 'auto',    defaultValue: null, persist: false},                {name: 'leaf',       type: 'bool',    defaultValue: false},                {name: 'cls',        type: 'string',  defaultValue: null, persist: false},                {name: 'iconCls',    type: 'string',  defaultValue: null, persist: false},                {name: 'icon',       type: 'string',  defaultValue: null, persist: false},                {name: 'root',       type: 'boolean', defaultValue: false, persist: false},                {name: 'isLast',     type: 'boolean', defaultValue: false, persist: false},                {name: 'isFirst',    type: 'boolean', defaultValue: false, persist: false},                {name: 'allowDrop',  type: 'boolean', defaultValue: true, persist: false},                {name: 'allowDrag',  type: 'boolean', defaultValue: true, persist: false},                {name: 'loaded',     type: 'boolean', defaultValue: false, persist: false},                {name: 'loading',    type: 'boolean', defaultValue: false, persist: false},                {name: 'href',       type: 'string',  defaultValue: null, persist: false},                {name: 'hrefTarget', type: 'string',  defaultValue: null, persist: false},                {name: 'qtip',       type: 'string',  defaultValue: null, persist: false},                {name: 'qtitle',     type: 'string',  defaultValue: null, persist: false},                {name: 'children',   type: 'auto',   defaultValue: null, persist: false}            ]);        },                applyFields: function(modelClass, addFields) {            var modelPrototype = modelClass.prototype,                fields = modelPrototype.fields,                keys = fields.keys,                ln = addFields.length,                addField, i;            for (i = 0; i < ln; i++) {                addField = addFields[i];                if (!Ext.Array.contains(keys, addField.name)) {                    fields.add(new Ext.data.Field(addField));                }            }        },        getPrototypeBody: function() {            return {<span id='Ext-data-NodeInterface-property-isNode'>                /**</span>                 * @property {Boolean} isNode                 * `true` in this class to identify an object as an instantiated Node, or subclass thereof.                 */                isNode: true,                                constructor: function() {                    var me = this;                    this.callParent(arguments);                    Ext.applyIf(me, {                        firstChild: null,                        lastChild: null,                        parentNode: null,                        previousSibling: null,                        nextSibling: null,                        childNodes: []                    });                    me.enableBubble([<span id='Ext-data-NodeInterface-event-append'>                        /**</span>                         * @event append                         * Fires when a new child node is appended                         * @param {Ext.data.NodeInterface} this This node                         * @param {Ext.data.NodeInterface} node The newly appended node                         * @param {Number} index The index of the newly appended node                         */                        "append",<span id='Ext-data-NodeInterface-event-remove'>                        /**</span>                         * @event remove                         * Fires when a child node is removed                         * @param {Ext.data.NodeInterface} this This node                         * @param {Ext.data.NodeInterface} node The removed node                         * @param {Boolean} isMove `true` if the child node is being removed so it can be moved to another position in the tree.                         * (a side effect of calling {@link Ext.data.NodeInterface#appendChild appendChild} or                         * {@link Ext.data.NodeInterface#insertBefore insertBefore} with a node that already has a parentNode)                         */                        "remove",<span id='Ext-data-NodeInterface-event-move'>                        /**</span>                         * @event move                         * Fires when this node is moved to a new location in the tree                         * @param {Ext.data.NodeInterface} this This node                         * @param {Ext.data.NodeInterface} oldParent The old parent of this node                         * @param {Ext.data.NodeInterface} newParent The new parent of this node                         * @param {Number} index The index it was moved to                         */                        "move",<span id='Ext-data-NodeInterface-event-insert'>                        /**</span>                         * @event insert                         * Fires when a new child node is inserted.                         * @param {Ext.data.NodeInterface} this This node                         * @param {Ext.data.NodeInterface} node The child node inserted                         * @param {Ext.data.NodeInterface} refNode The child node the node was inserted before                         */                        "insert",<span id='Ext-data-NodeInterface-event-beforeappend'>                        /**</span>                         * @event beforeappend                         * Fires before a new child is appended, return false to cancel the append.                         * @param {Ext.data.NodeInterface} this This node                         * @param {Ext.data.NodeInterface} node The child node to be appended                         */                        "beforeappend",<span id='Ext-data-NodeInterface-event-beforeremove'>                        /**</span>                         * @event beforeremove                         * Fires before a child is removed, return false to cancel the remove.                         * @param {Ext.data.NodeInterface} this This node                         * @param {Ext.data.NodeInterface} node The child node to be removed                         * @param {Boolean} isMove `true` if the child node is being removed so it can be moved to another position in the tree.                         * (a side effect of calling {@link Ext.data.NodeInterface#appendChild appendChild} or                         * {@link Ext.data.NodeInterface#insertBefore insertBefore} with a node that already has a parentNode)                         */                        "beforeremove",<span id='Ext-data-NodeInterface-event-beforemove'>                        /**</span>                         * @event beforemove                         * Fires before this node is moved to a new location in the tree. Return false to cancel the move.                         * @param {Ext.data.NodeInterface} this This node                         * @param {Ext.data.NodeInterface} oldParent The parent of this node                         * @param {Ext.data.NodeInterface} newParent The new parent this node is moving to                         * @param {Number} index The index it is being moved to                         */                        "beforemove",<span id='Ext-data-NodeInterface-event-beforeinsert'>                         /**</span>                          * @event beforeinsert                          * Fires before a new child is inserted, return false to cancel the insert.                          * @param {Ext.data.NodeInterface} this This node                          * @param {Ext.data.NodeInterface} node The child node to be inserted                          * @param {Ext.data.NodeInterface} refNode The child node the node is being inserted before                          */                        "beforeinsert",<span id='Ext-data-NodeInterface-event-expand'>                        /**</span>                         * @event expand                         * Fires when this node is expanded.                         * @param {Ext.data.NodeInterface} this The expanding node                         */                        "expand",<span id='Ext-data-NodeInterface-event-collapse'>                        /**</span>                         * @event collapse                         * Fires when this node is collapsed.                         * @param {Ext.data.NodeInterface} this The collapsing node                         */                        "collapse",<span id='Ext-data-NodeInterface-event-beforeexpand'>                        /**</span>                         * @event beforeexpand                         * Fires before this node is expanded.                         * @param {Ext.data.NodeInterface} this The expanding node                         */                        "beforeexpand",<span id='Ext-data-NodeInterface-event-beforecollapse'>                        /**</span>                         * @event beforecollapse                         * Fires before this node is collapsed.                         * @param {Ext.data.NodeInterface} this The collapsing node                         */                        "beforecollapse",<span id='Ext-data-NodeInterface-event-sort'>                        /**</span>                         * @event sort                         * Fires when this node's childNodes are sorted.                         * @param {Ext.data.NodeInterface} this This node.                         * @param {Ext.data.NodeInterface[]} childNodes The childNodes of this node.                         */                        "sort"                    ]);                    return me;                },<span id='Ext-data-NodeInterface-method-createNode'>                /**</span>                 * Ensures that the passed object is an instance of a Record with the NodeInterface applied                 * @return {Ext.data.NodeInterface}                 */                createNode: function(node) {                    if (Ext.isObject(node) && !node.isModel) {                        node = Ext.ModelManager.create(node, this.modelName);                    }                    // The node may already decorated, but may not have been                    // so when the model constructor was called. If not,                    // setup defaults here                    if (!node.childNodes) {                        Ext.applyIf(node, {                            firstChild: null,                            lastChild: null,                            parentNode: null,                            previousSibling: null,                            nextSibling: null,                            childNodes: []                        });                    }                    return node;                },<span id='Ext-data-NodeInterface-method-isLeaf'>                /**</span>                 * Returns true if this node is a leaf                 * @return {Boolean}                 */                isLeaf : function() {                    return this.get('leaf') === true;                },<span id='Ext-data-NodeInterface-method-setFirstChild'>                /**</span>                 * Sets the first child of this node                 * @private                 * @param {Ext.data.NodeInterface} node                 */                setFirstChild : function(node) {                    this.firstChild = node;                },<span id='Ext-data-NodeInterface-method-setLastChild'>                /**</span>                 * Sets the last child of this node                 * @private                 * @param {Ext.data.NodeInterface} node                 */                setLastChild : function(node) {                    this.lastChild = node;                },<span id='Ext-data-NodeInterface-method-updateInfo'>                /**</span>                 * Updates general data of this node like isFirst, isLast, depth. This                 * method is internally called after a node is moved. This shouldn't                 * have to be called by the developer unless they are creating custom                 * Tree plugins.                 * @return {Boolean}                 */                updateInfo: function(commit) {                    var me = this,                        isRoot = me.isRoot(),                        parentNode = me.parentNode,                        isFirst = (!parentNode || isRoot ? true : parentNode.firstChild === me),                        isLast = (!parentNode || isRoot ? true : parentNode.lastChild === me),                        depth = 0,                        parent = me,                        children = me.childNodes,                        len = children.length,                        i = 0,                        phantom = me.phantom;                    while (parent.parentNode) {                        ++depth;                        parent = parent.parentNode;                    }                    me.beginEdit();                    me.set({                        isFirst: isFirst,                        isLast: isLast,                        depth: depth,                        index: parentNode ? parentNode.indexOf(me) : 0,                        parentId: parentNode ? parentNode.getId() : null                    });                    me.endEdit(true);                    if (commit) {                        me.commit();                        me.phantom = phantom;                    }                    for (i = 0; i < len; i++) {                        children[i].updateInfo(commit);                    }                },<span id='Ext-data-NodeInterface-method-isLast'>                /**</span>                 * Returns true if this node is the last child of its parent                 * @return {Boolean}                 */                isLast : function() {                   return this.get('isLast');                },<span id='Ext-data-NodeInterface-method-isFirst'>                /**</span>                 * Returns true if this node is the first child of its parent                 * @return {Boolean}                 */                isFirst : function() {                   return this.get('isFirst');                },<span id='Ext-data-NodeInterface-method-hasChildNodes'>                /**</span>                 * Returns true if this node has one or more child nodes, else false.                 * @return {Boolean}                 */                hasChildNodes : function() {                    return !this.isLeaf() && this.childNodes.length > 0;                },<span id='Ext-data-NodeInterface-method-isExpandable'>                /**</span>                 * Returns true if this node has one or more child nodes, or if the <tt>expandable</tt>                 * node attribute is explicitly specified as true, otherwise returns false.                 * @return {Boolean}                 */                isExpandable : function() {                    var me = this;                    if (me.get('expandable')) {                        return !(me.isLeaf() || (me.isLoaded() && !me.hasChildNodes()));                    }                    return false;                },                                triggerUIUpdate: function(){                    // This isn't ideal, however none of the underlying fields have changed                    // but we still need to update the UI                    this.afterEdit([]);                    },<span id='Ext-data-NodeInterface-method-appendChild'>                /**</span>                 * Inserts node(s) as the last child node of this node.                 *                 * If the node was previously a child node of another parent node, it will be removed from that node first.                 *                 * @param {Ext.data.NodeInterface/Ext.data.NodeInterface[]} node The node or Array of nodes to append                 * @return {Ext.data.NodeInterface} The appended node if single append, or null if an array was passed                 */                appendChild : function(node, suppressEvents, commit) {                    var me = this,                        i, ln,                        index,                        oldParent,                        ps;                    // if passed an array do them one by one                    if (Ext.isArray(node)) {                        // suspend auto syncing while we append all the nodes                        me.callStore('suspendAutoSync');                        for (i = 0, ln = node.length - 1; i < ln; i++) {                            me.appendChild(node[i]);                        }                        // resume auto syncing before we append the last node                        me.callStore('resumeAutoSync');                        me.appendChild(node[ln]);                    } else {                        // Make sure it is a record                        node = me.createNode(node);                        if (suppressEvents !== true && (!me.hasListeners.beforeappend || me.fireEvent("beforeappend", me, node) === false)) {                            return false;                        }                        index = me.childNodes.length;                        oldParent = node.parentNode;                        // it's a move, make sure we move it cleanly                        if (oldParent) {                            if (suppressEvents !== true && (!me.hasListeners.beforeremove || node.fireEvent("beforemove", node, oldParent, me, index) === false)) {                                return false;                            }                            oldParent.removeChild(node, false, false, true);                        }                        index = me.childNodes.length;                        if (index === 0) {                            me.setFirstChild(node);                        }                        me.childNodes.push(node);                        node.parentNode = me;                        node.nextSibling = null;                        me.setLastChild(node);                        ps = me.childNodes[index - 1];                        if (ps) {                            node.previousSibling = ps;                            ps.nextSibling = node;                            ps.updateInfo(commit);                        } else {                            node.previousSibling = null;                        }                        node.updateInfo(commit);                        // As soon as we append a child to this node, we are loaded                        if (!me.isLoaded()) {                            me.set('loaded', true);                        } else if (me.childNodes.length === 1) {                            me.triggerUIUpdate();                        }                        if(!node.isLeaf() && node.phantom) {                            node.set('loaded', true);                        }                        if (suppressEvents !== true) {                            me.fireEvent("append", me, node, index);                            if (oldParent) {                                node.fireEvent("move", node, oldParent, me, index);                            }                        }                        return node;                    }                },<span id='Ext-data-NodeInterface-method-getBubbleTarget'>                /**</span>                 * Returns the bubble target for this node                 * @private                 * @return {Object} The bubble target                 */                getBubbleTarget: function() {                    return this.parentNode;                },<span id='Ext-data-NodeInterface-method-removeChild'>                /**</span>                 * Removes a child node from this node.                 * @param {Ext.data.NodeInterface} node The node to remove                 * @param {Boolean} [destroy=false] True to destroy the node upon removal.                 * @return {Ext.data.NodeInterface} The removed node                 */                removeChild : function(node, destroy, suppressEvents, isMove) {                    var me = this,                        index = me.indexOf(node),                        i, childCount;                    if (index == -1 || (suppressEvents !== true && (!me.hasListeners.beforeremove || me.fireEvent("beforeremove", me, node, !!isMove) === false))) {                        return false;                    }                    // remove it from childNodes collection                    Ext.Array.erase(me.childNodes, index, 1);                    // update child refs                    if (me.firstChild == node) {                        me.setFirstChild(node.nextSibling);                    }                    if (me.lastChild == node) {                        me.setLastChild(node.previousSibling);                    }                    // update siblings                    if (node.previousSibling) {                        node.previousSibling.nextSibling = node.nextSibling;                    }                    if (node.nextSibling) {                        node.nextSibling.previousSibling = node.previousSibling;                    }                    // update the info for all siblings starting at the index before the node's old index (or 0 if the removed node was the firstChild)                    for(i = index > 0 ? index - 1 : 0, childCount = me.childNodes.length; i < childCount; i++) {                        me.childNodes[i].updateInfo();                    }                    // If this node suddenly doesnt have childnodes anymore, update myself                    if (!me.childNodes.length) {                        me.triggerUIUpdate();                    }                    if (suppressEvents !== true) {                        if (me.hasListeners.remove) {                            me.fireEvent("remove", me, node, !!isMove);                        }                    }                    if (destroy) {                        node.destroy(true);                    } else {                        node.clear();                    }                    return node;                },<span id='Ext-data-NodeInterface-method-copy'>                /**</span>                 * Creates a copy (clone) of this Node.                 * @param {String} [id] A new id, defaults to this Node's id.                 * @param {Boolean} [deep=false] True to recursively copy all child Nodes into the new Node.                 * False to copy without child Nodes.                 * @return {Ext.data.NodeInterface} A copy of this Node.                 */                copy: function(newId, deep) {                    var me = this,                        result = me.callOverridden(arguments),                        len = me.childNodes ? me.childNodes.length : 0,                        i;                    // Move child nodes across to the copy if required                    if (deep) {                        for (i = 0; i < len; i++) {                            result.appendChild(me.childNodes[i].copy(true));                        }                    }                    return result;                },<span id='Ext-data-NodeInterface-method-clear'>                /**</span>                 * Clears the node.                 * @private                 * @param {Boolean} [destroy=false] True to destroy the node.                 */                clear : function(destroy) {                    var me = this;                    // clear any references from the node                    me.parentNode = me.previousSibling = me.nextSibling = null;                    if (destroy) {                        me.firstChild = me.lastChild = null;                    }                },<span id='Ext-data-NodeInterface-method-destroy'>                /**</span>                 * Destroys the node.                 */                destroy : function(silent) {                    /*                     * Silent is to be used in a number of cases                     * 1) When setRoot is called.                     * 2) When destroy on the tree is called                     * 3) For destroying child nodes on a node                     */                    var me      = this,                        options = me.destroyOptions,                        nodes   = me.childNodes,                        nLen    = nodes.length,                        n;                    if (silent === true) {                        me.clear(true);                        for (n = 0; n < nLen; n++) {                            nodes[n].destroy(true);                        }                        me.childNodes = null;                        delete me.destroyOptions;                        me.callOverridden([options]);                    } else {                        me.destroyOptions = silent;                        // overridden method will be called, since remove will end up calling destroy(true);                        me.remove(true);                    }                },<span id='Ext-data-NodeInterface-method-insertBefore'>                /**</span>                 * Inserts the first node before the second node in this nodes childNodes collection.                 * @param {Ext.data.NodeInterface} node The node to insert                 * @param {Ext.data.NodeInterface} refNode The node to insert before (if null the node is appended)                 * @return {Ext.data.NodeInterface} The inserted node                 */                insertBefore : function(node, refNode, suppressEvents) {                    var me = this,                        index     = me.indexOf(refNode),                        oldParent = node.parentNode,                        refIndex  = index,                        childCount, ps, i;                    if (!refNode) { // like standard Dom, refNode can be null for append                        return me.appendChild(node);                    }                    // nothing to do                    if (node == refNode) {                        return false;                    }                    // Make sure it is a record with the NodeInterface                    node = me.createNode(node);                    if (suppressEvents !== true && (!me.hasListeners.beforeinsert || me.fireEvent("beforeinsert", me, node, refNode) === false)) {                        return false;                    }                    // when moving internally, indexes will change after remove                    if (oldParent == me && me.indexOf(node) < index) {                        refIndex--;                    }                    // it's a move, make sure we move it cleanly                    if (oldParent) {                        if (suppressEvents !== true && (!me.hasListeners.beforeremove || node.fireEvent("beforemove", node, oldParent, me, index, refNode) === false)) {                            return false;                        }                        oldParent.removeChild(node, false, false, true);                    }                    if (refIndex === 0) {                        me.setFirstChild(node);                    }                    Ext.Array.splice(me.childNodes, refIndex, 0, node);                    node.parentNode = me;                    node.nextSibling = refNode;                    refNode.previousSibling = node;                    ps = me.childNodes[refIndex - 1];                    if (ps) {                        node.previousSibling = ps;                        ps.nextSibling = node;                    } else {                        node.previousSibling = null;                    }                    // update the info for all siblings starting at the index before the node's insertion point (or 0 if the inserted node is the firstChild)                    for(i = refIndex > 0 ? refIndex - 1 : 0, childCount = me.childNodes.length; i < childCount; i++) {                        me.childNodes[i].updateInfo();                    }                    if (!me.isLoaded()) {                        me.set('loaded', true);                    }                    // If this node didnt have any childnodes before, update myself                    else if (me.childNodes.length === 1) {                        me.triggerUIUpdate();                    }                    if(!node.isLeaf() && node.phantom) {                        node.set('loaded', true);                    }                    if (suppressEvents !== true) {                        if (me.hasListeners.insert) {                            me.fireEvent("insert", me, node, refNode);                        }                        if (oldParent && me.hasListeners.move) {                            node.fireEvent("move", node, oldParent, me, refIndex, refNode);                        }                    }                    return node;                },<span id='Ext-data-NodeInterface-method-insertChild'>                /**</span>                 * Inserts a node into this node.                 * @param {Number} index The zero-based index to insert the node at                 * @param {Ext.data.NodeInterface} node The node to insert                 * @return {Ext.data.NodeInterface} The node you just inserted                 */                insertChild: function(index, node) {                    var sibling = this.childNodes[index];                    if (sibling) {                        return this.insertBefore(node, sibling);                    }                    else {                        return this.appendChild(node);                    }                },<span id='Ext-data-NodeInterface-method-remove'>                /**</span>                 * Removes this node from its parent                 * @param {Boolean} [destroy=false] True to destroy the node upon removal.                 * @return {Ext.data.NodeInterface} this                 */                remove : function(destroy, suppressEvents) {                    var parentNode = this.parentNode;                    if (parentNode) {                        parentNode.removeChild(this, destroy, suppressEvents);                    }                    return this;                },<span id='Ext-data-NodeInterface-method-removeAll'>                /**</span>                 * Removes all child nodes from this node.                 * @param {Boolean} [destroy=false] <True to destroy the node upon removal.                 * @return {Ext.data.NodeInterface} this                 */                removeAll : function(destroy, suppressEvents) {                    var cn = this.childNodes,                        n;                    while ((n = cn[0])) {                        this.removeChild(n, destroy, suppressEvents);                    }                    return this;                },<span id='Ext-data-NodeInterface-method-getChildAt'>                /**</span>                 * Returns the child node at the specified index.                 * @param {Number} index                 * @return {Ext.data.NodeInterface}                 */                getChildAt : function(index) {                    return this.childNodes[index];                },<span id='Ext-data-NodeInterface-method-replaceChild'>                /**</span>                 * Replaces one child node in this node with another.                 * @param {Ext.data.NodeInterface} newChild The replacement node                 * @param {Ext.data.NodeInterface} oldChild The node to replace                 * @return {Ext.data.NodeInterface} The replaced node                 */                replaceChild : function(newChild, oldChild, suppressEvents) {                    var s = oldChild ? oldChild.nextSibling : null;                    this.removeChild(oldChild, false, suppressEvents);                    this.insertBefore(newChild, s, suppressEvents);                    return oldChild;                },<span id='Ext-data-NodeInterface-method-indexOf'>                /**</span>                 * Returns the index of a child node                 * @param {Ext.data.NodeInterface} node                 * @return {Number} The index of the node or -1 if it was not found                 */                indexOf : function(child) {                    return Ext.Array.indexOf(this.childNodes, child);                },                <span id='Ext-data-NodeInterface-method-indexOfId'>                /**</span>                 * Returns the index of a child node that matches the id                 * @param {String} id The id of the node to find                 * @return {Number} The index of the node or -1 if it was not found                 */                indexOfId: function(id) {                    var childNodes = this.childNodes,                        len = childNodes.length,                        i = 0;                                            for (; i < len; ++i) {                        if (childNodes[i].getId() === id) {                            return i;                        }                        }                    return -1;                },<span id='Ext-data-NodeInterface-method-getPath'>                /**</span>                 * Gets the hierarchical path from the root of the current node.                 * @param {String} [field] The field to construct the path from. Defaults to the model idProperty.                 * @param {String} [separator="/"] A separator to use.                 * @return {String} The node path                 */                getPath: function(field, separator) {                    field = field || this.idProperty;                    separator = separator || '/';                    var path = [this.get(field)],                        parent = this.parentNode;                    while (parent) {                        path.unshift(parent.get(field));                        parent = parent.parentNode;                    }                    return separator + path.join(separator);                },<span id='Ext-data-NodeInterface-method-getDepth'>                /**</span>                 * Returns depth of this node (the root node has a depth of 0)                 * @return {Number}                 */                getDepth : function() {                    return this.get('depth');                },<span id='Ext-data-NodeInterface-method-bubble'>                /**</span>                 * Bubbles up the tree from this node, calling the specified function with each node. The arguments to the function                 * will be the args provided or the current node. If the function returns false at any point,                 * the bubble is stopped.                 * @param {Function} fn The function to call                 * @param {Object} [scope] The scope (this reference) in which the function is executed. Defaults to the current Node.                 * @param {Array} [args] The args to call the function with. Defaults to passing the current Node.                 */                bubble : function(fn, scope, args) {                    var p = this;                    while (p) {                        if (fn.apply(scope || p, args || [p]) === false) {                            break;                        }                        p = p.parentNode;                    }                },                //<deprecated since=0.99>                cascade: function() {                    if (Ext.isDefined(Ext.global.console)) {                        Ext.global.console.warn('Ext.data.Node: cascade has been deprecated. Please use cascadeBy instead.');                    }                    return this.cascadeBy.apply(this, arguments);                },                //</deprecated><span id='Ext-data-NodeInterface-method-cascadeBy'>                /**</span>                 * Cascades down the tree from this node, calling the specified function with each node. The arguments to the function                 * will be the args provided or the current node. If the function returns false at any point,                 * the cascade is stopped on that branch.                 * @param {Function} fn The function to call                 * @param {Object} [scope] The scope (this reference) in which the function is executed. Defaults to the current Node.                 * @param {Array} [args] The args to call the function with. Defaults to passing the current Node.                 */                cascadeBy : function(fn, scope, args) {                    if (fn.apply(scope || this, args || [this]) !== false) {                        var childNodes = this.childNodes,                            length     = childNodes.length,                            i;                        for (i = 0; i < length; i++) {                            childNodes[i].cascadeBy(fn, scope, args);                        }                    }                },<span id='Ext-data-NodeInterface-method-eachChild'>                /**</span>                 * Interates the child nodes of this node, calling the specified function with each node. The arguments to the function                 * will be the args provided or the current node. If the function returns false at any point,                 * the iteration stops.                 * @param {Function} fn The function to call                 * @param {Object} [scope] The scope (this reference) in which the function is executed. Defaults to the current Node in iteration.                 * @param {Array} [args] The args to call the function with. Defaults to passing the current Node.                 */                eachChild : function(fn, scope, args) {                    var childNodes = this.childNodes,                        length     = childNodes.length,                        i;                    for (i = 0; i < length; i++) {                        if (fn.apply(scope || this, args || [childNodes[i]]) === false) {                            break;                        }                    }                },<span id='Ext-data-NodeInterface-method-findChild'>                /**</span>                 * Finds the first child that has the attribute with the specified value.                 * @param {String} attribute The attribute name                 * @param {Object} value The value to search for                 * @param {Boolean} [deep=false] True to search through nodes deeper than the immediate children                 * @return {Ext.data.NodeInterface} The found child or null if none was found                 */                findChild : function(attribute, value, deep) {                    return this.findChildBy(function() {                        return this.get(attribute) == value;                    }, null, deep);                },<span id='Ext-data-NodeInterface-method-findChildBy'>                /**</span>                 * Finds the first child by a custom function. The child matches if the function passed returns true.                 * @param {Function} fn A function which must return true if the passed Node is the required Node.                 * @param {Object} [scope] The scope (this reference) in which the function is executed. Defaults to the Node being tested.                 * @param {Boolean} [deep=false] True to search through nodes deeper than the immediate children                 * @return {Ext.data.NodeInterface} The found child or null if none was found                 */                findChildBy : function(fn, scope, deep) {                    var cs = this.childNodes,                        len = cs.length,                        i = 0, n, res;                    for (; i < len; i++) {                        n = cs[i];                        if (fn.call(scope || n, n) === true) {                            return n;                        }                        else if (deep) {                            res = n.findChildBy(fn, scope, deep);                            if (res !== null) {                                return res;                            }                        }                    }                    return null;                },<span id='Ext-data-NodeInterface-method-contains'>                /**</span>                 * Returns true if this node is an ancestor (at any point) of the passed node.                 * @param {Ext.data.NodeInterface} node                 * @return {Boolean}                 */                contains : function(node) {                    return node.isAncestor(this);                },<span id='Ext-data-NodeInterface-method-isAncestor'>                /**</span>                 * Returns true if the passed node is an ancestor (at any point) of this node.                 * @param {Ext.data.NodeInterface} node                 * @return {Boolean}                 */                isAncestor : function(node) {                    var p = this.parentNode;                    while (p) {                        if (p == node) {                            return true;                        }                        p = p.parentNode;                    }                    return false;                },<span id='Ext-data-NodeInterface-method-sort'>                /**</span>                 * Sorts this nodes children using the supplied sort function.                 * @param {Function} fn A function which, when passed two Nodes, returns -1, 0 or 1 depending upon required sort order.                 * @param {Boolean} [recursive=false] True to apply this sort recursively                 * @param {Boolean} [suppressEvent=false] True to not fire a sort event.                 */                sort : function(sortFn, recursive, suppressEvent) {                    var cs  = this.childNodes,                        ln = cs.length,                        i, n;                    if (ln > 0) {                        Ext.Array.sort(cs, sortFn);                        for (i = 0; i < ln; i++) {                            n = cs[i];                            n.previousSibling = cs[i-1];                            n.nextSibling = cs[i+1];                            if (i === 0) {                                this.setFirstChild(n);                            }                            if (i == ln - 1) {                                this.setLastChild(n);                            }                            n.updateInfo();                            if (recursive && !n.isLeaf()) {                                n.sort(sortFn, true, true);                            }                        }                        if (suppressEvent !== true) {                            this.fireEvent('sort', this, cs);                        }                    }                },<span id='Ext-data-NodeInterface-method-isExpanded'>                /**</span>                 * Returns true if this node is expaned                 * @return {Boolean}                 */                isExpanded: function() {                    return this.get('expanded');                },<span id='Ext-data-NodeInterface-method-isLoaded'>                /**</span>                 * Returns true if this node is loaded                 * @return {Boolean}                 */                isLoaded: function() {                    return this.get('loaded');                },<span id='Ext-data-NodeInterface-method-isLoading'>                /**</span>                 * Returns true if this node is loading                 * @return {Boolean}                 */                isLoading: function() {                    return this.get('loading');                },<span id='Ext-data-NodeInterface-method-isRoot'>                /**</span>                 * Returns true if this node is the root node                 * @return {Boolean}                 */                isRoot: function() {                    return !this.parentNode;                },<span id='Ext-data-NodeInterface-method-isVisible'>                /**</span>                 * Returns true if this node is visible                 * @return {Boolean}                 */                isVisible: function() {                    var parent = this.parentNode;                    while (parent) {                        if (!parent.isExpanded()) {                            return false;                        }                        parent = parent.parentNode;                    }                    return true;                },<span id='Ext-data-NodeInterface-method-expand'>                /**</span>                 * Expand this node.                 * @param {Boolean} [recursive=false] True to recursively expand all the children                 * @param {Function} [callback] The function to execute once the expand completes                 * @param {Object} [scope] The scope to run the callback in                 */                expand: function(recursive, callback, scope) {                    var me = this;                    // all paths must call the callback (eventually) or things like                    // selectPath fail                    // First we start by checking if this node is a parent                    if (!me.isLeaf()) {                        // If it's loaded, wait until it loads before proceeding                        if (me.isLoading()) {                            me.on('expand', function(){                                me.expand(recursive, callback, scope);                            }, me, {single: true});                        } else {                            // Now we check if this record is already expanding or expanded                            if (!me.isExpanded()) {                                // The TreeStore actually listens for the beforeexpand method and checks                                // whether we have to asynchronously load the children from the server                                // first. Thats why we pass a callback function to the event that the                                // store can call once it has loaded and parsed all the children.                                me.fireEvent('beforeexpand', me, function() {                                    me.set('expanded', true);                                    if (me.hasListeners.expand) {                                        me.fireEvent('expand', me, me.childNodes, false);                                    }                                    // Call the expandChildren method if recursive was set to true                                    if (recursive) {                                        me.expandChildren(true, callback, scope);                                    } else {                                        Ext.callback(callback, scope || me, [me.childNodes]);                                    }                                }, me);                            } else if (recursive) {                                // If it is is already expanded but we want to recursively expand then call expandChildren                                me.expandChildren(true, callback, scope);                            } else {                                Ext.callback(callback, scope || me, [me.childNodes]);                            }                        }                    } else {                        // If it's not then we fire the callback right away                        Ext.callback(callback, scope || me); // leaf = no childNodes                    }                },<span id='Ext-data-NodeInterface-method-expandChildren'>                /**</span>                 * Expand all the children of this node.                 * @param {Boolean} [recursive=false] True to recursively expand all the children                 * @param {Function} [callback] The function to execute once all the children are expanded                 * @param {Object} [scope] The scope to run the callback in                 */                expandChildren: function(recursive, callback, scope) {                    var me = this,                        i = 0,                        nodes = me.childNodes,                        ln = nodes.length,                        node,                        expanding = 0;                    for (; i < ln; ++i) {                        node = nodes[i];                        if (!node.isLeaf()) {                            expanding++;                            nodes[i].expand(recursive, function () {                                expanding--;                                if (callback && !expanding) {                                    Ext.callback(callback, scope || me, [me.childNodes]);                                }                            });                        }                    }                    if (!expanding && callback) {                        Ext.callback(callback, scope || me, [me.childNodes]);                    }                },<span id='Ext-data-NodeInterface-method-collapse'>                /**</span>                 * Collapse this node.                 * @param {Boolean} [recursive=false] True to recursively collapse all the children                 * @param {Function} [callback] The function to execute once the collapse completes                 * @param {Object} [scope] The scope to run the callback in                 */                collapse: function(recursive, callback, scope) {                    var me = this;                    // First we start by checking if this node is a parent                    if (!me.isLeaf()) {                        // Now we check if this record is already collapsing or collapsed                        if (!me.collapsing && me.isExpanded()) {                            me.fireEvent('beforecollapse', me, function() {                                me.set('expanded', false);                                if (me.hasListeners.collapse) {                                    me.fireEvent('collapse', me, me.childNodes, false);                                }                                // Call the collapseChildren method if recursive was set to true                                if (recursive) {                                    me.collapseChildren(true, callback, scope);                                }                                else {                                    Ext.callback(callback, scope || me, [me.childNodes]);                                }                            }, me);                        }                        // If it is is already collapsed but we want to recursively collapse then call collapseChildren                        else if (recursive) {                            me.collapseChildren(true, callback, scope);                        } else {                            Ext.callback(callback, scope || me, [me.childNodes]);                        }                    }                    // If it's not then we fire the callback right away                    else {                        Ext.callback(callback, scope || me, [me.childNodes]);                    }                },<span id='Ext-data-NodeInterface-method-collapseChildren'>                /**</span>                 * Collapse all the children of this node.                 * @param {Function} [recursive=false] True to recursively collapse all the children                 * @param {Function} [callback] The function to execute once all the children are collapsed                 * @param {Object} [scope] The scope to run the callback in                 */                collapseChildren: function(recursive, callback, scope) {                    var me = this,                        i = 0,                        nodes = me.childNodes,                        ln = nodes.length,                        node,                        collapsing = 0;                    for (; i < ln; ++i) {                        node = nodes[i];                        if (!node.isLeaf()) {                            collapsing++;                            nodes[i].collapse(recursive, function () {                                collapsing--;                                if (callback && !collapsing) {                                    Ext.callback(callback, scope || me, [me.childNodes]);                                }                            });                        }                    }                    if (!collapsing && callback) {                        Ext.callback(callback, scope || me, [me.childNodes]);                    }                }            };        }    }});</pre></body></html>
 |