]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/test/specs/grid/plugin/BufferedRenderer.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / test / specs / grid / plugin / BufferedRenderer.js
CommitLineData
6527f429
DM
1describe('Ext.grid.plugin.BufferedRenderer', function () {\r
2 var store, grid, tree, view, plugin,\r
3 synchronousLoad = true,\r
4 proxyStoreLoad = Ext.data.ProxyStore.prototype.load,\r
5 loadStore,\r
6 treeStoreLoad = Ext.data.TreeStore.prototype.load,\r
7 loadTreeStore,\r
8 itIE10p = Ext.isIE9m ? xit : it;\r
9\r
10 function createData(total, variableRowHeight, asymmetricRowHeight) {\r
11 var data = [],\r
12 i, len, n;\r
13\r
14 for (i = 0, len = total || 100; i < len; i++) {\r
15 n = i + 1;\r
16\r
17 data.push({\r
18 field1: variableRowHeight ? ('<div style="height:' + Ext.Number.randomInt(20, 40)+ 'px">' + n + '</div>') : asymmetricRowHeight ? 40 : n,\r
19 field2: n,\r
20 field3: n,\r
21 field4: n,\r
22 field5: n\r
23 });\r
24 }\r
25\r
26 return data;\r
27 }\r
28\r
29 function makeData(n, start) {\r
30 start = start || 1;\r
31\r
32 var data = [],\r
33 limit = start + n,\r
34 i;\r
35\r
36 for (i = start; i < limit; ++i) {\r
37 data.push({\r
38 id: i,\r
39 name: 'name' + i\r
40 });\r
41 }\r
42 return data;\r
43 }\r
44\r
45 function getData(start, limit) {\r
46 var end = start + limit,\r
47 recs = [],\r
48 i;\r
49\r
50 for (i = start; i < end; ++i) {\r
51 recs.push({\r
52 id: i,\r
53 namee: 'name' + i\r
54 });\r
55 }\r
56 return recs;\r
57 }\r
58\r
59 function satisfyRequests(total) {\r
60 var requests = Ext.Ajax.mockGetAllRequests(),\r
61 empty = total === 0,\r
62 request, params, data;\r
63\r
64 while (requests.length) {\r
65 request = requests[0];\r
66\r
67 params = request.options.params;\r
68 data = getData(empty ? 0 : params.start, empty ? 0 : params.limit);\r
69\r
70 Ext.Ajax.mockComplete({\r
71 status: 200,\r
72 responseText: Ext.encode({\r
73 total: (total || empty) ? total : 5000,\r
74 data: data\r
75 })\r
76 });\r
77\r
78 requests = Ext.Ajax.mockGetAllRequests();\r
79 }\r
80 }\r
81\r
82 function makeGrid(gridCfg, storeCfg) {\r
83 if (!storeCfg || !storeCfg.store) {\r
84 store = new Ext.data.Store(Ext.apply({\r
85 fields: ['name', 'email', 'phone'],\r
86 groupField: 'name',\r
87 data: [\r
88 {'name': 'Lisa', 'email': 'lisa@simpsons.com', 'phone': '555-111-1224', 'age': 14},\r
89 {'name': 'Lisa', 'email': 'aunt_lisa@simpsons.com', 'phone': '555-111-1274', 'age': 34},\r
90 {'name': 'Bart', 'email': 'bart@simpsons.com', 'phone': '555-222-1234', 'age': 12},\r
91 {'name': 'Homer', 'email': 'homer@simpsons.com', 'phone': '555-222-1244', 'age': 44},\r
92 {'name': 'Marge', 'email': 'marge@simpsons.com', 'phone': '555-222-1254', 'age': 41}\r
93 ],\r
94 autoDestroy: true\r
95 }, storeCfg));\r
96 } else {\r
97 store = storeCfg.store;\r
98 }\r
99\r
100 grid = new Ext.grid.Panel(Ext.apply({\r
101 columns: [\r
102 {header: 'Name', dataIndex: 'name', editor: 'textfield'},\r
103 {header: 'Email', dataIndex: 'email', flex:1,\r
104 editor: {\r
105 xtype: 'textfield',\r
106 allowBlank: false\r
107 }\r
108 },\r
109 {header: 'Phone', dataIndex: 'phone', editor: 'textfield'},\r
110 {header: 'Age', dataIndex: 'age', editor: 'textfield'}\r
111 ],\r
112 store: store,\r
113 width: 200,\r
114 height: 400,\r
115 renderTo: Ext.getBody()\r
116 }, gridCfg));\r
117\r
118 view = grid.view;\r
119\r
120 // Extract the buffered renderer from a real TableView, the topmost one might be a Locking pseudo view\r
121 plugin = grid.down('tableview').bufferedRenderer;\r
122 }\r
123\r
124 function createTreeData(count) {\r
125 var i = 0,\r
126 j = 0,\r
127 children = [],\r
128 grandKids;\r
129\r
130 for (; i < count; i++) {\r
131 grandKids = [];\r
132\r
133 for (j = 1; j < 7; j++) {\r
134 grandKids.push({\r
135 treeData: 'Child of ' + i + ', number ' + j,\r
136 leaf: true\r
137 });\r
138 }\r
139\r
140 children.push({\r
141 treeData: i,\r
142 children: grandKids\r
143 });\r
144 }\r
145\r
146 return {\r
147 children: children\r
148 };\r
149 }\r
150\r
151 function makeTree(treeCfg, count) {\r
152 store = new Ext.data.TreeStore({\r
153 fields: ['treeData'],\r
154 root: createTreeData(count || 20)\r
155 });\r
156\r
157 tree = new Ext.tree.Panel(Ext.apply({\r
158 columns: [{\r
159 xtype: 'treecolumn',\r
160 text: 'Tree Column',\r
161 width: 300,\r
162 dataIndex: 'treeData'\r
163 }],\r
164 height: 800,\r
165 width: 500,\r
166 store: store,\r
167 rootVisible: false,\r
168 animate: false,\r
169 renderTo: Ext.getBody()\r
170 }, treeCfg || {}));\r
171\r
172 view = tree.view;\r
173 }\r
174\r
175 function completeWithData(data) {\r
176 Ext.Ajax.mockComplete({\r
177 status: 200,\r
178 responseText: Ext.JSON.encode(data)\r
179 });\r
180 }\r
181\r
182 beforeEach(function () {\r
183 // Override so that we can control asynchronous loading\r
184 loadStore = Ext.data.ProxyStore.prototype.load = function() {\r
185 proxyStoreLoad.apply(this, arguments);\r
186 if (synchronousLoad) {\r
187 this.flushLoad.apply(this, arguments);\r
188 }\r
189 return this;\r
190 };\r
191 loadTreeStore = Ext.data.TreeStore.prototype.load = function() {\r
192 treeStoreLoad.apply(this, arguments);\r
193 if (synchronousLoad) {\r
194 this.flushLoad.apply(this, arguments);\r
195 }\r
196 return this;\r
197 };\r
198\r
199 MockAjaxManager.addMethods();\r
200 });\r
201\r
202 afterEach(function () {\r
203 // Undo the overrides.\r
204 Ext.data.ProxyStore.prototype.load = proxyStoreLoad;\r
205 Ext.data.TreeStore.prototype.load = treeStoreLoad;\r
206\r
207 MockAjaxManager.removeMethods();\r
208\r
209 if (grid) {\r
210 Ext.destroy(grid);\r
211 }\r
212\r
213 if (tree) {\r
214 Ext.destroy(tree);\r
215 }\r
216\r
217 store = grid = tree = view = plugin = null;\r
218 });\r
219\r
220 describe('updateing scroller when changing width', function() {\r
221 it('should update the horizontal scroll range', function() {\r
222 makeGrid();\r
223 var scroller = view.getScrollable(),\r
224 maxX = scroller.getMaxPosition().x;\r
225\r
226 grid.setWidth(grid.getWidth() - 100);\r
227\r
228 // The scroll range should have increased\r
229 expect(scroller.getMaxPosition().x).toBe(maxX + 100);\r
230 });\r
231 });\r
232\r
233 describe('autogenerating the plugin', function () {\r
234 var BR = Ext.grid.plugin.BufferedRenderer;\r
235\r
236 it('should create an instance by default', function () {\r
237 makeGrid();\r
238\r
239 expect(plugin instanceof BR).toBe(true);\r
240 });\r
241\r
242 it('should not create an instance when turned off', function () {\r
243 makeGrid({\r
244 bufferedRenderer: false\r
245 });\r
246\r
247 expect(plugin instanceof BR).toBe(false);\r
248 expect(plugin).toBeUndefined();\r
249 });\r
250\r
251 describe('locking grids', function () {\r
252 var normal, locked;\r
253\r
254 afterEach(function () {\r
255 normal = locked = null;\r
256 });\r
257\r
258 describe('init', function () {\r
259 function runTests(useBR) {\r
260 var not = useBR ? 'not' : '';\r
261\r
262 describe('buffered rendering = ' + useBR, function () {\r
263 beforeEach(function () {\r
264 makeGrid({\r
265 bufferedRenderer: useBR,\r
266 columns: [\r
267 {header: 'Name', dataIndex: 'name', editor: 'textfield'},\r
268 {header: 'Phone', dataIndex: 'phone', editor: 'textfield', locked: true},\r
269 {header: 'Age', dataIndex: 'age', editor: 'textfield'}\r
270 ]\r
271 });\r
272\r
273 normal = grid.normalGrid.bufferedRenderer;\r
274 locked = grid.lockedGrid.bufferedRenderer;\r
275 });\r
276\r
277 it('should ' + not + ' create an instance on the ownerGrid for locking grids', function () {\r
278 plugin = grid.bufferedRenderer;\r
279 expect(plugin instanceof BR).toBe(false);\r
280 });\r
281\r
282 it('should ' + not + ' create an instance by default on each child grid for locking grids', function () {\r
283 expect(normal instanceof BR).toBe(useBR);\r
284 expect(locked instanceof BR).toBe(useBR);\r
285 });\r
286 });\r
287 }\r
288\r
289 runTests(true);\r
290 runTests(false);\r
291 });\r
292\r
293 describe('syncing locking partners when scrolling', function () {\r
294 beforeEach(function () {\r
295 makeGrid({\r
296 columns: [\r
297 {header: 'Name', dataIndex: 'name', editor: 'textfield', locked: true},\r
298 {header: 'Email', dataIndex: 'email', flex:1,\r
299 editor: {\r
300 xtype: 'textfield',\r
301 allowBlank: false\r
302 }\r
303 },\r
304 {header: 'Phone', dataIndex: 'phone', editor: 'textfield'},\r
305 {header: 'Age', dataIndex: 'age', editor: 'textfield'}\r
306 ]\r
307 }, {\r
308 data: makeData(1000)\r
309 });\r
310\r
311 normal = grid.normalGrid.bufferedRenderer;\r
312 locked = grid.lockedGrid.bufferedRenderer;\r
313 });\r
314\r
315 it('should fetch the range', function () {\r
316 spyOn(normal, 'onRangeFetched').andCallThrough();\r
317 spyOn(locked, 'onRangeFetched').andCallThrough();\r
318\r
319 normal.scrollTo(500);\r
320\r
321 expect(normal.onRangeFetched).toHaveBeenCalled();\r
322 expect(locked.onRangeFetched).toHaveBeenCalled();\r
323 });\r
324\r
325 it('should sync the view els', function () {\r
326 normal.scrollTo(500);\r
327\r
328 expect(normal.bodyTop).toBe(locked.bodyTop);\r
329 });\r
330 });\r
331\r
332 describe('Load requests during scrolling', function () {\r
333 var scrollToLoadBufferValue,\r
334 scrollTimer,\r
335 Person = Ext.define(null, {\r
336 extend: 'Ext.data.Model',\r
337 fields: ['name'],\r
338 proxy: {\r
339 type: 'ajax',\r
340 url: '/foo',\r
341 reader: {\r
342 rootProperty: 'data'\r
343 }\r
344 }\r
345 });\r
346\r
347 function scrollTheGrid() {\r
348 // Scroll incrementally until the correct starting point is found\r
349 if (view && !view.destroyed) {\r
350 view.scrollBy(null, 100);\r
351 }\r
352 scrollTimer = 0;\r
353 }\r
354\r
355 beforeEach(function () {\r
356 scrollToLoadBufferValue = Ext.grid.plugin.BufferedRenderer.prototype.scrollToLoadBuffer;\r
357\r
358 // Make the timeout from attemptLoad call to the doAttemptLoad ten seconds\r
359 // The doAttemptLoad DelayedTask should not fire between scroll events which take place\r
360 // every 50 milliseconds\r
361 Ext.grid.plugin.BufferedRenderer.prototype.scrollToLoadBuffer = 10000;\r
362 makeGrid({\r
363 columns: [\r
364 {header: 'Name', dataIndex: 'name', editor: 'textfield'},\r
365 {header: 'Phone', dataIndex: 'phone', editor: 'textfield', locked: true},\r
366 {header: 'Age', dataIndex: 'age', editor: 'textfield'}\r
367 ]\r
368 }, {\r
369 store: new Ext.data.BufferedStore({\r
370 model: Person,\r
371 leadingBufferZone: 300,\r
372 pageSize: 100\r
373 })\r
374 });\r
375\r
376 // Tell the BufferedRenderer that there are 1000 rows.\r
377 // We plan not to satisfy any requests from now on so that\r
378 // on scroll, an attemptLoad call will be made.\r
379 // the timeout to doAttemptLoad should not expire during the scroll operation\r
380 store.load();\r
381 completeWithData({\r
382 total: 1000,\r
383 data: makeData(100)\r
384 });\r
385 completeWithData({\r
386 total: 1000,\r
387 data: makeData(100, 101)\r
388 });\r
389 completeWithData({\r
390 total: 1000,\r
391 data: makeData(100, 201)\r
392 });\r
393 completeWithData({\r
394 total: 1000,\r
395 data: makeData(100, 301)\r
396 });\r
397 });\r
398 afterEach(function() {\r
399 Ext.grid.plugin.BufferedRenderer.prototype.scrollToLoadBuffer = scrollToLoadBufferValue;\r
400 });\r
401 it('should not have time between scroll events to fire off any requests', function() {\r
402 spyOn(plugin, 'doAttemptLoad');\r
403 \r
404 // Scroll to close enough to the end in a slow manner, 50ms between each scroll.\r
405 // The doAttemptLoad timer should not timeout and fire off a page request between each scroll.\r
406 waitsFor(function() {\r
407 if (plugin.getLastVisibleRowIndex() <= 995) {\r
408 if (!scrollTimer) {\r
409 scrollTimer = setTimeout(scrollTheGrid, 50);\r
410 }\r
411 } else {\r
412 return true;\r
413 }\r
414 }, 'grid to scroll to end', Ext.isIE ? 40000 : 20000);\r
415\r
416 // The atteptLoad timer must never have fired during the scroll.\r
417 runs(function() {\r
418 expect(plugin.doAttemptLoad.callCount).toBe(0);\r
419 });\r
420 });\r
421 });\r
422 });\r
423 });\r
424\r
425 describe("Less data than the computed view size", function() {\r
426 it("should add new rows at top while scrolled to bottom", function() {\r
427 var Person = Ext.define(null, {\r
428 extend: 'Ext.data.Model',\r
429 fields: ['name'],\r
430 proxy: {\r
431 type: 'ajax',\r
432 url: '/foo',\r
433 reader: {\r
434 rootProperty: 'data'\r
435 }\r
436 }\r
437 });\r
438\r
439 store = new Ext.data.Store({\r
440 model: Person,\r
441 data: makeData(12)\r
442 });\r
443\r
444 grid = new Ext.grid.Panel({\r
445 width: 600,\r
446 height: 305,\r
447 store: store,\r
448 deferRowRender: false,\r
449 columns: [{\r
450 dataIndex: 'id',\r
451 renderer: function(v) {\r
452 return '<span style="line-height:25px">' + v + '</span>';\r
453 },\r
454 producesHTML: true\r
455 }, {\r
456 dataIndex: 'name'\r
457 }],\r
458 renderTo: Ext.getBody()\r
459 });\r
460 view = grid.getView();\r
461\r
462 // Wait until known correct condition is met.\r
463 // Timeout === test failure.\r
464 waitsFor(function() {\r
465 if (view.all.endIndex === store.getCount() - 1) {\r
466 return true;\r
467 }\r
468 else {\r
469 // Scroll incrementally until the correct starting point is found\r
470 view.scrollBy(null, 10);\r
471 }\r
472 }, 'view is scrolled to the last record');\r
473\r
474 runs(function() {\r
475 store.insert(0, {id: 666, name: 'Old Nick'});\r
476 view.scrollTo(0, 0);\r
477 \r
478 var r0 = view.all.item(0, true);\r
479\r
480 // Must have been rendered\r
481 expect(r0).not.toBeNull();\r
482\r
483 // The new row zero must have been rendered.\r
484 expect((r0.innerText || r0.textContent).replace(/\n/g,'').replace(/\r/g,'')).toBe("666Old Nick");\r
485 });\r
486 });\r
487 });\r
488\r
489 describe("basic functionality with a buffered store", function() {\r
490 it("should render rows in order", function() {\r
491 var Person = Ext.define(null, {\r
492 extend: 'Ext.data.Model',\r
493 fields: ['name'],\r
494 proxy: {\r
495 type: 'ajax',\r
496 url: '/foo',\r
497 reader: {\r
498 rootProperty: 'data'\r
499 }\r
500 }\r
501 });\r
502\r
503 store = new Ext.data.BufferedStore({\r
504 model: Person,\r
505 leadingBufferZone: 300,\r
506 pageSize: 100\r
507 });\r
508\r
509 grid = new Ext.grid.Panel({\r
510 width: 800,\r
511 height: 500,\r
512 store: store,\r
513 deferRowRender: false,\r
514 columns: [{\r
515 dataIndex: 'id'\r
516 }, {\r
517 dataIndex: 'name'\r
518 }],\r
519 renderTo: Ext.getBody()\r
520 });\r
521 store.load();\r
522 completeWithData({\r
523 total: 5000,\r
524 data: makeData(100)\r
525 });\r
526 completeWithData({\r
527 total: 5000,\r
528 data: makeData(100, 101)\r
529 });\r
530 completeWithData({\r
531 total: 5000,\r
532 data: makeData(100, 201)\r
533 });\r
534 completeWithData({\r
535 total: 5000,\r
536 data: makeData(100, 301)\r
537 });\r
538 var view = grid.getView(),\r
539 rows = view.all;\r
540\r
541 // Wait until known correct condition is met.\r
542 // Timeout === test failure.\r
543 waitsFor(function() {\r
544 if (rows.startIndex <= 100 && rows.endIndex >= 100) {\r
545 return true;\r
546 }\r
547 else {\r
548 // Scroll incrementally until the correct starting point is found\r
549 view.scrollBy(null, 10);\r
550 }\r
551 }, 'View to scroll record id 100 into the rendered block', 20000);\r
552\r
553 runs(function() {\r
554 var nodes = view.getNodes(),\r
555 len = nodes.length,\r
556 offset = rows.startIndex + 1,\r
557 i, rec;\r
558\r
559 expect(len).toBe(view.bufferedRenderer.viewSize);\r
560 for (i = 0; i < len; ++i) {\r
561 rec = view.getRecord(nodes[i]);\r
562 expect(rec.getId()).toBe(i + offset);\r
563 }\r
564\r
565 });\r
566 });\r
567\r
568 // EXTJS-16140\r
569 it("should scroll to the bottom of a locking grid with no error", function() {\r
570 var Person = Ext.define(null, {\r
571 extend: 'Ext.data.Model',\r
572 fields: ['name'],\r
573 proxy: {\r
574 type: 'ajax',\r
575 url: '/foo',\r
576 reader: {\r
577 rootProperty: 'data'\r
578 }\r
579 }\r
580 }),\r
581 lockedView,\r
582 normalView,\r
583 maxScroll;\r
584\r
585 store = new Ext.data.BufferedStore({\r
586 model: Person,\r
587 leadingBufferZone: 300,\r
588 pageSize: 100\r
589 });\r
590\r
591 grid = new Ext.grid.Panel({\r
592 width: 800,\r
593 height: 500,\r
594 store: store,\r
595 deferRowRender: false,\r
596 columns: [{\r
597 dataIndex: 'id',\r
598 locked: true\r
599 }, {\r
600 dataIndex: 'name'\r
601 }],\r
602 renderTo: Ext.getBody()\r
603 });\r
604 lockedView = grid.lockedGrid.view;\r
605 normalView = grid.normalGrid.view;\r
606\r
607 // Make the buffered renderers respond IMMEDIATELY to the scroll event, so that\r
608 // the waits(100) will be enough to wait for the newly scrolled-to region to be rendered.\r
609 lockedView.bufferedRenderer.scrollToLoadBuffer = normalView.bufferedRenderer.scrollToLoadBuffer = 0;\r
610\r
611 store.load();\r
612 completeWithData({\r
613 total: 5000,\r
614 data: makeData(100)\r
615 });\r
616\r
617 maxScroll = normalView.getScrollable().getMaxPosition().y;\r
618 normalView.setScrollY(maxScroll);\r
619\r
620 // Important: Simulate Ajax delay before returning data\r
621 waits(100);\r
622 runs(function() {\r
623 satisfyRequests();\r
624 });\r
625 \r
626 // Both views must render up to the last row with no error thrown\r
627 waitsFor(function() {\r
628 return lockedView.all.endIndex === 4999 && normalView.all.endIndex === 4999;\r
629 });\r
630 });\r
631\r
632 // EXTJS-17053\r
633 it('should maintain synchronization when scrolling locked, variable row height grid with keyboard', function() {\r
634 store = Ext.create('Ext.data.Store', {\r
635 idProperty: 'index',\r
636 fields: ['index', 'name', 'email', 'phone', 'isActive', 'eyeColor', 'company', 'gender'],\r
637 autoLoad: true,\r
638 data: [{\r
639 "_id": "54ff69d95aa43325cc4eee9f",\r
640 "index": 0,\r
641 "guid": "48c42a75-09a7-4671-86a1-e9a486bee6ab",\r
642 "isActive": true,\r
643 "balance": "$3,457.90",\r
644 "age": 20,\r
645 "eyeColor": "brown",\r
646 "name": "Louella Morrison",\r
647 "gender": "female",\r
648 "company": "ZBOO",\r
649 "email": "louellamorrison@zboo.com",\r
650 "phone": "+1 (803) 483-2686"\r
651 }, {\r
652 "_id": "54ff69d918616dbc093ca6cd",\r
653 "index": 1,\r
654 "guid": "17b3f923-96b5-40c9-b3c1-721485e5bf80",\r
655 "isActive": true,\r
656 "balance": "$1,377.85",\r
657 "age": 20,\r
658 "eyeColor": "brown",\r
659 "name": "Madden Coffey",\r
660 "gender": "male",\r
661 "company": "COMDOM",\r
662 "email": "maddencoffey@comdom.com",\r
663 "phone": "+1 (850) 534-2345"\r
664 }, {\r
665 "_id": "54ff69d91a4917f9643178b0",\r
666 "index": 2,\r
667 "guid": "f62da049-ab17-49fd-9f4c-3439d33cbb93",\r
668 "isActive": false,\r
669 "balance": "$3,798.71",\r
670 "age": 22,\r
671 "eyeColor": "blue",\r
672 "name": "Chase Crawford",\r
673 "gender": "male",\r
674 "company": "PYRAMAX",\r
675 "email": "chasecrawford@pyramax.com",\r
676 "phone": "+1 (944) 494-2920"\r
677 }, {\r
678 "_id": "54ff69d9a63b6103f9e1530f",\r
679 "index": 3,\r
680 "guid": "3640c402-f878-4f97-bbda-564de91d2dde",\r
681 "isActive": true,\r
682 "balance": "$2,480.02",\r
683 "age": 39,\r
684 "eyeColor": "blue",\r
685 "name": "Johanna Pollard",\r
686 "gender": "female",\r
687 "company": "ZEROLOGY",\r
688 "email": "johannapollard@zerology.com",\r
689 "phone": "+1 (813) 512-3311"\r
690 }, {\r
691 "_id": "54ff69d9048722389ffde4bb",\r
692 "index": 4,\r
693 "guid": "361089ba-e6dc-4701-b316-c7e977b21cb2",\r
694 "isActive": true,\r
695 "balance": "$3,973.38",\r
696 "age": 20,\r
697 "eyeColor": "brown",\r
698 "name": "Malone Bentley",\r
699 "gender": "male",\r
700 "company": "DIGIPRINT",\r
701 "email": "malonebentley@digiprint.com",\r
702 "phone": "+1 (905) 435-2056"\r
703 }, {\r
704 "_id": "54ff69d9f75a66fb8e08b335",\r
705 "index": 5,\r
706 "guid": "4cec529a-232a-4d5f-bedc-6141adc9f2fa",\r
707 "isActive": true,\r
708 "balance": "$3,956.60",\r
709 "age": 21,\r
710 "eyeColor": "green",\r
711 "name": "Jennings Rodgers",\r
712 "gender": "male",\r
713 "company": "LUDAK",\r
714 "email": "jenningsrodgers@ludak.com",\r
715 "phone": "+1 (833) 543-2230"\r
716 }, {\r
717 "_id": "54ff69d974c1757e026721cb",\r
718 "index": 6,\r
719 "guid": "6ce0c1e1-adc6-4cd0-b9c9-e2214e63aa8f",\r
720 "isActive": true,\r
721 "balance": "$2,874.71",\r
722 "age": 40,\r
723 "eyeColor": "green",\r
724 "name": "Mosley Mcgowan",\r
725 "gender": "male",\r
726 "company": "AMTAP",\r
727 "email": "mosleymcgowan@amtap.com",\r
728 "phone": "+1 (990) 486-3229"\r
729 }, {\r
730 "_id": "54ff69d949a3873336e2e446",\r
731 "index": 7,\r
732 "guid": "0f88d544-4aa0-4a05-a236-363c64b40988",\r
733 "isActive": false,\r
734 "balance": "$3,277.11",\r
735 "age": 28,\r
736 "eyeColor": "green",\r
737 "name": "Patton Whitaker",\r
738 "gender": "male",\r
739 "company": "IMMUNICS",\r
740 "email": "pattonwhitaker@immunics.com",\r
741 "phone": "+1 (944) 557-2615"\r
742 }, {\r
743 "_id": "54ff69d917f9642ab989e999",\r
744 "index": 8,\r
745 "guid": "6577bb0c-f7ed-495f-a3db-7f7d35f6fe49",\r
746 "isActive": false,\r
747 "balance": "$1,091.47",\r
748 "age": 35,\r
749 "eyeColor": "green",\r
750 "name": "Neal Rivera",\r
751 "gender": "male",\r
752 "company": "NETILITY",\r
753 "email": "nealrivera@netility.com",\r
754 "phone": "+1 (816) 590-2358"\r
755 }, {\r
756 "_id": "54ff69d94573c1c04f0a9940",\r
757 "index": 9,\r
758 "guid": "29be9274-d3cb-461f-a565-2374768689df",\r
759 "isActive": false,\r
760 "balance": "$1,885.75",\r
761 "age": 25,\r
762 "eyeColor": "brown",\r
763 "name": "May Barron",\r
764 "gender": "male",\r
765 "company": "TELEPARK",\r
766 "email": "maybarron@telepark.com",\r
767 "phone": "+1 (958) 486-2915"\r
768 }, {\r
769 "_id": "54ff69d9c0e2f4aee9180984",\r
770 "index": 10,\r
771 "guid": "479320d7-70ef-4f55-99b9-f3ef3a76b72e",\r
772 "isActive": false,\r
773 "balance": "$2,031.57",\r
774 "age": 36,\r
775 "eyeColor": "brown",\r
776 "name": "Janna Howell",\r
777 "gender": "female",\r
778 "company": "PYRAMIS",\r
779 "email": "jannahowell@pyramis.com",\r
780 "phone": "+1 (823) 423-2342"\r
781 }, {\r
782 "_id": "54ff69d96e7f08b674de7cb9",\r
783 "index": 11,\r
784 "guid": "9f6df0e4-b92c-4272-ad75-981305e9bb09",\r
785 "isActive": true,\r
786 "balance": "$2,279.79",\r
787 "age": 33,\r
788 "eyeColor": "green",\r
789 "name": "Nieves Short",\r
790 "gender": "male",\r
791 "company": "PETICULAR",\r
792 "email": "nievesshort@peticular.com",\r
793 "phone": "+1 (904) 556-3401"\r
794 }, {\r
795 "_id": "54ff69d9fb987df7ecf3d8ab",\r
796 "index": 12,\r
797 "guid": "32c80cfd-d880-48a6-a3b0-e687c1e52b30",\r
798 "isActive": false,\r
799 "balance": "$3,830.03",\r
800 "age": 26,\r
801 "eyeColor": "green",\r
802 "name": "Tania Gillespie",\r
803 "gender": "female",\r
804 "company": "AUSTEX",\r
805 "email": "taniagillespie@austex.com",\r
806 "phone": "+1 (969) 527-3521"\r
807 }, {\r
808 "_id": "54ff69d9f586c6e7e9a08b4b",\r
809 "index": 13,\r
810 "guid": "e6a006c4-1d5e-4a09-9dd6-496426fc4982",\r
811 "isActive": false,\r
812 "balance": "$3,411.76",\r
813 "age": 32,\r
814 "eyeColor": "blue",\r
815 "name": "Joyner Suarez",\r
816 "gender": "male",\r
817 "company": "GEOFARM",\r
818 "email": "joynersuarez@geofarm.com",\r
819 "phone": "+1 (879) 571-3671"\r
820 }, {\r
821 "_id": "54ff69d94eaa44d993966048",\r
822 "index": 14,\r
823 "guid": "00927bfa-dfd7-4850-bfd7-a2c25c476327",\r
824 "isActive": true,\r
825 "balance": "$2,402.44",\r
826 "age": 35,\r
827 "eyeColor": "brown",\r
828 "name": "Hull Cooley",\r
829 "gender": "male",\r
830 "company": "ENERVATE",\r
831 "email": "hullcooley@enervate.com",\r
832 "phone": "+1 (910) 476-3577"\r
833 }, {\r
834 "_id": "54ff69d9b341bfef697e75ac",\r
835 "index": 15,\r
836 "guid": "cd6a241c-35a4-4038-ae01-d32640719dc7",\r
837 "isActive": false,\r
838 "balance": "$2,889.76",\r
839 "age": 28,\r
840 "eyeColor": "green",\r
841 "name": "Cortez Fleming",\r
842 "gender": "male",\r
843 "company": "CIPROMOX",\r
844 "email": "cortezfleming@cipromox.com",\r
845 "phone": "+1 (964) 460-3159"\r
846 }, {\r
847 "_id": "54ff69d9a1f835d92cb8a017",\r
848 "index": 16,\r
849 "guid": "45ad04ed-c154-4f16-a60b-d091e2ab8c13",\r
850 "isActive": true,\r
851 "balance": "$1,994.50",\r
852 "age": 21,\r
853 "eyeColor": "green",\r
854 "name": "Hazel Rodriguez",\r
855 "gender": "female",\r
856 "company": "SILODYNE",\r
857 "email": "hazelrodriguez@silodyne.com",\r
858 "phone": "+1 (962) 492-3107"\r
859 }, {\r
860 "_id": "54ff69d93989153e00dc5f02",\r
861 "index": 17,\r
862 "guid": "b2a702d1-b47e-4f2b-98f2-4ab2e70b126f",\r
863 "isActive": true,\r
864 "balance": "$2,826.88",\r
865 "age": 30,\r
866 "eyeColor": "green",\r
867 "name": "Keri Pearson",\r
868 "gender": "female",\r
869 "company": "CENTICE",\r
870 "email": "keripearson@centice.com",\r
871 "phone": "+1 (858) 417-3541"\r
872 }, {\r
873 "_id": "54ff69d9377beb85134e2761",\r
874 "index": 18,\r
875 "guid": "9bbb9bd7-d517-4bbb-a9b6-76f4fab0e5ab",\r
876 "isActive": false,\r
877 "balance": "$1,119.17",\r
878 "age": 24,\r
879 "eyeColor": "brown",\r
880 "name": "Daisy Mcconnell",\r
881 "gender": "female",\r
882 "company": "MONDICIL",\r
883 "email": "daisymcconnell@mondicil.com",\r
884 "phone": "+1 (836) 470-3995"\r
885 }, {\r
886 "_id": "54ff69d999e3637d8287287f",\r
887 "index": 19,\r
888 "guid": "c2dbece0-7554-4666-9378-805a625789db",\r
889 "isActive": false,\r
890 "balance": "$3,855.83",\r
891 "age": 30,\r
892 "eyeColor": "blue",\r
893 "name": "Michelle Espinoza",\r
894 "gender": "female",\r
895 "company": "STEELFAB",\r
896 "email": "michelleespinoza@steelfab.com",\r
897 "phone": "+1 (882) 508-2376"\r
898 }, {\r
899 "_id": "54ff69d93826cfb24af88797",\r
900 "index": 20,\r
901 "guid": "20be5f38-dc45-4a2f-8889-e9ba5ade8bed",\r
902 "isActive": false,\r
903 "balance": "$1,366.06",\r
904 "age": 39,\r
905 "eyeColor": "blue",\r
906 "name": "Wall Sears",\r
907 "gender": "male",\r
908 "company": "PLAYCE",\r
909 "email": "wallsears@playce.com",\r
910 "phone": "+1 (846) 505-3782"\r
911 }, {\r
912 "_id": "54ff69d97f6a23afdd06849c",\r
913 "index": 21,\r
914 "guid": "66fc61ba-38ef-4d49-862d-eb7d5fa68245",\r
915 "isActive": false,\r
916 "balance": "$2,379.73",\r
917 "age": 20,\r
918 "eyeColor": "green",\r
919 "name": "Caldwell Cain",\r
920 "gender": "male",\r
921 "company": "ORBIXTAR",\r
922 "email": "caldwellcain@orbixtar.com",\r
923 "phone": "+1 (831) 456-3297"\r
924 }, {\r
925 "_id": "54ff69d970154f7ac17b1438",\r
926 "index": 22,\r
927 "guid": "85b6d275-3bff-4475-8c42-0c4f8ec2d385",\r
928 "isActive": true,\r
929 "balance": "$2,572.21",\r
930 "age": 20,\r
931 "eyeColor": "green",\r
932 "name": "Viola Mckay",\r
933 "gender": "female",\r
934 "company": "SPRINGBEE",\r
935 "email": "violamckay@springbee.com",\r
936 "phone": "+1 (901) 412-3479"\r
937 }, {\r
938 "_id": "54ff69d98ac67b26bce2d4a8",\r
939 "index": 23,\r
940 "guid": "1d7460af-09a7-479a-8476-c3187a85ba8d",\r
941 "isActive": false,\r
942 "balance": "$2,467.39",\r
943 "age": 40,\r
944 "eyeColor": "blue",\r
945 "name": "Gutierrez Conway",\r
946 "gender": "male",\r
947 "company": "ULTRASURE",\r
948 "email": "gutierrezconway@ultrasure.com",\r
949 "phone": "+1 (939) 438-3340"\r
950 }, {\r
951 "_id": "54ff69d93a9b81bdb7af6473",\r
952 "index": 24,\r
953 "guid": "2da97cff-a16c-47a2-b9b0-d05d7ce8655d",\r
954 "isActive": false,\r
955 "balance": "$2,496.66",\r
956 "age": 20,\r
957 "eyeColor": "brown",\r
958 "name": "Chandler Schmidt",\r
959 "gender": "male",\r
960 "company": "ZANITY",\r
961 "email": "chandlerschmidt@zanity.com",\r
962 "phone": "+1 (822) 461-2247"\r
963 }, {\r
964 "_id": "54ff69d99e5b0a9b8db8da2b",\r
965 "index": 26,\r
966 "guid": "b8081e85-d0a9-4575-9fdd-83baa0cfe79b",\r
967 "isActive": false,\r
968 "balance": "$3,044.12",\r
969 "age": 21,\r
970 "eyeColor": "brown",\r
971 "name": "Bradshaw Ware",\r
972 "gender": "male",\r
973 "company": "BEDDER",\r
974 "email": "bradshawware@bedder.com",\r
975 "phone": "+1 (932) 496-3718"\r
976 }, {\r
977 "_id": "54ff69d9a9827e6a14480e37",\r
978 "index": 27,\r
979 "guid": "f0d49a25-fa17-4319-9f6a-9e88bb974755",\r
980 "isActive": true,\r
981 "balance": "$1,799.46",\r
982 "age": 38,\r
983 "eyeColor": "green",\r
984 "name": "Krystal Bush",\r
985 "gender": "female",\r
986 "company": "ZOLAREX",\r
987 "email": "krystalbush@zolarex.com",\r
988 "phone": "+1 (928) 577-3693"\r
989 }, {\r
990 "_id": "54ff69d97e57e2cab6272464",\r
991 "index": 28,\r
992 "guid": "40860305-ba5a-44ec-9783-21d4a1a4927b",\r
993 "isActive": true,\r
994 "balance": "$1,856.24",\r
995 "age": 20,\r
996 "eyeColor": "green",\r
997 "name": "Madeline Grant",\r
998 "gender": "female",\r
999 "company": "APEXIA",\r
1000 "email": "madelinegrant@apexia.com",\r
1001 "phone": "+1 (895) 521-2877"\r
1002 }, {\r
1003 "_id": "54ff69d9431984c9fdb6f25a",\r
1004 "index": 29,\r
1005 "guid": "36d78b3f-a9dd-4180-bb66-c12a1147e92d",\r
1006 "isActive": true,\r
1007 "balance": "$3,971.70",\r
1008 "age": 40,\r
1009 "eyeColor": "brown",\r
1010 "name": "Flora Ortiz",\r
1011 "gender": "female",\r
1012 "company": "ACCUSAGE",\r
1013 "email": "floraortiz@accusage.com",\r
1014 "phone": "+1 (992) 561-2107"\r
1015 }, {\r
1016 "_id": "54ff69d9c7c52140a4572361",\r
1017 "index": 30,\r
1018 "guid": "ba91387f-cab7-4487-a650-1bd94a650306",\r
1019 "isActive": false,\r
1020 "balance": "$1,408.31",\r
1021 "age": 37,\r
1022 "eyeColor": "brown",\r
1023 "name": "Bobbie Atkins",\r
1024 "gender": "female",\r
1025 "company": "GRAINSPOT",\r
1026 "email": "bobbieatkins@grainspot.com",\r
1027 "phone": "+1 (840) 497-2564"\r
1028 }, {\r
1029 "_id": "54ff69d982ac77cad23cb28d",\r
1030 "index": 31,\r
1031 "guid": "7068b1b5-cb81-4127-b252-ccc3ff8d3b5a",\r
1032 "isActive": true,\r
1033 "balance": "$3,375.36",\r
1034 "age": 39,\r
1035 "eyeColor": "brown",\r
1036 "name": "Mayer Osborne",\r
1037 "gender": "male",\r
1038 "company": "DEEPENDS",\r
1039 "email": "mayerosborne@deepends.com",\r
1040 "phone": "+1 (952) 498-3050"\r
1041 }, {\r
1042 "_id": "54ff69d99aefdc9cdd70a0df",\r
1043 "index": 32,\r
1044 "guid": "087771d5-4f39-46aa-bad7-7a051e807770",\r
1045 "isActive": true,\r
1046 "balance": "$3,345.55",\r
1047 "age": 38,\r
1048 "eyeColor": "blue",\r
1049 "name": "Sullivan Gibson",\r
1050 "gender": "male",\r
1051 "company": "AQUASURE",\r
1052 "email": "sullivangibson@aquasure.com",\r
1053 "phone": "+1 (833) 463-3464"\r
1054 }, {\r
1055 "_id": "54ff69d970a46678753362fc",\r
1056 "index": 33,\r
1057 "guid": "23e28ddc-a102-4f7c-b53b-4e3b8e45c64e",\r
1058 "isActive": false,\r
1059 "balance": "$2,521.22",\r
1060 "age": 28,\r
1061 "eyeColor": "green",\r
1062 "name": "Nikki Whitley",\r
1063 "gender": "female",\r
1064 "company": "FUTURIS",\r
1065 "email": "nikkiwhitley@futuris.com",\r
1066 "phone": "+1 (883) 561-2974"\r
1067 }, {\r
1068 "_id": "54ff69d9f7ca2fa585ecbac6",\r
1069 "index": 34,\r
1070 "guid": "b711bd69-e672-48f5-8138-d3120bbedb40",\r
1071 "isActive": true,\r
1072 "balance": "$2,388.02",\r
1073 "age": 21,\r
1074 "eyeColor": "green",\r
1075 "name": "Juana Doyle",\r
1076 "gender": "female",\r
1077 "company": "HOUSEDOWN",\r
1078 "email": "juanadoyle@housedown.com",\r
1079 "phone": "+1 (847) 428-3271"\r
1080 }, {\r
1081 "_id": "54ff69d9295e29d7b81a31be",\r
1082 "index": 35,\r
1083 "guid": "d393a87f-0789-4762-8ab8-d0fb66fc0fcb",\r
1084 "isActive": true,\r
1085 "balance": "$1,126.53",\r
1086 "age": 32,\r
1087 "eyeColor": "green",\r
1088 "name": "Marci Shaffer",\r
1089 "gender": "female",\r
1090 "company": "TRASOLA",\r
1091 "email": "marcishaffer@trasola.com",\r
1092 "phone": "+1 (929) 502-2533"\r
1093 }, {\r
1094 "_id": "54ff69d9d8f81e674722a7d5",\r
1095 "index": 36,\r
1096 "guid": "281bbeea-5bef-4c37-8e2a-22481c9616c3",\r
1097 "isActive": false,\r
1098 "balance": "$2,616.22",\r
1099 "age": 26,\r
1100 "eyeColor": "green",\r
1101 "name": "Maynard Watts",\r
1102 "gender": "male",\r
1103 "company": "AEORA",\r
1104 "email": "maynardwatts@aeora.com",\r
1105 "phone": "+1 (896) 418-3281"\r
1106 }, {\r
1107 "_id": "54ff69d98f504a9e6c63dedb",\r
1108 "index": 37,\r
1109 "guid": "48698e76-8996-40d2-9abe-3fdd8fe98cf7",\r
1110 "isActive": true,\r
1111 "balance": "$3,441.08",\r
1112 "age": 21,\r
1113 "eyeColor": "brown",\r
1114 "name": "Ollie Mooney",\r
1115 "gender": "female",\r
1116 "company": "ACCUPRINT",\r
1117 "email": "olliemooney@accuprint.com",\r
1118 "phone": "+1 (811) 512-3357"\r
1119 }, {\r
1120 "_id": "54ff69d9fc55f5cd34359bf9",\r
1121 "index": 38,\r
1122 "guid": "495c9d9e-95d8-48a2-83b4-c0f314f7aa26",\r
1123 "isActive": true,\r
1124 "balance": "$1,134.21",\r
1125 "age": 30,\r
1126 "eyeColor": "green",\r
1127 "name": "Mattie Collins",\r
1128 "gender": "female",\r
1129 "company": "EARGO",\r
1130 "email": "mattiecollins@eargo.com",\r
1131 "phone": "+1 (800) 463-2474"\r
1132 }, {\r
1133 "_id": "54ff69d94692077fe1587d2b",\r
1134 "index": 39,\r
1135 "guid": "9c259004-63be-4056-b291-7989cd582d41",\r
1136 "isActive": true,\r
1137 "balance": "$1,429.64",\r
1138 "age": 23,\r
1139 "eyeColor": "brown",\r
1140 "name": "Weeks Mcdowell",\r
1141 "gender": "male",\r
1142 "company": "ORBAXTER",\r
1143 "email": "weeksmcdowell@orbaxter.com",\r
1144 "phone": "+1 (913) 562-2677"\r
1145 }, {\r
1146 "_id": "54ff69d95c44a1cefcb13a58",\r
1147 "index": 40,\r
1148 "guid": "44fa1564-9ef2-4503-b887-5f0f282b1bd3",\r
1149 "isActive": false,\r
1150 "balance": "$1,340.36",\r
1151 "age": 30,\r
1152 "eyeColor": "brown",\r
1153 "name": "Hammond Valencia",\r
1154 "gender": "male",\r
1155 "company": "IZZBY",\r
1156 "email": "hammondvalencia@izzby.com",\r
1157 "phone": "+1 (899) 577-2537"\r
1158 }, {\r
1159 "_id": "54ff69d9c513f5b3c8ba15d7",\r
1160 "index": 41,\r
1161 "guid": "70c237d2-4a51-4b41-a5e2-e3bc1def56c5",\r
1162 "isActive": true,\r
1163 "balance": "$2,979.67",\r
1164 "age": 39,\r
1165 "eyeColor": "brown",\r
1166 "name": "Ramona Fitzgerald",\r
1167 "gender": "female",\r
1168 "company": "GOLISTIC",\r
1169 "email": "ramonafitzgerald@golistic.com",\r
1170 "phone": "+1 (965) 432-2851"\r
1171 }, {\r
1172 "_id": "54ff69d9affa1d1749cd11d5",\r
1173 "index": 42,\r
1174 "guid": "80ef3c8e-b6ca-4048-9920-e651fa2a11b0",\r
1175 "isActive": false,\r
1176 "balance": "$3,671.11",\r
1177 "age": 27,\r
1178 "eyeColor": "blue",\r
1179 "name": "Hyde Alford",\r
1180 "gender": "male",\r
1181 "company": "COFINE",\r
1182 "email": "hydealford@cofine.com",\r
1183 "phone": "+1 (806) 588-3800"\r
1184 }, {\r
1185 "_id": "54ff69d9bd4f8a5bc1e34937",\r
1186 "index": 43,\r
1187 "guid": "3d5ed46a-0b40-4e2d-8438-ada9007f4d49",\r
1188 "isActive": true,\r
1189 "balance": "$1,051.71",\r
1190 "age": 36,\r
1191 "eyeColor": "brown",\r
1192 "name": "Sonia Salazar",\r
1193 "gender": "female",\r
1194 "company": "RENOVIZE",\r
1195 "email": "soniasalazar@renovize.com",\r
1196 "phone": "+1 (855) 547-2046"\r
1197 }, {\r
1198 "_id": "54ff69d9c59ba53ca1b15c7f",\r
1199 "index": 44,\r
1200 "guid": "fe908aad-5474-4767-baf4-66a4e9fcf106",\r
1201 "isActive": true,\r
1202 "balance": "$3,531.45",\r
1203 "age": 21,\r
1204 "eyeColor": "blue",\r
1205 "name": "Johnston Nolan",\r
1206 "gender": "male",\r
1207 "company": "VELOS",\r
1208 "email": "johnstonnolan@velos.com",\r
1209 "phone": "+1 (950) 510-3191"\r
1210 }, {\r
1211 "_id": "54ff69d96252c760ec1787a4",\r
1212 "index": 45,\r
1213 "guid": "efd7b2aa-804b-4463-a1e4-7931bcac6a18",\r
1214 "isActive": true,\r
1215 "balance": "$2,238.60",\r
1216 "age": 40,\r
1217 "eyeColor": "green",\r
1218 "name": "Salazar Walters",\r
1219 "gender": "male",\r
1220 "company": "GEEKNET",\r
1221 "email": "salazarwalters@geeknet.com",\r
1222 "phone": "+1 (834) 510-2779"\r
1223 }, {\r
1224 "_id": "54ff69d9672f19a45f583e87",\r
1225 "index": 46,\r
1226 "guid": "25d3dddd-3983-49ae-b7f4-224e73bdacd9",\r
1227 "isActive": true,\r
1228 "balance": "$2,092.02",\r
1229 "age": 21,\r
1230 "eyeColor": "brown",\r
1231 "name": "Emma Mcfarland",\r
1232 "gender": "female",\r
1233 "company": "COWTOWN",\r
1234 "email": "emmamcfarland@cowtown.com",\r
1235 "phone": "+1 (858) 410-3273"\r
1236 }, {\r
1237 "_id": "54ff69d902facac3a9fc9fbf",\r
1238 "index": 47,\r
1239 "guid": "e22f488c-a5ad-49d3-b9ec-f3dd9f287318",\r
1240 "isActive": false,\r
1241 "balance": "$1,199.34",\r
1242 "age": 39,\r
1243 "eyeColor": "blue",\r
1244 "name": "Lisa Sutton",\r
1245 "gender": "female",\r
1246 "company": "EXTRAGEN",\r
1247 "email": "lisasutton@extragen.com",\r
1248 "phone": "+1 (815) 583-2428"\r
1249 }, {\r
1250 "_id": "54ff69d958481e8cde608526",\r
1251 "index": 48,\r
1252 "guid": "aa976349-e7dc-4a38-aae7-e497c986c288",\r
1253 "isActive": true,\r
1254 "balance": "$3,680.82",\r
1255 "age": 37,\r
1256 "eyeColor": "blue",\r
1257 "name": "Blackburn Ingram",\r
1258 "gender": "male",\r
1259 "company": "EXTREMO",\r
1260 "email": "blackburningram@extremo.com",\r
1261 "phone": "+1 (800) 407-3564"\r
1262 }, {\r
1263 "_id": "54ff69d9e28a5207c6ce32f2",\r
1264 "index": 49,\r
1265 "guid": "e95d0949-d9e5-4665-bee0-29697d6b6e61",\r
1266 "isActive": true,\r
1267 "balance": "$3,399.52",\r
1268 "age": 24,\r
1269 "eyeColor": "blue",\r
1270 "name": "Preston Hardy",\r
1271 "gender": "male",\r
1272 "company": "PROXSOFT",\r
1273 "email": "prestonhardy@proxsoft.com",\r
1274 "phone": "+1 (960) 444-3169"\r
1275 }, {\r
1276 "_id": "54ff69d92e96909171f3e1b1",\r
1277 "index": 50,\r
1278 "guid": "0d6b5e73-7b1d-4c96-9a16-d73d0e74c364",\r
1279 "isActive": false,\r
1280 "balance": "$2,920.49",\r
1281 "age": 21,\r
1282 "eyeColor": "green",\r
1283 "name": "Mia Mcgee",\r
1284 "gender": "female",\r
1285 "company": "GEEKOLOGY",\r
1286 "email": "miamcgee@geekology.com",\r
1287 "phone": "+1 (921) 464-2944"\r
1288 }, {\r
1289 "_id": "54ff69d94e56363d2f4110cb",\r
1290 "index": 51,\r
1291 "guid": "c355ad3a-a137-4dc4-9eeb-2ef6c5385076",\r
1292 "isActive": true,\r
1293 "balance": "$2,738.07",\r
1294 "age": 36,\r
1295 "eyeColor": "brown",\r
1296 "name": "Doris Mccullough",\r
1297 "gender": "female",\r
1298 "company": "PRIMORDIA",\r
1299 "email": "dorismccullough@primordia.com",\r
1300 "phone": "+1 (823) 470-2961"\r
1301 }, {\r
1302 "_id": "54ff69d99d447d751c48fefc",\r
1303 "index": 52,\r
1304 "guid": "564a646d-4bd9-4e4b-bb64-522eea292751",\r
1305 "isActive": false,\r
1306 "balance": "$1,966.01",\r
1307 "age": 30,\r
1308 "eyeColor": "brown",\r
1309 "name": "Fernandez Shepard",\r
1310 "gender": "male",\r
1311 "company": "PAWNAGRA",\r
1312 "email": "fernandezshepard@pawnagra.com",\r
1313 "phone": "+1 (903) 453-3876"\r
1314 }, {\r
1315 "_id": "54ff69d949dfc5b655d10e58",\r
1316 "index": 53,\r
1317 "guid": "4b07ab75-7a20-4515-9561-10323a712c37",\r
1318 "isActive": false,\r
1319 "balance": "$3,447.93",\r
1320 "age": 38,\r
1321 "eyeColor": "green",\r
1322 "name": "Yvette Caldwell",\r
1323 "gender": "female",\r
1324 "company": "OLUCORE",\r
1325 "email": "yvettecaldwell@olucore.com",\r
1326 "phone": "+1 (861) 417-2291"\r
1327 }, {\r
1328 "_id": "54ff69d9e7ab8c4e8029f2d6",\r
1329 "index": 54,\r
1330 "guid": "73917fc2-53d6-4331-8ac9-ec65943d8e75",\r
1331 "isActive": false,\r
1332 "balance": "$1,949.14",\r
1333 "age": 25,\r
1334 "eyeColor": "green",\r
1335 "name": "Gibson Molina",\r
1336 "gender": "male",\r
1337 "company": "STREZZO",\r
1338 "email": "gibsonmolina@strezzo.com",\r
1339 "phone": "+1 (809) 485-2161"\r
1340 }, {\r
1341 "_id": "54ff69d958fcd9a733351136",\r
1342 "index": 55,\r
1343 "guid": "ad310b11-965c-480e-9088-4d65c27d6d04",\r
1344 "isActive": false,\r
1345 "balance": "$2,512.16",\r
1346 "age": 40,\r
1347 "eyeColor": "brown",\r
1348 "name": "Hicks Ferguson",\r
1349 "gender": "male",\r
1350 "company": "COMTEXT",\r
1351 "email": "hicksferguson@comtext.com",\r
1352 "phone": "+1 (897) 565-2845"\r
1353 }, {\r
1354 "_id": "54ff69d94a48d9b5a556f495",\r
1355 "index": 56,\r
1356 "guid": "17bca210-7a7f-4236-badd-4d52abc4d73f",\r
1357 "isActive": false,\r
1358 "balance": "$3,950.51",\r
1359 "age": 28,\r
1360 "eyeColor": "brown",\r
1361 "name": "Dale Stephens",\r
1362 "gender": "female",\r
1363 "company": "ZENSOR",\r
1364 "email": "dalestephens@zensor.com",\r
1365 "phone": "+1 (867) 474-3050"\r
1366 }, {\r
1367 "_id": "54ff69d94f91296292db728e",\r
1368 "index": 57,\r
1369 "guid": "1cd712d4-b477-496d-aea6-d8b75f0aebcc",\r
1370 "isActive": false,\r
1371 "balance": "$1,385.99",\r
1372 "age": 37,\r
1373 "eyeColor": "brown",\r
1374 "name": "Burris Nash",\r
1375 "gender": "male",\r
1376 "company": "BRAINCLIP",\r
1377 "email": "burrisnash@brainclip.com",\r
1378 "phone": "+1 (873) 533-2943"\r
1379 }, {\r
1380 "_id": "54ff69d9b8edd89a22d08814",\r
1381 "index": 58,\r
1382 "guid": "3cab0ec2-bece-43a2-b49f-1213cbd8bbb0",\r
1383 "isActive": false,\r
1384 "balance": "$3,652.39",\r
1385 "age": 37,\r
1386 "eyeColor": "brown",\r
1387 "name": "Janie Harrington",\r
1388 "gender": "female",\r
1389 "company": "ZISIS",\r
1390 "email": "janieharrington@zisis.com",\r
1391 "phone": "+1 (920) 441-3329"\r
1392 }, {\r
1393 "_id": "54ff69d90550f9ffe4676013",\r
1394 "index": 59,\r
1395 "guid": "536e1f5f-474f-412e-a4ad-258a20a7cb77",\r
1396 "isActive": false,\r
1397 "balance": "$3,937.99",\r
1398 "age": 24,\r
1399 "eyeColor": "brown",\r
1400 "name": "Beulah Burch",\r
1401 "gender": "female",\r
1402 "company": "PLASTO",\r
1403 "email": "beulahburch@plasto.com",\r
1404 "phone": "+1 (904) 452-2143"\r
1405 }, {\r
1406 "_id": "54ff69d920a5eed9e3d2cb29",\r
1407 "index": 60,\r
1408 "guid": "54a44fee-8614-492f-a1bd-c4a6248fce48",\r
1409 "isActive": true,\r
1410 "balance": "$3,024.67",\r
1411 "age": 25,\r
1412 "eyeColor": "green",\r
1413 "name": "Osborne Carter",\r
1414 "gender": "male",\r
1415 "company": "ARTIQ",\r
1416 "email": "osbornecarter@artiq.com",\r
1417 "phone": "+1 (937) 431-2440"\r
1418 }, {\r
1419 "_id": "54ff69d921ee90fcb998a583",\r
1420 "index": 61,\r
1421 "guid": "6e899cc3-f935-405d-995c-43635d3ed121",\r
1422 "isActive": true,\r
1423 "balance": "$3,189.34",\r
1424 "age": 37,\r
1425 "eyeColor": "green",\r
1426 "name": "Rice Mcclain",\r
1427 "gender": "male",\r
1428 "company": "EVENTIX",\r
1429 "email": "ricemcclain@eventix.com",\r
1430 "phone": "+1 (924) 448-3107"\r
1431 }, {\r
1432 "_id": "54ff69d9c70b2ae884142f6f",\r
1433 "index": 62,\r
1434 "guid": "0e62a562-ced9-4922-9985-8c813a647d87",\r
1435 "isActive": false,\r
1436 "balance": "$2,135.22",\r
1437 "age": 34,\r
1438 "eyeColor": "green",\r
1439 "name": "Jerri Knowles",\r
1440 "gender": "female",\r
1441 "company": "VANTAGE",\r
1442 "email": "jerriknowles@vantage.com",\r
1443 "phone": "+1 (926) 566-3957"\r
1444 }, {\r
1445 "_id": "54ff69d950ea8f13f7e0adc3",\r
1446 "index": 63,\r
1447 "guid": "70e8cbfa-9f24-4e58-b827-9d683765e383",\r
1448 "isActive": false,\r
1449 "balance": "$1,360.09",\r
1450 "age": 24,\r
1451 "eyeColor": "blue",\r
1452 "name": "Rose Chapman",\r
1453 "gender": "male",\r
1454 "company": "STEELTAB",\r
1455 "email": "rosechapman@steeltab.com",\r
1456 "phone": "+1 (922) 514-3065"\r
1457 }, {\r
1458 "_id": "54ff69d939f6877321458bf6",\r
1459 "index": 64,\r
1460 "guid": "ddb4264b-de31-464b-89ff-dc7b89c120c5",\r
1461 "isActive": true,\r
1462 "balance": "$1,331.51",\r
1463 "age": 32,\r
1464 "eyeColor": "green",\r
1465 "name": "Larson Baxter",\r
1466 "gender": "male",\r
1467 "company": "HALAP",\r
1468 "email": "larsonbaxter@halap.com",\r
1469 "phone": "+1 (968) 451-2570"\r
1470 }, {\r
1471 "_id": "54ff69d9e8c4ac69c408d5a5",\r
1472 "index": 65,\r
1473 "guid": "92f7f97e-469f-4e61-93ba-58d440f9bdee",\r
1474 "isActive": false,\r
1475 "balance": "$3,771.47",\r
1476 "age": 28,\r
1477 "eyeColor": "green",\r
1478 "name": "Sweeney Shepherd",\r
1479 "gender": "male",\r
1480 "company": "OVOLO",\r
1481 "email": "sweeneyshepherd@ovolo.com",\r
1482 "phone": "+1 (963) 413-2263"\r
1483 }, {\r
1484 "_id": "54ff69d97caf29d7106b9a22",\r
1485 "index": 66,\r
1486 "guid": "ccff96f2-0dea-4d72-ae9b-5f2c5e1bccf8",\r
1487 "isActive": false,\r
1488 "balance": "$3,022.08",\r
1489 "age": 35,\r
1490 "eyeColor": "blue",\r
1491 "name": "Maribel Henry",\r
1492 "gender": "female",\r
1493 "company": "CHILLIUM",\r
1494 "email": "maribelhenry@chillium.com",\r
1495 "phone": "+1 (814) 489-2410"\r
1496 }, {\r
1497 "_id": "54ff69d9ea34002e4fc91d67",\r
1498 "index": 67,\r
1499 "guid": "133b0c0a-1517-487c-84b9-b0eb1fc8bfd1",\r
1500 "isActive": false,\r
1501 "balance": "$1,995.00",\r
1502 "age": 20,\r
1503 "eyeColor": "brown",\r
1504 "name": "Deann Bray",\r
1505 "gender": "female",\r
1506 "company": "VERTON",\r
1507 "email": "deannbray@verton.com",\r
1508 "phone": "+1 (847) 540-2423"\r
1509 }, {\r
1510 "_id": "54ff69d9837c8279be6854e0",\r
1511 "index": 68,\r
1512 "guid": "d562f05e-b605-475e-b7ea-e38cf8c6b32f",\r
1513 "isActive": true,\r
1514 "balance": "$1,035.74",\r
1515 "age": 35,\r
1516 "eyeColor": "brown",\r
1517 "name": "Hart Dillon",\r
1518 "gender": "male",\r
1519 "company": "SOLAREN",\r
1520 "email": "hartdillon@solaren.com",\r
1521 "phone": "+1 (885) 540-3322"\r
1522 }, {\r
1523 "_id": "54ff69d975a0df7615047dda",\r
1524 "index": 69,\r
1525 "guid": "7ec2a46e-9d61-42ad-9aa0-d06596232252",\r
1526 "isActive": false,\r
1527 "balance": "$1,317.78",\r
1528 "age": 40,\r
1529 "eyeColor": "green",\r
1530 "name": "Daphne Mercado",\r
1531 "gender": "female",\r
1532 "company": "TERRASYS",\r
1533 "email": "daphnemercado@terrasys.com",\r
1534 "phone": "+1 (915) 491-2470"\r
1535 }, {\r
1536 "_id": "54ff69d9a6aafdf53cf7899d",\r
1537 "index": 70,\r
1538 "guid": "99c23548-6731-4236-a6b1-0455172d931b",\r
1539 "isActive": false,\r
1540 "balance": "$3,395.05",\r
1541 "age": 22,\r
1542 "eyeColor": "blue",\r
1543 "name": "Aguilar Ramsey",\r
1544 "gender": "male",\r
1545 "company": "SONIQUE",\r
1546 "email": "aguilarramsey@sonique.com",\r
1547 "phone": "+1 (918) 407-2528"\r
1548 }, {\r
1549 "_id": "54ff69d98368d84760f7ffb4",\r
1550 "index": 71,\r
1551 "guid": "919aa130-2a9a-4c18-9f82-a4cc5fa9d18f",\r
1552 "isActive": true,\r
1553 "balance": "$3,961.57",\r
1554 "age": 23,\r
1555 "eyeColor": "blue",\r
1556 "name": "Alyssa Garrett",\r
1557 "gender": "female",\r
1558 "company": "ZORK",\r
1559 "email": "alyssagarrett@zork.com",\r
1560 "phone": "+1 (816) 467-3019"\r
1561 }, {\r
1562 "_id": "54ff69d97100f98d64a49826",\r
1563 "index": 72,\r
1564 "guid": "32301d04-6bd8-4db2-a1d0-b98ae4a53877",\r
1565 "isActive": true,\r
1566 "balance": "$2,245.64",\r
1567 "age": 27,\r
1568 "eyeColor": "blue",\r
1569 "name": "Vickie Castro",\r
1570 "gender": "female",\r
1571 "company": "QUOTEZART",\r
1572 "email": "vickiecastro@quotezart.com",\r
1573 "phone": "+1 (894) 530-3406"\r
1574 }, {\r
1575 "_id": "54ff69d944ae1efb286accdf",\r
1576 "index": 73,\r
1577 "guid": "a15615f1-2077-4d7f-800c-f19aad0cf45a",\r
1578 "isActive": false,\r
1579 "balance": "$3,610.39",\r
1580 "age": 26,\r
1581 "eyeColor": "brown",\r
1582 "name": "Sheryl Cherry",\r
1583 "gender": "female",\r
1584 "company": "TOYLETRY",\r
1585 "email": "sherylcherry@toyletry.com",\r
1586 "phone": "+1 (883) 527-2393"\r
1587 }]\r
1588 });\r
1589\r
1590 grid = Ext.create('Ext.grid.Panel', {\r
1591 title: 'Simpsons',\r
1592 store: store,\r
1593 height: 350,\r
1594 width: 600,\r
1595 renderTo: document.body,\r
1596 columns: [{\r
1597 text: 'index',\r
1598 dataIndex: 'index',\r
1599 locked: true\r
1600 }, {\r
1601 text: 'Name',\r
1602 dataIndex: 'name',\r
1603 locked: true,\r
1604 cellWrap: true,\r
1605 width: 75\r
1606 }, {\r
1607 text: 'Email',\r
1608 dataIndex: 'email',\r
1609 flex: 1\r
1610 }, {\r
1611 text: 'Phone',\r
1612 dataIndex: 'phone'\r
1613 }, {\r
1614 text: 'isActive',\r
1615 dataIndex: 'isActive'\r
1616\r
1617 }, {\r
1618 text: 'eyeColor',\r
1619 dataIndex: 'eyeColor'\r
1620 }, {\r
1621 text: 'company',\r
1622 dataIndex: 'company'\r
1623 }, {\r
1624 text: 'gender',\r
1625 dataIndex: 'gender'\r
1626 }],\r
1627 region: 'center'\r
1628 });\r
1629\r
1630 var normalView = grid.normalGrid.getView(),\r
1631 lockedView = grid.lockedGrid.getView(),\r
1632 lockedScroller = lockedView.getScrollable(),\r
1633 normalScroller = normalView.getScrollable(),\r
1634 normalRows = normalView.all,\r
1635 lockedRows = lockedView.all,\r
1636 navModel = normalView.getNavigationModel();\r
1637\r
1638 waitsFor(function() {\r
1639 return normalView.all.getCount();\r
1640 });\r
1641\r
1642 runs(function() {\r
1643 navModel.setPosition(new Ext.grid.CellContext(lockedView).setPosition(0, 0));\r
1644 });\r
1645\r
1646 waitsFor(function() {\r
1647 var a = Ext.Element.getActiveElement(),\r
1648 p = navModel.getPosition();\r
1649\r
1650 if (p) {\r
1651 // Scroll only when the last scroll signal has found both views and caused them to update\r
1652 if (navModel.getCell() && (a === navModel.getCell().dom) && normalRows.startIndex === lockedRows.startIndex && lockedScroller.getPosition().y === normalScroller.getPosition().y) {\r
1653 jasmine.fireKeyEvent(a, 'keydown', Ext.event.Event.PAGE_DOWN);\r
1654 }\r
1655\r
1656 // Scroll until the end\r
1657 return (navModel.getPosition().rowIdx === store.getCount() - 1);\r
1658 }\r
1659 }, 'down arrow to scroll to the last row. 20 seconds expired', 20000);\r
1660\r
1661 runs(function() {\r
1662 var i;\r
1663\r
1664 // Row count must be in sync\r
1665 expect(lockedRows.getCount()).toBe(normalRows.getCount());\r
1666\r
1667 // view sizes must still be in sync\r
1668 expect(lockedView.bufferedRenderer.viewSize).toBe(normalView.bufferedRenderer.viewSize);\r
1669\r
1670 // Every row must be the same height\r
1671 for (i = normalRows.startIndex; i <= normalRows.endIndex; i++) {\r
1672 expect(normalRows.item(i).getHeight()).toBe(lockedRows.item(i).getHeight());\r
1673 }\r
1674 });\r
1675 });\r
1676 });\r
1677\r
1678 describe('gridpanel', function () {\r
1679 describe('locking grid', function () {\r
1680 function doIt(reconfigure) {\r
1681 var columns = [{\r
1682 text: 'Col 1',\r
1683 dataIndex: 'field1',\r
1684 width: 100,\r
1685 locked: true\r
1686 }, {\r
1687 text: 'Col 2',\r
1688 dataIndex: 'field2',\r
1689 width: 100\r
1690 }, {\r
1691 text: 'Col 3',\r
1692 dataIndex: 'field3',\r
1693 width: 100\r
1694 }, {\r
1695 text: 'Col 4',\r
1696 dataIndex: 'field4',\r
1697 width: 100\r
1698 }, {\r
1699 text: 'Col 5',\r
1700 dataIndex: 'field5',\r
1701 height: 25,\r
1702 width: 150,\r
1703 xtype: 'widgetcolumn',\r
1704 widget: {\r
1705 xtype: 'progressbarwidget',\r
1706 height: 25,\r
1707 textTpl: ['{percent:number("0")}% capacity']\r
1708 }\r
1709 }],\r
1710 nodeCache;\r
1711\r
1712 makeGrid({\r
1713 columns: columns\r
1714 }, {\r
1715 fields: ['field1', 'field2', 'field3', 'field4', 'field5'],\r
1716 data: createData(100)\r
1717 });\r
1718\r
1719 view = grid.view.normalView;\r
1720 nodeCache = view.all;\r
1721\r
1722 if (reconfigure) {\r
1723 grid.reconfigure(null, columns);\r
1724 }\r
1725\r
1726 waitsFor(function () {\r
1727 if (nodeCache.endIndex === 99 && view.bufferedRenderer.getLastVisibleRowIndex() === 99) {\r
1728 return true;\r
1729 }\r
1730 else {\r
1731 // Scroll incrementally until the correct end point is found\r
1732 view.scrollBy(null, 20);\r
1733 }\r
1734 }, 'last node to scroll into view', 10000, 50);\r
1735\r
1736 runs(function () {\r
1737 expect(view.el.down('.x-grid-item-container').getHeight() === view.lockingPartner.el.down('.x-grid-item-container').getHeight()).toBe(true);\r
1738 });\r
1739 }\r
1740\r
1741 it('should have the same height for each locking partner when scrolling', function () {\r
1742 doIt(false);\r
1743 });\r
1744\r
1745 it('should have the same height for each locking partner when scrolling after a reconfigure', function () {\r
1746 doIt(true);\r
1747 });\r
1748 });\r
1749\r
1750 describe('locking grid with variableRowHeight', function () {\r
1751 itIE10p('should keep the row heights on both sides synchronized', function() {\r
1752 var columns = [{\r
1753 text: 'Col 1',\r
1754 dataIndex: 'field1',\r
1755 width: 100,\r
1756 locked: true,\r
1757 variableRowHeight: true\r
1758 }, {\r
1759 text: 'Col 2',\r
1760 dataIndex: 'field2',\r
1761 width: 100\r
1762 }, {\r
1763 text: 'Col 3',\r
1764 dataIndex: 'field3',\r
1765 width: 100\r
1766 }, {\r
1767 text: 'Col 4',\r
1768 dataIndex: 'field4',\r
1769 width: 100\r
1770 }, {\r
1771 text: 'Col 5',\r
1772 dataIndex: 'field5',\r
1773 height: 25,\r
1774 width: 150,\r
1775 xtype: 'widgetcolumn',\r
1776 widget: {\r
1777 xtype: 'progressbarwidget',\r
1778 height: 25,\r
1779 textTpl: ['{percent:number("0")}% capacity']\r
1780 }\r
1781 }],\r
1782 nodeCache,\r
1783 lockedView,\r
1784 bufferedRendererInvocationCount = 0,\r
1785 onSyncHeights = function() {\r
1786 var lockedItems = lockedView.all.slice(),\r
1787 normalItems = nodeCache.slice(),\r
1788 lockedSize = lockedItems.length,\r
1789 normalSize = normalItems.length,\r
1790 i,\r
1791 allEqual = true;\r
1792\r
1793 // must be same number of rows\r
1794 expect(lockedSize).toBe(normalSize);\r
1795\r
1796 for (i = 0; allEqual && i < lockedSize; i++) {\r
1797 allEqual = allEqual && normalItems[i].offsetHeight === lockedItems[i].offsetHeight;\r
1798 }\r
1799 // All rows must be same size\r
1800 expect(allEqual).toBe(true);\r
1801 bufferedRendererInvocationCount++;\r
1802 };\r
1803\r
1804 // Make grid with small buffer zones.\r
1805 makeGrid({\r
1806 columns: columns,\r
1807 syncRowHeight: true\r
1808 }, {\r
1809 fields: ['field1', 'field2', 'field3', 'field4', 'field5'],\r
1810 data: createData(1000, true)\r
1811 });\r
1812\r
1813 lockedView = grid.view.lockedView;\r
1814 view = grid.view.normalView;\r
1815 nodeCache = view.all;\r
1816\r
1817 // Set up a sequence on the buffered renderers to check that all rows are always synced\r
1818 view.bufferedRenderer.syncRowHeights = Ext.Function.createSequence(view.bufferedRenderer.syncRowHeights, onSyncHeights);\r
1819 lockedView.bufferedRenderer.syncRowHeights = Ext.Function.createSequence(view.bufferedRenderer.syncRowHeights, onSyncHeights);\r
1820\r
1821 waitsFor(function () {\r
1822 var reachedTargetRow = nodeCache.startIndex <= 99 && nodeCache.endIndex >= 99;\r
1823\r
1824 // If row 99 is in the nodeCache, we're done\r
1825 if (reachedTargetRow) {\r
1826 return view.getScrollY() === lockedView.getScrollY() && nodeCache.startIndex === lockedView.all.startIndex && lockedView.position === view.position && lockedView.bodyTop === view.bodyTop;\r
1827 }\r
1828 else {\r
1829 // Scroll incrementally until the correct end point is found\r
1830 view.scrollBy(null, 20);\r
1831 }\r
1832 }, 'row 99 to be rendered', 20000, 50);\r
1833\r
1834 // Must have invoked the row syncher and the two body heights must be the same\r
1835 runs(function () {\r
1836\r
1837 expect(bufferedRendererInvocationCount).toBeGreaterThan(0);\r
1838 expect(view.el.down('.x-grid-item-container', true).offsetHeight === view.lockingPartner.el.down('.x-grid-item-container', true).offsetHeight).toBe(true);\r
1839 bufferedRendererInvocationCount = 0;\r
1840 });\r
1841\r
1842 // Now teleport down to neat the bottom\r
1843 waitsFor(function () {\r
1844 var reachedTargetRow = view.bufferedRenderer.getLastVisibleRowIndex() > 990;\r
1845\r
1846 if (reachedTargetRow) {\r
1847 return view.getScrollY() === lockedView.getScrollY() && view.all.startIndex === lockedView.all.startIndex;\r
1848 }\r
1849 else {\r
1850 // Scroll in teleporting chunks until the correct end point is found\r
1851 view.scrollBy(null, 1000);\r
1852 }\r
1853 }, 'row 990 to scroll into view', 30000, 100);\r
1854 \r
1855 // Scrolling is too fast for IE8, need to repaint the grid\r
1856 // so that measurements below will yield correct values\r
1857 if (Ext.isIE8) {\r
1858 runs(function() {\r
1859 grid.hide();\r
1860 grid.show();\r
1861 });\r
1862 }\r
1863\r
1864 // Must have invoked the row syncher and the two body heights must be the same\r
1865 runs(function () {\r
1866 expect(bufferedRendererInvocationCount).toBeGreaterThan(0);\r
1867 \r
1868 var mainHeight = view.el.down('.x-grid-item-container').getHeight(),\r
1869 partnerHeight = view.lockingPartner.el.down('.x-grid-item-container').getHeight();\r
1870 \r
1871 expect(partnerHeight).toBe(mainHeight);\r
1872 bufferedRendererInvocationCount = 0;\r
1873 });\r
1874 });\r
1875 });\r
1876\r
1877 describe('locking grid with asymmetricRowHeight', function () {\r
1878 it('should keep the row heights on both sides synchronized', function() {\r
1879 // Note that we do NOT set variableRowHeight. All row heights are the same\r
1880 // even if one side drives the row height, and the sides need syncing.\r
1881 // This means BufferedRenderer can use simple arithmetic to find first/last visible row index.\r
1882 var columns = [{\r
1883 text: 'Col 1',\r
1884 dataIndex: 'field1',\r
1885 width: 100,\r
1886 locked: true\r
1887 }, {\r
1888 text: 'Col 2',\r
1889 dataIndex: 'field2',\r
1890 width: 100\r
1891 }, {\r
1892 text: 'Col 3',\r
1893 dataIndex: 'field3',\r
1894 width: 100\r
1895 }, {\r
1896 text: 'Col 4',\r
1897 dataIndex: 'field4',\r
1898 width: 100\r
1899 }, {\r
1900 text: 'Col 5',\r
1901 dataIndex: 'field5',\r
1902 height: 25,\r
1903 width: 150,\r
1904 xtype: 'widgetcolumn',\r
1905 widget: {\r
1906 xtype: 'progressbarwidget',\r
1907 height: 25,\r
1908 textTpl: ['{percent:number("0")}% capacity']\r
1909 }\r
1910 }],\r
1911 nodeCache,\r
1912 lockedView,\r
1913 bufferedRendererInvocationCount = 0,\r
1914 onSyncHeights = function() {\r
1915 var lockedItems = lockedView.all.slice(),\r
1916 normalItems = nodeCache.slice(),\r
1917 lockedSize = lockedItems.length,\r
1918 normalSize = normalItems.length,\r
1919 i,\r
1920 allEqual = true;\r
1921\r
1922 // must be same number of rows\r
1923 expect(lockedSize).toBe(normalSize);\r
1924\r
1925 for (i = 0; allEqual && i < lockedSize; i++) {\r
1926 allEqual = allEqual && normalItems[i].offsetHeight === lockedItems[i].offsetHeight;\r
1927 }\r
1928 // All rows must be same size\r
1929 expect(allEqual).toBe(true);\r
1930 bufferedRendererInvocationCount++;\r
1931 };\r
1932\r
1933 // Make grid with small buffer zones.\r
1934 makeGrid({\r
1935 columns: columns,\r
1936 syncRowHeight: true\r
1937 }, {\r
1938 fields: ['field1', 'field2', 'field3', 'field4', 'field5'],\r
1939 data: createData(1000, false, true),\r
1940\r
1941 // Make sure store.isGrouped() returns false\r
1942 // otherwise variableRowHeight will be detected\r
1943 groupField: undefined\r
1944 });\r
1945\r
1946 lockedView = grid.view.lockedView;\r
1947 view = grid.view.normalView;\r
1948 nodeCache = view.all;\r
1949\r
1950 // Set up a sequence on the buffered renderers to check that all rows are always synced\r
1951 view.bufferedRenderer.syncRowHeights = Ext.Function.createSequence(view.bufferedRenderer.syncRowHeights, onSyncHeights);\r
1952 lockedView.bufferedRenderer.syncRowHeights = Ext.Function.createSequence(view.bufferedRenderer.syncRowHeights, onSyncHeights);\r
1953\r
1954 waitsFor(function () {\r
1955 var reachedTargetRow = nodeCache.startIndex <= 99 && nodeCache.endIndex >= 99;\r
1956\r
1957 // If row 99 is in the nodeCache, we're done\r
1958 if (reachedTargetRow) {\r
1959 return view.getScrollY() === lockedView.getScrollY() && nodeCache.startIndex === lockedView.all.startIndex && lockedView.position === view.position && lockedView.bodyTop === view.bodyTop;\r
1960 }\r
1961 else {\r
1962 // Scroll incrementally until the correct end point is found\r
1963 view.scrollBy(null, 20);\r
1964 }\r
1965 }, 'row 99 to be rendered', 20000, 50);\r
1966\r
1967 // Must have invoked the row syncher and the two body heights must be the same\r
1968 runs(function () {\r
1969 expect(bufferedRendererInvocationCount).toBeGreaterThan(0);\r
1970 expect(view.el.down('.x-grid-item-container').getHeight() === view.lockingPartner.el.down('.x-grid-item-container').getHeight()).toBe(true);\r
1971 bufferedRendererInvocationCount = 0;\r
1972 });\r
1973\r
1974 // Now teleport down to neat the bottom\r
1975 waitsFor(function () {\r
1976 var reachedTargetRow = view.bufferedRenderer.getLastVisibleRowIndex() > 990;\r
1977\r
1978 if (reachedTargetRow) {\r
1979 return view.getScrollY() === lockedView.getScrollY() && view.all.startIndex === lockedView.all.startIndex;\r
1980 }\r
1981 else {\r
1982 // Scroll in teleporting chunks until the correct end point is found\r
1983 view.scrollBy(null, 1000);\r
1984 }\r
1985 }, 'row 990 to scroll into view', 30000, 100);\r
1986 \r
1987 // Scrolling is too fast for IE8, need to repaint the grid\r
1988 // so that measurements below will yield correct values\r
1989 if (Ext.isIE8) {\r
1990 runs(function() {\r
1991 grid.hide();\r
1992 grid.show();\r
1993 });\r
1994 }\r
1995\r
1996 // Must have invoked the row syncher and the two body heights must be the same\r
1997 runs(function () {\r
1998 expect(bufferedRendererInvocationCount).toBeGreaterThan(0);\r
1999 \r
2000 var mainHeight = view.el.down('.x-grid-item-container').getHeight(),\r
2001 partnerHeight = view.lockingPartner.el.down('.x-grid-item-container').getHeight();\r
2002 \r
2003 expect(partnerHeight).toBe(mainHeight);\r
2004 bufferedRendererInvocationCount = 0;\r
2005 });\r
2006 });\r
2007 });\r
2008\r
2009 describe('reconfiguring', function () {\r
2010 it('should never return `undefined` records when called in a metachange event', function () {\r
2011 // When reconfigure is called within a metchange event listener, the view is refreshed and\r
2012 // `undefined` is returned when AbstractView.getViewRange() -> PageMap.getRange() is called.\r
2013 // This isn't usually a problem, but if there are data records in the PageMap hash that don't exist\r
2014 // in a current page then `undefined` will be returned when instead an array is expected. This, of\r
2015 // course, will throw an exception when the rows are attempted to be created by the template in\r
2016 // AbstractView.refresh(). See EXTJS-12633.\r
2017 var successData = {\r
2018 success: true,\r
2019 totally: 1000,\r
2020 data: [{\r
2021 first: 'First',\r
2022 last: 'Last'\r
2023 }, {\r
2024 first: 'First',\r
2025 last: 'Last'\r
2026 }],\r
2027 metaData: {\r
2028 root: 'data',\r
2029 totalProperty: 'totally',\r
2030 fields: ['first', 'last'],\r
2031 columns: [{\r
2032 text: 'First',\r
2033 dataIndex: 'first'\r
2034 }, {\r
2035 text: 'Last',\r
2036 dataIndex: 'last'\r
2037 }]\r
2038 }\r
2039 },\r
2040 wasCalled = false;\r
2041\r
2042 makeGrid(null, {\r
2043 data: null,\r
2044 fields: [],\r
2045 leadingBufferZone: 50,\r
2046 pageSize: 25,\r
2047 proxy: {\r
2048 type: 'ajax',\r
2049 url: 'derp'\r
2050 },\r
2051 listeners: {\r
2052 metachange: function (store, meta) {\r
2053 grid.reconfigure(store, meta.columns);\r
2054 wasCalled = true;\r
2055 }\r
2056 }\r
2057 });\r
2058\r
2059 // Overriding the PageMap method to return a value > 0 when there isn't a representative\r
2060 // page map will reproduce the bug.\r
2061 spyOn(store.data, 'getCount').andCallFake(function () {\r
2062 store.totalCount = 1000;\r
2063 return 25;\r
2064 });\r
2065\r
2066 store.load();\r
2067 completeWithData(successData);\r
2068\r
2069 expect(wasCalled).toBe(true);\r
2070 });\r
2071\r
2072 describe('with grouping feature', function () {\r
2073 it('reconfiguring should bind the groupStore to the plugin', function () {\r
2074 // This test demonstrates that reconfiguring the grid will properly bind the feature's group\r
2075 // store to the plugin.\r
2076 //\r
2077 // This bug only is reproducible when reconfigure is called on a grid with the buffered\r
2078 // renderer plugin and grouping feature. The bug was that the buffered renderer plugin\r
2079 // would bind the data store to the plugin rather than the group store (created when\r
2080 // there's a grouping feature).\r
2081 //\r
2082 // See EXTJS-11860 and EXTJS-11892.\r
2083 makeGrid({\r
2084 features: [{ftype: 'grouping'}]\r
2085 });\r
2086\r
2087 grid.reconfigure(store);\r
2088\r
2089 expect(grid.view.bufferedRenderer.store.isFeatureStore).toBe(true);\r
2090 });\r
2091 });\r
2092 });\r
2093\r
2094 describe('refreshing the view', function () {\r
2095 describe('filtering out all records', function () {\r
2096 function makeData(len) {\r
2097 var data = [],\r
2098 i, str;\r
2099\r
2100 len = len || 100;\r
2101\r
2102 for (i = 0; i < len; i++) {\r
2103 str = 'emp_' + i;\r
2104\r
2105 data.push({\r
2106 name: str,\r
2107 email: str + '@sencha.com',\r
2108 phone: '1-888-' + i,\r
2109 age: i\r
2110 });\r
2111 }\r
2112\r
2113 return data;\r
2114 }\r
2115\r
2116 function runTests(scroll) {\r
2117 describe('scrolled = ' + scroll, function () {\r
2118 it('should trigger a view refresh', function () {\r
2119 var wasCalled = false;\r
2120\r
2121 makeGrid({\r
2122 viewConfig: {\r
2123 listeners: {\r
2124 refresh: function () {\r
2125 wasCalled = true;\r
2126 }\r
2127 }\r
2128 }\r
2129 });\r
2130\r
2131 if (scroll) {\r
2132 plugin.scrollTo(50);\r
2133 }\r
2134\r
2135 // Filter out all data.\r
2136 store.filter('name', '______');\r
2137\r
2138 expect(wasCalled).toBe(true);\r
2139 });\r
2140\r
2141 it('should reset the view body', function () {\r
2142 makeGrid(null, {\r
2143 data: makeData(500)\r
2144 });\r
2145\r
2146 if (scroll) {\r
2147 plugin.scrollTo(50);\r
2148\r
2149 expect(plugin.bodyTop).toBeGreaterThan(0);\r
2150 expect(plugin.scrollHeight).toBeGreaterThan(0);\r
2151 }\r
2152\r
2153 // Filter out all data.\r
2154 store.filter('name', '______');\r
2155\r
2156 expect(plugin.bodyTop).toBe(0);\r
2157 expect(plugin.scrollHeight).toBe(0);\r
2158 });\r
2159 });\r
2160 }\r
2161\r
2162 runTests(true);\r
2163 runTests(false);\r
2164 });\r
2165 });\r
2166 });\r
2167\r
2168 describe('treepanel', function () {\r
2169 describe('expanding/collapsing', function () {\r
2170 it('should always render the view nodes when expanding', function () {\r
2171 var nodeCache;\r
2172\r
2173 makeTree({\r
2174 height: 300\r
2175 }, 100);\r
2176\r
2177 nodeCache = view.all;\r
2178\r
2179 // Scroll until the last tree node is the last in the rendered block.\r
2180 waitsFor(function () {\r
2181 if (nodeCache.endIndex === 99 && view.bufferedRenderer.getLastVisibleRowIndex() === 99) {\r
2182 return true;\r
2183 }\r
2184 else {\r
2185 // Scroll incrementally until the correct end point is found\r
2186 view.scrollBy(null, 10);\r
2187 }\r
2188 }, 'last node to scroll into view', 10000, 50);\r
2189\r
2190 // Expanding that last node should append some child nodes to replenish the leading buffer zone.\r
2191 runs(function () {\r
2192 // Expand node 99\r
2193 store.getAt(99).expand();\r
2194 });\r
2195\r
2196 // Scroll until the last of those expanded children is the last in the rendered block.\r
2197 waitsFor(function () {\r
2198 if (nodeCache.endIndex === 105) {\r
2199 return true;\r
2200 }\r
2201 else {\r
2202 // Scroll incrementally until the correct end point is found\r
2203 view.scrollBy(null, 10);\r
2204 }\r
2205 }, 'new last leaf node to scroll into view', 10000, 50);\r
2206\r
2207 // Expanding that last node should append the child nodes to the view even though the buffer rendered block is the correct size already\r
2208 runs(function () {\r
2209 //expect(view.bufferedRenderer.position).toBe(view.el.dom.scrollTop);\r
2210 expect(view.getRecord(view.all.last()).get('treeData')).toBe('Child of 99, number 6');\r
2211\r
2212 // Now let's collapse the parent node by simulating a click on the elbow node.\r
2213 jasmine.fireMouseEvent(nodeCache.item(99).down('.x-tree-expander'), 'click');\r
2214 });\r
2215 });\r
2216 });\r
2217\r
2218 describe('loadMask config', function () {\r
2219 it('should create a mask by default if not configured', function () {\r
2220 makeTree({\r
2221 store: {\r
2222 proxy: {\r
2223 type: 'ajax',\r
2224 url: 'foo'\r
2225 }\r
2226 }\r
2227 });\r
2228 expect(view.loadMask instanceof Ext.LoadMask).toBe(true);\r
2229 });\r
2230\r
2231 it('should honor the value if configured', function () {\r
2232 makeTree({\r
2233 store: {\r
2234 proxy: {\r
2235 type: 'ajax',\r
2236 url: 'foo'\r
2237 }\r
2238 },\r
2239 viewConfig: {\r
2240 loadMask: false\r
2241 }\r
2242 });\r
2243 expect(view.loadMask).toBe(false);\r
2244 });\r
2245 });\r
2246\r
2247 describe('Measuring row height', function() {\r
2248 it('should measure row height', function() {\r
2249 makeGrid(null, {\r
2250 groupField: null,\r
2251 data: [\r
2252 {'name': '<div style="height:30px">Lisa</div>', 'email': 'lisa@simpsons.com', 'phone': '555-111-1224', 'age': 14},\r
2253 {'name': 'Lisa', 'email': 'aunt_lisa@simpsons.com', 'phone': '555-111-1274', 'age': 34},\r
2254 {'name': 'Bart', 'email': 'bart@simpsons.com', 'phone': '555-222-1234', 'age': 12},\r
2255 {'name': 'Homer', 'email': 'homer@simpsons.com', 'phone': '555-222-1244', 'age': 44},\r
2256 {'name': 'Marge', 'email': 'marge@simpsons.com', 'phone': '555-222-1254', 'age': 41}\r
2257 ]\r
2258 });\r
2259\r
2260 // Should measure the row height be looking at the first row when we do NOT have variableRowHeight: true\r
2261 // EXTJS-15942 - did not measure, stayed at classic default of 21\r
2262 var row = view.all.first(),\r
2263 rowHeight = row.getHeight();\r
2264 \r
2265 // In IE8 we're adding a bottom border on the rows and shifting the row up\r
2266 // at -border-width to compensate for that\r
2267 if (Ext.isIE8) {\r
2268 rowHeight -= row.getBorderWidth('b');\r
2269 }\r
2270 \r
2271 expect(plugin.rowHeight).toBe(rowHeight);\r
2272 });\r
2273 });\r
2274 });\r
2275\r
2276 describe('filtering the store', function () {\r
2277 var Hobbit, store;\r
2278\r
2279 afterEach(function() {\r
2280 Ext.destroy(Hobbit, store);\r
2281 });\r
2282\r
2283 it('should reset the cached position so the grid-item-container is at the top of the view on filter', function () {\r
2284 Hobbit = Ext.define(null, {\r
2285 extend: 'Ext.data.Model',\r
2286 fields: ['name'],\r
2287 proxy: {\r
2288 type: 'ajax',\r
2289 url: '/foo',\r
2290 reader: {\r
2291 rootProperty: 'data'\r
2292 }\r
2293 }\r
2294 });\r
2295\r
2296 store = new Ext.data.BufferedStore({\r
2297 model: Hobbit,\r
2298 remoteGroup: true,\r
2299 leadingBufferZone: 300,\r
2300 pageSize: 100,\r
2301 autoDestroy: true\r
2302 });\r
2303\r
2304 makeGrid({\r
2305 columns: [{\r
2306 dataIndex: 'name',\r
2307 width: 100\r
2308 }]\r
2309 }, {\r
2310 store: store\r
2311 });\r
2312\r
2313 store.load();\r
2314\r
2315 completeWithData({\r
2316 total: 5000,\r
2317 data: makeData(100)\r
2318 });\r
2319\r
2320 completeWithData({\r
2321 total: 5000,\r
2322 data: makeData(100, 101)\r
2323 });\r
2324\r
2325 completeWithData({\r
2326 total: 5000,\r
2327 data: makeData(100, 201)\r
2328 });\r
2329\r
2330 completeWithData({\r
2331 total: 5000,\r
2332 data: makeData(100, 301)\r
2333 });\r
2334\r
2335 waitsFor(function () {\r
2336 view.scrollBy(null, 10);\r
2337 return view.all.startIndex <= 199 && view.all.endIndex >= 199;\r
2338 }, 'row 199 to scroll into the rendered block', 10000);\r
2339\r
2340 runs(function () {\r
2341 store.addFilter({\r
2342 property: 'name',\r
2343 value: 'name212'\r
2344 });\r
2345\r
2346 // Unfortunately, we're testing private properties here :(\r
2347 expect(plugin.bodyTop).toBe(0);\r
2348 expect(plugin.position).toBe(0);\r
2349 });\r
2350 });\r
2351 it('should reset the cached position so the grid-item-container is at the top of the view on clearFilter', function () {\r
2352 var selModel;\r
2353\r
2354 Hobbit = Ext.define(null, {\r
2355 extend: 'Ext.data.Model',\r
2356 fields: ['name'],\r
2357 proxy: {\r
2358 type: 'ajax',\r
2359 url: '/foo',\r
2360 reader: {\r
2361 rootProperty: 'data'\r
2362 }\r
2363 }\r
2364 });\r
2365\r
2366 store = new Ext.data.Store({\r
2367 model: Hobbit,\r
2368 remoteFilter: false,\r
2369 autoDestroy: true,\r
2370 proxy: {\r
2371 type: 'memory',\r
2372 data: makeData(5000)\r
2373 },\r
2374 autoLoad: true\r
2375 });\r
2376\r
2377 makeGrid({\r
2378 columns: [{\r
2379 dataIndex: 'name',\r
2380 width: 100\r
2381 }],\r
2382 selModel: {\r
2383 type: 'rowmodel',\r
2384 mode: 'MULTI'\r
2385 }\r
2386 }, {\r
2387 store: store\r
2388 });\r
2389 selModel = grid.selModel;\r
2390\r
2391 // Wait for first block to be rendered\r
2392 waitsFor(function() {\r
2393 return view.all.startIndex === 0 && view.all.getCount();\r
2394 });\r
2395\r
2396 runs(function() {\r
2397\r
2398 // Only show the first 2500\r
2399 store.addFilter({\r
2400 property: 'id',\r
2401 value: 2500,\r
2402 operator: '<='\r
2403 });\r
2404\r
2405 // We have filtered out the top 2500 IDs: 2501-5000\r
2406 expect(store.getCount()).toBe(2500);\r
2407\r
2408 // Click to select first row\r
2409 jasmine.fireMouseEvent(view.getCellByPosition({row: 0, column: 0}, true), 'click');\r
2410 expect(view.selModel.getSelection().length).toBe(1);\r
2411 });\r
2412\r
2413 // Scroll all the way to the end\r
2414 waitsFor(function () {\r
2415 view.scrollBy(null, 100);\r
2416 return view.all.endIndex === 2499;\r
2417 }, 'scroll to end', 10000);\r
2418\r
2419 runs(function () {\r
2420 // Click to select from start to end.\r
2421 jasmine.fireMouseEvent(view.getCellByPosition({row: 2499, column: 0}, true), 'click', null, null, null, true);\r
2422 expect(view.selModel.getSelection().length).toBe(2500);\r
2423\r
2424 store.remove(selModel.getSelection());\r
2425\r
2426 // All records gone. (There are still 2500) filtered out though...\r
2427 expect(store.getCount()).toBe(0);\r
2428\r
2429 // Should have gone to top\r
2430 expect(view.all.getCount()).toBe(0);\r
2431 expect(view.getScrollY()).toBe(0);\r
2432 \r
2433 // Unfortunately, we're testing private properties here :(\r
2434 expect(plugin.bodyTop).toBe(0);\r
2435 expect(plugin.position).toBe(0);\r
2436\r
2437 store.clearFilter();\r
2438\r
2439 // The 2500 filtered out records should jump back in\r
2440 expect(store.getCount()).toBe(2500);\r
2441\r
2442 // Unfortunately, we're testing private properties here :(\r
2443 expect(plugin.bodyTop).toBe(0);\r
2444 expect(plugin.position).toBe(0);\r
2445 });\r
2446 });\r
2447 });\r
2448\r
2449 describe("reloading store", function() {\r
2450 describe("from having items to not having items", function() {\r
2451 it("should not cause an error when reloading", function() {\r
2452 var store = new Ext.data.BufferedStore({\r
2453 fields: ['id'],\r
2454 autoDestroy: true,\r
2455 proxy: {\r
2456 type: 'ajax',\r
2457 url: '/foo',\r
2458 reader: {\r
2459 type: 'json',\r
2460 rootProperty: 'data',\r
2461 totalProperty: 'total'\r
2462 }\r
2463 }\r
2464 });\r
2465\r
2466 makeGrid({\r
2467 columns: [{\r
2468 dataIndex: 'name',\r
2469 width: 100\r
2470 }]\r
2471 }, {\r
2472 store: store\r
2473 });\r
2474\r
2475 store.load();\r
2476 satisfyRequests();\r
2477\r
2478 store.reload();\r
2479 satisfyRequests(0);\r
2480\r
2481 expect(view.getNodes()).toEqual([]);\r
2482 });\r
2483\r
2484 it("should show emptyText if specified", function() {\r
2485 var store = new Ext.data.BufferedStore({\r
2486 fields: ['id'],\r
2487 autoDestroy: true,\r
2488 proxy: {\r
2489 type: 'ajax',\r
2490 url: '/foo',\r
2491 reader: {\r
2492 type: 'json',\r
2493 rootProperty: 'data',\r
2494 totalProperty: 'total'\r
2495 }\r
2496 }\r
2497 });\r
2498\r
2499 makeGrid({\r
2500 columns: [{\r
2501 dataIndex: 'name',\r
2502 width: 100\r
2503 }],\r
2504 emptyText: 'Empty'\r
2505 }, {\r
2506 store: store\r
2507 });\r
2508\r
2509 store.load();\r
2510 satisfyRequests();\r
2511\r
2512 store.reload();\r
2513 satisfyRequests(0);\r
2514\r
2515 expect(grid.el.down('.' + grid.emptyCls, true)).hasHTML('Empty');\r
2516 });\r
2517 });\r
2518\r
2519 describe('loading the bound store', function () {\r
2520 function testLockable(locked) {\r
2521 makeTree({\r
2522 columns: [{\r
2523 xtype: 'treecolumn',\r
2524 text: 'Tree Column',\r
2525 width: 300,\r
2526 locked: locked,\r
2527 dataIndex: 'task'\r
2528 }, {\r
2529 text: 'Task1',\r
2530 dataIndex: 'task1'\r
2531 }, {\r
2532 text: 'Task2',\r
2533 dataIndex: 'task2'\r
2534 }, {\r
2535 text: 'Task3',\r
2536 dataIndex: 'task3'\r
2537 }, {\r
2538 text: 'Task4',\r
2539 dataIndex: 'task4'\r
2540 }, {\r
2541 text: 'Task5',\r
2542 dataIndex: 'task5'\r
2543 }],\r
2544 }, 1000);\r
2545 }\r
2546\r
2547 it('should not scroll the view, non-locked grid', function () {\r
2548\r
2549 testLockable(false);\r
2550\r
2551 expect(view.el.dom.scrollTop).toBe(0);\r
2552 store.load();\r
2553 expect(view.el.dom.scrollTop).toBe(0);\r
2554 });\r
2555\r
2556 it('should not scroll the view, locked grid', function () {\r
2557 var lockedView, normalView;\r
2558\r
2559 testLockable(true);\r
2560 lockedViewDom = view.lockedView.el.dom;\r
2561 normalViewDom = view.normalView.el.dom;\r
2562\r
2563 expect(lockedViewDom.scrollTop).toBe(0);\r
2564 expect(normalViewDom.scrollTop).toBe(0);\r
2565 store.load();\r
2566 expect(lockedViewDom.scrollTop).toBe(0);\r
2567 expect(normalViewDom.scrollTop).toBe(0);\r
2568 });\r
2569 });\r
2570 });\r
2571\r
2572 describe('Expanding view size', function() {\r
2573 var window;\r
2574\r
2575 afterEach(function() {\r
2576 window.destroy();\r
2577 });\r
2578\r
2579 it('should scroll to top when view size expands to encapsulate whole dataset', function() {\r
2580 var Person = Ext.define(null, {\r
2581 extend: 'Ext.data.Model',\r
2582 fields: ['name'],\r
2583 proxy: {\r
2584 type: 'ajax',\r
2585 url: '/foo',\r
2586 reader: {\r
2587 rootProperty: 'data'\r
2588 }\r
2589 }\r
2590 });\r
2591\r
2592 var store = new Ext.data.Store({\r
2593 model: Person,\r
2594 proxy: {\r
2595 type: 'memory',\r
2596 data: makeData(52)\r
2597 }\r
2598 });\r
2599 store.load();\r
2600 var store1 = new Ext.data.Store({\r
2601 model: Person,\r
2602 proxy: {\r
2603 type: 'memory',\r
2604 data: makeData(52)\r
2605 }\r
2606 });\r
2607 store1.load();\r
2608\r
2609 var grid = new Ext.grid.Panel({\r
2610 hideMode: 'offsets',\r
2611 title: 'Grid 1',\r
2612 store: store,\r
2613 deferRowRender: false,\r
2614 columns: [{\r
2615 dataIndex: 'id'\r
2616 }, {\r
2617 dataIndex: 'name'\r
2618 }]\r
2619 });\r
2620 var grid1 = new Ext.grid.Panel({\r
2621 hideMode: 'offsets',\r
2622 title: 'Grid 2',\r
2623 store: store1,\r
2624 deferRowRender: false,\r
2625 columns: [{\r
2626 dataIndex: 'id'\r
2627 }, {\r
2628 dataIndex: 'name'\r
2629 }]\r
2630 });\r
2631\r
2632 window = new Ext.window.Window({\r
2633 title: 'Test',\r
2634 height: 395,\r
2635 width: 800,\r
2636 x: 10,\r
2637 y: 10,\r
2638 autoShow: true,\r
2639 maximizable: true,\r
2640 minimizable: true,\r
2641 constrain: false,\r
2642 layout: 'fit',\r
2643 items: {\r
2644 xtype: 'tabpanel',\r
2645 items: [\r
2646 grid, grid1\r
2647 ]\r
2648 }\r
2649 });\r
2650 var tabPanel = window.child('tabpanel');\r
2651\r
2652 var view = grid.getView();\r
2653\r
2654 // Scroll all the way to the end\r
2655 waitsFor(function () {\r
2656 view.scrollBy(null, 100);\r
2657 return view.all.endIndex === view.store.getCount() - 1;\r
2658 }, 'scroll to end', 10000);\r
2659\r
2660 runs(function() {\r
2661 view.scrollBy(null, 100);\r
2662\r
2663 tabPanel.setActiveTab(1);\r
2664\r
2665 // inserting at top\r
2666 grid.store.insert(0,{'title': 'hi',replycount:5});\r
2667 grid.store.insert(0,{'title': 'hi2',replycount:5});\r
2668\r
2669 grid1.store.insert(0,{'title': 'hi',replycount:5});\r
2670 grid1.store.insert(0,{'title': 'hi2',replycount:5});\r
2671\r
2672 tabPanel.setActiveTab(0);\r
2673\r
2674 window.setHeight(940);\r
2675 });\r
2676 \r
2677 // Scroll all the way to the start\r
2678 waitsFor(function () {\r
2679 view.scrollBy(null, -100);\r
2680 return view.getScrollY() === 0;;\r
2681 }, 'scroll to top', 10000);\r
2682\r
2683 runs(function() {\r
2684 expect(view.bufferedRenderer.bodyTop).toBe(0);\r
2685 });\r
2686 });\r
2687 });\r
2688\r
2689 describe('ensureVisible', function() {\r
2690 it('should work in a viewready listener', function() {\r
2691 var done,\r
2692 columns = [{\r
2693 text: 'Col 1',\r
2694 dataIndex: 'field1',\r
2695 width: 100\r
2696 }, {\r
2697 text: 'Col 2',\r
2698 dataIndex: 'field2',\r
2699 width: 100\r
2700 }, {\r
2701 text: 'Col 3',\r
2702 dataIndex: 'field3',\r
2703 width: 100\r
2704 }, {\r
2705 text: 'Col 4',\r
2706 dataIndex: 'field4',\r
2707 width: 100\r
2708 }];\r
2709 \r
2710 makeGrid({\r
2711 columns: columns,\r
2712 listeners : {\r
2713 viewready : function(grid) {\r
2714 grid.ensureVisible(grid.getStore().last(), {\r
2715 callback: function() {\r
2716 done = true;\r
2717 }\r
2718 });\r
2719 }\r
2720 }\r
2721 }, {\r
2722 fields: ['field1', 'field2', 'field3', 'field4'],\r
2723 data: createData(1000)\r
2724 });\r
2725\r
2726 waitsFor(function() {\r
2727 return done;\r
2728 });\r
2729\r
2730 // Should have scrolled all the way to the end\r
2731 expect(view.all.endIndex).toBe(999);\r
2732 expect(view.bufferedRenderer.getLastVisibleRowIndex()).toBe(999);\r
2733 });\r
2734 });\r
2735});\r
2736\r