Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / data / NodeStore.js
diff --git a/src/data/NodeStore.js b/src/data/NodeStore.js
new file mode 100644 (file)
index 0000000..e5da19c
--- /dev/null
@@ -0,0 +1,247 @@
+/**
+ * @class Ext.data.NodeStore
+ * @extends Ext.data.AbstractStore
+ * Node Store
+ * @ignore
+ */
+Ext.define('Ext.data.NodeStore', {
+    extend: 'Ext.data.Store',
+    alias: 'store.node',
+    requires: ['Ext.data.NodeInterface'],
+    
+    /**
+     * @cfg {Ext.data.Record} node The Record you want to bind this Store to. Note that
+     * this record will be decorated with the Ext.data.NodeInterface if this is not the
+     * case yet.
+     */
+    node: null,
+    
+    /**
+     * @cfg {Boolean} recursive Set this to true if you want this NodeStore to represent
+     * all the descendents of the node in its flat data collection. This is useful for
+     * rendering a tree structure to a DataView and is being used internally by
+     * the TreeView. Any records that are moved, removed, inserted or appended to the
+     * node at any depth below the node this store is bound to will be automatically
+     * updated in this Store's internal flat data structure.
+     */
+    recursive: false,
+    
+    /** 
+     * @cfg {Boolean} rootVisible <tt>false</tt> to not include the root node in this Stores collection (defaults to <tt>true</tt>)
+     */    
+    rootVisible: false,
+    
+    constructor: function(config) {
+        var me = this,
+            node;
+            
+        config = config || {};
+        Ext.apply(me, config);
+        
+        //<debug>
+        if (Ext.isDefined(me.proxy)) {
+            Ext.Error.raise("A NodeStore cannot be bound to a proxy. Instead bind it to a record " +
+                            "decorated with the NodeInterface by setting the node config.");
+        }
+        //</debug>
+
+        config.proxy = {type: 'proxy'};
+        me.callParent([config]);
+
+        me.addEvents('expand', 'collapse', 'beforeexpand', 'beforecollapse');
+        
+        node = me.node;
+        if (node) {
+            me.node = null;
+            me.setNode(node);
+        }
+    },
+    
+    setNode: function(node) {
+        var me = this;
+        
+        if (me.node && me.node != node) {
+            // We want to unbind our listeners on the old node
+            me.mun(me.node, {
+                expand: me.onNodeExpand,
+                collapse: me.onNodeCollapse,
+                append: me.onNodeAppend,
+                insert: me.onNodeInsert,
+                remove: me.onNodeRemove,
+                sort: me.onNodeSort,
+                scope: me
+            });
+            me.node = null;
+        }
+        
+        if (node) {
+            Ext.data.NodeInterface.decorate(node);
+            me.removeAll();
+            if (me.rootVisible) {
+                me.add(node);
+            }
+            me.mon(node, {
+                expand: me.onNodeExpand,
+                collapse: me.onNodeCollapse,
+                append: me.onNodeAppend,
+                insert: me.onNodeInsert,
+                remove: me.onNodeRemove,
+                sort: me.onNodeSort,
+                scope: me
+            });
+            me.node = node;
+            if (node.isExpanded() && node.isLoaded()) {
+                me.onNodeExpand(node, node.childNodes, true);
+            }
+        }
+    },
+    
+    onNodeSort: function(node, childNodes) {
+        var me = this;
+        
+        if ((me.indexOf(node) !== -1 || (node === me.node && !me.rootVisible) && node.isExpanded())) {
+            me.onNodeCollapse(node, childNodes, true);
+            me.onNodeExpand(node, childNodes, true);
+        }
+    },
+    
+    onNodeExpand: function(parent, records, suppressEvent) {
+        var me = this,
+            insertIndex = me.indexOf(parent) + 1,
+            ln = records ? records.length : 0,
+            i, record;
+            
+        if (!me.recursive && parent !== me.node) {
+            return;
+        }
+        
+        if (!me.isVisible(parent)) {
+            return;
+        }
+
+        if (!suppressEvent && me.fireEvent('beforeexpand', parent, records, insertIndex) === false) {
+            return;
+        }
+        
+        if (ln) {
+            me.insert(insertIndex, records);
+            for (i = 0; i < ln; i++) {
+                record = records[i];
+                if (record.isExpanded()) {
+                    if (record.isLoaded()) {
+                        // Take a shortcut                        
+                        me.onNodeExpand(record, record.childNodes, true);
+                    }
+                    else {
+                        record.set('expanded', false);
+                        record.expand();
+                    }
+                }
+            }
+        }
+
+        if (!suppressEvent) {
+            me.fireEvent('expand', parent, records);
+        }
+    },
+
+    onNodeCollapse: function(parent, records, suppressEvent) {
+        var me = this,
+            ln = records.length,
+            collapseIndex = me.indexOf(parent) + 1,
+            i, record;
+            
+        if (!me.recursive && parent !== me.node) {
+            return;
+        }
+        
+        if (!suppressEvent && me.fireEvent('beforecollapse', parent, records, collapseIndex) === false) {
+            return;
+        }
+
+        for (i = 0; i < ln; i++) {
+            record = records[i];
+            me.remove(record);
+            if (record.isExpanded()) {
+                me.onNodeCollapse(record, record.childNodes, true);
+            }
+        }
+        
+        if (!suppressEvent) {
+            me.fireEvent('collapse', parent, records, collapseIndex);
+        }
+    },
+    
+    onNodeAppend: function(parent, node, index) {
+        var me = this,
+            refNode, sibling;
+
+        if (me.isVisible(node)) {
+            if (index === 0) {
+                refNode = parent;
+            } else {
+                sibling = node.previousSibling;
+                while (sibling.isExpanded() && sibling.lastChild) {
+                    sibling = sibling.lastChild;
+                }
+                refNode = sibling;
+            }
+            me.insert(me.indexOf(refNode) + 1, node);
+            if (!node.isLeaf() && node.isExpanded()) {
+                if (node.isLoaded()) {
+                    // Take a shortcut                        
+                    me.onNodeExpand(node, node.childNodes, true);
+                }
+                else {
+                    node.set('expanded', false);
+                    node.expand();
+                }
+            }
+        } 
+    },
+    
+    onNodeInsert: function(parent, node, refNode) {
+        var me = this,
+            index = this.indexOf(refNode);
+            
+        if (index != -1 && me.isVisible(node)) {
+            me.insert(index, node);
+            if (!node.isLeaf() && node.isExpanded()) {
+                if (node.isLoaded()) {
+                    // Take a shortcut                        
+                    me.onNodeExpand(node, node.childNodes, true);
+                }
+                else {
+                    node.set('expanded', false);
+                    node.expand();
+                }
+            }
+        }
+    },
+    
+    onNodeRemove: function(parent, node, index) {
+        var me = this;
+        if (me.indexOf(node) != -1) {
+            if (!node.isLeaf() && node.isExpanded()) {
+                me.onNodeCollapse(node, node.childNodes, true);
+            }            
+            me.remove(node);
+        }
+    },
+    
+    isVisible: function(node) {
+        var parent = node.parentNode;
+        while (parent) {
+            if (parent === this.node && !this.rootVisible && parent.isExpanded()) {
+                return true;
+            }
+            
+            if (this.indexOf(parent) === -1 || !parent.isExpanded()) {
+                return false;
+            }
+            
+            parent = parent.parentNode;
+        }
+        return true;
+    }
+});
\ No newline at end of file