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
<!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-view-NodeCache'>/**
</span> * @private
 * A cache of View elements keyed using the index of the associated record in the store.
 * 
 * This implements the methods of {Ext.dom.CompositeElement} which are used by {@link Ext.view.AbstractView}
 * to privide a map of record nodes and methods to manipulate the nodes.
 */
Ext.define('Ext.view.NodeCache', {
<span id='Ext-view-NodeCache-method-constructor'>    constructor: function(view) {
</span>        this.view = view;
        this.clear();
        this.el = new Ext.dom.AbstractElement.Fly();
    },
 
<span id='Ext-view-NodeCache-method-clear'>    /**
</span>    * Removes all elements from this NodeCache.
    * @param {Boolean} [removeDom] True to also remove the elements from the document.
    */
    clear: function(removeDom) {
        var me = this,
            elements = this.elements,
            i, el;
 
        if (removeDom) {
            for (i in elements) {
                el = elements[i];
                el.parentNode.removeChild(el);
            }
        }
        me.elements = {};
        me.count = me.startIndex = 0;
        me.endIndex = -1;
    },
 
<span id='Ext-view-NodeCache-method-fill'>    /**
</span>    * Clears this NodeCache and adds the elements passed.
    * @param {HTMLElement[]} els An array of DOM elements from which to fill this NodeCache.
    * @return {Ext.view.NodeCache} this
    */
    fill: function(newElements, startIndex) {
        var me = this,
            elements = me.elements = {},
            i,
            len = newElements.length;
 
        if (!startIndex) {
            startIndex = 0;
        }
        for (i = 0; i &lt; len; i++) {
            elements[startIndex + i] = newElements[i];
        }
        me.startIndex = startIndex;
        me.endIndex = startIndex + len - 1;
        me.count = len;
        return this;
    },
 
<span id='Ext-view-NodeCache-method-insert'>    insert: function(insertPoint, nodes) {
</span>        var me = this,
            elements = me.elements,
            i,
            nodeCount = nodes.length;
 
        // If not inserting into empty cache, validate, and possibly shuffle.
        if (me.count) {
            //&lt;debug&gt;
            if (insertPoint &gt; me.endIndex + 1 || insertPoint + nodes.length - 1 &lt; me.startIndex) {
                Ext.Error.raise('Discontiguous range would result from inserting ' + nodes.length + ' nodes at ' + insertPoint);
            }
            //&lt;/debug&gt;
 
            // Move following nodes forwards by &lt;nodeCount&gt; positions
            if (insertPoint &lt; me.count) {
                for (i = me.endIndex + nodeCount; i &gt;= insertPoint + nodeCount; i--) {
                    elements[i] = elements[i - nodeCount];
                    elements[i].setAttribute('data-recordIndex', i);
                }
            }
            me.endIndex = me.endIndex + nodeCount;
        }
        // Empty cache. set up counters
        else {
            me.startIndex = insertPoint;
            me.endIndex = insertPoint + nodeCount - 1;
        }
 
        // Insert new nodes into place
        for (i = 0; i &lt; nodeCount; i++, insertPoint++) {
            elements[insertPoint] = nodes[i];
            elements[insertPoint].setAttribute('data-recordIndex', insertPoint);
        }
        me.count += nodeCount;
    },
 
<span id='Ext-view-NodeCache-method-item'>    item: function(index, asDom) {
</span>        var el = this.elements[index],
            result = null;
 
        if (el) {
            result = asDom ? this.elements[index] : this.el.attach(this.elements[index]);
        }
        return result;
    },
 
<span id='Ext-view-NodeCache-method-first'>    first: function(asDom) {
</span>        return this.item(this.startIndex, asDom);
    },
 
<span id='Ext-view-NodeCache-method-last'>    last: function(asDom) {
</span>        return this.item(this.endIndex, asDom);
    },
 
<span id='Ext-view-NodeCache-method-getCount'>    getCount : function() {
</span>        return this.count;
    },
 
<span id='Ext-view-NodeCache-method-slice'>    slice: function(start, end) {
</span>        var elements = this.elements,
            result = [],
            i;
 
        if (arguments.length &lt; 2) {
            end = this.endIndex;
        } else {
            end = Math.min(this.endIndex, end - 1);
        }
        for (i = start||this.startIndex; i &lt;= end; i++) {
            result.push(elements[i]);
        }
        return result;
    },
 
<span id='Ext-view-NodeCache-method-replaceElement'>    /**
</span>    * Replaces the specified element with the passed element.
    * @param {String/HTMLElement/Ext.Element/Number} el The id of an element, the Element itself, the index of the
    * element in this composite to replace.
    * @param {String/Ext.Element} replacement The id of an element or the Element itself.
    * @param {Boolean} [domReplace] True to remove and replace the element in the document too.
    */
    replaceElement: function(el, replacement, domReplace) {
        var elements = this.elements,
            index = (typeof el === 'number') ? el : this.indexOf(el);
 
        if (index &gt; -1) {
            replacement = Ext.getDom(replacement);
            if (domReplace) {
                el = elements[index];
                el.parentNode.insertBefore(replacement, el);
                Ext.removeNode(el);
                replacement.setAttribute('data-recordIndex', index);
            }
            this.elements[index] = replacement;
        }
        return this;
    },
 
<span id='Ext-view-NodeCache-method-indexOf'>    /**
</span>    * Find the index of the passed element within the composite collection.
    * @param {String/HTMLElement/Ext.Element/Number} el The id of an element, or an Ext.dom.Element, or an HtmlElement
    * to find within the composite collection.
    * @return {Number} The index of the passed Ext.dom.Element in the composite collection, or -1 if not found.
    */
    indexOf: function(el) {
        var elements = this.elements,
            index;
 
        el = Ext.getDom(el);
        for (index = this.startIndex; index &lt;= this.endIndex; index++) {
            if (elements[index] === el) {
                return index;
            }
        }
        return -1;
    },
 
<span id='Ext-view-NodeCache-method-removeRange'>    removeRange: function(start, end, removeDom) {
</span>        var me = this,
            elements = me.elements,
            el,
            i, removeCount, fromPos;
 
        if (end === undefined) {
            end = me.count;
        } else {
            end = Math.min(me.endIndex + 1, end + 1);
        }
        if (!start) {
            start = 0;
        }
        removeCount = end - start;
        for (i = start, fromPos = end; i &lt; me.endIndex; i++, fromPos++) {
            // Within removal range and we are removing from DOM
            if (removeDom &amp;&amp; i &lt; end) {
                Ext.removeNode(elements[i]);
            }
            // If the from position is occupied, shuffle that entry back into reference &quot;i&quot;
            if (fromPos &lt;= me.endIndex) {
                el = elements[i] = elements[fromPos];
                el.setAttribute('data-recordIndex', i);
            }
            // The from position has walked off the end, so delete reference &quot;i&quot;
            else {
                delete elements[i];
            }
        }
        me.count -= removeCount;
        me.endIndex -= removeCount;
    },
 
<span id='Ext-view-NodeCache-method-removeElement'>    /**
</span>    * Removes the specified element(s).
    * @param {String/HTMLElement/Ext.Element/Number} el The id of an element, the Element itself, the index of the
    * element in this composite or an array of any of those.
    * @param {Boolean} [removeDom] True to also remove the element from the document
    */
    removeElement: function(keys, removeDom) {
        var me = this,
            inKeys,
            key,
            elements = me.elements,
            el,
            deleteCount,
            keyIndex = 0, index,
            fromIndex;
 
        // Sort the keys into ascending order so that we can iterate through the elements
        // collection, and delete items encountered in the keys array as we encounter them.
        if (Ext.isArray(keys)) {
            inKeys = keys;
            keys = [];
            deleteCount = inKeys.length;
            for (keyIndex = 0; keyIndex &lt; deleteCount; keyIndex++) {
                key = inKeys[keyIndex];
                if (typeof key !== 'number') {
                    key = me.indexOf(key);
                }
                // Could be asked to remove data above the start, or below the end of rendered zone in a buffer rendered view
                // So only collect keys which are within our range
                if (key &gt;= me.startIndex &amp;&amp; key &lt;= me.endIndex) {
                    keys[keys.length] = key;
                }
            }
            Ext.Array.sort(keys);
            deleteCount = keys.length;
        } else {
            // Could be asked to remove data above the start, or below the end of rendered zone in a buffer rendered view
            if (keys &lt; me.startIndex || keys &gt; me.endIndex) {
                return;
            }
            deleteCount = 1;
            keys = [keys];
        }
 
        // Iterate through elements starting at the element referenced by the first deletion key.
        // We also start off and index zero in the keys to delete array.
        for (index = fromIndex = keys[0], keyIndex = 0; index &lt;= me.endIndex; index++, fromIndex++) {
 
            // If the current index matches the next key in the delete keys array, this 
            // entry is being deleted, so increment the fromIndex to skip it.
            // Advance to next entry in keys array.
            if (keyIndex &lt; deleteCount &amp;&amp; index === keys[keyIndex]) {
                fromIndex++;
                keyIndex++;
                if (removeDom) {
                    Ext.removeNode(elements[index]);
                }
            }
 
            // Shuffle entries forward of the delete range back into contiguity.
            if (fromIndex &lt;= me.endIndex &amp;&amp; fromIndex &gt;= me.startIndex) {
                el = elements[index] = elements[fromIndex];
                el.setAttribute('data-recordIndex', index);
            } else {
                delete elements[index];
            }
        }
        me.endIndex -= deleteCount;
        me.count -= deleteCount;
    },
 
<span id='Ext-view-NodeCache-method-scroll'>    /**
</span>     * Appends/prepends records depending on direction flag
     * @param {Ext.data.Model[]} newRecords Items to append/prepend
     * @param {Number} direction `-1' = scroll up, `0` = scroll down.
     * @param {Number} removeCount The number of records to remove from the end. if scrolling
     * down, rows are removed from the top and the new rows are added at the bottom.
     */
    scroll: function(newRecords, direction, removeCount) {
        var me = this,
            elements = me.elements,
            recCount = newRecords.length,
            i, el, removeEnd,
            newNodes,
            nodeContainer = me.view.getNodeContainer(),
            frag = document.createDocumentFragment();
 
        // Scrolling up (content moved down - new content needed at top, remove from bottom)
        if (direction == -1) {
            for (i = (me.endIndex - removeCount) + 1; i &lt;= me.endIndex; i++) {
                el = elements[i];
                delete elements[i];
                el.parentNode.removeChild(el);
            }
            me.endIndex -= removeCount;
 
            // grab all nodes rendered, not just the data rows
            newNodes = me.view.bufferRender(newRecords, me.startIndex -= recCount);
            for (i = 0; i &lt; recCount; i++) {
                elements[me.startIndex + i] = newNodes[i];
                frag.appendChild(newNodes[i]);
            }
            nodeContainer.insertBefore(frag, nodeContainer.firstChild);
        }
 
        // Scrolling down (content moved up - new content needed at bottom, remove from top)
        else {
            removeEnd = me.startIndex + removeCount;
            for (i = me.startIndex; i &lt; removeEnd; i++) {
                el = elements[i];
                delete elements[i];
                el.parentNode.removeChild(el);
            }
            me.startIndex = i;
 
            // grab all nodes rendered, not just the data rows
            newNodes = me.view.bufferRender(newRecords, me.endIndex + 1);
            for (i = 0; i &lt; recCount; i++) {
                elements[me.endIndex += 1] = newNodes[i];
                frag.appendChild(newNodes[i]);
            }
            nodeContainer.appendChild(frag);
        }
        // Keep count consistent.
        me.count = me.endIndex - me.startIndex + 1;
    }
});</pre>
</body>
</html>