1 describe('Ext.grid.plugin.BufferedRenderer', function () {
2 var store
, grid
, tree
, view
, plugin
,
3 synchronousLoad
= true,
4 proxyStoreLoad
= Ext
.data
.ProxyStore
.prototype.load
,
6 treeStoreLoad
= Ext
.data
.TreeStore
.prototype.load
,
8 itIE10p
= Ext
.isIE9m
? xit
: it
;
10 function createData(total
, variableRowHeight
, asymmetricRowHeight
) {
14 for (i
= 0, len
= total
|| 100; i
< len
; i
++) {
18 field1
: variableRowHeight
? ('<div style="height:' + Ext
.Number
.randomInt(20, 40)+ 'px">' + n
+ '</div>') : asymmetricRowHeight
? 40 : n
,
29 function makeData(n
, start
) {
36 for (i
= start
; i
< limit
; ++i
) {
45 function getData(start
, limit
) {
46 var end
= start
+ limit
,
50 for (i
= start
; i
< end
; ++i
) {
59 function satisfyRequests(total
) {
60 var requests
= Ext
.Ajax
.mockGetAllRequests(),
62 request
, params
, data
;
64 while (requests
.length
) {
65 request
= requests
[0];
67 params
= request
.options
.params
;
68 data
= getData(empty
? 0 : params
.start
, empty
? 0 : params
.limit
);
70 Ext
.Ajax
.mockComplete({
72 responseText
: Ext
.encode({
73 total
: (total
|| empty
) ? total
: 5000,
78 requests
= Ext
.Ajax
.mockGetAllRequests();
82 function makeGrid(gridCfg
, storeCfg
) {
83 if (!storeCfg
|| !storeCfg
.store
) {
84 store
= new Ext
.data
.Store(Ext
.apply({
85 fields
: ['name', 'email', 'phone'],
88 {'name': 'Lisa', 'email': 'lisa@simpsons.com', 'phone': '555-111-1224', 'age': 14},
89 {'name': 'Lisa', 'email': 'aunt_lisa@simpsons.com', 'phone': '555-111-1274', 'age': 34},
90 {'name': 'Bart', 'email': 'bart@simpsons.com', 'phone': '555-222-1234', 'age': 12},
91 {'name': 'Homer', 'email': 'homer@simpsons.com', 'phone': '555-222-1244', 'age': 44},
92 {'name': 'Marge', 'email': 'marge@simpsons.com', 'phone': '555-222-1254', 'age': 41}
97 store
= storeCfg
.store
;
100 grid
= new Ext
.grid
.Panel(Ext
.apply({
102 {header
: 'Name', dataIndex
: 'name', editor
: 'textfield'},
103 {header
: 'Email', dataIndex
: 'email', flex
:1,
109 {header
: 'Phone', dataIndex
: 'phone', editor
: 'textfield'},
110 {header
: 'Age', dataIndex
: 'age', editor
: 'textfield'}
115 renderTo
: Ext
.getBody()
120 // Extract the buffered renderer from a real TableView, the topmost one might be a Locking pseudo view
121 plugin
= grid
.down('tableview').bufferedRenderer
;
124 function createTreeData(count
) {
130 for (; i
< count
; i
++) {
133 for (j
= 1; j
< 7; j
++) {
135 treeData
: 'Child of ' + i
+ ', number ' + j
,
151 function makeTree(treeCfg
, count
) {
152 store
= new Ext
.data
.TreeStore({
153 fields
: ['treeData'],
154 root
: createTreeData(count
|| 20)
157 tree
= new Ext
.tree
.Panel(Ext
.apply({
162 dataIndex
: 'treeData'
169 renderTo
: Ext
.getBody()
175 function completeWithData(data
) {
176 Ext
.Ajax
.mockComplete({
178 responseText
: Ext
.JSON
.encode(data
)
182 beforeEach(function () {
183 // Override so that we can control asynchronous loading
184 loadStore
= Ext
.data
.ProxyStore
.prototype.load = function() {
185 proxyStoreLoad
.apply(this, arguments
);
186 if (synchronousLoad
) {
187 this.flushLoad
.apply(this, arguments
);
191 loadTreeStore
= Ext
.data
.TreeStore
.prototype.load = function() {
192 treeStoreLoad
.apply(this, arguments
);
193 if (synchronousLoad
) {
194 this.flushLoad
.apply(this, arguments
);
199 MockAjaxManager
.addMethods();
202 afterEach(function () {
203 // Undo the overrides.
204 Ext
.data
.ProxyStore
.prototype.load
= proxyStoreLoad
;
205 Ext
.data
.TreeStore
.prototype.load
= treeStoreLoad
;
207 MockAjaxManager
.removeMethods();
217 store
= grid
= tree
= view
= plugin
= null;
220 describe('updateing scroller when changing width', function() {
221 it('should update the horizontal scroll range', function() {
223 var scroller
= view
.getScrollable(),
224 maxX
= scroller
.getMaxPosition().x
;
226 grid
.setWidth(grid
.getWidth() - 100);
228 // The scroll range should have increased
229 expect(scroller
.getMaxPosition().x
).toBe(maxX
+ 100);
233 describe('autogenerating the plugin', function () {
234 var BR
= Ext
.grid
.plugin
.BufferedRenderer
;
236 it('should create an instance by default', function () {
239 expect(plugin
instanceof BR
).toBe(true);
242 it('should not create an instance when turned off', function () {
244 bufferedRenderer
: false
247 expect(plugin
instanceof BR
).toBe(false);
248 expect(plugin
).toBeUndefined();
251 describe('locking grids', function () {
254 afterEach(function () {
255 normal
= locked
= null;
258 describe('init', function () {
259 function runTests(useBR
) {
260 var not
= useBR
? 'not' : '';
262 describe('buffered rendering = ' + useBR
, function () {
263 beforeEach(function () {
265 bufferedRenderer
: useBR
,
267 {header
: 'Name', dataIndex
: 'name', editor
: 'textfield'},
268 {header
: 'Phone', dataIndex
: 'phone', editor
: 'textfield', locked
: true},
269 {header
: 'Age', dataIndex
: 'age', editor
: 'textfield'}
273 normal
= grid
.normalGrid
.bufferedRenderer
;
274 locked
= grid
.lockedGrid
.bufferedRenderer
;
277 it('should ' + not
+ ' create an instance on the ownerGrid for locking grids', function () {
278 plugin
= grid
.bufferedRenderer
;
279 expect(plugin
instanceof BR
).toBe(false);
282 it('should ' + not
+ ' create an instance by default on each child grid for locking grids', function () {
283 expect(normal
instanceof BR
).toBe(useBR
);
284 expect(locked
instanceof BR
).toBe(useBR
);
293 describe('syncing locking partners when scrolling', function () {
294 beforeEach(function () {
297 {header
: 'Name', dataIndex
: 'name', editor
: 'textfield', locked
: true},
298 {header
: 'Email', dataIndex
: 'email', flex
:1,
304 {header
: 'Phone', dataIndex
: 'phone', editor
: 'textfield'},
305 {header
: 'Age', dataIndex
: 'age', editor
: 'textfield'}
311 normal
= grid
.normalGrid
.bufferedRenderer
;
312 locked
= grid
.lockedGrid
.bufferedRenderer
;
315 it('should fetch the range', function () {
316 spyOn(normal
, 'onRangeFetched').andCallThrough();
317 spyOn(locked
, 'onRangeFetched').andCallThrough();
319 normal
.scrollTo(500);
321 expect(normal
.onRangeFetched
).toHaveBeenCalled();
322 expect(locked
.onRangeFetched
).toHaveBeenCalled();
325 it('should sync the view els', function () {
326 normal
.scrollTo(500);
328 expect(normal
.bodyTop
).toBe(locked
.bodyTop
);
332 describe('Load requests during scrolling', function () {
333 var scrollToLoadBufferValue
,
335 Person
= Ext
.define(null, {
336 extend
: 'Ext.data.Model',
347 function scrollTheGrid() {
348 // Scroll incrementally until the correct starting point is found
349 if (view
&& !view
.destroyed
) {
350 view
.scrollBy(null, 100);
355 beforeEach(function () {
356 scrollToLoadBufferValue
= Ext
.grid
.plugin
.BufferedRenderer
.prototype.scrollToLoadBuffer
;
358 // Make the timeout from attemptLoad call to the doAttemptLoad ten seconds
359 // The doAttemptLoad DelayedTask should not fire between scroll events which take place
360 // every 50 milliseconds
361 Ext
.grid
.plugin
.BufferedRenderer
.prototype.scrollToLoadBuffer
= 10000;
364 {header
: 'Name', dataIndex
: 'name', editor
: 'textfield'},
365 {header
: 'Phone', dataIndex
: 'phone', editor
: 'textfield', locked
: true},
366 {header
: 'Age', dataIndex
: 'age', editor
: 'textfield'}
369 store
: new Ext
.data
.BufferedStore({
371 leadingBufferZone
: 300,
376 // Tell the BufferedRenderer that there are 1000 rows.
377 // We plan not to satisfy any requests from now on so that
378 // on scroll, an attemptLoad call will be made.
379 // the timeout to doAttemptLoad should not expire during the scroll operation
387 data
: makeData(100, 101)
391 data
: makeData(100, 201)
395 data
: makeData(100, 301)
398 afterEach(function() {
399 Ext
.grid
.plugin
.BufferedRenderer
.prototype.scrollToLoadBuffer
= scrollToLoadBufferValue
;
401 it('should not have time between scroll events to fire off any requests', function() {
402 spyOn(plugin
, 'doAttemptLoad');
404 // Scroll to close enough to the end in a slow manner, 50ms between each scroll.
405 // The doAttemptLoad timer should not timeout and fire off a page request between each scroll.
406 waitsFor(function() {
407 if (plugin
.getLastVisibleRowIndex() <= 995) {
409 scrollTimer
= setTimeout(scrollTheGrid
, 50);
414 }, 'grid to scroll to end', Ext
.isIE
? 40000 : 20000);
416 // The atteptLoad timer must never have fired during the scroll.
418 expect(plugin
.doAttemptLoad
.callCount
).toBe(0);
425 describe("Less data than the computed view size", function() {
426 it("should add new rows at top while scrolled to bottom", function() {
427 var Person
= Ext
.define(null, {
428 extend
: 'Ext.data.Model',
439 store
= new Ext
.data
.Store({
444 grid
= new Ext
.grid
.Panel({
448 deferRowRender
: false,
451 renderer: function(v
) {
452 return '<span style="line-height:25px">' + v
+ '</span>';
458 renderTo
: Ext
.getBody()
460 view
= grid
.getView();
462 // Wait until known correct condition is met.
463 // Timeout === test failure.
464 waitsFor(function() {
465 if (view
.all
.endIndex
=== store
.getCount() - 1) {
469 // Scroll incrementally until the correct starting point is found
470 view
.scrollBy(null, 10);
472 }, 'view is scrolled to the last record');
475 store
.insert(0, {id
: 666, name
: 'Old Nick'});
478 var r0
= view
.all
.item(0, true);
480 // Must have been rendered
481 expect(r0
).not
.toBeNull();
483 // The new row zero must have been rendered.
484 expect((r0
.innerText
|| r0
.textContent
).replace(/\n/g,'').replace(/\r/g,'')).toBe("666Old Nick");
489 describe("basic functionality with a buffered store", function() {
490 it("should render rows in order", function() {
491 var Person
= Ext
.define(null, {
492 extend
: 'Ext.data.Model',
503 store
= new Ext
.data
.BufferedStore({
505 leadingBufferZone
: 300,
509 grid
= new Ext
.grid
.Panel({
513 deferRowRender
: false,
519 renderTo
: Ext
.getBody()
528 data
: makeData(100, 101)
532 data
: makeData(100, 201)
536 data
: makeData(100, 301)
538 var view
= grid
.getView(),
541 // Wait until known correct condition is met.
542 // Timeout === test failure.
543 waitsFor(function() {
544 if (rows
.startIndex
<= 100 && rows
.endIndex
>= 100) {
548 // Scroll incrementally until the correct starting point is found
549 view
.scrollBy(null, 10);
551 }, 'View to scroll record id 100 into the rendered block', 20000);
554 var nodes
= view
.getNodes(),
556 offset
= rows
.startIndex
+ 1,
559 expect(len
).toBe(view
.bufferedRenderer
.viewSize
);
560 for (i
= 0; i
< len
; ++i
) {
561 rec
= view
.getRecord(nodes
[i
]);
562 expect(rec
.getId()).toBe(i
+ offset
);
569 it("should scroll to the bottom of a locking grid with no error", function() {
570 var Person
= Ext
.define(null, {
571 extend
: 'Ext.data.Model',
585 store
= new Ext
.data
.BufferedStore({
587 leadingBufferZone
: 300,
591 grid
= new Ext
.grid
.Panel({
595 deferRowRender
: false,
602 renderTo
: Ext
.getBody()
604 lockedView
= grid
.lockedGrid
.view
;
605 normalView
= grid
.normalGrid
.view
;
607 // Make the buffered renderers respond IMMEDIATELY to the scroll event, so that
608 // the waits(100) will be enough to wait for the newly scrolled-to region to be rendered.
609 lockedView
.bufferedRenderer
.scrollToLoadBuffer
= normalView
.bufferedRenderer
.scrollToLoadBuffer
= 0;
617 maxScroll
= normalView
.getScrollable().getMaxPosition().y
;
618 normalView
.setScrollY(maxScroll
);
620 // Important: Simulate Ajax delay before returning data
626 // Both views must render up to the last row with no error thrown
627 waitsFor(function() {
628 return lockedView
.all
.endIndex
=== 4999 && normalView
.all
.endIndex
=== 4999;
633 it('should maintain synchronization when scrolling locked, variable row height grid with keyboard', function() {
634 store
= Ext
.create('Ext.data.Store', {
636 fields
: ['index', 'name', 'email', 'phone', 'isActive', 'eyeColor', 'company', 'gender'],
639 "_id": "54ff69d95aa43325cc4eee9f",
641 "guid": "48c42a75-09a7-4671-86a1-e9a486bee6ab",
643 "balance": "$3,457.90",
646 "name": "Louella Morrison",
649 "email": "louellamorrison@zboo.com",
650 "phone": "+1 (803) 483-2686"
652 "_id": "54ff69d918616dbc093ca6cd",
654 "guid": "17b3f923-96b5-40c9-b3c1-721485e5bf80",
656 "balance": "$1,377.85",
659 "name": "Madden Coffey",
662 "email": "maddencoffey@comdom.com",
663 "phone": "+1 (850) 534-2345"
665 "_id": "54ff69d91a4917f9643178b0",
667 "guid": "f62da049-ab17-49fd-9f4c-3439d33cbb93",
669 "balance": "$3,798.71",
672 "name": "Chase Crawford",
674 "company": "PYRAMAX",
675 "email": "chasecrawford@pyramax.com",
676 "phone": "+1 (944) 494-2920"
678 "_id": "54ff69d9a63b6103f9e1530f",
680 "guid": "3640c402-f878-4f97-bbda-564de91d2dde",
682 "balance": "$2,480.02",
685 "name": "Johanna Pollard",
687 "company": "ZEROLOGY",
688 "email": "johannapollard@zerology.com",
689 "phone": "+1 (813) 512-3311"
691 "_id": "54ff69d9048722389ffde4bb",
693 "guid": "361089ba-e6dc-4701-b316-c7e977b21cb2",
695 "balance": "$3,973.38",
698 "name": "Malone Bentley",
700 "company": "DIGIPRINT",
701 "email": "malonebentley@digiprint.com",
702 "phone": "+1 (905) 435-2056"
704 "_id": "54ff69d9f75a66fb8e08b335",
706 "guid": "4cec529a-232a-4d5f-bedc-6141adc9f2fa",
708 "balance": "$3,956.60",
711 "name": "Jennings Rodgers",
714 "email": "jenningsrodgers@ludak.com",
715 "phone": "+1 (833) 543-2230"
717 "_id": "54ff69d974c1757e026721cb",
719 "guid": "6ce0c1e1-adc6-4cd0-b9c9-e2214e63aa8f",
721 "balance": "$2,874.71",
724 "name": "Mosley Mcgowan",
727 "email": "mosleymcgowan@amtap.com",
728 "phone": "+1 (990) 486-3229"
730 "_id": "54ff69d949a3873336e2e446",
732 "guid": "0f88d544-4aa0-4a05-a236-363c64b40988",
734 "balance": "$3,277.11",
737 "name": "Patton Whitaker",
739 "company": "IMMUNICS",
740 "email": "pattonwhitaker@immunics.com",
741 "phone": "+1 (944) 557-2615"
743 "_id": "54ff69d917f9642ab989e999",
745 "guid": "6577bb0c-f7ed-495f-a3db-7f7d35f6fe49",
747 "balance": "$1,091.47",
750 "name": "Neal Rivera",
752 "company": "NETILITY",
753 "email": "nealrivera@netility.com",
754 "phone": "+1 (816) 590-2358"
756 "_id": "54ff69d94573c1c04f0a9940",
758 "guid": "29be9274-d3cb-461f-a565-2374768689df",
760 "balance": "$1,885.75",
763 "name": "May Barron",
765 "company": "TELEPARK",
766 "email": "maybarron@telepark.com",
767 "phone": "+1 (958) 486-2915"
769 "_id": "54ff69d9c0e2f4aee9180984",
771 "guid": "479320d7-70ef-4f55-99b9-f3ef3a76b72e",
773 "balance": "$2,031.57",
776 "name": "Janna Howell",
778 "company": "PYRAMIS",
779 "email": "jannahowell@pyramis.com",
780 "phone": "+1 (823) 423-2342"
782 "_id": "54ff69d96e7f08b674de7cb9",
784 "guid": "9f6df0e4-b92c-4272-ad75-981305e9bb09",
786 "balance": "$2,279.79",
789 "name": "Nieves Short",
791 "company": "PETICULAR",
792 "email": "nievesshort@peticular.com",
793 "phone": "+1 (904) 556-3401"
795 "_id": "54ff69d9fb987df7ecf3d8ab",
797 "guid": "32c80cfd-d880-48a6-a3b0-e687c1e52b30",
799 "balance": "$3,830.03",
802 "name": "Tania Gillespie",
805 "email": "taniagillespie@austex.com",
806 "phone": "+1 (969) 527-3521"
808 "_id": "54ff69d9f586c6e7e9a08b4b",
810 "guid": "e6a006c4-1d5e-4a09-9dd6-496426fc4982",
812 "balance": "$3,411.76",
815 "name": "Joyner Suarez",
817 "company": "GEOFARM",
818 "email": "joynersuarez@geofarm.com",
819 "phone": "+1 (879) 571-3671"
821 "_id": "54ff69d94eaa44d993966048",
823 "guid": "00927bfa-dfd7-4850-bfd7-a2c25c476327",
825 "balance": "$2,402.44",
828 "name": "Hull Cooley",
830 "company": "ENERVATE",
831 "email": "hullcooley@enervate.com",
832 "phone": "+1 (910) 476-3577"
834 "_id": "54ff69d9b341bfef697e75ac",
836 "guid": "cd6a241c-35a4-4038-ae01-d32640719dc7",
838 "balance": "$2,889.76",
841 "name": "Cortez Fleming",
843 "company": "CIPROMOX",
844 "email": "cortezfleming@cipromox.com",
845 "phone": "+1 (964) 460-3159"
847 "_id": "54ff69d9a1f835d92cb8a017",
849 "guid": "45ad04ed-c154-4f16-a60b-d091e2ab8c13",
851 "balance": "$1,994.50",
854 "name": "Hazel Rodriguez",
856 "company": "SILODYNE",
857 "email": "hazelrodriguez@silodyne.com",
858 "phone": "+1 (962) 492-3107"
860 "_id": "54ff69d93989153e00dc5f02",
862 "guid": "b2a702d1-b47e-4f2b-98f2-4ab2e70b126f",
864 "balance": "$2,826.88",
867 "name": "Keri Pearson",
869 "company": "CENTICE",
870 "email": "keripearson@centice.com",
871 "phone": "+1 (858) 417-3541"
873 "_id": "54ff69d9377beb85134e2761",
875 "guid": "9bbb9bd7-d517-4bbb-a9b6-76f4fab0e5ab",
877 "balance": "$1,119.17",
880 "name": "Daisy Mcconnell",
882 "company": "MONDICIL",
883 "email": "daisymcconnell@mondicil.com",
884 "phone": "+1 (836) 470-3995"
886 "_id": "54ff69d999e3637d8287287f",
888 "guid": "c2dbece0-7554-4666-9378-805a625789db",
890 "balance": "$3,855.83",
893 "name": "Michelle Espinoza",
895 "company": "STEELFAB",
896 "email": "michelleespinoza@steelfab.com",
897 "phone": "+1 (882) 508-2376"
899 "_id": "54ff69d93826cfb24af88797",
901 "guid": "20be5f38-dc45-4a2f-8889-e9ba5ade8bed",
903 "balance": "$1,366.06",
906 "name": "Wall Sears",
909 "email": "wallsears@playce.com",
910 "phone": "+1 (846) 505-3782"
912 "_id": "54ff69d97f6a23afdd06849c",
914 "guid": "66fc61ba-38ef-4d49-862d-eb7d5fa68245",
916 "balance": "$2,379.73",
919 "name": "Caldwell Cain",
921 "company": "ORBIXTAR",
922 "email": "caldwellcain@orbixtar.com",
923 "phone": "+1 (831) 456-3297"
925 "_id": "54ff69d970154f7ac17b1438",
927 "guid": "85b6d275-3bff-4475-8c42-0c4f8ec2d385",
929 "balance": "$2,572.21",
932 "name": "Viola Mckay",
934 "company": "SPRINGBEE",
935 "email": "violamckay@springbee.com",
936 "phone": "+1 (901) 412-3479"
938 "_id": "54ff69d98ac67b26bce2d4a8",
940 "guid": "1d7460af-09a7-479a-8476-c3187a85ba8d",
942 "balance": "$2,467.39",
945 "name": "Gutierrez Conway",
947 "company": "ULTRASURE",
948 "email": "gutierrezconway@ultrasure.com",
949 "phone": "+1 (939) 438-3340"
951 "_id": "54ff69d93a9b81bdb7af6473",
953 "guid": "2da97cff-a16c-47a2-b9b0-d05d7ce8655d",
955 "balance": "$2,496.66",
958 "name": "Chandler Schmidt",
961 "email": "chandlerschmidt@zanity.com",
962 "phone": "+1 (822) 461-2247"
964 "_id": "54ff69d99e5b0a9b8db8da2b",
966 "guid": "b8081e85-d0a9-4575-9fdd-83baa0cfe79b",
968 "balance": "$3,044.12",
971 "name": "Bradshaw Ware",
974 "email": "bradshawware@bedder.com",
975 "phone": "+1 (932) 496-3718"
977 "_id": "54ff69d9a9827e6a14480e37",
979 "guid": "f0d49a25-fa17-4319-9f6a-9e88bb974755",
981 "balance": "$1,799.46",
984 "name": "Krystal Bush",
986 "company": "ZOLAREX",
987 "email": "krystalbush@zolarex.com",
988 "phone": "+1 (928) 577-3693"
990 "_id": "54ff69d97e57e2cab6272464",
992 "guid": "40860305-ba5a-44ec-9783-21d4a1a4927b",
994 "balance": "$1,856.24",
997 "name": "Madeline Grant",
1000 "email": "madelinegrant@apexia.com",
1001 "phone": "+1 (895) 521-2877"
1003 "_id": "54ff69d9431984c9fdb6f25a",
1005 "guid": "36d78b3f-a9dd-4180-bb66-c12a1147e92d",
1007 "balance": "$3,971.70",
1009 "eyeColor": "brown",
1010 "name": "Flora Ortiz",
1012 "company": "ACCUSAGE",
1013 "email": "floraortiz@accusage.com",
1014 "phone": "+1 (992) 561-2107"
1016 "_id": "54ff69d9c7c52140a4572361",
1018 "guid": "ba91387f-cab7-4487-a650-1bd94a650306",
1020 "balance": "$1,408.31",
1022 "eyeColor": "brown",
1023 "name": "Bobbie Atkins",
1025 "company": "GRAINSPOT",
1026 "email": "bobbieatkins@grainspot.com",
1027 "phone": "+1 (840) 497-2564"
1029 "_id": "54ff69d982ac77cad23cb28d",
1031 "guid": "7068b1b5-cb81-4127-b252-ccc3ff8d3b5a",
1033 "balance": "$3,375.36",
1035 "eyeColor": "brown",
1036 "name": "Mayer Osborne",
1038 "company": "DEEPENDS",
1039 "email": "mayerosborne@deepends.com",
1040 "phone": "+1 (952) 498-3050"
1042 "_id": "54ff69d99aefdc9cdd70a0df",
1044 "guid": "087771d5-4f39-46aa-bad7-7a051e807770",
1046 "balance": "$3,345.55",
1049 "name": "Sullivan Gibson",
1051 "company": "AQUASURE",
1052 "email": "sullivangibson@aquasure.com",
1053 "phone": "+1 (833) 463-3464"
1055 "_id": "54ff69d970a46678753362fc",
1057 "guid": "23e28ddc-a102-4f7c-b53b-4e3b8e45c64e",
1059 "balance": "$2,521.22",
1061 "eyeColor": "green",
1062 "name": "Nikki Whitley",
1064 "company": "FUTURIS",
1065 "email": "nikkiwhitley@futuris.com",
1066 "phone": "+1 (883) 561-2974"
1068 "_id": "54ff69d9f7ca2fa585ecbac6",
1070 "guid": "b711bd69-e672-48f5-8138-d3120bbedb40",
1072 "balance": "$2,388.02",
1074 "eyeColor": "green",
1075 "name": "Juana Doyle",
1077 "company": "HOUSEDOWN",
1078 "email": "juanadoyle@housedown.com",
1079 "phone": "+1 (847) 428-3271"
1081 "_id": "54ff69d9295e29d7b81a31be",
1083 "guid": "d393a87f-0789-4762-8ab8-d0fb66fc0fcb",
1085 "balance": "$1,126.53",
1087 "eyeColor": "green",
1088 "name": "Marci Shaffer",
1090 "company": "TRASOLA",
1091 "email": "marcishaffer@trasola.com",
1092 "phone": "+1 (929) 502-2533"
1094 "_id": "54ff69d9d8f81e674722a7d5",
1096 "guid": "281bbeea-5bef-4c37-8e2a-22481c9616c3",
1098 "balance": "$2,616.22",
1100 "eyeColor": "green",
1101 "name": "Maynard Watts",
1104 "email": "maynardwatts@aeora.com",
1105 "phone": "+1 (896) 418-3281"
1107 "_id": "54ff69d98f504a9e6c63dedb",
1109 "guid": "48698e76-8996-40d2-9abe-3fdd8fe98cf7",
1111 "balance": "$3,441.08",
1113 "eyeColor": "brown",
1114 "name": "Ollie Mooney",
1116 "company": "ACCUPRINT",
1117 "email": "olliemooney@accuprint.com",
1118 "phone": "+1 (811) 512-3357"
1120 "_id": "54ff69d9fc55f5cd34359bf9",
1122 "guid": "495c9d9e-95d8-48a2-83b4-c0f314f7aa26",
1124 "balance": "$1,134.21",
1126 "eyeColor": "green",
1127 "name": "Mattie Collins",
1130 "email": "mattiecollins@eargo.com",
1131 "phone": "+1 (800) 463-2474"
1133 "_id": "54ff69d94692077fe1587d2b",
1135 "guid": "9c259004-63be-4056-b291-7989cd582d41",
1137 "balance": "$1,429.64",
1139 "eyeColor": "brown",
1140 "name": "Weeks Mcdowell",
1142 "company": "ORBAXTER",
1143 "email": "weeksmcdowell@orbaxter.com",
1144 "phone": "+1 (913) 562-2677"
1146 "_id": "54ff69d95c44a1cefcb13a58",
1148 "guid": "44fa1564-9ef2-4503-b887-5f0f282b1bd3",
1150 "balance": "$1,340.36",
1152 "eyeColor": "brown",
1153 "name": "Hammond Valencia",
1156 "email": "hammondvalencia@izzby.com",
1157 "phone": "+1 (899) 577-2537"
1159 "_id": "54ff69d9c513f5b3c8ba15d7",
1161 "guid": "70c237d2-4a51-4b41-a5e2-e3bc1def56c5",
1163 "balance": "$2,979.67",
1165 "eyeColor": "brown",
1166 "name": "Ramona Fitzgerald",
1168 "company": "GOLISTIC",
1169 "email": "ramonafitzgerald@golistic.com",
1170 "phone": "+1 (965) 432-2851"
1172 "_id": "54ff69d9affa1d1749cd11d5",
1174 "guid": "80ef3c8e-b6ca-4048-9920-e651fa2a11b0",
1176 "balance": "$3,671.11",
1179 "name": "Hyde Alford",
1181 "company": "COFINE",
1182 "email": "hydealford@cofine.com",
1183 "phone": "+1 (806) 588-3800"
1185 "_id": "54ff69d9bd4f8a5bc1e34937",
1187 "guid": "3d5ed46a-0b40-4e2d-8438-ada9007f4d49",
1189 "balance": "$1,051.71",
1191 "eyeColor": "brown",
1192 "name": "Sonia Salazar",
1194 "company": "RENOVIZE",
1195 "email": "soniasalazar@renovize.com",
1196 "phone": "+1 (855) 547-2046"
1198 "_id": "54ff69d9c59ba53ca1b15c7f",
1200 "guid": "fe908aad-5474-4767-baf4-66a4e9fcf106",
1202 "balance": "$3,531.45",
1205 "name": "Johnston Nolan",
1208 "email": "johnstonnolan@velos.com",
1209 "phone": "+1 (950) 510-3191"
1211 "_id": "54ff69d96252c760ec1787a4",
1213 "guid": "efd7b2aa-804b-4463-a1e4-7931bcac6a18",
1215 "balance": "$2,238.60",
1217 "eyeColor": "green",
1218 "name": "Salazar Walters",
1220 "company": "GEEKNET",
1221 "email": "salazarwalters@geeknet.com",
1222 "phone": "+1 (834) 510-2779"
1224 "_id": "54ff69d9672f19a45f583e87",
1226 "guid": "25d3dddd-3983-49ae-b7f4-224e73bdacd9",
1228 "balance": "$2,092.02",
1230 "eyeColor": "brown",
1231 "name": "Emma Mcfarland",
1233 "company": "COWTOWN",
1234 "email": "emmamcfarland@cowtown.com",
1235 "phone": "+1 (858) 410-3273"
1237 "_id": "54ff69d902facac3a9fc9fbf",
1239 "guid": "e22f488c-a5ad-49d3-b9ec-f3dd9f287318",
1241 "balance": "$1,199.34",
1244 "name": "Lisa Sutton",
1246 "company": "EXTRAGEN",
1247 "email": "lisasutton@extragen.com",
1248 "phone": "+1 (815) 583-2428"
1250 "_id": "54ff69d958481e8cde608526",
1252 "guid": "aa976349-e7dc-4a38-aae7-e497c986c288",
1254 "balance": "$3,680.82",
1257 "name": "Blackburn Ingram",
1259 "company": "EXTREMO",
1260 "email": "blackburningram@extremo.com",
1261 "phone": "+1 (800) 407-3564"
1263 "_id": "54ff69d9e28a5207c6ce32f2",
1265 "guid": "e95d0949-d9e5-4665-bee0-29697d6b6e61",
1267 "balance": "$3,399.52",
1270 "name": "Preston Hardy",
1272 "company": "PROXSOFT",
1273 "email": "prestonhardy@proxsoft.com",
1274 "phone": "+1 (960) 444-3169"
1276 "_id": "54ff69d92e96909171f3e1b1",
1278 "guid": "0d6b5e73-7b1d-4c96-9a16-d73d0e74c364",
1280 "balance": "$2,920.49",
1282 "eyeColor": "green",
1283 "name": "Mia Mcgee",
1285 "company": "GEEKOLOGY",
1286 "email": "miamcgee@geekology.com",
1287 "phone": "+1 (921) 464-2944"
1289 "_id": "54ff69d94e56363d2f4110cb",
1291 "guid": "c355ad3a-a137-4dc4-9eeb-2ef6c5385076",
1293 "balance": "$2,738.07",
1295 "eyeColor": "brown",
1296 "name": "Doris Mccullough",
1298 "company": "PRIMORDIA",
1299 "email": "dorismccullough@primordia.com",
1300 "phone": "+1 (823) 470-2961"
1302 "_id": "54ff69d99d447d751c48fefc",
1304 "guid": "564a646d-4bd9-4e4b-bb64-522eea292751",
1306 "balance": "$1,966.01",
1308 "eyeColor": "brown",
1309 "name": "Fernandez Shepard",
1311 "company": "PAWNAGRA",
1312 "email": "fernandezshepard@pawnagra.com",
1313 "phone": "+1 (903) 453-3876"
1315 "_id": "54ff69d949dfc5b655d10e58",
1317 "guid": "4b07ab75-7a20-4515-9561-10323a712c37",
1319 "balance": "$3,447.93",
1321 "eyeColor": "green",
1322 "name": "Yvette Caldwell",
1324 "company": "OLUCORE",
1325 "email": "yvettecaldwell@olucore.com",
1326 "phone": "+1 (861) 417-2291"
1328 "_id": "54ff69d9e7ab8c4e8029f2d6",
1330 "guid": "73917fc2-53d6-4331-8ac9-ec65943d8e75",
1332 "balance": "$1,949.14",
1334 "eyeColor": "green",
1335 "name": "Gibson Molina",
1337 "company": "STREZZO",
1338 "email": "gibsonmolina@strezzo.com",
1339 "phone": "+1 (809) 485-2161"
1341 "_id": "54ff69d958fcd9a733351136",
1343 "guid": "ad310b11-965c-480e-9088-4d65c27d6d04",
1345 "balance": "$2,512.16",
1347 "eyeColor": "brown",
1348 "name": "Hicks Ferguson",
1350 "company": "COMTEXT",
1351 "email": "hicksferguson@comtext.com",
1352 "phone": "+1 (897) 565-2845"
1354 "_id": "54ff69d94a48d9b5a556f495",
1356 "guid": "17bca210-7a7f-4236-badd-4d52abc4d73f",
1358 "balance": "$3,950.51",
1360 "eyeColor": "brown",
1361 "name": "Dale Stephens",
1363 "company": "ZENSOR",
1364 "email": "dalestephens@zensor.com",
1365 "phone": "+1 (867) 474-3050"
1367 "_id": "54ff69d94f91296292db728e",
1369 "guid": "1cd712d4-b477-496d-aea6-d8b75f0aebcc",
1371 "balance": "$1,385.99",
1373 "eyeColor": "brown",
1374 "name": "Burris Nash",
1376 "company": "BRAINCLIP",
1377 "email": "burrisnash@brainclip.com",
1378 "phone": "+1 (873) 533-2943"
1380 "_id": "54ff69d9b8edd89a22d08814",
1382 "guid": "3cab0ec2-bece-43a2-b49f-1213cbd8bbb0",
1384 "balance": "$3,652.39",
1386 "eyeColor": "brown",
1387 "name": "Janie Harrington",
1390 "email": "janieharrington@zisis.com",
1391 "phone": "+1 (920) 441-3329"
1393 "_id": "54ff69d90550f9ffe4676013",
1395 "guid": "536e1f5f-474f-412e-a4ad-258a20a7cb77",
1397 "balance": "$3,937.99",
1399 "eyeColor": "brown",
1400 "name": "Beulah Burch",
1402 "company": "PLASTO",
1403 "email": "beulahburch@plasto.com",
1404 "phone": "+1 (904) 452-2143"
1406 "_id": "54ff69d920a5eed9e3d2cb29",
1408 "guid": "54a44fee-8614-492f-a1bd-c4a6248fce48",
1410 "balance": "$3,024.67",
1412 "eyeColor": "green",
1413 "name": "Osborne Carter",
1416 "email": "osbornecarter@artiq.com",
1417 "phone": "+1 (937) 431-2440"
1419 "_id": "54ff69d921ee90fcb998a583",
1421 "guid": "6e899cc3-f935-405d-995c-43635d3ed121",
1423 "balance": "$3,189.34",
1425 "eyeColor": "green",
1426 "name": "Rice Mcclain",
1428 "company": "EVENTIX",
1429 "email": "ricemcclain@eventix.com",
1430 "phone": "+1 (924) 448-3107"
1432 "_id": "54ff69d9c70b2ae884142f6f",
1434 "guid": "0e62a562-ced9-4922-9985-8c813a647d87",
1436 "balance": "$2,135.22",
1438 "eyeColor": "green",
1439 "name": "Jerri Knowles",
1441 "company": "VANTAGE",
1442 "email": "jerriknowles@vantage.com",
1443 "phone": "+1 (926) 566-3957"
1445 "_id": "54ff69d950ea8f13f7e0adc3",
1447 "guid": "70e8cbfa-9f24-4e58-b827-9d683765e383",
1449 "balance": "$1,360.09",
1452 "name": "Rose Chapman",
1454 "company": "STEELTAB",
1455 "email": "rosechapman@steeltab.com",
1456 "phone": "+1 (922) 514-3065"
1458 "_id": "54ff69d939f6877321458bf6",
1460 "guid": "ddb4264b-de31-464b-89ff-dc7b89c120c5",
1462 "balance": "$1,331.51",
1464 "eyeColor": "green",
1465 "name": "Larson Baxter",
1468 "email": "larsonbaxter@halap.com",
1469 "phone": "+1 (968) 451-2570"
1471 "_id": "54ff69d9e8c4ac69c408d5a5",
1473 "guid": "92f7f97e-469f-4e61-93ba-58d440f9bdee",
1475 "balance": "$3,771.47",
1477 "eyeColor": "green",
1478 "name": "Sweeney Shepherd",
1481 "email": "sweeneyshepherd@ovolo.com",
1482 "phone": "+1 (963) 413-2263"
1484 "_id": "54ff69d97caf29d7106b9a22",
1486 "guid": "ccff96f2-0dea-4d72-ae9b-5f2c5e1bccf8",
1488 "balance": "$3,022.08",
1491 "name": "Maribel Henry",
1493 "company": "CHILLIUM",
1494 "email": "maribelhenry@chillium.com",
1495 "phone": "+1 (814) 489-2410"
1497 "_id": "54ff69d9ea34002e4fc91d67",
1499 "guid": "133b0c0a-1517-487c-84b9-b0eb1fc8bfd1",
1501 "balance": "$1,995.00",
1503 "eyeColor": "brown",
1504 "name": "Deann Bray",
1506 "company": "VERTON",
1507 "email": "deannbray@verton.com",
1508 "phone": "+1 (847) 540-2423"
1510 "_id": "54ff69d9837c8279be6854e0",
1512 "guid": "d562f05e-b605-475e-b7ea-e38cf8c6b32f",
1514 "balance": "$1,035.74",
1516 "eyeColor": "brown",
1517 "name": "Hart Dillon",
1519 "company": "SOLAREN",
1520 "email": "hartdillon@solaren.com",
1521 "phone": "+1 (885) 540-3322"
1523 "_id": "54ff69d975a0df7615047dda",
1525 "guid": "7ec2a46e-9d61-42ad-9aa0-d06596232252",
1527 "balance": "$1,317.78",
1529 "eyeColor": "green",
1530 "name": "Daphne Mercado",
1532 "company": "TERRASYS",
1533 "email": "daphnemercado@terrasys.com",
1534 "phone": "+1 (915) 491-2470"
1536 "_id": "54ff69d9a6aafdf53cf7899d",
1538 "guid": "99c23548-6731-4236-a6b1-0455172d931b",
1540 "balance": "$3,395.05",
1543 "name": "Aguilar Ramsey",
1545 "company": "SONIQUE",
1546 "email": "aguilarramsey@sonique.com",
1547 "phone": "+1 (918) 407-2528"
1549 "_id": "54ff69d98368d84760f7ffb4",
1551 "guid": "919aa130-2a9a-4c18-9f82-a4cc5fa9d18f",
1553 "balance": "$3,961.57",
1556 "name": "Alyssa Garrett",
1559 "email": "alyssagarrett@zork.com",
1560 "phone": "+1 (816) 467-3019"
1562 "_id": "54ff69d97100f98d64a49826",
1564 "guid": "32301d04-6bd8-4db2-a1d0-b98ae4a53877",
1566 "balance": "$2,245.64",
1569 "name": "Vickie Castro",
1571 "company": "QUOTEZART",
1572 "email": "vickiecastro@quotezart.com",
1573 "phone": "+1 (894) 530-3406"
1575 "_id": "54ff69d944ae1efb286accdf",
1577 "guid": "a15615f1-2077-4d7f-800c-f19aad0cf45a",
1579 "balance": "$3,610.39",
1581 "eyeColor": "brown",
1582 "name": "Sheryl Cherry",
1584 "company": "TOYLETRY",
1585 "email": "sherylcherry@toyletry.com",
1586 "phone": "+1 (883) 527-2393"
1590 grid
= Ext
.create('Ext.grid.Panel', {
1595 renderTo
: document
.body
,
1615 dataIndex
: 'isActive'
1619 dataIndex
: 'eyeColor'
1622 dataIndex
: 'company'
1630 var normalView
= grid
.normalGrid
.getView(),
1631 lockedView
= grid
.lockedGrid
.getView(),
1632 lockedScroller
= lockedView
.getScrollable(),
1633 normalScroller
= normalView
.getScrollable(),
1634 normalRows
= normalView
.all
,
1635 lockedRows
= lockedView
.all
,
1636 navModel
= normalView
.getNavigationModel();
1638 waitsFor(function() {
1639 return normalView
.all
.getCount();
1643 navModel
.setPosition(new Ext
.grid
.CellContext(lockedView
).setPosition(0, 0));
1646 waitsFor(function() {
1647 var a
= Ext
.Element
.getActiveElement(),
1648 p
= navModel
.getPosition();
1651 // Scroll only when the last scroll signal has found both views and caused them to update
1652 if (navModel
.getCell() && (a
=== navModel
.getCell().dom
) && normalRows
.startIndex
=== lockedRows
.startIndex
&& lockedScroller
.getPosition().y
=== normalScroller
.getPosition().y
) {
1653 jasmine
.fireKeyEvent(a
, 'keydown', Ext
.event
.Event
.PAGE_DOWN
);
1656 // Scroll until the end
1657 return (navModel
.getPosition().rowIdx
=== store
.getCount() - 1);
1659 }, 'down arrow to scroll to the last row. 20 seconds expired', 20000);
1664 // Row count must be in sync
1665 expect(lockedRows
.getCount()).toBe(normalRows
.getCount());
1667 // view sizes must still be in sync
1668 expect(lockedView
.bufferedRenderer
.viewSize
).toBe(normalView
.bufferedRenderer
.viewSize
);
1670 // Every row must be the same height
1671 for (i
= normalRows
.startIndex
; i
<= normalRows
.endIndex
; i
++) {
1672 expect(normalRows
.item(i
).getHeight()).toBe(lockedRows
.item(i
).getHeight());
1678 describe('gridpanel', function () {
1679 describe('locking grid', function () {
1680 function doIt(reconfigure
) {
1683 dataIndex
: 'field1',
1688 dataIndex
: 'field2',
1692 dataIndex
: 'field3',
1696 dataIndex
: 'field4',
1700 dataIndex
: 'field5',
1703 xtype
: 'widgetcolumn',
1705 xtype
: 'progressbarwidget',
1707 textTpl
: ['{percent:number("0")}% capacity']
1715 fields
: ['field1', 'field2', 'field3', 'field4', 'field5'],
1716 data
: createData(100)
1719 view
= grid
.view
.normalView
;
1720 nodeCache
= view
.all
;
1723 grid
.reconfigure(null, columns
);
1726 waitsFor(function () {
1727 if (nodeCache
.endIndex
=== 99 && view
.bufferedRenderer
.getLastVisibleRowIndex() === 99) {
1731 // Scroll incrementally until the correct end point is found
1732 view
.scrollBy(null, 20);
1734 }, 'last node to scroll into view', 10000, 50);
1737 expect(view
.el
.down('.x-grid-item-container').getHeight() === view
.lockingPartner
.el
.down('.x-grid-item-container').getHeight()).toBe(true);
1741 it('should have the same height for each locking partner when scrolling', function () {
1745 it('should have the same height for each locking partner when scrolling after a reconfigure', function () {
1750 describe('locking grid with variableRowHeight', function () {
1751 itIE10p('should keep the row heights on both sides synchronized', function() {
1754 dataIndex
: 'field1',
1757 variableRowHeight
: true
1760 dataIndex
: 'field2',
1764 dataIndex
: 'field3',
1768 dataIndex
: 'field4',
1772 dataIndex
: 'field5',
1775 xtype
: 'widgetcolumn',
1777 xtype
: 'progressbarwidget',
1779 textTpl
: ['{percent:number("0")}% capacity']
1784 bufferedRendererInvocationCount
= 0,
1785 onSyncHeights = function() {
1786 var lockedItems
= lockedView
.all
.slice(),
1787 normalItems
= nodeCache
.slice(),
1788 lockedSize
= lockedItems
.length
,
1789 normalSize
= normalItems
.length
,
1793 // must be same number of rows
1794 expect(lockedSize
).toBe(normalSize
);
1796 for (i
= 0; allEqual
&& i
< lockedSize
; i
++) {
1797 allEqual
= allEqual
&& normalItems
[i
].offsetHeight
=== lockedItems
[i
].offsetHeight
;
1799 // All rows must be same size
1800 expect(allEqual
).toBe(true);
1801 bufferedRendererInvocationCount
++;
1804 // Make grid with small buffer zones.
1809 fields
: ['field1', 'field2', 'field3', 'field4', 'field5'],
1810 data
: createData(1000, true)
1813 lockedView
= grid
.view
.lockedView
;
1814 view
= grid
.view
.normalView
;
1815 nodeCache
= view
.all
;
1817 // Set up a sequence on the buffered renderers to check that all rows are always synced
1818 view
.bufferedRenderer
.syncRowHeights
= Ext
.Function
.createSequence(view
.bufferedRenderer
.syncRowHeights
, onSyncHeights
);
1819 lockedView
.bufferedRenderer
.syncRowHeights
= Ext
.Function
.createSequence(view
.bufferedRenderer
.syncRowHeights
, onSyncHeights
);
1821 waitsFor(function () {
1822 var reachedTargetRow
= nodeCache
.startIndex
<= 99 && nodeCache
.endIndex
>= 99;
1824 // If row 99 is in the nodeCache, we're done
1825 if (reachedTargetRow
) {
1826 return view
.getScrollY() === lockedView
.getScrollY() && nodeCache
.startIndex
=== lockedView
.all
.startIndex
&& lockedView
.position
=== view
.position
&& lockedView
.bodyTop
=== view
.bodyTop
;
1829 // Scroll incrementally until the correct end point is found
1830 view
.scrollBy(null, 20);
1832 }, 'row 99 to be rendered', 20000, 50);
1834 // Must have invoked the row syncher and the two body heights must be the same
1837 expect(bufferedRendererInvocationCount
).toBeGreaterThan(0);
1838 expect(view
.el
.down('.x-grid-item-container', true).offsetHeight
=== view
.lockingPartner
.el
.down('.x-grid-item-container', true).offsetHeight
).toBe(true);
1839 bufferedRendererInvocationCount
= 0;
1842 // Now teleport down to neat the bottom
1843 waitsFor(function () {
1844 var reachedTargetRow
= view
.bufferedRenderer
.getLastVisibleRowIndex() > 990;
1846 if (reachedTargetRow
) {
1847 return view
.getScrollY() === lockedView
.getScrollY() && view
.all
.startIndex
=== lockedView
.all
.startIndex
;
1850 // Scroll in teleporting chunks until the correct end point is found
1851 view
.scrollBy(null, 1000);
1853 }, 'row 990 to scroll into view', 30000, 100);
1855 // Scrolling is too fast for IE8, need to repaint the grid
1856 // so that measurements below will yield correct values
1864 // Must have invoked the row syncher and the two body heights must be the same
1866 expect(bufferedRendererInvocationCount
).toBeGreaterThan(0);
1868 var mainHeight
= view
.el
.down('.x-grid-item-container').getHeight(),
1869 partnerHeight
= view
.lockingPartner
.el
.down('.x-grid-item-container').getHeight();
1871 expect(partnerHeight
).toBe(mainHeight
);
1872 bufferedRendererInvocationCount
= 0;
1877 describe('locking grid with asymmetricRowHeight', function () {
1878 it('should keep the row heights on both sides synchronized', function() {
1879 // Note that we do NOT set variableRowHeight. All row heights are the same
1880 // even if one side drives the row height, and the sides need syncing.
1881 // This means BufferedRenderer can use simple arithmetic to find first/last visible row index.
1884 dataIndex
: 'field1',
1889 dataIndex
: 'field2',
1893 dataIndex
: 'field3',
1897 dataIndex
: 'field4',
1901 dataIndex
: 'field5',
1904 xtype
: 'widgetcolumn',
1906 xtype
: 'progressbarwidget',
1908 textTpl
: ['{percent:number("0")}% capacity']
1913 bufferedRendererInvocationCount
= 0,
1914 onSyncHeights = function() {
1915 var lockedItems
= lockedView
.all
.slice(),
1916 normalItems
= nodeCache
.slice(),
1917 lockedSize
= lockedItems
.length
,
1918 normalSize
= normalItems
.length
,
1922 // must be same number of rows
1923 expect(lockedSize
).toBe(normalSize
);
1925 for (i
= 0; allEqual
&& i
< lockedSize
; i
++) {
1926 allEqual
= allEqual
&& normalItems
[i
].offsetHeight
=== lockedItems
[i
].offsetHeight
;
1928 // All rows must be same size
1929 expect(allEqual
).toBe(true);
1930 bufferedRendererInvocationCount
++;
1933 // Make grid with small buffer zones.
1938 fields
: ['field1', 'field2', 'field3', 'field4', 'field5'],
1939 data
: createData(1000, false, true),
1941 // Make sure store.isGrouped() returns false
1942 // otherwise variableRowHeight will be detected
1943 groupField
: undefined
1946 lockedView
= grid
.view
.lockedView
;
1947 view
= grid
.view
.normalView
;
1948 nodeCache
= view
.all
;
1950 // Set up a sequence on the buffered renderers to check that all rows are always synced
1951 view
.bufferedRenderer
.syncRowHeights
= Ext
.Function
.createSequence(view
.bufferedRenderer
.syncRowHeights
, onSyncHeights
);
1952 lockedView
.bufferedRenderer
.syncRowHeights
= Ext
.Function
.createSequence(view
.bufferedRenderer
.syncRowHeights
, onSyncHeights
);
1954 waitsFor(function () {
1955 var reachedTargetRow
= nodeCache
.startIndex
<= 99 && nodeCache
.endIndex
>= 99;
1957 // If row 99 is in the nodeCache, we're done
1958 if (reachedTargetRow
) {
1959 return view
.getScrollY() === lockedView
.getScrollY() && nodeCache
.startIndex
=== lockedView
.all
.startIndex
&& lockedView
.position
=== view
.position
&& lockedView
.bodyTop
=== view
.bodyTop
;
1962 // Scroll incrementally until the correct end point is found
1963 view
.scrollBy(null, 20);
1965 }, 'row 99 to be rendered', 20000, 50);
1967 // Must have invoked the row syncher and the two body heights must be the same
1969 expect(bufferedRendererInvocationCount
).toBeGreaterThan(0);
1970 expect(view
.el
.down('.x-grid-item-container').getHeight() === view
.lockingPartner
.el
.down('.x-grid-item-container').getHeight()).toBe(true);
1971 bufferedRendererInvocationCount
= 0;
1974 // Now teleport down to neat the bottom
1975 waitsFor(function () {
1976 var reachedTargetRow
= view
.bufferedRenderer
.getLastVisibleRowIndex() > 990;
1978 if (reachedTargetRow
) {
1979 return view
.getScrollY() === lockedView
.getScrollY() && view
.all
.startIndex
=== lockedView
.all
.startIndex
;
1982 // Scroll in teleporting chunks until the correct end point is found
1983 view
.scrollBy(null, 1000);
1985 }, 'row 990 to scroll into view', 30000, 100);
1987 // Scrolling is too fast for IE8, need to repaint the grid
1988 // so that measurements below will yield correct values
1996 // Must have invoked the row syncher and the two body heights must be the same
1998 expect(bufferedRendererInvocationCount
).toBeGreaterThan(0);
2000 var mainHeight
= view
.el
.down('.x-grid-item-container').getHeight(),
2001 partnerHeight
= view
.lockingPartner
.el
.down('.x-grid-item-container').getHeight();
2003 expect(partnerHeight
).toBe(mainHeight
);
2004 bufferedRendererInvocationCount
= 0;
2009 describe('reconfiguring', function () {
2010 it('should never return `undefined` records when called in a metachange event', function () {
2011 // When reconfigure is called within a metchange event listener, the view is refreshed and
2012 // `undefined` is returned when AbstractView.getViewRange() -> PageMap.getRange() is called.
2013 // This isn't usually a problem, but if there are data records in the PageMap hash that don't exist
2014 // in a current page then `undefined` will be returned when instead an array is expected. This, of
2015 // course, will throw an exception when the rows are attempted to be created by the template in
2016 // AbstractView.refresh(). See EXTJS-12633.
2029 totalProperty
: 'totally',
2030 fields
: ['first', 'last'],
2045 leadingBufferZone
: 50,
2052 metachange: function (store
, meta
) {
2053 grid
.reconfigure(store
, meta
.columns
);
2059 // Overriding the PageMap method to return a value > 0 when there isn't a representative
2060 // page map will reproduce the bug.
2061 spyOn(store
.data
, 'getCount').andCallFake(function () {
2062 store
.totalCount
= 1000;
2067 completeWithData(successData
);
2069 expect(wasCalled
).toBe(true);
2072 describe('with grouping feature', function () {
2073 it('reconfiguring should bind the groupStore to the plugin', function () {
2074 // This test demonstrates that reconfiguring the grid will properly bind the feature's group
2075 // store to the plugin.
2077 // This bug only is reproducible when reconfigure is called on a grid with the buffered
2078 // renderer plugin and grouping feature. The bug was that the buffered renderer plugin
2079 // would bind the data store to the plugin rather than the group store (created when
2080 // there's a grouping feature).
2082 // See EXTJS-11860 and EXTJS-11892.
2084 features
: [{ftype
: 'grouping'}]
2087 grid
.reconfigure(store
);
2089 expect(grid
.view
.bufferedRenderer
.store
.isFeatureStore
).toBe(true);
2094 describe('refreshing the view', function () {
2095 describe('filtering out all records', function () {
2096 function makeData(len
) {
2102 for (i
= 0; i
< len
; i
++) {
2107 email
: str
+ '@sencha.com',
2108 phone
: '1-888-' + i
,
2116 function runTests(scroll
) {
2117 describe('scrolled = ' + scroll
, function () {
2118 it('should trigger a view refresh', function () {
2119 var wasCalled
= false;
2124 refresh: function () {
2132 plugin
.scrollTo(50);
2135 // Filter out all data.
2136 store
.filter('name', '______');
2138 expect(wasCalled
).toBe(true);
2141 it('should reset the view body', function () {
2147 plugin
.scrollTo(50);
2149 expect(plugin
.bodyTop
).toBeGreaterThan(0);
2150 expect(plugin
.scrollHeight
).toBeGreaterThan(0);
2153 // Filter out all data.
2154 store
.filter('name', '______');
2156 expect(plugin
.bodyTop
).toBe(0);
2157 expect(plugin
.scrollHeight
).toBe(0);
2168 describe('treepanel', function () {
2169 describe('expanding/collapsing', function () {
2170 it('should always render the view nodes when expanding', function () {
2177 nodeCache
= view
.all
;
2179 // Scroll until the last tree node is the last in the rendered block.
2180 waitsFor(function () {
2181 if (nodeCache
.endIndex
=== 99 && view
.bufferedRenderer
.getLastVisibleRowIndex() === 99) {
2185 // Scroll incrementally until the correct end point is found
2186 view
.scrollBy(null, 10);
2188 }, 'last node to scroll into view', 10000, 50);
2190 // Expanding that last node should append some child nodes to replenish the leading buffer zone.
2193 store
.getAt(99).expand();
2196 // Scroll until the last of those expanded children is the last in the rendered block.
2197 waitsFor(function () {
2198 if (nodeCache
.endIndex
=== 105) {
2202 // Scroll incrementally until the correct end point is found
2203 view
.scrollBy(null, 10);
2205 }, 'new last leaf node to scroll into view', 10000, 50);
2207 // Expanding that last node should append the child nodes to the view even though the buffer rendered block is the correct size already
2209 //expect(view.bufferedRenderer.position).toBe(view.el.dom.scrollTop);
2210 expect(view
.getRecord(view
.all
.last()).get('treeData')).toBe('Child of 99, number 6');
2212 // Now let's collapse the parent node by simulating a click on the elbow node.
2213 jasmine
.fireMouseEvent(nodeCache
.item(99).down('.x-tree-expander'), 'click');
2218 describe('loadMask config', function () {
2219 it('should create a mask by default if not configured', function () {
2228 expect(view
.loadMask
instanceof Ext
.LoadMask
).toBe(true);
2231 it('should honor the value if configured', function () {
2243 expect(view
.loadMask
).toBe(false);
2247 describe('Measuring row height', function() {
2248 it('should measure row height', function() {
2252 {'name': '<div style="height:30px">Lisa</div>', 'email': 'lisa@simpsons.com', 'phone': '555-111-1224', 'age': 14},
2253 {'name': 'Lisa', 'email': 'aunt_lisa@simpsons.com', 'phone': '555-111-1274', 'age': 34},
2254 {'name': 'Bart', 'email': 'bart@simpsons.com', 'phone': '555-222-1234', 'age': 12},
2255 {'name': 'Homer', 'email': 'homer@simpsons.com', 'phone': '555-222-1244', 'age': 44},
2256 {'name': 'Marge', 'email': 'marge@simpsons.com', 'phone': '555-222-1254', 'age': 41}
2260 // Should measure the row height be looking at the first row when we do NOT have variableRowHeight: true
2261 // EXTJS-15942 - did not measure, stayed at classic default of 21
2262 var row
= view
.all
.first(),
2263 rowHeight
= row
.getHeight();
2265 // In IE8 we're adding a bottom border on the rows and shifting the row up
2266 // at -border-width to compensate for that
2268 rowHeight
-= row
.getBorderWidth('b');
2271 expect(plugin
.rowHeight
).toBe(rowHeight
);
2276 describe('filtering the store', function () {
2279 afterEach(function() {
2280 Ext
.destroy(Hobbit
, store
);
2283 it('should reset the cached position so the grid-item-container is at the top of the view on filter', function () {
2284 Hobbit
= Ext
.define(null, {
2285 extend
: 'Ext.data.Model',
2291 rootProperty
: 'data'
2296 store
= new Ext
.data
.BufferedStore({
2299 leadingBufferZone
: 300,
2322 data
: makeData(100, 101)
2327 data
: makeData(100, 201)
2332 data
: makeData(100, 301)
2335 waitsFor(function () {
2336 view
.scrollBy(null, 10);
2337 return view
.all
.startIndex
<= 199 && view
.all
.endIndex
>= 199;
2338 }, 'row 199 to scroll into the rendered block', 10000);
2346 // Unfortunately, we're testing private properties here :(
2347 expect(plugin
.bodyTop
).toBe(0);
2348 expect(plugin
.position
).toBe(0);
2351 it('should reset the cached position so the grid-item-container is at the top of the view on clearFilter', function () {
2354 Hobbit
= Ext
.define(null, {
2355 extend
: 'Ext.data.Model',
2361 rootProperty
: 'data'
2366 store
= new Ext
.data
.Store({
2368 remoteFilter
: false,
2372 data
: makeData(5000)
2389 selModel
= grid
.selModel
;
2391 // Wait for first block to be rendered
2392 waitsFor(function() {
2393 return view
.all
.startIndex
=== 0 && view
.all
.getCount();
2398 // Only show the first 2500
2405 // We have filtered out the top 2500 IDs: 2501-5000
2406 expect(store
.getCount()).toBe(2500);
2408 // Click to select first row
2409 jasmine
.fireMouseEvent(view
.getCellByPosition({row
: 0, column
: 0}, true), 'click');
2410 expect(view
.selModel
.getSelection().length
).toBe(1);
2413 // Scroll all the way to the end
2414 waitsFor(function () {
2415 view
.scrollBy(null, 100);
2416 return view
.all
.endIndex
=== 2499;
2417 }, 'scroll to end', 10000);
2420 // Click to select from start to end.
2421 jasmine
.fireMouseEvent(view
.getCellByPosition({row
: 2499, column
: 0}, true), 'click', null, null, null, true);
2422 expect(view
.selModel
.getSelection().length
).toBe(2500);
2424 store
.remove(selModel
.getSelection());
2426 // All records gone. (There are still 2500) filtered out though...
2427 expect(store
.getCount()).toBe(0);
2429 // Should have gone to top
2430 expect(view
.all
.getCount()).toBe(0);
2431 expect(view
.getScrollY()).toBe(0);
2433 // Unfortunately, we're testing private properties here :(
2434 expect(plugin
.bodyTop
).toBe(0);
2435 expect(plugin
.position
).toBe(0);
2437 store
.clearFilter();
2439 // The 2500 filtered out records should jump back in
2440 expect(store
.getCount()).toBe(2500);
2442 // Unfortunately, we're testing private properties here :(
2443 expect(plugin
.bodyTop
).toBe(0);
2444 expect(plugin
.position
).toBe(0);
2449 describe("reloading store", function() {
2450 describe("from having items to not having items", function() {
2451 it("should not cause an error when reloading", function() {
2452 var store
= new Ext
.data
.BufferedStore({
2460 rootProperty
: 'data',
2461 totalProperty
: 'total'
2481 expect(view
.getNodes()).toEqual([]);
2484 it("should show emptyText if specified", function() {
2485 var store
= new Ext
.data
.BufferedStore({
2493 rootProperty
: 'data',
2494 totalProperty
: 'total'
2515 expect(grid
.el
.down('.' + grid
.emptyCls
, true)).hasHTML('Empty');
2519 describe('loading the bound store', function () {
2520 function testLockable(locked
) {
2523 xtype
: 'treecolumn',
2524 text
: 'Tree Column',
2547 it('should not scroll the view, non-locked grid', function () {
2549 testLockable(false);
2551 expect(view
.el
.dom
.scrollTop
).toBe(0);
2553 expect(view
.el
.dom
.scrollTop
).toBe(0);
2556 it('should not scroll the view, locked grid', function () {
2557 var lockedView
, normalView
;
2560 lockedViewDom
= view
.lockedView
.el
.dom
;
2561 normalViewDom
= view
.normalView
.el
.dom
;
2563 expect(lockedViewDom
.scrollTop
).toBe(0);
2564 expect(normalViewDom
.scrollTop
).toBe(0);
2566 expect(lockedViewDom
.scrollTop
).toBe(0);
2567 expect(normalViewDom
.scrollTop
).toBe(0);
2572 describe('Expanding view size', function() {
2575 afterEach(function() {
2579 it('should scroll to top when view size expands to encapsulate whole dataset', function() {
2580 var Person
= Ext
.define(null, {
2581 extend
: 'Ext.data.Model',
2587 rootProperty
: 'data'
2592 var store
= new Ext
.data
.Store({
2600 var store1
= new Ext
.data
.Store({
2609 var grid
= new Ext
.grid
.Panel({
2610 hideMode
: 'offsets',
2613 deferRowRender
: false,
2620 var grid1
= new Ext
.grid
.Panel({
2621 hideMode
: 'offsets',
2624 deferRowRender
: false,
2632 window
= new Ext
.window
.Window({
2650 var tabPanel
= window
.child('tabpanel');
2652 var view
= grid
.getView();
2654 // Scroll all the way to the end
2655 waitsFor(function () {
2656 view
.scrollBy(null, 100);
2657 return view
.all
.endIndex
=== view
.store
.getCount() - 1;
2658 }, 'scroll to end', 10000);
2661 view
.scrollBy(null, 100);
2663 tabPanel
.setActiveTab(1);
2666 grid
.store
.insert(0,{'title': 'hi',replycount
:5});
2667 grid
.store
.insert(0,{'title': 'hi2',replycount
:5});
2669 grid1
.store
.insert(0,{'title': 'hi',replycount
:5});
2670 grid1
.store
.insert(0,{'title': 'hi2',replycount
:5});
2672 tabPanel
.setActiveTab(0);
2674 window
.setHeight(940);
2677 // Scroll all the way to the start
2678 waitsFor(function () {
2679 view
.scrollBy(null, -100);
2680 return view
.getScrollY() === 0;;
2681 }, 'scroll to top', 10000);
2684 expect(view
.bufferedRenderer
.bodyTop
).toBe(0);
2689 describe('ensureVisible', function() {
2690 it('should work in a viewready listener', function() {
2694 dataIndex
: 'field1',
2698 dataIndex
: 'field2',
2702 dataIndex
: 'field3',
2706 dataIndex
: 'field4',
2713 viewready : function(grid
) {
2714 grid
.ensureVisible(grid
.getStore().last(), {
2715 callback: function() {
2722 fields
: ['field1', 'field2', 'field3', 'field4'],
2723 data
: createData(1000)
2726 waitsFor(function() {
2730 // Should have scrolled all the way to the end
2731 expect(view
.all
.endIndex
).toBe(999);
2732 expect(view
.bufferedRenderer
.getLastVisibleRowIndex()).toBe(999);