3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.data.NodeStore
17 * @extends Ext.data.AbstractStore
21 Ext.define('Ext.data.NodeStore', {
22 extend: 'Ext.data.Store',
24 requires: ['Ext.data.NodeInterface'],
27 * @cfg {Ext.data.Record} node The Record you want to bind this Store to. Note that
28 * this record will be decorated with the Ext.data.NodeInterface if this is not the
34 * @cfg {Boolean} recursive Set this to true if you want this NodeStore to represent
35 * all the descendents of the node in its flat data collection. This is useful for
36 * rendering a tree structure to a DataView and is being used internally by
37 * the TreeView. Any records that are moved, removed, inserted or appended to the
38 * node at any depth below the node this store is bound to will be automatically
39 * updated in this Store's internal flat data structure.
44 * @cfg {Boolean} rootVisible <tt>false</tt> to not include the root node in this Stores collection (defaults to <tt>true</tt>)
48 constructor: function(config) {
52 config = config || {};
53 Ext.apply(me, config);
56 if (Ext.isDefined(me.proxy)) {
57 Ext.Error.raise("A NodeStore cannot be bound to a proxy. Instead bind it to a record " +
58 "decorated with the NodeInterface by setting the node config.");
62 config.proxy = {type: 'proxy'};
63 me.callParent([config]);
65 me.addEvents('expand', 'collapse', 'beforeexpand', 'beforecollapse');
74 setNode: function(node) {
77 if (me.node && me.node != node) {
78 // We want to unbind our listeners on the old node
80 expand: me.onNodeExpand,
81 collapse: me.onNodeCollapse,
82 append: me.onNodeAppend,
83 insert: me.onNodeInsert,
84 remove: me.onNodeRemove,
92 Ext.data.NodeInterface.decorate(node);
98 expand: me.onNodeExpand,
99 collapse: me.onNodeCollapse,
100 append: me.onNodeAppend,
101 insert: me.onNodeInsert,
102 remove: me.onNodeRemove,
107 if (node.isExpanded() && node.isLoaded()) {
108 me.onNodeExpand(node, node.childNodes, true);
113 onNodeSort: function(node, childNodes) {
116 if ((me.indexOf(node) !== -1 || (node === me.node && !me.rootVisible) && node.isExpanded())) {
117 me.onNodeCollapse(node, childNodes, true);
118 me.onNodeExpand(node, childNodes, true);
122 onNodeExpand: function(parent, records, suppressEvent) {
124 insertIndex = me.indexOf(parent) + 1,
125 ln = records ? records.length : 0,
128 if (!me.recursive && parent !== me.node) {
132 if (!me.isVisible(parent)) {
136 if (!suppressEvent && me.fireEvent('beforeexpand', parent, records, insertIndex) === false) {
141 me.insert(insertIndex, records);
142 for (i = 0; i < ln; i++) {
144 if (record.isExpanded()) {
145 if (record.isLoaded()) {
147 me.onNodeExpand(record, record.childNodes, true);
150 record.set('expanded', false);
157 if (!suppressEvent) {
158 me.fireEvent('expand', parent, records);
162 onNodeCollapse: function(parent, records, suppressEvent) {
165 collapseIndex = me.indexOf(parent) + 1,
168 if (!me.recursive && parent !== me.node) {
172 if (!suppressEvent && me.fireEvent('beforecollapse', parent, records, collapseIndex) === false) {
176 for (i = 0; i < ln; i++) {
179 if (record.isExpanded()) {
180 me.onNodeCollapse(record, record.childNodes, true);
184 if (!suppressEvent) {
185 me.fireEvent('collapse', parent, records, collapseIndex);
189 onNodeAppend: function(parent, node, index) {
193 if (me.isVisible(node)) {
197 sibling = node.previousSibling;
198 while (sibling.isExpanded() && sibling.lastChild) {
199 sibling = sibling.lastChild;
203 me.insert(me.indexOf(refNode) + 1, node);
204 if (!node.isLeaf() && node.isExpanded()) {
205 if (node.isLoaded()) {
207 me.onNodeExpand(node, node.childNodes, true);
210 node.set('expanded', false);
217 onNodeInsert: function(parent, node, refNode) {
219 index = this.indexOf(refNode);
221 if (index != -1 && me.isVisible(node)) {
222 me.insert(index, node);
223 if (!node.isLeaf() && node.isExpanded()) {
224 if (node.isLoaded()) {
226 me.onNodeExpand(node, node.childNodes, true);
229 node.set('expanded', false);
236 onNodeRemove: function(parent, node, index) {
238 if (me.indexOf(node) != -1) {
239 if (!node.isLeaf() && node.isExpanded()) {
240 me.onNodeCollapse(node, node.childNodes, true);
246 isVisible: function(node) {
247 var parent = node.parentNode;
249 if (parent === this.node && !this.rootVisible && parent.isExpanded()) {
253 if (this.indexOf(parent) === -1 || !parent.isExpanded()) {
257 parent = parent.parentNode;