]> git.proxmox.com Git - extjs.git/blame - extjs/classic/classic/test/specs/grid/grid-celledit.js
add extjs 6.0.1 sources
[extjs.git] / extjs / classic / classic / test / specs / grid / grid-celledit.js
CommitLineData
6527f429
DM
1describe("grid-celledit", function(){\r
2 var webkitIt = Ext.isWebKit ? it : xit,\r
3 grid, GridEventModel = Ext.define(null, {\r
4 extend: 'Ext.data.Model',\r
5 fields: [\r
6 'field1',\r
7 'field2',\r
8 'field3',\r
9 'field4',\r
10 'field5',\r
11 'field6',\r
12 'field7',\r
13 'field8',\r
14 'field9',\r
15 'field10'\r
16 ]\r
17 }),\r
18 synchronousLoad = true,\r
19 proxyStoreLoad = Ext.data.ProxyStore.prototype.load,\r
20 loadStore;\r
21\r
22 function findCell(rowIdx, cellIdx) {\r
23 return grid.getView().getCellInclusive({\r
24 row: rowIdx,\r
25 column: cellIdx\r
26 }, true);\r
27 }\r
28 \r
29 function triggerCellMouseEvent(type, rowIdx, cellIdx, button, x, y) {\r
30 var target = findCell(rowIdx, cellIdx);\r
31\r
32 jasmine.fireMouseEvent(target, type, x, y, button);\r
33 }\r
34 \r
35 function triggerCellKeyEvent(type, rowIdx, cellIdx, key) {\r
36 var target = findCell(rowIdx, cellIdx);\r
37 jasmine.fireKeyEvent(target, type, key);\r
38 }\r
39\r
40 beforeEach(function() {\r
41 // Override so that we can control asynchronous loading\r
42 loadStore = Ext.data.ProxyStore.prototype.load = function() {\r
43 proxyStoreLoad.apply(this, arguments);\r
44 if (synchronousLoad) {\r
45 this.flushLoad.apply(this, arguments);\r
46 }\r
47 return this;\r
48 };\r
49 });\r
50\r
51 afterEach(function() {\r
52 // Undo the overrides.\r
53 Ext.data.ProxyStore.prototype.load = proxyStoreLoad;\r
54 });\r
55\r
56 function createSuite(buffered) {\r
57 describe(buffered ? "with buffered rendering" : "without buffered rendering", function() {\r
58 var colRef = [],\r
59 view, store, plugin, editorFocus;\r
60\r
61 var TAB = 9,\r
62 ENTER = 13,\r
63 ESC = 27,\r
64 PAGE_UP = 33,\r
65 PAGE_DOWN = 34,\r
66 END = 35,\r
67 HOME = 36,\r
68 LEFT = 37,\r
69 UP = 38,\r
70 RIGHT = 39,\r
71 DOWN = 40;\r
72 \r
73 function startEditing(row, column, skipWait) {\r
74 runs(function() {\r
75 triggerCellMouseEvent('dblclick', row, column);\r
76 });\r
77 \r
78 if (!skipWait) {\r
79 waitsFor(function() {\r
80 return !!plugin.activeEditor;\r
81 }, 'editing to start', 1000);\r
82 \r
83 runs(function() {\r
84 jasmine.waitForFocus(plugin.getActiveEditor().field);\r
85 });\r
86 }\r
87 }\r
88 \r
89 function triggerEditorKey(key) {\r
90 var target = plugin.getActiveEditor().field.inputEl.dom;\r
91 jasmine.fireKeyEvent(target, 'keydown', key);\r
92 jasmine.fireKeyEvent(target, 'keyup', key);\r
93 jasmine.fireKeyEvent(target, 'keypress', key);\r
94 }\r
95\r
96 function getRec(index) {\r
97 return store.getAt(index);\r
98 }\r
99 \r
100 function makeGrid(columns, pluginCfg, gridCfg) { \r
101 var data = [],\r
102 defaultCols = [],\r
103 i;\r
104 \r
105 if (!columns) {\r
106 for (i = 1; i <= 5; ++i) {\r
107 defaultCols.push({\r
108 name: 'F' + i,\r
109 dataIndex: 'field' + i,\r
110 field: {\r
111 xtype: 'textfield',\r
112 id: 'field' + i,\r
113 name: 'field' + i\r
114 }\r
115 });\r
116 }\r
117 }\r
118 \r
119 for (i = 1; i <= 10; ++i) {\r
120 data.push({\r
121 field1: i + '.' + 1,\r
122 field2: i + '.' + 2,\r
123 field3: i + '.' + 3,\r
124 field4: i + '.' + 4,\r
125 field5: i + '.' + 5,\r
126 field6: i + '.' + 6,\r
127 field7: i + '.' + 7,\r
128 field8: i + '.' + 8,\r
129 field9: i + '.' + 9,\r
130 field10: i + '.' + 10\r
131 });\r
132 }\r
133 \r
134 store = new Ext.data.Store({\r
135 model: GridEventModel,\r
136 data: data\r
137 });\r
138 \r
139 if (pluginCfg !== null) {\r
140 plugin = new Ext.grid.plugin.CellEditing(pluginCfg);\r
141 }\r
142\r
143 grid = new Ext.grid.Panel(Ext.apply({\r
144 columns: columns || defaultCols,\r
145 store: store,\r
146 selType: 'cellmodel',\r
147 plugins: plugin ? [plugin] : undefined,\r
148 width: 1000,\r
149 height: 500,\r
150 bufferedRenderer: buffered,\r
151 viewConfig: {\r
152 mouseOverOutBuffer: 0\r
153 },\r
154 renderTo: Ext.getBody()\r
155 }, gridCfg));\r
156 view = grid.getView();\r
157 colRef = grid.getColumnManager().getColumns();\r
158 }\r
159 \r
160 afterEach(function() {\r
161 Ext.destroy(grid, store);\r
162 plugin = grid = store = view = null;\r
163 colRef.length = 0;\r
164 Ext.data.Model.schema.clear();\r
165 });\r
166\r
167 describe("plugin configuration", function() {\r
168 it("should be able to add the plugin after rendering the grid", function() {\r
169 makeGrid(null, null);\r
170 plugin = new Ext.grid.plugin.CellEditing();\r
171 grid.addPlugin(plugin);\r
172 triggerCellMouseEvent('dblclick', 0, 0);\r
173 expect(plugin.editing).toBe(true);\r
174 expect(plugin.getActiveColumn()).toBe(colRef[0]);\r
175 expect(plugin.getActiveRecord()).toBe(store.getAt(0));\r
176 });\r
177 });\r
178\r
179 describe("resolveListenerScope", function() {\r
180 it("should resolve the scope to the grid", function() {\r
181 var fooScope = {\r
182 someFn: function() {}\r
183 };\r
184\r
185 spyOn(fooScope, 'someFn');\r
186\r
187 makeGrid(null, {\r
188 listeners: {\r
189 'beforeedit': 'someFn'\r
190 }\r
191 });\r
192 grid.resolveSatelliteListenerScope = function() {\r
193 return fooScope;\r
194 };\r
195 triggerCellMouseEvent('dblclick', 0, 0);\r
196 expect(fooScope.someFn).toHaveBeenCalled();\r
197 });\r
198 });\r
199\r
200 describe("basic editing", function(){\r
201 var editorParentNode;\r
202\r
203 beforeEach(function(){\r
204 makeGrid();\r
205 editorParentNode = view.getCellByPosition({\r
206 row: 0,\r
207 column: 0\r
208 }, true);\r
209 });\r
210\r
211 // https://sencha.jira.com/browse/EXTJS-18773\r
212 it('should scroll a record that is outside the rendered block into view and edit it', function() {\r
213 var data = [],\r
214 i;\r
215\r
216 for (i = 11; i <= 1000; ++i) {\r
217 data.push({\r
218 field1: i + '.' + 1,\r
219 field2: i + '.' + 2,\r
220 field3: i + '.' + 3,\r
221 field4: i + '.' + 4,\r
222 field5: i + '.' + 5,\r
223 field6: i + '.' + 6,\r
224 field7: i + '.' + 7,\r
225 field8: i + '.' + 8,\r
226 field9: i + '.' + 9,\r
227 field10: i + '.' + 10\r
228 });\r
229 }\r
230 store.add(data);\r
231 plugin.startEdit(900, 0);\r
232 expect(plugin.editing).toBe(true);\r
233 expect(plugin.getEditor(plugin.context.record, plugin.context.column).isVisible()).toBe(true);\r
234 expect(plugin.getActiveColumn()).toBe(colRef[0]);\r
235 expect(plugin.getActiveRecord()).toBe(store.getAt(900));\r
236 });\r
237\r
238 it("should trigger the edit on cell interaction", function(){\r
239 triggerCellMouseEvent('dblclick', 0, 0);\r
240 expect(plugin.editing).toBe(true);\r
241 expect(plugin.getActiveColumn()).toBe(colRef[0]);\r
242 expect(plugin.getActiveRecord()).toBe(store.getAt(0));\r
243\r
244 // CellEditors should be rendered into the grid view which they are editing, and should scroll along with the view.\r
245 expect(plugin.getActiveEditor().el.dom.parentNode).toBe(editorParentNode);\r
246 }); \r
247 \r
248 it("should be able to be trigger by passing a position", function(){\r
249 plugin.startEditByPosition({\r
250 row: 0,\r
251 column: 2\r
252 });\r
253 expect(plugin.editing).toBe(true);\r
254 expect(plugin.getActiveColumn()).toBe(colRef[2]);\r
255 expect(plugin.getActiveRecord()).toBe(store.getAt(0));\r
256 });\r
257 \r
258 it("should be able to be trigger by passing a record/header", function(){\r
259 plugin.startEdit(store.getAt(1), colRef[3]);\r
260 expect(plugin.editing).toBe(true);\r
261 expect(plugin.getActiveColumn()).toBe(colRef[3]);\r
262 expect(plugin.getActiveRecord()).toBe(store.getAt(1));\r
263 });\r
264 \r
265 it("should use the specified column field", function(){\r
266 triggerCellMouseEvent('dblclick', 0, 0);\r
267 expect(plugin.getActiveEditor().field.getId()).toBe('field1');\r
268 });\r
269 \r
270 it("should get the underlying record value", function(){\r
271 triggerCellMouseEvent('dblclick', 0, 1);\r
272 expect(plugin.getActiveEditor().field.getValue()).toBe('1.2'); \r
273 });\r
274 \r
275 it("should cancel editing on removing a column", function(){\r
276 var col0Editor;\r
277\r
278 triggerCellMouseEvent('dblclick', 0, 0);\r
279 col0Editor = plugin.getActiveEditor();\r
280 expect(col0Editor.isVisible()).toBe(true);\r
281\r
282 grid.headerCt.remove(colRef[0]);\r
283\r
284 // That editor must have been blurred and hidden\r
285 expect(col0Editor.isVisible()).toBe(false);\r
286 });\r
287\r
288 it("should continue editing after a refresh", function(){\r
289 triggerCellMouseEvent('dblclick', 0, 0);\r
290\r
291 // Editing must have started.\r
292 expect(plugin.editing).toBe(true); \r
293 expect(plugin.getActiveEditor().isVisible()).toBe(true); \r
294 expect(plugin.getActiveEditor().field.getValue()).toBe('1.1'); \r
295\r
296 // No refresh the grid\r
297 grid.view.refresh();\r
298\r
299 // Wait for *sometimes* asynchronous blur/focus events to get done\r
300 waits(100);\r
301\r
302 // Editor must be there undamaged\r
303 runs(function() {\r
304 expect(plugin.editing).toBe(true); \r
305 expect(plugin.getActiveEditor().isVisible()).toBe(true); \r
306 expect(plugin.getActiveEditor().field.getValue()).toBe('1.1'); \r
307 });\r
308 });\r
309 });\r
310\r
311 describe("clean up", function() {\r
312 function makeCleanupSuite(withLocking) {\r
313 describe(withLocking ? "with locking" : "without locking", function() {\r
314 var CM;\r
315\r
316 beforeEach(function() {\r
317 CM = Ext.ComponentManager;\r
318 });\r
319\r
320 afterEach(function() {\r
321 CM = null;\r
322 });\r
323\r
324 describe("not activated", function() {\r
325 function makeRenderSuite(beforeRender) {\r
326 describe(beforeRender ? "before render" : "after render", function() {\r
327 it("should destroy an editor instance", function() {\r
328 var count = CM.getCount();\r
329\r
330 makeGrid([{\r
331 dataIndex: 'field1',\r
332 locked: withLocking,\r
333 editor: new Ext.form.field.Text()\r
334 }, {\r
335 dataIndex: 'field2'\r
336 }], {}, {\r
337 renderTo: beforeRender ? null : Ext.getBody()\r
338 });\r
339 grid.destroy();\r
340 expect(CM.getCount()).toBe(count);\r
341 });\r
342\r
343 it("should destroy a field instance", function() {\r
344 var count = CM.getCount();\r
345\r
346 makeGrid([{\r
347 dataIndex: 'field1',\r
348 locked: withLocking,\r
349 field: new Ext.form.field.Text()\r
350 }, {\r
351 dataIndex: 'field2'\r
352 }], {}, {\r
353 renderTo: beforeRender ? null : Ext.getBody()\r
354 });\r
355 grid.destroy();\r
356 expect(CM.getCount()).toBe(count);\r
357 });\r
358\r
359 it("should not leave an instance with an editor config", function() {\r
360 var count = CM.getCount();\r
361\r
362 makeGrid([{\r
363 dataIndex: 'field1',\r
364 locked: withLocking,\r
365 editor: {\r
366 xtype: 'textfield'\r
367 }\r
368 }, {\r
369 dataIndex: 'field2'\r
370 }], {}, {\r
371 renderTo: beforeRender ? null : Ext.getBody()\r
372 });\r
373 grid.destroy();\r
374 expect(CM.getCount()).toBe(count);\r
375 });\r
376\r
377 it("should not leave an instance with a field config", function() {\r
378 var count = CM.getCount();\r
379\r
380 makeGrid([{\r
381 dataIndex: 'field1',\r
382 locked: withLocking,\r
383 field: {\r
384 xtype: 'textfield'\r
385 }\r
386 }, {\r
387 dataIndex: 'field2'\r
388 }], {}, {\r
389 renderTo: beforeRender ? null : Ext.getBody()\r
390 });\r
391 grid.destroy();\r
392 expect(CM.getCount()).toBe(count);\r
393 });\r
394 });\r
395 }\r
396 makeRenderSuite(false);\r
397 makeRenderSuite(true);\r
398 });\r
399\r
400 describe("after activation", function() {\r
401 it("should destroy an editor instance", function() {\r
402 var count = CM.getCount();\r
403\r
404 makeGrid([{\r
405 dataIndex: 'field1',\r
406 locked: withLocking,\r
407 editor: new Ext.form.field.Text()\r
408 }, {\r
409 dataIndex: 'field2'\r
410 }]);\r
411 triggerCellMouseEvent('click', 0, 0);\r
412 grid.destroy();\r
413 expect(CM.getCount()).toBe(count);\r
414 });\r
415\r
416 it("should destroy a field instance", function() {\r
417 var count = CM.getCount();\r
418\r
419 makeGrid([{\r
420 dataIndex: 'field1',\r
421 locked: withLocking,\r
422 field: new Ext.form.field.Text()\r
423 }, {\r
424 dataIndex: 'field2'\r
425 }]);\r
426 triggerCellMouseEvent('click', 0, 0);\r
427 grid.destroy();\r
428 expect(CM.getCount()).toBe(count);\r
429 });\r
430\r
431 it("should destroy an editor config", function() {\r
432 var count = CM.getCount();\r
433\r
434 makeGrid([{\r
435 dataIndex: 'field1',\r
436 locked: withLocking,\r
437 editor: {\r
438 xtype: 'textfield'\r
439 }\r
440 }, {\r
441 dataIndex: 'field2'\r
442 }]);\r
443 triggerCellMouseEvent('click', 0, 0);\r
444 grid.destroy();\r
445 expect(CM.getCount()).toBe(count);\r
446 });\r
447\r
448 it("should destroy a field instance", function() {\r
449 var count = CM.getCount();\r
450\r
451 makeGrid([{\r
452 dataIndex: 'field1',\r
453 locked: withLocking,\r
454 field: {\r
455 xtype: 'textfield'\r
456 }\r
457 }, {\r
458 dataIndex: 'field2'\r
459 }]);\r
460 triggerCellMouseEvent('click', 0, 0);\r
461 grid.destroy();\r
462 expect(CM.getCount()).toBe(count);\r
463 });\r
464 });\r
465 });\r
466 }\r
467 makeCleanupSuite(false);\r
468 makeCleanupSuite(true);\r
469 });\r
470 \r
471 describe('non-editable cells', function () {\r
472 function makeCols(){\r
473 var i = 1,\r
474 cols = [];\r
475\r
476 for (; i <= 10; i++) {\r
477 if (i % 2 === 0) {\r
478 cols.push(new Ext.grid.column.Column({\r
479 name: 'F' + i,\r
480 dataIndex: 'field' + i,\r
481 field: {\r
482 xtype: 'textfield',\r
483 id: 'field' + i,\r
484 name: 'field' + i\r
485 }\r
486 }));\r
487 } else {\r
488 cols.push(new Ext.grid.column.Column({\r
489 name: 'F' + i,\r
490 dataIndex: 'field' + i\r
491 }));\r
492 }\r
493\r
494 colRef[i - 1] = cols[i - 1];\r
495 }\r
496\r
497 return cols;\r
498 }\r
499\r
500 it('should not trigger a call to .startEdit() if a non-editable cell is clicked', function () {\r
501 makeGrid(\r
502 makeCols()\r
503 );\r
504\r
505 spyOn(plugin, 'startEdit');\r
506 triggerCellMouseEvent('dblclick', 0, 0);\r
507\r
508 expect(plugin.startEdit).not.toHaveBeenCalled();\r
509 }); \r
510\r
511 describe('using checkboxmodel as selType', function () {\r
512 beforeEach(function () {\r
513 makeGrid(\r
514 makeCols(),\r
515 { clicksToEdit: 1 },\r
516 {selType: 'checkboxmodel'}\r
517 );\r
518 });\r
519\r
520 it('should not trigger a call to startEdit() if the checkboxmodel is clicked', function () {\r
521 spyOn(plugin, 'startEdit');\r
522 triggerCellMouseEvent('click', 0, 0);\r
523\r
524 expect(plugin.startEdit).not.toHaveBeenCalled();\r
525 }); \r
526\r
527 xit('should move to the next editable cell when tabbing', function () {\r
528 triggerCellMouseEvent('click', 0, 2);\r
529 triggerEditorKey(TAB);\r
530\r
531 expect(plugin.getActiveColumn()).toBe(colRef[3]);\r
532 });\r
533 }); \r
534 });\r
535\r
536 describe("events", function() {\r
537 beforeEach(function() {\r
538 makeGrid();\r
539 });\r
540 \r
541 describe("beforeedit", function(){\r
542 it("should fire the event", function() {\r
543 var called = false;\r
544 \r
545 runs(function() {\r
546 plugin.on('beforeedit', function() {\r
547 called = true;\r
548 });\r
549 \r
550 startEditing(0, 0);\r
551 });\r
552 \r
553 runs(function() {\r
554 expect(called).toBe(true);\r
555 });\r
556 });\r
557 \r
558 it("should fire the event with the plugin & an event context", function() {\r
559 var p, context;\r
560 \r
561 runs(function() {\r
562 plugin.on('beforeedit', function(a1, a2) {\r
563 p = a1;\r
564 context = a2;\r
565 });\r
566 \r
567 startEditing(0, 0);\r
568 });\r
569 \r
570 runs(function() {\r
571 expect(p).toBe(plugin);\r
572 expect(context.colIdx).toBe(0);\r
573 expect(context.column).toBe(colRef[0]);\r
574 expect(context.field).toBe('field1');\r
575 expect(context.grid).toBe(grid);\r
576 expect(context.originalValue).toBe('1.1');\r
577 expect(context.record).toBe(getRec(0));\r
578 expect(context.row).toBe(view.getRow(0));\r
579 expect(context.rowIdx).toBe(0);\r
580 expect(context.store).toBe(store);\r
581 expect(context.value).toBe('1.1');\r
582 });\r
583 });\r
584\r
585 it("should prevent editing if false is returned from the plugin's beforeedit event", function() {\r
586 runs(function() {\r
587 plugin.on('beforeedit', function(plugin, context) {\r
588 // Only allow editing on rows other than the first\r
589 return context.rowIdx > 0;\r
590 });\r
591 \r
592 startEditing(0, 0, true);\r
593 });\r
594 \r
595 runs(function() {\r
596 expect(plugin.editing).toBeFalsy();\r
597 \r
598 // Editing must still start on other rows\r
599 startEditing(1, 0);\r
600 });\r
601 \r
602 runs(function() {\r
603 expect(plugin.editing).toBeTruthy();\r
604 });\r
605 });\r
606 \r
607 it("should prevent editing if false is returned from the CellEditor's beforestartedit event", function() {\r
608 runs(function() {\r
609 plugin.getEditor(store.getAt(0), colRef[0]).on('beforestartedit', function(editor, boundEl, value) {\r
610 // Only allow editing on rows other than the first\r
611 return editor.context.rowIdx > 0;\r
612 });\r
613 \r
614 startEditing(0, 0, true);\r
615 });\r
616 \r
617 runs(function() {\r
618 expect(plugin.editing).toBeFalsy();\r
619 \r
620 // Editing must still start on other rows\r
621 startEditing(1, 0);\r
622 });\r
623 \r
624 runs(function() {\r
625 expect(plugin.editing).toBeTruthy();\r
626 });\r
627 });\r
628 \r
629 it("should prevent editing if context.cancel is set", function() {\r
630 runs(function() {\r
631 plugin.on('beforeedit', function(p, context){\r
632 context.cancel = true;\r
633 });\r
634 \r
635 startEditing(0, 0, true);\r
636 });\r
637 \r
638 runs(function() {\r
639 expect(plugin.editing).toBeFalsy();\r
640 });\r
641 });\r
642 }); \r
643 \r
644 describe("canceledit", function() {\r
645 it("should fire the event when editing is cancelled", function() {\r
646 var called = false;\r
647 \r
648 runs(function() {\r
649 plugin.on('canceledit', function(p, context){\r
650 called = true;\r
651 });\r
652 \r
653 startEditing(0, 0);\r
654 });\r
655 \r
656 runs(function() {\r
657 // Cancellation is synchronous so we don't have to wait\r
658 plugin.cancelEdit();\r
659 \r
660 expect(called).toBe(true);\r
661 expect(plugin.editing).toBe(false);\r
662 });\r
663 });\r
664 \r
665 it("should pass the plugin and the context", function() {\r
666 var p, context;\r
667 \r
668 runs(function() {\r
669 plugin.on('canceledit', function(a1, a2){\r
670 p = a1;\r
671 context = a2;\r
672 });\r
673 \r
674 startEditing(0, 0);\r
675 });\r
676 \r
677 runs(function() {\r
678 plugin.cancelEdit();\r
679 \r
680 expect(p).toBe(plugin);\r
681 expect(context.colIdx).toBe(0);\r
682 expect(context.column).toBe(colRef[0]);\r
683 expect(context.field).toBe('field1');\r
684 expect(context.grid).toBe(grid);\r
685 expect(context.originalValue).toBe('1.1');\r
686 expect(context.record).toBe(getRec(0));\r
687 expect(context.row).toBe(view.getRow(0));\r
688 expect(context.rowIdx).toBe(0);\r
689 expect(context.store).toBe(store);\r
690 expect(context.value).toBe('1.1');\r
691 });\r
692 });\r
693 });\r
694 \r
695 describe("validateedit", function() {\r
696 it("should fire the validateedit event before edit", function() {\r
697 var calledFirst = false,\r
698 editFired = false;\r
699 \r
700 runs(function() {\r
701 plugin.on('validateedit', function() {\r
702 calledFirst = !editFired;\r
703 });\r
704 \r
705 plugin.on('edit', function(p, context) {\r
706 editFired = true;\r
707 });\r
708 \r
709 startEditing(0, 0);\r
710 });\r
711 \r
712 runs(function() {\r
713 plugin.completeEdit();\r
714 \r
715 expect(calledFirst).toBe(true);\r
716 });\r
717 }); \r
718 \r
719 it("should pass the plugin and the context", function(){\r
720 var p, context;\r
721 \r
722 runs(function() {\r
723 plugin.on('validateedit', function(a1, a2){\r
724 p = a1;\r
725 context = a2;\r
726 });\r
727 startEditing(0, 0);\r
728 });\r
729 \r
730 runs(function() {\r
731 plugin.getActiveEditor().field.setValue('foo');\r
732 plugin.completeEdit();\r
733 \r
734 expect(p).toBe(plugin);\r
735 expect(context.colIdx).toBe(0);\r
736 expect(context.column).toBe(colRef[0]);\r
737 expect(context.field).toBe('field1');\r
738 expect(context.grid).toBe(grid);\r
739 expect(context.originalValue).toBe('1.1');\r
740 expect(context.record).toBe(getRec(0));\r
741 expect(context.row).toBe(view.getRow(0));\r
742 expect(context.rowIdx).toBe(0);\r
743 expect(context.store).toBe(store);\r
744 expect(context.value).toBe('foo');\r
745\r
746 // The flag set in beforeitemupdate listener of the editor\r
747 // should not still be set\r
748 expect(view.refreshing).toBe(false);\r
749 });\r
750 }); \r
751 \r
752 it("should cancel the edit if we return false", function(){\r
753 var called = false;\r
754 \r
755 runs(function() {\r
756 plugin.on('validateedit', function(){\r
757 return false;\r
758 });\r
759 plugin.on('edit', function(p, context){\r
760 called = true;\r
761 });\r
762 \r
763 startEditing(0, 0);\r
764 });\r
765 \r
766 runs(function() {\r
767 plugin.completeEdit();\r
768 \r
769 expect(plugin.editing).toBe(false);\r
770 expect(called).toBe(false);\r
771 });\r
772 });\r
773 \r
774 it("should cancel the edit if we set context.cancel", function(){\r
775 var called = false;\r
776\r
777 plugin.on('validateedit', function(p, context){\r
778 context.cancel = true;\r
779 });\r
780 plugin.on('edit', function(p, context){\r
781 called = true;\r
782 });\r
783 triggerCellMouseEvent('dblclick', 0, 0);\r
784 plugin.completeEdit();\r
785 expect(plugin.editing).toBe(false);\r
786 expect(called).toBe(false);\r
787 });\r
788 });\r
789 \r
790 describe("edit", function(){\r
791 it("should fire the edit event", function(){\r
792 var called = false;\r
793\r
794 plugin.on('edit', function(p, context){\r
795 called = true;\r
796 });\r
797 triggerCellMouseEvent('dblclick', 0, 0);\r
798 plugin.completeEdit();\r
799 expect(plugin.editing).toBe(false);\r
800 expect(called).toBe(true);\r
801 }); \r
802 \r
803 it("should pass the plugin and the context", function(){\r
804 var p, context;\r
805\r
806 plugin.on('edit', function(a1, a2){\r
807 p = a1;\r
808 context = a2;\r
809 });\r
810 triggerCellMouseEvent('dblclick', 0, 0);\r
811 plugin.getActiveEditor().field.setValue('foo');\r
812 plugin.completeEdit();\r
813 expect(p).toBe(plugin);\r
814 expect(context.colIdx).toBe(0);\r
815 expect(context.column).toBe(colRef[0]);\r
816 expect(context.field).toBe('field1');\r
817 expect(context.grid).toBe(grid);\r
818 expect(context.originalValue).toBe('1.1');\r
819 expect(context.record).toBe(getRec(0));\r
820 expect(context.row).toBe(view.getRow(0));\r
821 expect(context.rowIdx).toBe(0);\r
822 expect(context.store).toBe(store);\r
823 expect(context.value).toBe('foo');\r
824 });\r
825 \r
826 it("should update the value in the model", function(){\r
827\r
828 triggerCellMouseEvent('dblclick', 0, 0);\r
829 plugin.getActiveEditor().field.setValue('foo');\r
830 plugin.completeEdit();\r
831 expect(getRec(0).get('field1')).toBe('foo');\r
832 });\r
833 });\r
834\r
835 describe('beforerefresh', function () {\r
836 it('should check for the presence of dom.parentNode before executing beforeViewRefresh callback', function () {\r
837 // See EXTJSIV-12487 && EXTJSIV-11713.\r
838 var column = grid.visibleColumnManager.getColumns()[0],\r
839 dummy = jasmine.createSpy('dummy');\r
840\r
841 store.on('sort', dummy);\r
842\r
843 plugin.startEdit(0, 0);\r
844\r
845 // dom.parentNode will be removed in CellEditor.beforeViewRefresh().\r
846 column.sort();\r
847 // Sorting again (and refreshing the view) would trigger the bug.\r
848 column.sort();\r
849\r
850 expect(dummy.callCount).toBe(2);\r
851\r
852 store.un('sort', dummy);\r
853 });\r
854 });\r
855 });\r
856\r
857 describe("positioning", function() {\r
858 function getCellXY(rowIdx, colIdx) {\r
859 return Ext.fly(view.getCell(store.getAt(rowIdx), colRef[colIdx])).getXY();\r
860 }\r
861\r
862 it("should position correctly on first render", function() {\r
863 makeGrid();\r
864 triggerCellMouseEvent('dblclick', 0, 3);\r
865 expect(plugin.getActiveEditor().getXY()).toEqual(getCellXY(0, 3));\r
866 });\r
867\r
868 it("should position correctly on subsequent shows", function() {\r
869 makeGrid();\r
870 triggerCellMouseEvent('dblclick', 0, 3);\r
871 plugin.getActiveEditor().completeEdit();\r
872 triggerCellMouseEvent('dblclick', 0, 0);\r
873 expect(plugin.getActiveEditor().getXY()).toEqual(getCellXY(0, 0));\r
874 plugin.completeEdit();\r
875 triggerCellMouseEvent('dblclick', 2, 1);\r
876 expect(plugin.getActiveEditor().getXY()).toEqual(getCellXY(2, 1));\r
877 });\r
878 });\r
879 \r
880 describe("dynamic editors", function(){\r
881 beforeEach(function() {\r
882 // Suppress console warnings about Trigger field being deprecated\r
883 spyOn(Ext.log, 'warn');\r
884 });\r
885 \r
886 it("should allow the editor to change dynamically", function(){\r
887 makeGrid();\r
888 colRef[0].setEditor(new Ext.form.field.Trigger());\r
889 triggerCellMouseEvent('dblclick', 0, 0);\r
890 expect(plugin.getActiveEditor().field.getXType()).toBe('triggerfield');\r
891 });\r
892 \r
893 it("should allow the editor to change in the beforeedit event", function() {\r
894 makeGrid();\r
895 plugin.on('beforeedit', function(){\r
896 colRef[0].setEditor(new Ext.form.field.Trigger());\r
897 }); \r
898 triggerCellMouseEvent('dblclick', 0, 0);\r
899 expect(plugin.getActiveEditor().field.getXType()).toBe('triggerfield');\r
900 });\r
901 \r
902 it("should allow us to set an editor if one wasn't there before", function() {\r
903 var called = false;\r
904 makeGrid([{\r
905 dataIndex: 'field1'\r
906 }, {\r
907 dataIndex: 'field2',\r
908 field: 'textfield'\r
909 }]);\r
910 colRef = grid.getColumnManager().getColumns();\r
911 colRef[0].setEditor(new Ext.form.field.Text());\r
912 plugin.on('beforeedit', function() {\r
913 called = true;\r
914 });\r
915 triggerCellMouseEvent('dblclick', 0, 0);\r
916 expect(called).toBe(true);\r
917 });\r
918 \r
919 it("should allow us to clear out an editor", function() {\r
920 var called = false;\r
921 makeGrid();\r
922 colRef[0].setEditor(null);\r
923 plugin.on('beforeedit', function() {\r
924 called = true;\r
925 });\r
926 triggerCellMouseEvent('dblclick', 0, 0);\r
927 expect(called).toBe(false);\r
928 });\r
929 \r
930 it("should destroy the old field", function() {\r
931 var field = new Ext.form.field.Text();\r
932 \r
933 makeGrid([{\r
934 dataIndex: 'field1',\r
935 field: field\r
936 }]); \r
937 colRef = grid.getColumnManager().getColumns();\r
938 colRef[0].setEditor(new Ext.form.field.Text());\r
939 expect(field.destroyed).toBe(true);\r
940 });\r
941 });\r
942 \r
943 describe("hidden columns", function(){\r
944 beforeEach(function(){\r
945 makeGrid([{\r
946 dataIndex: 'field1',\r
947 field: {\r
948 xtype: 'textfield',\r
949 itemId: 'field1'\r
950 }\r
951 }, {\r
952 hidden: true,\r
953 dataIndex: 'field2',\r
954 field: {\r
955 xtype: 'textfield',\r
956 itemId: 'field2'\r
957 }\r
958 }, {\r
959 hidden: true,\r
960 dataIndex: 'field3',\r
961 field: {\r
962 xtype: 'textfield',\r
963 itemId: 'field3'\r
964 }\r
965 }, {\r
966 dataIndex: 'field4',\r
967 field: {\r
968 xtype: 'textfield',\r
969 itemId: 'field4'\r
970 }\r
971 }, {\r
972 dataIndex: 'field5',\r
973 field: {\r
974 xtype: 'textfield',\r
975 itemId: 'field5'\r
976 }\r
977 }, {\r
978 hidden: true,\r
979 dataIndex: 'field6',\r
980 field: {\r
981 xtype: 'textfield',\r
982 itemId: 'field6'\r
983 }\r
984 }, {\r
985 dataIndex: 'field7',\r
986 field: {\r
987 xtype: 'textfield',\r
988 itemId: 'field7'\r
989 }\r
990 }]);\r
991 colRef = grid.getColumnManager().getColumns();\r
992 });\r
993 \r
994 it("should start the edit before any hidden columns", function(){\r
995 var c;\r
996 plugin.on('beforeedit', function(p, context){\r
997 c = context;\r
998 });\r
999 triggerCellMouseEvent('dblclick', 0, 0);\r
1000 expect(c.column).toBe(colRef[0]);\r
1001 expect(c.value).toBe('1.1');\r
1002 });\r
1003 \r
1004 it("should start the edit in between hidden columns", function(){\r
1005 var c;\r
1006 plugin.on('beforeedit', function(p, context){\r
1007 c = context;\r
1008 });\r
1009 triggerCellMouseEvent('dblclick', 0, 3);\r
1010 expect(c.column).toBe(colRef[3]);\r
1011 expect(c.value).toBe('1.4');\r
1012 });\r
1013 \r
1014 it("should start the edit after hidden columns", function(){\r
1015 var c;\r
1016 plugin.on('beforeedit', function(p, context){\r
1017 c = context;\r
1018 });\r
1019 triggerCellMouseEvent('dblclick', 0, 6);\r
1020 expect(c.column).toBe(colRef[6]);\r
1021 expect(c.value).toBe('1.7');\r
1022 });\r
1023 \r
1024 describe("calling on a hidden column", function() {\r
1025 it("should choose the next visible column when called on a hidden column", function() {\r
1026 var c;\r
1027 plugin.on('beforeedit', function(p, context){\r
1028 c = context;\r
1029 });\r
1030 plugin.startEditByPosition({\r
1031 row: 0,\r
1032 column: 1\r
1033 });\r
1034 expect(c.column).toBe(colRef[3]);\r
1035 });\r
1036 \r
1037 it("should use a previous visible column if next is not available", function() {\r
1038 colRef[6].hide();\r
1039 var c;\r
1040 plugin.on('beforeedit', function(p, context){\r
1041 c = context;\r
1042 });\r
1043 plugin.startEditByPosition({\r
1044 row: 0,\r
1045 column: 5\r
1046 });\r
1047 expect(c.column).toBe(colRef[4]);\r
1048 });\r
1049 });\r
1050 \r
1051 describe("dynamic", function(){\r
1052 it("should trigger an edit after showing the column", function(){\r
1053 colRef[2].show();\r
1054 var c;\r
1055 plugin.on('beforeedit', function(p, context){\r
1056 c = context;\r
1057 });\r
1058 triggerCellMouseEvent('dblclick', 0, 2);\r
1059 expect(c.column).toBe(colRef[2]);\r
1060 expect(c.value).toBe('1.3');\r
1061 }); \r
1062 \r
1063 it("should trigger an edit after hiding a column", function(){\r
1064 colRef[3].hide();\r
1065 var c;\r
1066 plugin.on('beforeedit', function(p, context){\r
1067 c = context;\r
1068 });\r
1069 triggerCellMouseEvent('dblclick', 0, 4);\r
1070 expect(c.column).toBe(colRef[4]);\r
1071 expect(c.value).toBe('1.5');\r
1072 }); \r
1073 });\r
1074 });\r
1075 \r
1076 describe("locking", function(){\r
1077 beforeEach(function(){\r
1078 makeGrid([{\r
1079 locked: true,\r
1080 dataIndex: 'field1',\r
1081 field: {\r
1082 xtype: 'textfield'\r
1083 }\r
1084 }, {\r
1085 locked: true,\r
1086 dataIndex: 'field2',\r
1087 field: {\r
1088 xtype: 'textfield'\r
1089 }\r
1090 }, {\r
1091 dataIndex: 'field3',\r
1092 field: {\r
1093 xtype: 'textfield'\r
1094 }\r
1095 }, {\r
1096 dataIndex: 'field4',\r
1097 field: {\r
1098 xtype: 'textfield'\r
1099 }\r
1100 }]);\r
1101 colRef = grid.getColumnManager().getColumns();\r
1102 });\r
1103 \r
1104 // The API clones the plugins, need to do weird\r
1105 // stuff to actually access the events. Gross.\r
1106 it("should trigger an edit on the locked part", function(){\r
1107 var context,\r
1108 activeView = grid.lockedGrid.getView();\r
1109\r
1110 plugin = grid.plugins[0];\r
1111 plugin.on('beforeedit', function(a1, a2){\r
1112 context = a2;\r
1113 });\r
1114 triggerCellMouseEvent('dblclick', 0, 0);\r
1115 expect(context.colIdx).toBe(0);\r
1116 expect(context.column).toBe(colRef[0]);\r
1117 expect(context.field).toBe('field1');\r
1118 expect(context.grid).toBe(grid.lockedGrid);\r
1119 expect(context.originalValue).toBe('1.1');\r
1120 expect(context.record).toBe(getRec(0));\r
1121 expect(context.row).toBe(activeView.getRow(0));\r
1122 expect(context.rowIdx).toBe(0);\r
1123 expect(context.store).toBe(store);\r
1124 expect(context.value).toBe('1.1');\r
1125\r
1126 // CellEditors should be rendered into the grid view which they are editing, and should scroll along with the view.\r
1127 expect(plugin.getActiveEditor().el.dom.parentNode).toBe(context.cell);\r
1128 });\r
1129\r
1130 it("should trigger an edit on the unlocked part", function(){\r
1131 var context,\r
1132 activeView = grid.normalGrid.getView();\r
1133\r
1134 plugin = grid.plugins[0];\r
1135 plugin.on('beforeedit', function(a1, a2){\r
1136 context = a2;\r
1137 });\r
1138 triggerCellMouseEvent('dblclick', 0, 3);\r
1139 // Local col idx\r
1140 expect(context.colIdx).toBe(1);\r
1141 expect(context.column).toBe(colRef[3]);\r
1142 expect(context.field).toBe('field4');\r
1143 expect(context.grid).toBe(grid.normalGrid);\r
1144 expect(context.originalValue).toBe('1.4');\r
1145 expect(context.record).toBe(getRec(0));\r
1146 expect(context.row).toBe(activeView.getRow(0));\r
1147 expect(context.rowIdx).toBe(0);\r
1148 expect(context.store).toBe(store);\r
1149 expect(context.value).toBe('1.4');\r
1150\r
1151 // CellEditors should be rendered into the grid view which they are editing, and should scroll along with the view.\r
1152 expect(plugin.getActiveEditor().el.dom.parentNode).toBe(context.cell);\r
1153 });\r
1154\r
1155 it("should move the editor when a column is locked", function(){\r
1156 var context,\r
1157 activeView = grid.normalGrid.getView();\r
1158\r
1159 plugin = grid.plugins[0];\r
1160 plugin.on({\r
1161 beforeedit: function(a1, a2){\r
1162 context = a2;\r
1163 }\r
1164 });\r
1165 triggerCellMouseEvent('dblclick', 0, 2);\r
1166\r
1167 // CellEditors should be rendered into the grid view which they are editing, and should scroll along with the view.\r
1168 expect(plugin.getActiveEditor().el.dom.parentNode).toBe(context.cell);\r
1169\r
1170 plugin.completeEdit();\r
1171\r
1172 grid.lock(colRef[2]);\r
1173 activeView = grid.lockedGrid.getView();\r
1174\r
1175 // Edit the same column. It's now in the locked side.\r
1176 // Everything should still work\r
1177 triggerCellMouseEvent('dblclick', 0, 2);\r
1178 // Local col idx\r
1179 expect(context.colIdx).toBe(2);\r
1180 expect(context.column).toBe(colRef[2]);\r
1181 expect(context.field).toBe('field3');\r
1182 expect(context.grid).toBe(grid.lockedGrid);\r
1183 expect(context.originalValue).toBe('1.3');\r
1184 expect(context.record).toBe(getRec(0));\r
1185 expect(context.row).toBe(activeView.getRow(activeView.all.first()));\r
1186 expect(context.rowIdx).toBe(0);\r
1187 expect(context.store).toBe(store);\r
1188 expect(context.value).toBe('1.3');\r
1189\r
1190 // CellEditors should be rendered into the grid view which they are editing, and should scroll along with the view.\r
1191 expect(plugin.getActiveEditor().el.dom.parentNode).toBe(context.cell);\r
1192 });\r
1193 });\r
1194 \r
1195 describe("reconfigure", function() {\r
1196 var old;\r
1197 beforeEach(function() {\r
1198 makeGrid();\r
1199 old = [];\r
1200 Ext.Array.forEach(grid.getColumnManager().getColumns(), function(col) {\r
1201 old.push(col.getEditor()); \r
1202 });\r
1203 grid.reconfigure(null, [{\r
1204 dataIndex: 'field1',\r
1205 field: {\r
1206 id: 'newEd'\r
1207 }\r
1208 }, {\r
1209 dataIndex: 'field2'\r
1210 }]);\r
1211 colRef = grid.getColumnManager().getColumns();\r
1212 });\r
1213 \r
1214 it("should destroy old editors", function() {\r
1215 Ext.Array.forEach(old, function(item){\r
1216 expect(item.destroyed).toBe(true); \r
1217 });\r
1218 });\r
1219 \r
1220 it("should update columns with no editors", function() {\r
1221 triggerCellMouseEvent('dblclick', 0, 1);\r
1222 expect(plugin.editing).toBeFalsy();\r
1223 }); \r
1224 \r
1225 it("should use new editors", function() {\r
1226 triggerCellMouseEvent('dblclick', 0, 0);\r
1227 expect(plugin.getActiveEditor().field.getId()).toBe('newEd');\r
1228 expect(plugin.editing).toBe(true);\r
1229 });\r
1230 });\r
1231 \r
1232 describe("key handling", function() {\r
1233 beforeEach(function() {\r
1234 makeGrid();\r
1235 });\r
1236 \r
1237 it("should move to the next cell when tabbing", function() {\r
1238 startEditing(0, 0);\r
1239 \r
1240 runs(function() {\r
1241 plugin.getActiveEditor().field.setValue('foobar');\r
1242 triggerEditorKey(TAB);\r
1243 });\r
1244\r
1245 // https://sencha.jira.com/browse/EXTJS-17224\r
1246 // We need to wait for the beforeitemupdate to push the CellEditor out\r
1247 // And the asynchronous blur to happen to test this bug.\r
1248 waits(100);\r
1249\r
1250 // New editor should be visible and focused\r
1251 waitsFor(function() {\r
1252 // The next editor must be the active one and must be focused\r
1253 return plugin.getActiveColumn() === colRef[1] && Ext.Element.getActiveElement() === plugin.getActiveEditor().field.inputEl.dom;\r
1254 });\r
1255 });\r
1256 \r
1257 it("should move to the next row if at the last cell", function() {\r
1258 startEditing(0, 4);\r
1259 \r
1260 runs(function() {\r
1261 triggerEditorKey(TAB);\r
1262 });\r
1263 \r
1264 waitsFor(function() {\r
1265 return plugin.getActiveColumn() === colRef[0] &&\r
1266 plugin.getActiveRecord() === getRec(1);\r
1267 });\r
1268 });\r
1269 \r
1270 it("should complete the edit on enter", function() {\r
1271 startEditing(1, 1);\r
1272 \r
1273 runs(function() {\r
1274 plugin.getActiveEditor().field.setValue('foo');\r
1275 plugin.getActiveEditor().specialKeyDelay = 0;\r
1276 \r
1277 triggerEditorKey(ENTER);\r
1278 \r
1279 expect(getRec(1).get('field2')).toBe('foo');\r
1280 });\r
1281 });\r
1282 \r
1283 it("should cancel the edit on ESC", function() {\r
1284 startEditing(1, 1);\r
1285 \r
1286 runs(function() {\r
1287 plugin.getActiveEditor().field.setValue('foo');\r
1288 plugin.getActiveEditor().specialKeyDelay = 0;\r
1289 triggerEditorKey(ESC);\r
1290 expect(getRec(1).get('field2')).toBe('2.2');\r
1291 });\r
1292 });\r
1293 \r
1294 it('should navigate to the other side when tabbing at a locking boundary', function() {\r
1295 grid.destroy();\r
1296 makeGrid([{\r
1297 locked: true,\r
1298 dataIndex: 'field1',\r
1299 field: {\r
1300 xtype: 'textfield'\r
1301 }\r
1302 }, {\r
1303 dataIndex: 'field4',\r
1304 field: {\r
1305 xtype: 'textfield'\r
1306 }\r
1307 }]);\r
1308\r
1309 startEditing(0, 0);\r
1310 \r
1311 runs(function() {\r
1312\r
1313 // We should be editing in the locked side\r
1314 expect(plugin.getActiveEditor().context.view === grid.lockedGrid.view).toBe(true);\r
1315 expect(plugin.getActiveEditor().context.isEqual(grid.lockedGrid.view.actionPosition)).toBe(true);\r
1316\r
1317 // This should Tab into the normal side\r
1318 triggerEditorKey(TAB);\r
1319 });\r
1320\r
1321 // Wait for the active editor's context's view to be the normal view\r
1322 waitsFor(function() {\r
1323 return plugin.getActiveEditor().context.view === grid.normalGrid.view;\r
1324 });\r
1325 runs(function() {\r
1326 // locked grid's actiobPosition is null indicating that it does not contain the action position\r
1327 // even though it is actionable mode\r
1328 expect(grid.lockedGrid.view.actionPosition).toBeNull();\r
1329 expect(plugin.getActiveEditor().context.isEqual(grid.normalGrid.view.actionPosition)).toBe(true);\r
1330 });\r
1331 });\r
1332 });\r
1333 \r
1334 describe("misc", function() {\r
1335 it("should not have the editors participate as part of a form", function() {\r
1336 makeGrid(undefined, undefined, {\r
1337 renderTo: null\r
1338 });\r
1339 var form = new Ext.form.Panel({\r
1340 renderTo: Ext.getBody(),\r
1341 items: [{\r
1342 name: 'foo',\r
1343 xtype: 'textfield',\r
1344 value: 'v1'\r
1345 }, {\r
1346 name: 'bar',\r
1347 xtype: 'textfield',\r
1348 value: 'v2'\r
1349 }, grid]\r
1350 });\r
1351 \r
1352 triggerCellMouseEvent('dblclick', 0, 0);\r
1353 \r
1354 var values = form.getForm().getValues();\r
1355 expect(values).toEqual({\r
1356 foo: 'v1',\r
1357 bar: 'v2'\r
1358 });\r
1359 \r
1360 form.destroy();\r
1361 }); \r
1362 });\r
1363\r
1364 describe("locking with group headers", function() {\r
1365 it("should start edit after moving a locked column to a group header in the unlocked view (EXTJSIV-11294)", function() {\r
1366 makeGrid([{ \r
1367 dataIndex: 'name', \r
1368 locked: true, \r
1369 editor: 'textfield' \r
1370 }, {\r
1371 itemId: 'ct',\r
1372 columns: [{ \r
1373 dataIndex: 'email', \r
1374 flex: 1 \r
1375 }, {\r
1376 dataIndex: 'phone' \r
1377 }] \r
1378 }]);\r
1379\r
1380 var headerCt = grid.headerCt;\r
1381\r
1382 grid.unlock(headerCt.getHeaderAtIndex(0), 1, grid.down('#ct'));\r
1383 plugin = grid.view.editingPlugin;\r
1384 plugin.startEdit(0, 1);\r
1385 expect(plugin.editing).toBe(true);\r
1386 expect(plugin.getActiveColumn()).toBe(headerCt.getHeaderAtIndex(1));\r
1387 expect(plugin.getActiveRecord()).toBe(store.getAt(0));\r
1388 });\r
1389 });\r
1390\r
1391 describe('Autorepeat TAB in ungrouped grid', function() {\r
1392 function isEditing(rowIndex, columnIndex) {\r
1393 return plugin.editing && plugin.activeColumn === colRef[columnIndex] && plugin.activeRecord === store.getAt(rowIndex);\r
1394 }\r
1395\r
1396 var buttonFocused = false;\r
1397\r
1398 beforeEach(function() {\r
1399 makeGrid();\r
1400 grid.addDocked({\r
1401 dock: 'top',\r
1402 xtype: 'toolbar',\r
1403 items: [{\r
1404 text: "button",\r
1405 listeners: {\r
1406 focus: function() {\r
1407 buttonFocused = true;\r
1408 }\r
1409 }\r
1410 }]\r
1411 });\r
1412 // Make last column non editable\r
1413 delete colRef[4].field;\r
1414 });\r
1415\r
1416 // Only Webkit is good enough to run these fast event firing tests\r
1417 webkitIt('should not lose track of editing position during repeated tabbing', function() {\r
1418 // Begin editing 1.1\r
1419\r
1420 triggerCellMouseEvent('dblclick', 0, 0);\r
1421 waitsFor(function() {\r
1422 return isEditing(0, 0);\r
1423 });\r
1424 runs(function() {\r
1425 expect(plugin.editing).toBe(true);\r
1426 // Tab to 1.2\r
1427 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1428 });\r
1429 waitsFor(function() {\r
1430 return isEditing(0, 1);\r
1431 }, 'move to cell 0, 1');\r
1432 runs(function() {\r
1433 // Tab to 1.3\r
1434 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1435 });\r
1436 waitsFor(function() {\r
1437 return isEditing(0, 2);\r
1438 }, 'move to cell 0, 2');\r
1439 runs(function() {\r
1440 // Tab to 1.4\r
1441 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1442 });\r
1443 waitsFor(function() {\r
1444 return isEditing(0, 3);\r
1445 }, 'move to cell 0, 3');\r
1446 runs(function() {\r
1447 // Tab to 1.5. This is not editiable, so will skip to 1, 0\r
1448 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1449 });\r
1450 waitsFor(function() {\r
1451 return isEditing(1, 0);\r
1452 }, 'move to cell 1, 0');\r
1453 runs(function() {\r
1454 // Tab to 2.2\r
1455 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1456 });\r
1457 waitsFor(function() {\r
1458 return isEditing(1, 1);\r
1459 }, 'move to cell 1, 1');\r
1460 runs(function() {\r
1461 // Tab to 2.3\r
1462 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1463 });\r
1464 waitsFor(function() {\r
1465 return isEditing(1, 2);\r
1466 }, 'move to cell 1, 2');\r
1467 runs(function() {\r
1468 // Tab to 2.4\r
1469 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1470 });\r
1471 waitsFor(function() {\r
1472 return isEditing(1, 3);\r
1473 }, 'move to cell 1, 3');\r
1474 runs(function() {\r
1475 // Tab to 2.5. This is not editiable, so will skip to 2, 0\r
1476 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1477 });\r
1478 waitsFor(function() {\r
1479 return isEditing(2, 0);\r
1480 }, 'move to cell 2, 0');\r
1481 runs(function() {\r
1482\r
1483 // Focus sohuld not have escaped from the grid into the button\r
1484 expect(buttonFocused).toBe(false);\r
1485\r
1486 // Check that the navigation did exactly what we expected\r
1487 expect(plugin.getActiveColumn()).toBe(colRef[0]);\r
1488 expect(plugin.getActiveRecord()).toBe(store.getAt(2));\r
1489 });\r
1490 }); // eo: it\r
1491 });\r
1492\r
1493 describe('Autorepeat TAB in grouped grid', function() {\r
1494 webkitIt("should not lose track of editing position when autotabbing over group headers", function() {\r
1495 makeGrid([{\r
1496 dataIndex: 'field1',\r
1497 editor: 'textfield'\r
1498 }, {\r
1499 dataIndex: 'field2',\r
1500 editor: 'textfield'\r
1501 }, {\r
1502 dataIndex: 'field3',\r
1503 editor: 'textfield'\r
1504 }], {}, {\r
1505 features: {\r
1506 ftype: 'grouping'\r
1507 }\r
1508 });\r
1509 plugin.startEdit(0, 0);\r
1510 expect(plugin.editing).toBe(true);\r
1511\r
1512 // Check we are at 0,0\r
1513 expect(plugin.getActiveColumn()).toBe(colRef[0]);\r
1514 expect(plugin.getActiveRecord()).toBe(store.getAt(0));\r
1515\r
1516 // To 0,1\r
1517 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1518 waits(20);\r
1519 runs(function() {\r
1520 // To 0,2\r
1521 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1522 });\r
1523 waits(20);\r
1524 runs(function() {\r
1525 // To 1,0\r
1526 jasmine.fireKeyEvent(Ext.Element.getActiveElement(), 'keydown', TAB);\r
1527 });\r
1528 waits(20);\r
1529 runs(function() {\r
1530 expect(plugin.getActiveColumn()).toBe(colRef[0]);\r
1531 expect(plugin.getActiveRecord()).toBe(store.getAt(1));\r
1532 });\r
1533 });\r
1534 });\r
1535\r
1536 describe('refreshing view', function() {\r
1537 beforeEach(function(){\r
1538 // Must wait for async focus events from previous suite to complete.\r
1539 waits(10);\r
1540 \r
1541 runs(function() {\r
1542 makeGrid();\r
1543 });\r
1544 });\r
1545\r
1546 it('CellEditor should survive a refresh in active state', function() {\r
1547 var refreshCounter;\r
1548\r
1549 plugin.startEdit(0, 0);\r
1550 expect(plugin.editing).toBe(true);\r
1551 expect(plugin.getActiveEditor().isVisible()).toBe(true);\r
1552\r
1553 refreshCounter = view.refreshCounter;\r
1554 view.refresh();\r
1555 \r
1556 // A refresh must have taken place\r
1557 expect(view.refreshCounter).toEqual(refreshCounter + 1);\r
1558\r
1559 // Editing must still be active\r
1560 expect(plugin.editing).toBe(true);\r
1561 expect(plugin.getActiveEditor().isVisible()).toBe(true);\r
1562 });\r
1563 });\r
1564\r
1565 describe('Dragging out of an active cell editor in a locking view, and mouseup in the locking partner view', function() {\r
1566 it('should not throw an error when dragging out of an active cell editor in a locking view, and mouseup in the locking partner view', function() {\r
1567 makeGrid([{\r
1568 locked: true,\r
1569 dataIndex: 'field1',\r
1570 field: {\r
1571 xtype: 'textfield'\r
1572 }\r
1573 }, {\r
1574 locked: true,\r
1575 dataIndex: 'field2',\r
1576 field: {\r
1577 xtype: 'textfield'\r
1578 }\r
1579 }, {\r
1580 dataIndex: 'field3',\r
1581 field: {\r
1582 xtype: 'textfield'\r
1583 }\r
1584 }, {\r
1585 dataIndex: 'field4',\r
1586 field: {\r
1587 xtype: 'textfield'\r
1588 }\r
1589 }]);\r
1590 plugin = grid.view.editingPlugin;\r
1591 colRef = grid.getColumnManager().getColumns();\r
1592 var cell00 = findCell(0, 0),\r
1593 cell00xy = Ext.fly(cell00).getAnchorXY('c'),\r
1594 inputField,\r
1595 editorxy;\r
1596\r
1597 plugin.startEdit(0, 0);\r
1598 expect(plugin.editing).toBe(true);\r
1599 expect(plugin.getActiveEditor().isVisible()).toBe(true);\r
1600\r
1601 // Mousedown in the input field, and drag accross to the other side\r
1602 inputField = plugin.getActiveEditor().field.inputEl.dom;\r
1603 editorxy = Ext.fly(inputField).getAnchorXY('c');\r
1604 jasmine.fireMouseEvent(inputField, 'mousedown', editorxy[0], editorxy[1]);\r
1605 jasmine.fireMouseEvent(inputField, 'mousemove', editorxy[0], editorxy[1]);\r
1606 jasmine.fireMouseEvent(cell00, 'mousemove', cell00xy[0], cell00xy[1]);\r
1607 jasmine.fireMouseEvent(cell00, 'mouseup', cell00xy[0], cell00xy[1]);\r
1608 });\r
1609 });\r
1610\r
1611 describe('Single column editing using a single editor', function() {\r
1612 function isEditing(rowIndex, columnIndex) {\r
1613 return plugin.editing && plugin.activeColumn === colRef[columnIndex] && plugin.activeRecord === store.getAt(rowIndex);\r
1614 }\r
1615\r
1616 webkitIt('should use the same editor for same typed cells, and not blur between edits', function() {\r
1617 grid = new Ext.grid.property.Grid({\r
1618 renderTo: document.body,\r
1619 width: 300,\r
1620 source: {\r
1621 '(name)': 'Properties Grid',\r
1622 autoFitColumns: true,\r
1623 borderWidth: 1,\r
1624 created: Ext.Date.parse('10/15/2006', 'm/d/Y'),\r
1625 grouping: false,\r
1626 productionQuality: false,\r
1627 tested: false,\r
1628 version: 0.01\r
1629 }\r
1630 });\r
1631 colRef = grid.getColumnManager().getColumns();\r
1632 plugin = grid.view.editingPlugin;\r
1633 store = grid.store;\r
1634\r
1635 var activeEditor,\r
1636 lastActiveEditor;\r
1637\r
1638 plugin.startEdit(3, 1);\r
1639 \r
1640 waitsFor(function() {\r
1641 return isEditing(3, 1);\r
1642 }, 'move to cell 3, 1');\r
1643 \r
1644 runs(function() {\r
1645 expect(plugin.editing).toBe(true);\r
1646 activeEditor = plugin.getActiveEditor();\r
1647 expect(activeEditor.isVisible()).toBe(true);\r
1648\r
1649 // Tab down from "created" to "grouping"\r
1650 jasmine.fireKeyEvent(activeEditor.field.inputEl, 'keydown', TAB);\r
1651 });\r
1652\r
1653 waitsFor(function() {\r
1654 return isEditing(4, 1);\r
1655 }, 'move to cell 4, 1');\r
1656 \r
1657 runs(function() {\r
1658\r
1659 // A different editor should be active on "grouping".\r
1660 expect(plugin.getActiveEditor()).not.toBe(activeEditor);\r
1661 activeEditor = plugin.getActiveEditor();\r
1662 expect(activeEditor.isVisible()).toBe(true);\r
1663 expect(activeEditor.field.getValue()).toEqual(false);\r
1664 activeEditor.on({\r
1665 complete: function() {\r
1666 lastActiveEditor = activeEditor;\r
1667 }\r
1668 });\r
1669\r
1670 // Tab down from "grouping" to "productionQuality"\r
1671 jasmine.fireKeyEvent(activeEditor.field.inputEl, 'keydown', TAB);\r
1672 });\r
1673\r
1674 waitsFor(function() {\r
1675 return isEditing(5, 1);\r
1676 }, 'move to cell 5, 1');\r
1677 \r
1678 runs(function() {\r
1679\r
1680 // The same editor should be active on "productionQuality", and it should not have blurred\r
1681 expect(plugin.getActiveEditor()).toBe(activeEditor);\r
1682 expect(activeEditor.isVisible()).toBe(true);\r
1683 expect(activeEditor.field.getValue()).toEqual(false);\r
1684\r
1685 // Tab down from "productionQuality" to "QA"\r
1686 jasmine.fireKeyEvent(activeEditor.field.inputEl, 'keydown', TAB);\r
1687 });\r
1688\r
1689 waitsFor(function() {\r
1690 return isEditing(6, 1);\r
1691 }, 'move to cell 6, 1');\r
1692 \r
1693 runs(function() {\r
1694\r
1695 // The same editor should be active on "QA", and it should not have blurred\r
1696 expect(plugin.getActiveEditor()).toBe(activeEditor);\r
1697 expect(activeEditor.isVisible()).toBe(true);\r
1698 expect(activeEditor.field.getValue()).toEqual(false);\r
1699\r
1700 // Tab down from "QA" to "version"\r
1701 jasmine.fireKeyEvent(activeEditor.field.inputEl, 'keydown', TAB);\r
1702 });\r
1703\r
1704 waitsFor(function() {\r
1705 return isEditing(7, 1);\r
1706 }, 'move to cell 7, 1');\r
1707\r
1708 runs(function() {\r
1709\r
1710 // A different editor should be active on "version"\r
1711 expect(plugin.getActiveEditor()).not.toBe(activeEditor);\r
1712\r
1713 // To avoid focus leaving the panel, it's hidden only after the new editor takes focus.\r
1714 activeEditor = plugin.getActiveEditor();\r
1715 expect(activeEditor.isVisible()).toBe(true);\r
1716 expect(activeEditor.field.getValue()).toEqual(0.01);\r
1717\r
1718 // At this time, the previously active editor should have been hidden\r
1719 expect(lastActiveEditor.isVisible()).toBe(false);\r
1720 });\r
1721 });\r
1722 });\r
1723\r
1724 describe("with combos", function() {\r
1725 it("should retain the value when tabbing and not modifying the value after reusing the editor", function() {\r
1726 makeGrid([{\r
1727 dataIndex: 'field1',\r
1728 editor: {\r
1729 xtype: 'combobox',\r
1730 store: ['Foo', 'Bar', 'Baz']\r
1731 }\r
1732 }]);\r
1733 plugin.startEditByPosition({\r
1734 row: 0,\r
1735 column: 0\r
1736 });\r
1737 var field = plugin.getActiveEditor().field;\r
1738 jasmine.waitForFocus(field);\r
1739 runs(function() {\r
1740 // Trigger combo to expand, then down to last value\r
1741 jasmine.fireKeyEvent(field.inputEl, 'keydown', Ext.event.Event.DOWN);\r
1742 jasmine.fireKeyEvent(field.inputEl, 'keydown', Ext.event.Event.DOWN);\r
1743 jasmine.fireKeyEvent(field.inputEl, 'keydown', Ext.event.Event.DOWN);\r
1744 // Begin edit on next field\r
1745 jasmine.fireKeyEvent(field.inputEl, 'keydown', Ext.event.Event.TAB);\r
1746 expect(store.getAt(0).get('field1')).toBe('Baz');\r
1747 });\r
1748 jasmine.waitForFocus(field);\r
1749 runs(function() {\r
1750 jasmine.fireKeyEvent(field.inputEl, 'keydown', Ext.event.Event.TAB);\r
1751 expect(store.getAt(1).get('field1')).toBe('2.1');\r
1752 });\r
1753 });\r
1754 });\r
1755 });\r
1756 }\r
1757 createSuite(false);\r
1758 createSuite(true);\r
1759\r
1760 describe("misc", function() {\r
1761 describe("property grid editing with textfield and triggerfield - blurring test", function() {\r
1762 var tree, cellEditing;\r
1763\r
1764 beforeEach(function() {\r
1765 tree = new Ext.tree.Panel({\r
1766 height:100,\r
1767 root:{\r
1768 text: 'node1',\r
1769 expanded: true,\r
1770 children: [{\r
1771 text:'node2',\r
1772 leaf:true\r
1773 }]\r
1774 },\r
1775 width: 200,\r
1776 viewConfig: {\r
1777 plugins: {\r
1778 pluginId: 'ddPlug',\r
1779 ptype: 'treeviewdragdrop'\r
1780 }\r
1781 },\r
1782 renderTo: document.body\r
1783 });\r
1784\r
1785 grid = new Ext.grid.property.Grid({\r
1786 width: 200,\r
1787 height: 200,\r
1788 renderTo: document.body,\r
1789 source: {\r
1790 text: "abc",\r
1791 autoFitColumns: true\r
1792 }\r
1793 });\r
1794 cellEditing = grid.findPlugin('cellediting');\r
1795 });\r
1796 afterEach(function() {\r
1797 Ext.destroy(tree, grid);\r
1798 });\r
1799\r
1800 webkitIt("should blur and hide the cell editor on focusing the tree", function() {\r
1801 var cell01_editor;\r
1802\r
1803 // Wait until the grid has rendered rows\r
1804 waitsFor(function() {\r
1805 return grid.view.all.getCount();\r
1806 });\r
1807 runs(function() {\r
1808 // Invoke the textfield editor\r
1809 triggerCellMouseEvent('click', 0, 1);\r
1810 });\r
1811\r
1812 // Wait for editing to begin\r
1813 waitsFor(function() {\r
1814 cell01_editor = cellEditing.editors.items[0];\r
1815 return cell01_editor.isVisible() && cell01_editor.editing;\r
1816 });\r
1817 \r
1818 runs(function() {\r
1819 // Focus the tree. Should blur and hide the editor\r
1820 tree.getView().getNavigationModel().setPosition(0);\r
1821 });\r
1822\r
1823 // Wait for the blur handler to hide the editor\r
1824 waitsFor(function() {\r
1825 return cell01_editor.isVisible() === false;\r
1826 }, 'grid cell editor to hide');\r
1827\r
1828 runs(function() {\r
1829 jasmine.fireMouseEvent(tree.view.getNode(1), 'mouseup');\r
1830\r
1831 // Invoke the triggerfield editor\r
1832 triggerCellMouseEvent('click', 1, 1);\r
1833 expect(cellEditing.editors.items[1].isVisible()).toBe(true);\r
1834\r
1835 // Focus the tree. Should blur and hide the editor\r
1836 tree.getNavigationModel().setPosition(0, 0);\r
1837 });\r
1838\r
1839 // Wait for the blur handler to hide the editor\r
1840 waitsFor(function() {\r
1841 return cellEditing.editors.items[1].isVisible() === false;\r
1842 }, 'second grid cell editor to hide');\r
1843 runs(function() {\r
1844 jasmine.fireMouseEvent(tree.view.getNode(1), 'mouseup');\r
1845 });\r
1846 });\r
1847 });\r
1848 });\r
1849});