13693261870
2022-09-16 354b3dbfbffb3df45212a2a44dbbf48b4acc2594
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
<!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-NodeStore'>/**
</span> * Node Store
 * @private
 */
Ext.define('Ext.data.NodeStore', {
    extend: 'Ext.data.Store',
    alias: 'store.node',
    requires: ['Ext.data.NodeInterface'],
 
<span id='Ext-data-NodeStore-property-isNodeStore'>    /**
</span>     * @property {Boolean} isNodeStore
     * `true` in this class to identify an object as an instantiated NodeStore, or subclass thereof.
     */
    isNodeStore: true,
 
<span id='Ext-data-NodeStore-cfg-node'>    /**
</span>     * @cfg {Ext.data.Model} 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,
 
<span id='Ext-data-NodeStore-cfg-recursive'>    /**
</span>     * @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,
 
<span id='Ext-data-NodeStore-cfg-rootVisible'>    /**
</span>     * @cfg {Boolean} rootVisible
     * False to not include the root node in this Stores collection.
     */
    rootVisible: false,
 
<span id='Ext-data-NodeStore-cfg-treeStore'>    /**
</span>     * @cfg {Ext.data.TreeStore} treeStore
     * The TreeStore that is used by this NodeStore's Ext.tree.View.
     */
 
<span id='Ext-data-NodeStore-property-isExpandingOrCollapsing'>    /**
</span>     * @protected
     * Recursion level counter. Incremented when expansion or collaping of a node is initiated,
     * including when nested nodes below the expanding/collapsing root begin expanding or collapsing.
     * 
     * This ensures that collapsestart, collapsecomplete, expandstart and expandcomplete only
     * fire on the top level node being collapsed/expanded.
     * 
     * Also, allows listeners to the `add` and `remove` events to know whether a collapse of expand is in progress.
     */
    isExpandingOrCollapsing: 0,
 
<span id='Ext-data-NodeStore-method-constructor'>    constructor: function(config) {
</span>        var me = this,
            node;
 
        config = config || {};
        Ext.apply(me, config);
 
        //&lt;debug&gt;
        if (Ext.isDefined(me.proxy)) {
            Ext.Error.raise(&quot;A NodeStore cannot be bound to a proxy. Instead bind it to a record &quot; +
                            &quot;decorated with the NodeInterface by setting the node config.&quot;);
        }
        me.useModelWarning = false;
        //&lt;/debug&gt;
 
        config.proxy = {type: 'proxy'};
        me.callParent([config]);
 
        node = me.node;
        if (node) {
            me.node = null;
            me.setNode(node);
        }
    },
 
<span id='Ext-data-NodeStore-method-getTotalCount'>    // NodeStores are never buffered or paged. They are loaded from the TreeStore to reflect all visible
</span>    // nodes.
    // BufferedRenderer always asks for the *total* count, so this must return the count.
    getTotalCount: function() {
        return this.getCount();
    },
 
<span id='Ext-data-NodeStore-method-setNode'>    setNode: function(node) {
</span>        var me = this;
        if (me.node &amp;&amp; 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,
                bulkremove: me.onBulkRemove,
                remove: me.onNodeRemove,
                sort: me.onNodeSort,
                scope: me
            });
            me.node = null;
        }
 
        if (node) {
            Ext.data.NodeInterface.decorate(node.self);
            me.removeAll();
            if (me.rootVisible) {
                me.add(node);
            } else if (!node.isExpanded() &amp;&amp; me.treeStore.autoLoad !== false) {
                node.expand();
            }
 
            me.mon(node, {
                expand: me.onNodeExpand,
                collapse: me.onNodeCollapse,
                append: me.onNodeAppend,
                insert: me.onNodeInsert,
                bulkremove: me.onBulkRemove,
                remove: me.onNodeRemove,
                sort: me.onNodeSort,
                scope: me
            });
            me.node = node;
            if (node.isExpanded() &amp;&amp; node.isLoaded()) {
                me.onNodeExpand(node, node.childNodes, true);
            }
        }
    },
 
<span id='Ext-data-NodeStore-method-onNodeSort'>    onNodeSort: function(node, childNodes) {
</span>        var me = this;
 
        if ((me.indexOf(node) !== -1 || (node === me.node &amp;&amp; !me.rootVisible) &amp;&amp; node.isExpanded())) {
            Ext.suspendLayouts();
            me.onNodeCollapse(node, childNodes, true);
            me.onNodeExpand(node, childNodes, true);
            Ext.resumeLayouts(true);
        }
    },
 
<span id='Ext-data-NodeStore-method-onNodeExpand'>    // Triggered by a NodeInterface's bubbled &quot;expand&quot; event.
</span>    onNodeExpand: function(parent, records, suppressEvent) {
        var me = this,
            insertIndex = me.indexOf(parent) + 1,
            toAdd = [];
 
        // Used by the TreeView to bracket recursive expand &amp; collapse ops
        // and refresh the size. This is most effective when folder nodes are loaded,
        // and this method is able to recurse.
        if (!suppressEvent) {
            me.fireEvent('beforeexpand', parent, records, insertIndex);
        }
 
        me.handleNodeExpand(parent, records, toAdd);
 
        // The add event from this insertion is handled by TreeView.onAdd.
        // That implementation calls parent and then ensures the previous sibling's joining lines are correct.
        // The datachanged event is relayed by the TreeStore. Internally, that's not used.
        me.insert(insertIndex, toAdd);
 
        // Triggers the TreeView's onExpand method which calls refreshSize,
        // and fires its afteritemexpand event
        if (!suppressEvent) {
            me.fireEvent('expand', parent, records);
        }
    },
 
<span id='Ext-data-NodeStore-method-handleNodeExpand'>    // Collects child nodes to remove into the passed toRemove array.
</span>    // When available, all descendant nodes are pushed into that array using recursion.
    handleNodeExpand: function(parent, records, toAdd) {
        var me = this,
            ln = records ? records.length : 0,
            i, record;
 
        // recursive is hardcoded to true in TreeView.
        if (!me.recursive &amp;&amp; parent !== me.node) {
            return;
        }
 
        if (parent !== this.node &amp;&amp; !me.isVisible(parent)) {
            return;
        }
 
        if (ln) {
            // The view items corresponding to these are rendered.
            // Loop through and expand any of the non-leaf nodes which are expanded
            for (i = 0; i &lt; ln; i++) {
                record = records[i];
 
                // Add to array being collected by recursion when child nodes are loaded.
                // Must be done here in loop so that child nodes are inserted into the stream in place
                // in recursive calls.
                toAdd.push(record);
 
                if (record.isExpanded()) {
                    if (record.isLoaded()) {
                        // Take a shortcut - appends to toAdd array
                        me.handleNodeExpand(record, record.childNodes, toAdd);
                    }
                    else {
                        // Might be asynchronous if child nodes are not immediately available
                        record.set('expanded', false);
                        record.expand();
                    }
                }
            }
        }
    },
    
<span id='Ext-data-NodeStore-method-onBulkRemove'>    // Triggered by NodeInterface's bubbled bulkremove event
</span>    onBulkRemove: function(parent, childNodes, isMove) {
        this.onNodeCollapse(parent, childNodes, true);
    },
 
<span id='Ext-data-NodeStore-method-onNodeCollapse'>    // Triggered by a NodeInterface's bubbled &quot;collapse&quot; event.
</span>    onNodeCollapse: function(parent, records, suppressEvent, callback, scope) {
        var me = this,
            collapseIndex = me.indexOf(parent) + 1,
            node, lastNodeIndexPlus, sibling, found;
 
        if (!me.recursive &amp;&amp; parent !== me.node) {
            return;
        }
 
        // Used by the TreeView to bracket recursive expand &amp; collapse ops.
        // The TreeViewsets up the animWrap object if we are animating.
        // It also caches the collapse callback to call when it receives the
        // end collapse event. See below.
        if (!suppressEvent) {
            me.fireEvent('beforecollapse', parent, records, collapseIndex, callback, scope);
        }
 
        // Only attempt to remove the records if they are there.
        // Collapsing an ancestor node *immediately removes from the view, ALL its descendant nodes at all levels*.
        // But if the collapse was recursive, all descendant root nodes will still fire their
        // events. But we must ignore those events here - we have nothing to do.
        if (records.length &amp;&amp; me.data.contains(records[0])) {
            
            // Calculate the index *one beyond* the last node we are going to remove
            // Need to loop up the tree to find the nearest view sibling, since it could
            // exist at some level above the current node.
            node = parent;
            while (node.parentNode) {
                sibling = node.nextSibling;
                if (sibling) {
                    found = true;
                    lastNodeIndexPlus = me.indexOf(sibling); 
                    break;
                } else {
                    node = node.parentNode;
                }
            }
            if (!found) {
                lastNodeIndexPlus = me.getCount();
            }
 
            // Remove the whole collapsed node set.
            me.removeAt(collapseIndex, lastNodeIndexPlus - collapseIndex);
        }
 
        // Triggers the TreeView's onCollapse method which calls refreshSize,
        // and fires its afteritecollapse event
        if (!suppressEvent) {
            me.fireEvent('collapse', parent, records, collapseIndex);
        }
    },
 
<span id='Ext-data-NodeStore-method-onNodeAppend'>    onNodeAppend: function(parent, node, index) {
</span>        var me = this,
            refNode, sibling;
 
        // Only react to a node append if it is to a node which is expanded, and is part of a tree
        if (me.isVisible(node)) {
            if (index === 0) {
                refNode = parent;
            } else {
                sibling = node.previousSibling;
                while (sibling.isExpanded() &amp;&amp; sibling.lastChild) {
                    sibling = sibling.lastChild;
                }
                refNode = sibling;
            }
            me.insert(me.indexOf(refNode) + 1, node);
            if (!node.isLeaf() &amp;&amp; node.isExpanded()) {
                if (node.isLoaded()) {
                    // Take a shortcut
                    me.onNodeExpand(node, node.childNodes, true);
                } else if (!me.treeStore.fillCount ) {
                    // If the node has been marked as expanded, it means the children
                    // should be provided as part of the raw data. If we're filling the nodes,
                    // the children may not have been loaded yet, so only do this if we're
                    // not in the middle of populating the nodes.
                    node.set('expanded', false);
                    node.expand();
                }
            }
        }
    },
 
<span id='Ext-data-NodeStore-method-onNodeInsert'>    onNodeInsert: function(parent, node, refNode) {
</span>        var me = this,
            index = this.indexOf(refNode);
 
        if (index != -1 &amp;&amp; me.isVisible(node)) {
            me.insert(index, node);
            if (!node.isLeaf() &amp;&amp; node.isExpanded()) {
                if (node.isLoaded()) {
                    // Take a shortcut
                    me.onNodeExpand(node, node.childNodes, true);
                }
                else {
                    node.set('expanded', false);
                    node.expand();
                }
            }
        }
    },
 
<span id='Ext-data-NodeStore-method-onNodeRemove'>    onNodeRemove: function(parent, node, isMove) {
</span>        var me = this;
        if (me.indexOf(node) != -1) {
 
            // If the removed node is a non-leaf and is expanded, use the onCollapse method to get rid
            // of all descendants at any level.
            if (!node.isLeaf() &amp;&amp; node.isExpanded()) {
 
                // onCollapse expects to be able to use the &quot;collapsing&quot; node's parentNode
                // and nextSibling pointers so temporarily reinstate them.
                // Reinstating them is safe because we pass the suppressEvents flag, and no user code
                // is executed.
                node.parentNode = node.removeContext.parentNode;
                node.nextSibling = node.removeContext.nextSibling;
                me.onNodeCollapse(node, node.childNodes, true);
                node.parentNode = node.nextSibling = null;
            }
            me.remove(node);
        }
    },
 
<span id='Ext-data-NodeStore-method-isVisible'>    isVisible: function(node) {
</span>        var parent = node.parentNode;
        while (parent) {
            // Hit root and it is expanded, the node is visible
            if (parent === this.node &amp;&amp; parent.data.expanded) {
                return true;
            }
 
            // Hit a collapsed ancestor, the node is not visible
            if (!parent.data.expanded) {
                return false;
            }
 
            parent = parent.parentNode;
        }
        // Walked off the top - the node is not part of the tree structure
        return false;
    }
});</pre>
</body>
</html>