]>
Commit | Line | Data |
---|---|---|
6527f429 DM |
1 | describe('Ext.grid.plugin.CellEditing', function () {\r |
2 | var store, plugin, grid, view, record, column, field,\r | |
3 | TAB = 9,\r | |
4 | synchronousLoad = true,\r | |
5 | proxyStoreLoad = Ext.data.ProxyStore.prototype.load,\r | |
6 | loadStore;\r | |
7 | \r | |
8 | function makeGrid(pluginCfg, gridCfg, storeCfg, locked) {\r | |
9 | store = new Ext.data.Store(Ext.apply({\r | |
10 | fields: ['name', 'email', 'phone'],\r | |
11 | data: [\r | |
12 | {'name': 'Lisa', 'email': 'lisa@simpsons.com', 'phone': '555-111-1224', 'age': 14},\r | |
13 | {'name': 'Bart', 'email': 'bart@simpsons.com', 'phone': '555-222-1234', 'age': 12},\r | |
14 | {'name': 'Homer', 'email': 'homer@simpsons.com', 'phone': '555-222-1244', 'age': 44},\r | |
15 | {'name': 'Marge', 'email': 'marge@simpsons.com', 'phone': '555-222-1254', 'age': 41}\r | |
16 | ],\r | |
17 | autoDestroy: true\r | |
18 | }, storeCfg));\r | |
19 | \r | |
20 | plugin = new Ext.grid.plugin.CellEditing(pluginCfg);\r | |
21 | \r | |
22 | grid = new Ext.grid.Panel(Ext.apply({\r | |
23 | columns: [\r | |
24 | {header: 'Name', dataIndex: 'name', editor: 'textfield', locked: locked},\r | |
25 | {header: 'Email', dataIndex: 'email', flex:1,\r | |
26 | editor: {\r | |
27 | xtype: 'textareafield',\r | |
28 | allowBlank: false,\r | |
29 | grow: true\r | |
30 | }\r | |
31 | },\r | |
32 | {header: 'Phone', dataIndex: 'phone', editor: 'textfield'},\r | |
33 | {header: 'Age', dataIndex: 'age', editor: 'textfield'}\r | |
34 | ],\r | |
35 | store: store,\r | |
36 | selModel: 'cellmodel',\r | |
37 | plugins: [plugin],\r | |
38 | width: 200,\r | |
39 | height: 400,\r | |
40 | renderTo: Ext.getBody()\r | |
41 | }, gridCfg));\r | |
42 | \r | |
43 | view = grid.view;\r | |
44 | }\r | |
45 | \r | |
46 | function startEdit(recId, colId) {\r | |
47 | record = store.getAt(recId || 0);\r | |
48 | column = grid.columns[colId || 0];\r | |
49 | plugin.startEdit(record, column);\r | |
50 | field = column.field;\r | |
51 | }\r | |
52 | \r | |
53 | function triggerEditorKey(target, key) {\r | |
54 | // Ext.supports.SpecialKeyDownRepeat changes the event Ext.form.field.Base listens for!\r | |
55 | jasmine.fireKeyEvent(target, Ext.supports.SpecialKeyDownRepeat ? 'keydown' : 'keypress', key);\r | |
56 | }\r | |
57 | \r | |
58 | beforeEach(function() {\r | |
59 | // Override so that we can control asynchronous loading\r | |
60 | loadStore = Ext.data.ProxyStore.prototype.load = function() {\r | |
61 | proxyStoreLoad.apply(this, arguments);\r | |
62 | if (synchronousLoad) {\r | |
63 | this.flushLoad.apply(this, arguments);\r | |
64 | }\r | |
65 | return this;\r | |
66 | };\r | |
67 | \r | |
68 | MockAjaxManager.addMethods();\r | |
69 | });\r | |
70 | \r | |
71 | afterEach(function() {\r | |
72 | // Undo the overrides.\r | |
73 | Ext.data.ProxyStore.prototype.load = proxyStoreLoad;\r | |
74 | \r | |
75 | tearDown();\r | |
76 | MockAjaxManager.removeMethods();\r | |
77 | });\r | |
78 | \r | |
79 | function tearDown() {\r | |
80 | store = plugin = grid = view = record = column = field = Ext.destroy(grid);\r | |
81 | }\r | |
82 | \r | |
83 | describe('finding the cell editing plugin in a locking grid', function() {\r | |
84 | beforeEach(function() {\r | |
85 | makeGrid({pluginId:'test-cell-editing'}, null, null, true);\r | |
86 | });\r | |
87 | \r | |
88 | it('should find it by id', function() {\r | |
89 | expect(grid.getPlugin('test-cell-editing')).toBe(plugin);\r | |
90 | });\r | |
91 | it('should find it by ptype', function() {\r | |
92 | expect(grid.findPlugin('cellediting')).toBe(plugin);\r | |
93 | });\r | |
94 | });\r | |
95 | \r | |
96 | describe('effect of hiding columns on cell editing selection', function () {\r | |
97 | // These specs show that hiding columns pre- or post- cell edit will not place the x-grid-cell-selected class on the wrong\r | |
98 | // cell in the wrong column when the row is updated since Ext.view.Table:renderCell is now looking up the cell context by\r | |
99 | // header rather than by index. See EXTJSIV-11653.\r | |
100 | var wasEdited = false,\r | |
101 | columnManager, cell;\r | |
102 | \r | |
103 | beforeEach(function () {\r | |
104 | makeGrid({\r | |
105 | listeners: {\r | |
106 | edit: function (editor) {\r | |
107 | wasEdited = true;\r | |
108 | }\r | |
109 | }\r | |
110 | }, {\r | |
111 | selType: 'cellmodel'\r | |
112 | });\r | |
113 | \r | |
114 | columnManager = grid.getColumnManager();\r | |
115 | });\r | |
116 | \r | |
117 | afterEach(function () {\r | |
118 | wasEdited = false;\r | |
119 | columnManager = null;\r | |
120 | });\r | |
121 | \r | |
122 | it('should give the edited cell the selected class after initially hiding columns', function () {\r | |
123 | // First hide the columns.\r | |
124 | columnManager.getColumns()[0].hide();\r | |
125 | columnManager.getColumns()[1].hide();\r | |
126 | \r | |
127 | // Then do the edit.\r | |
128 | record = grid.store.getAt(0);\r | |
129 | column = columnManager.getColumns()[2];\r | |
130 | cell = grid.view.getCell(record, column);\r | |
131 | \r | |
132 | jasmine.fireMouseEvent(cell, 'dblclick');\r | |
133 | plugin.getEditor(record, column).setValue('111-111-1111');\r | |
134 | plugin.completeEdit();\r | |
135 | \r | |
136 | waitsFor(function () {\r | |
137 | return wasEdited;\r | |
138 | });\r | |
139 | \r | |
140 | runs(function () {\r | |
141 | // Finally show that the selected cell is in the correct column.\r | |
142 | cell = Ext.fly(grid.view.getNode(record)).down('.x-grid-cell-selected');\r | |
143 | expect(cell.hasCls('x-grid-cell-' + column.id)).toBe(true);\r | |
144 | });\r | |
145 | });\r | |
146 | \r | |
147 | it('should move the selected cell along with its column when other columns are hidden', function () {\r | |
148 | record = grid.store.getAt(0);\r | |
149 | column = columnManager.columns[2];\r | |
150 | cell = grid.view.getCell(record, column);\r | |
151 | \r | |
152 | jasmine.fireMouseEvent(cell, 'dblclick');\r | |
153 | plugin.getEditor(record, column).setValue('111-111-1111');\r | |
154 | plugin.completeEdit();\r | |
155 | \r | |
156 | waitsFor(function () {\r | |
157 | return wasEdited;\r | |
158 | });\r | |
159 | \r | |
160 | runs(function () {\r | |
161 | // First simply show that the selected cell is in the correct column.\r | |
162 | cell = Ext.fly(grid.view.getNode(record)).down('.x-grid-cell-selected');\r | |
163 | expect(cell.hasCls('x-grid-cell-' + column.id)).toBe(true);\r | |
164 | \r | |
165 | columnManager.columns[0].hide();\r | |
166 | \r | |
167 | // Now show that the selected cell is still in the correct column.\r | |
168 | cell = Ext.fly(grid.view.getNode(record)).down('.x-grid-cell-selected');\r | |
169 | expect(cell.hasCls('x-grid-cell-' + column.id)).toBe(true);\r | |
170 | });\r | |
171 | });\r | |
172 | });\r | |
173 | \r | |
174 | describe('events', function () {\r | |
175 | var editorContext, cancelEditFired;\r | |
176 | \r | |
177 | afterEach(function () {\r | |
178 | editorContext = null;\r | |
179 | });\r | |
180 | \r | |
181 | describe('beforeedit', function () {\r | |
182 | it('should retain changes to the editing context in the event handler', function () {\r | |
183 | // See EXTJSIV-11643.\r | |
184 | makeGrid({\r | |
185 | listeners: {\r | |
186 | beforeedit: function (editor, context) {\r | |
187 | context.value = 'motley';\r | |
188 | editorContext = context;\r | |
189 | }\r | |
190 | }\r | |
191 | });\r | |
192 | \r | |
193 | startEdit();\r | |
194 | \r | |
195 | expect(editorContext.value).toBe('motley');\r | |
196 | });\r | |
197 | });\r | |
198 | \r | |
199 | describe('canceledit', function () {\r | |
200 | beforeEach(function () {\r | |
201 | \r | |
202 | // Must wait for async focus events from previous suite to complete.\r | |
203 | waits(10);\r | |
204 | \r | |
205 | runs(function() {\r | |
206 | cancelEditFired = false;\r | |
207 | \r | |
208 | makeGrid({\r | |
209 | listeners: {\r | |
210 | canceledit: function (editor, context) {\r | |
211 | cancelEditFired = true;\r | |
212 | editorContext = context;\r | |
213 | }\r | |
214 | }\r | |
215 | });\r | |
216 | \r | |
217 | startEdit();\r | |
218 | });\r | |
219 | });\r | |
220 | \r | |
221 | it('should be able to get the original value when canceling the edit by the plugin', function() {\r | |
222 | expect(plugin.editing).toBe(true);\r | |
223 | \r | |
224 | // Note that the columnmove and columnresize events go through plugin.cancelEdit().\r | |
225 | column.getEditor().setValue('baz');\r | |
226 | plugin.cancelEdit();\r | |
227 | \r | |
228 | expect(cancelEditFired).toBe(true);\r | |
229 | expect(editorContext.originalValue).toBe('Lisa');\r | |
230 | });\r | |
231 | \r | |
232 | it('should be able to get the edited value when canceling the edit by the plugin', function() {\r | |
233 | expect(plugin.editing).toBe(true);\r | |
234 | \r | |
235 | // Note that the columnmove and columnresize events go through plugin.cancelEdit().\r | |
236 | column.getEditor().setValue('foo');\r | |
237 | plugin.cancelEdit();\r | |
238 | \r | |
239 | expect(cancelEditFired).toBe(true);\r | |
240 | expect(editorContext.value).toBe('foo');\r | |
241 | });\r | |
242 | \r | |
243 | it('should have different values for edited value and original value when canceling', function() {\r | |
244 | expect(plugin.editing).toBe(true);\r | |
245 | \r | |
246 | column.getEditor().setValue('foo');\r | |
247 | plugin.cancelEdit();\r | |
248 | \r | |
249 | expect(cancelEditFired).toBe(true);\r | |
250 | expect(editorContext.value).not.toBe(editorContext.originalValue);\r | |
251 | });\r | |
252 | \r | |
253 | it('should be able to get the edited value when canceling the edit by the editor', function() {\r | |
254 | expect(plugin.editing).toBe(true);\r | |
255 | \r | |
256 | // Note that the canceledit event goes through editor.cancelEdit().\r | |
257 | column.getEditor().setValue('bar');\r | |
258 | plugin.getEditor(record, column).cancelEdit();\r | |
259 | \r | |
260 | expect(cancelEditFired).toBe(true);\r | |
261 | expect(editorContext.value).not.toBe(editorContext.originalValue);\r | |
262 | expect(editorContext.value).toBe('bar');\r | |
263 | });\r | |
264 | \r | |
265 | describe('falsey values', function () {\r | |
266 | it('should be able to capture falsey values when canceled by the plugin', function() {\r | |
267 | expect(plugin.editing).toBe(true);\r | |
268 | \r | |
269 | // Note that the columnmove and columnresize events go through plugin.cancelEdit().\r | |
270 | column.getEditor().setValue('');\r | |
271 | plugin.cancelEdit();\r | |
272 | \r | |
273 | expect(cancelEditFired).toBe(true);\r | |
274 | expect(editorContext.value).toBe('');\r | |
275 | });\r | |
276 | \r | |
277 | it('should be able to capture falsey values for the editedValue when canceled by the editor', function() {\r | |
278 | expect(plugin.editing).toBe(true);\r | |
279 | \r | |
280 | // Note that the canceledit event goes through editor.cancelEdit().\r | |
281 | column.getEditor().setValue('');\r | |
282 | plugin.getEditor(record, column).cancelEdit();\r | |
283 | \r | |
284 | waitsFor(function() {\r | |
285 | return cancelEditFired;\r | |
286 | });\r | |
287 | runs(function() {\r | |
288 | expect(editorContext.value).toBe('');\r | |
289 | });\r | |
290 | });\r | |
291 | });\r | |
292 | });\r | |
293 | \r | |
294 | describe('selecting ranges', function () {\r | |
295 | // See EXTJS-16608.\r | |
296 | var selModel;\r | |
297 | \r | |
298 | function fireEvent(rowNum, eventName, shift) {\r | |
299 | jasmine.fireMouseEvent(view.getNode(rowNum).getElementsByTagName('td')[0],eventName, null, null, null, !!shift);\r | |
300 | }\r | |
301 | \r | |
302 | function expectSelected(rec) {\r | |
303 | var i, len;\r | |
304 | \r | |
305 | if (arguments.length === 1) {\r | |
306 | if (typeof rec == 'number') {\r | |
307 | rec = store.getAt(rec);\r | |
308 | }\r | |
309 | expect(selModel.isSelected(rec)).toBe(true);\r | |
310 | } else {\r | |
311 | for (i = 0, len = arguments.length; i < len; ++i) {\r | |
312 | expectSelected(arguments[i]);\r | |
313 | }\r | |
314 | }\r | |
315 | }\r | |
316 | \r | |
317 | afterEach(function () {\r | |
318 | selModel = null;\r | |
319 | });\r | |
320 | \r | |
321 | function selectRange(eventName) {\r | |
322 | describe('MULTI', function () {\r | |
323 | beforeEach(function () {\r | |
324 | makeGrid({\r | |
325 | clicksToEdit: eventName === 'click' ? 1: 2\r | |
326 | }, {\r | |
327 | selModel: {\r | |
328 | type: 'rowmodel',\r | |
329 | mode: 'MULTI'\r | |
330 | }\r | |
331 | });\r | |
332 | \r | |
333 | selModel = grid.selModel;\r | |
334 | });\r | |
335 | \r | |
336 | it('should select a range if we have a selection start point and shift is pressed', function () {\r | |
337 | fireEvent(0, eventName);\r | |
338 | fireEvent(3, eventName, true);\r | |
339 | expectSelected(0, 1, 2, 3);\r | |
340 | });\r | |
341 | \r | |
342 | it('should maintain selection with a complex sequence', function() {\r | |
343 | fireEvent(0, eventName);\r | |
344 | expectSelected(0);\r | |
345 | fireEvent(2, eventName, true);\r | |
346 | expectSelected(0, 1, 2);\r | |
347 | fireEvent(3, eventName);\r | |
348 | expectSelected(3);\r | |
349 | fireEvent(1, eventName, true);\r | |
350 | expectSelected(1, 2, 3);\r | |
351 | \r | |
352 | fireEvent(2, eventName);\r | |
353 | expectSelected(2);\r | |
354 | fireEvent(0, eventName, true);\r | |
355 | expectSelected(0, 1, 2);\r | |
356 | fireEvent(3, eventName, true);\r | |
357 | expectSelected(2, 3);\r | |
358 | });\r | |
359 | });\r | |
360 | }\r | |
361 | \r | |
362 | selectRange('click');\r | |
363 | selectRange('dblclick');\r | |
364 | });\r | |
365 | });\r | |
366 | \r | |
367 | describe('sorting', function () {\r | |
368 | it('should complete the edit when focusing the column', function () {\r | |
369 | makeGrid();\r | |
370 | startEdit();\r | |
371 | column.focus();\r | |
372 | \r | |
373 | expect(plugin.editing).toBe(false);\r | |
374 | });\r | |
375 | });\r | |
376 | \r | |
377 | describe('making multiple selections with checkbox model', function () {\r | |
378 | var store, selModel;\r | |
379 | \r | |
380 | afterEach(function () {\r | |
381 | store = selModel = null;\r | |
382 | });\r | |
383 | \r | |
384 | it('should keep existing selections when editing a cell in an previously-selected row', function () {\r | |
385 | makeGrid(null, {\r | |
386 | selModel: new Ext.selection.CheckboxModel({})\r | |
387 | });\r | |
388 | \r | |
389 | store = grid.store;\r | |
390 | selModel = grid.selModel;\r | |
391 | \r | |
392 | // Select all models in the store.\r | |
393 | selModel.select(store.data.items);\r | |
394 | \r | |
395 | // Now edit a cell.\r | |
396 | startEdit(2);\r | |
397 | \r | |
398 | // All the previous selections should still be selected.\r | |
399 | expect(selModel.getSelection().length).toBe(store.data.length);\r | |
400 | });\r | |
401 | \r | |
402 | it('should expect that the correct records have been selected', function () {\r | |
403 | var contains = Ext.Array.contains,\r | |
404 | selections;\r | |
405 | \r | |
406 | makeGrid(null, {\r | |
407 | selModel: new Ext.selection.CheckboxModel({})\r | |
408 | });\r | |
409 | \r | |
410 | store = grid.store;\r | |
411 | selModel = grid.selModel;\r | |
412 | \r | |
413 | // Make some selections.\r | |
414 | selModel.select([store.getAt(1), store.getAt(3)]);\r | |
415 | \r | |
416 | // Now edit a cell in an unselected row.\r | |
417 | // As of 5.0.1, it should NOT select, but should preserve existing MULTI selections: https://sencha.jira.com/browse/EXTJS-14472\r | |
418 | startEdit();\r | |
419 | \r | |
420 | selections = selModel.getSelection();\r | |
421 | \r | |
422 | expect(contains(selections, store.getAt(0))).toBe(false);\r | |
423 | expect(contains(selections, store.getAt(1))).toBe(true);\r | |
424 | expect(contains(selections, store.getAt(2))).toBe(false);\r | |
425 | expect(contains(selections, store.getAt(3))).toBe(true);\r | |
426 | });\r | |
427 | \r | |
428 | it('should keep existing selections when editing a cell in an unselected row', function () {\r | |
429 | makeGrid(null, {\r | |
430 | selModel: new Ext.selection.CheckboxModel({})\r | |
431 | });\r | |
432 | \r | |
433 | store = grid.store;\r | |
434 | selModel = grid.selModel;\r | |
435 | \r | |
436 | // Make some selections.\r | |
437 | selModel.select([store.getAt(0), store.getAt(1)]);\r | |
438 | \r | |
439 | // Now edit a cell in an unselected row.\r | |
440 | // As of 5.0.1, it should NOT select, but should preserve existing MULTI selections: https://sencha.jira.com/browse/EXTJS-14472\r | |
441 | startEdit(3, 0);\r | |
442 | \r | |
443 | // The selections should now also include the row that contains the cell being edited.\r | |
444 | expect(selModel.getSelection().length).toBe(2);\r | |
445 | });\r | |
446 | });\r | |
447 | \r | |
448 | describe('setting value while remote querying', function () {\r | |
449 | // These tests simulates a test case where a value is entered in the editor (either as .value or .rawValue) and then\r | |
450 | // is tabbed out of the editor (and completing the edit) before the response returns and the combo store is loaded.\r | |
451 | // See EXTJS-13127.\r | |
452 | //\r | |
453 | // There is a lot of coverage for combos, but we also needed to test the behavior of combos as cell editors. There have\r | |
454 | // been bugs where raw values have been retained by the editor across tabs, i.e., if 'foo' is entered in the editor that\r | |
455 | // same value will be retained as the user tabs through the grid (although this only seems to happen in grids where only\r | |
456 | // a single column is editable, as tested below). Also, there have been bugs where the same editor value (.value) has been\r | |
457 | // been written to each model as the user tabs (obviously not good). The following tests cover both of these scenarios.\r | |
458 | //\r | |
459 | // In addition, the tests cover what should happen if a value or raw value is set prior to or during the combo store load,\r | |
460 | // both when forceSelection is on and off. In either case (of forceSelection), we have decided that the value should be\r | |
461 | // allowed because the combo store hasn't been loaded yet. The contract with forceSelection is with the combo store, and if\r | |
462 | // the user chooses to enter a value before said store is loaded then we cannot do anything about that as we cannot look\r | |
463 | // anything up.\r | |
464 | \r | |
465 | var comboStore, ed;\r | |
466 | \r | |
467 | function createUI(forceSelection) {\r | |
468 | comboStore = new Ext.data.Store({\r | |
469 | fields: ['id', 'state', 'nickname'],\r | |
470 | proxy: {\r | |
471 | type: 'ajax',\r | |
472 | url: 'fake',\r | |
473 | reader: {\r | |
474 | type: 'array'\r | |
475 | }\r | |
476 | }\r | |
477 | });\r | |
478 | \r | |
479 | makeGrid(null, {\r | |
480 | columns: [{\r | |
481 | header: 'State',\r | |
482 | dataIndex: 'id',\r | |
483 | renderer: function (value, metaData, record) {\r | |
484 | return record.get('state');\r | |
485 | },\r | |
486 | editor: {\r | |
487 | xtype: 'combo',\r | |
488 | store: comboStore,\r | |
489 | queryMode: 'remote',\r | |
490 | typeAhead: true,\r | |
491 | minChars: 2,\r | |
492 | displayField: 'state',\r | |
493 | valueField: 'id',\r | |
494 | forceSelection: forceSelection\r | |
495 | }\r | |
496 | }]\r | |
497 | }, {\r | |
498 | fields: ['id', 'state', 'nickname'],\r | |
499 | data: [\r | |
500 | ['AL', 'Alabama', 'The Heart of Dixie'],\r | |
501 | ['AK', 'Alaska', 'The Land of the Midnight Sun'],\r | |
502 | ['AR', 'Arkansas', 'The Natural State'],\r | |
503 | ['AZ', 'Arizona', 'The Grand Canyon State']\r | |
504 | ],\r | |
505 | proxy: {\r | |
506 | type: 'memory',\r | |
507 | reader: {\r | |
508 | type: 'array'\r | |
509 | }\r | |
510 | }\r | |
511 | });\r | |
512 | }\r | |
513 | \r | |
514 | describe('only one editable column', function () {\r | |
515 | function initiateTests(expectation, loadStore) {\r | |
516 | describe(expectation, function () {\r | |
517 | function forceSelection(force) {\r | |
518 | describe('forceSelection = ' + force, function () {\r | |
519 | beforeEach(function () {\r | |
520 | createUI(force);\r | |
521 | });\r | |
522 | \r | |
523 | afterEach(function () {\r | |
524 | Ext.destroy(comboStore);\r | |
525 | comboStore = ed = null;\r | |
526 | });\r | |
527 | \r | |
528 | function setup(force, method) {\r | |
529 | // Initiate the edit.\r | |
530 | jasmine.fireMouseEvent(grid.view.getNode(store.getAt(0)).getElementsByTagName('td')[0], 'dblclick');\r | |
531 | ed = plugin.getActiveEditor();\r | |
532 | \r | |
533 | if (loadStore) {\r | |
534 | comboStore.load();\r | |
535 | }\r | |
536 | \r | |
537 | \r | |
538 | // Simulate the load which happens when text is typed into the editor.\r | |
539 | // Let's then tab out to complete the edit.\r | |
540 | if (method === 'setRawValue') {\r | |
541 | ed.field.setRawValue('ben');\r | |
542 | } else {\r | |
543 | ed.setValue('ben');\r | |
544 | }\r | |
545 | \r | |
546 | jasmine.fireKeyEvent(ed.field.inputEl, 'keydown', 9);\r | |
547 | }\r | |
548 | \r | |
549 | function setValue(raw) {\r | |
550 | var method = raw ? 'setRawValue' : 'setValue';\r | |
551 | \r | |
552 | describe(method, function () {\r | |
553 | it('should write the value to the model', function () {\r | |
554 | var val = 'ben';\r | |
555 | \r | |
556 | setup(force, method);\r | |
557 | \r | |
558 | if (force && method === 'setRawValue') {\r | |
559 | val = 'AL';\r | |
560 | }\r | |
561 | \r | |
562 | record = store.getAt(0);\r | |
563 | expect(record.get('id')).toBe(val);\r | |
564 | expect(record.get('state')).toBe('Alabama');\r | |
565 | });\r | |
566 | \r | |
567 | it('should not set any other fields in the model across tabs', function () {\r | |
568 | // There have been bugs which caused the same value to be set in different models across tabs.\r | |
569 | setup(force, method);\r | |
570 | \r | |
571 | record = store.getAt(1);\r | |
572 | expect(record.get('id')).toBe('AK');\r | |
573 | expect(record.get('state')).toBe('Alaska');\r | |
574 | \r | |
575 | record = store.getAt(2);\r | |
576 | jasmine.fireKeyEvent(ed.field.inputEl, 'keydown', 9);\r | |
577 | expect(record.get('state')).toBe('Arkansas');\r | |
578 | expect(record.get('nickname')).toBe('The Natural State');\r | |
579 | \r | |
580 | record = store.getAt(3);\r | |
581 | jasmine.fireKeyEvent(ed.field.inputEl, 'keydown', 9);\r | |
582 | expect(record.get('state')).toBe('Arizona');\r | |
583 | expect(record.get('nickname')).toBe('The Grand Canyon State');\r | |
584 | });\r | |
585 | \r | |
586 | it('should give the editor different values across tabs', function () {\r | |
587 | // There have been bugs which caused the editor to keep the same value across tabs.\r | |
588 | setup(force, method);\r | |
589 | \r | |
590 | // It should not propagate the user-inputted value.\r | |
591 | \r | |
592 | // Let's make sure the editor has the correct value...\r | |
593 | expect(ed.getValue()).toBe('AK');\r | |
594 | expect(ed.field.getRawValue()).toBe('');\r | |
595 | \r | |
596 | jasmine.fireKeyEvent(ed.field.inputEl, 'keydown', 9);\r | |
597 | expect(ed.getValue()).toBe('AR');\r | |
598 | \r | |
599 | jasmine.fireKeyEvent(ed.field.inputEl, 'keydown', 9);\r | |
600 | expect(ed.getValue()).toBe('AZ');\r | |
601 | });\r | |
602 | \r | |
603 | it('should not give the editor a raw value because the combo store has not been loaded', function () {\r | |
604 | // There have been bugs which caused the editor to keep the same raw value across tabs.\r | |
605 | setup(force, method);\r | |
606 | \r | |
607 | expect(ed.field.getRawValue()).toBe('');\r | |
608 | \r | |
609 | jasmine.fireKeyEvent(ed.field.inputEl, 'keydown', 9);\r | |
610 | expect(ed.field.getRawValue()).toBe('');\r | |
611 | \r | |
612 | jasmine.fireKeyEvent(ed.field.inputEl, 'keydown', 9);\r | |
613 | expect(ed.field.getRawValue()).toBe('');\r | |
614 | });\r | |
615 | });\r | |
616 | }\r | |
617 | \r | |
618 | setValue(false);\r | |
619 | setValue(true);\r | |
620 | });\r | |
621 | }\r | |
622 | \r | |
623 | forceSelection(false);\r | |
624 | forceSelection(true);\r | |
625 | });\r | |
626 | }\r | |
627 | \r | |
628 | initiateTests('before store load is initiated', false);\r | |
629 | initiateTests('while store is loading', true);\r | |
630 | \r | |
631 | describe('when tabbing (down/up to the contiguous row)', function () {\r | |
632 | var activeEditor;\r | |
633 | \r | |
634 | beforeEach(function () {\r | |
635 | makeGrid({\r | |
636 | clicksToEdit: 1\r | |
637 | }, {\r | |
638 | columns: [\r | |
639 | {header: 'Name', dataIndex: 'name', editor: 'textfield'},\r | |
640 | {header: 'Email', dataIndex: 'email', flex:1},\r | |
641 | {header: 'Phone', dataIndex: 'phone'},\r | |
642 | {header: 'Age', dataIndex: 'age'}\r | |
643 | ],\r | |
644 | selModel: 'rowmodel'\r | |
645 | });\r | |
646 | \r | |
647 | startEdit();\r | |
648 | \r | |
649 | activeEditor = plugin.activeEditor;\r | |
650 | \r | |
651 | // Spy on afterHide to count *successful* hides.\r | |
652 | // hide may be called when already hidden during CellEditing tabbing sequence.\r | |
653 | spyOn(activeEditor, 'afterHide').andCallThrough();\r | |
654 | \r | |
655 | jasmine.fireKeyEvent(column.field.inputEl, 'keydown', 9);\r | |
656 | });\r | |
657 | \r | |
658 | afterEach(function () {\r | |
659 | activeEditor = null;\r | |
660 | });\r | |
661 | \r | |
662 | it('should not complete', function () {\r | |
663 | expect(activeEditor).not.toBe(null);\r | |
664 | expect(plugin.activeColumn).not.toBe(null);\r | |
665 | expect(plugin.activeRecord).not.toBe(null);\r | |
666 | });\r | |
667 | \r | |
668 | it('should hide the editor', function () {\r | |
669 | expect(activeEditor).not.toBe(null);\r | |
670 | expect(activeEditor.isVisible()).toBe(true);\r | |
671 | \r | |
672 | // CellEditing is just part of actionable mode.\r | |
673 | // Actionable mode does not know that you are going to focus to the same editor.\r | |
674 | // It just desctivates the old row, activates the new row, and focuses the first tabbable element.\r | |
675 | // Deactivating a row will hide the editors.\r | |
676 | // So the "name" editor will have been hidden when that row was deactivated.\r | |
677 | expect(activeEditor.afterHide.callCount).toBe(1);\r | |
678 | });\r | |
679 | });\r | |
680 | });\r | |
681 | });\r | |
682 | \r | |
683 | describe('clicksToEdit', function () {\r | |
684 | describe('2 clicks', function () {\r | |
685 | beforeEach(function () {\r | |
686 | makeGrid();\r | |
687 | });\r | |
688 | \r | |
689 | it('should default to 2', function () {\r | |
690 | expect(plugin.clicksToEdit).toBe(2);\r | |
691 | });\r | |
692 | \r | |
693 | it('should begin editing when double-clicked', function () {\r | |
694 | record = grid.store.getAt(0);\r | |
695 | node = grid.view.getNodeByRecord(record);\r | |
696 | jasmine.fireMouseEvent(Ext.fly(node).down('.x-grid-cell'), 'dblclick');\r | |
697 | \r | |
698 | expect(plugin.activeEditor).not.toBeFalsy();\r | |
699 | });\r | |
700 | \r | |
701 | it('should not begin editing when single-clicked', function () {\r | |
702 | record = grid.store.getAt(0);\r | |
703 | node = grid.view.getNodeByRecord(record);\r | |
704 | jasmine.fireMouseEvent(Ext.fly(node).down('.x-grid-cell'), 'click');\r | |
705 | \r | |
706 | expect(plugin.activeEditor).toBeFalsy();\r | |
707 | });\r | |
708 | \r | |
709 | describe('editing a new cell', function () {\r | |
710 | var cells, boundEl;\r | |
711 | \r | |
712 | afterEach(function () {\r | |
713 | cells = boundEl = null;\r | |
714 | });\r | |
715 | \r | |
716 | it('should update the activeEditor to point to the new cell, adjacent', function () {\r | |
717 | record = grid.store.getAt(0);\r | |
718 | node = grid.view.getNodeByRecord(record);\r | |
719 | cells = Ext.fly(node).query('.x-grid-cell');\r | |
720 | \r | |
721 | boundEl = cells[0];\r | |
722 | jasmine.fireMouseEvent(boundEl, 'dblclick');\r | |
723 | \r | |
724 | expect(plugin.activeEditor.boundEl.dom).toBe(boundEl);\r | |
725 | \r | |
726 | // Update the boundEl to our new cell.\r | |
727 | boundEl = cells[1];\r | |
728 | jasmine.fireMouseEvent(boundEl, 'dblclick');\r | |
729 | \r | |
730 | expect(plugin.activeEditor.boundEl.dom).toBe(boundEl);\r | |
731 | });\r | |
732 | \r | |
733 | it('should update the activeEditor to point to the new cell, below', function () {\r | |
734 | record = grid.store.getAt(0);\r | |
735 | node = grid.view.getNodeByRecord(record);\r | |
736 | boundEl = Ext.fly(node).down('.x-grid-cell').dom;\r | |
737 | \r | |
738 | jasmine.fireMouseEvent(boundEl, 'dblclick');\r | |
739 | \r | |
740 | expect(plugin.activeEditor.boundEl.dom).toBe(boundEl);\r | |
741 | \r | |
742 | record = grid.store.getAt(1);\r | |
743 | node = grid.view.getNodeByRecord(record);\r | |
744 | \r | |
745 | // Update the boundEl to our new cell.\r | |
746 | boundEl = Ext.fly(node).down('.x-grid-cell').dom;\r | |
747 | \r | |
748 | jasmine.fireMouseEvent(boundEl, 'dblclick');\r | |
749 | \r | |
750 | expect(plugin.activeEditor.boundEl.dom).toBe(boundEl);\r | |
751 | });\r | |
752 | });\r | |
753 | });\r | |
754 | \r | |
755 | describe('1 click', function () {\r | |
756 | beforeEach(function () {\r | |
757 | makeGrid({\r | |
758 | clicksToEdit: 1\r | |
759 | });\r | |
760 | });\r | |
761 | \r | |
762 | it('should honor a different number than the default', function () {\r | |
763 | expect(plugin.clicksToEdit).toBe(1);\r | |
764 | });\r | |
765 | \r | |
766 | it('should begin editing when single-clicked', function () {\r | |
767 | record = grid.store.getAt(0);\r | |
768 | node = grid.view.getNodeByRecord(record);\r | |
769 | jasmine.fireMouseEvent(Ext.fly(node).down('.x-grid-cell'), 'click');\r | |
770 | \r | |
771 | expect(plugin.activeEditor).not.toBeFalsy();\r | |
772 | });\r | |
773 | \r | |
774 | // Note: I'm disabling this for IE b/c certain versions (esp. 10 & 11) could not distinguish\r | |
775 | // between single- and double-click.\r | |
776 | if (!Ext.isIE) {\r | |
777 | it('should not begin editing when double-clicked', function () {\r | |
778 | record = grid.store.getAt(0);\r | |
779 | node = grid.view.getNodeByRecord(record);\r | |
780 | jasmine.fireMouseEvent(Ext.fly(node).down('.x-grid-cell'), 'dblclick');\r | |
781 | \r | |
782 | expect(plugin.activeEditor).toBeFalsy();\r | |
783 | });\r | |
784 | }\r | |
785 | \r | |
786 | describe('editing a new cell', function () {\r | |
787 | var cells, boundEl;\r | |
788 | \r | |
789 | afterEach(function () {\r | |
790 | cells = boundEl = null;\r | |
791 | });\r | |
792 | \r | |
793 | it('should update the activeEditor to point to the new cell, adjacent', function () {\r | |
794 | record = grid.store.getAt(0);\r | |
795 | node = grid.view.getNodeByRecord(record);\r | |
796 | cells = Ext.fly(node).query('.x-grid-cell');\r | |
797 | \r | |
798 | boundEl = cells[0];\r | |
799 | jasmine.fireMouseEvent(boundEl, 'click');\r | |
800 | \r | |
801 | expect(plugin.activeEditor.boundEl.dom).toBe(boundEl);\r | |
802 | \r | |
803 | // Update the boundEl to our new cell.\r | |
804 | boundEl = cells[1];\r | |
805 | jasmine.fireMouseEvent(boundEl, 'click');\r | |
806 | \r | |
807 | expect(plugin.activeEditor.boundEl.dom).toBe(boundEl);\r | |
808 | });\r | |
809 | \r | |
810 | it('should update the activeEditor to point to the new cell, below', function () {\r | |
811 | record = grid.store.getAt(0);\r | |
812 | node = grid.view.getNodeByRecord(record);\r | |
813 | boundEl = Ext.fly(node).down('.x-grid-cell').dom;\r | |
814 | \r | |
815 | jasmine.fireMouseEvent(boundEl, 'click');\r | |
816 | \r | |
817 | expect(plugin.activeEditor.boundEl.dom).toBe(boundEl);\r | |
818 | \r | |
819 | record = grid.store.getAt(1);\r | |
820 | node = grid.view.getNodeByRecord(record);\r | |
821 | \r | |
822 | // Update the boundEl to our new cell.\r | |
823 | boundEl = Ext.fly(node).down('.x-grid-cell').dom;\r | |
824 | \r | |
825 | jasmine.fireMouseEvent(boundEl, 'click');\r | |
826 | \r | |
827 | expect(plugin.activeEditor.boundEl.dom).toBe(boundEl);\r | |
828 | });\r | |
829 | });\r | |
830 | });\r | |
831 | });\r | |
832 | \r | |
833 | describe('the CellEditor', function () {\r | |
834 | beforeEach(function () {\r | |
835 | makeGrid();\r | |
836 | startEdit();\r | |
837 | });\r | |
838 | \r | |
839 | it('should get an ownerCmp reference to the grid', function () {\r | |
840 | waitsFor(function() {\r | |
841 | return plugin.activeEditor && plugin.activeEditor.ownerCmp === grid;\r | |
842 | });\r | |
843 | });\r | |
844 | \r | |
845 | it('should be able to lookup up its owner in the component hierarchy chain', function () {\r | |
846 | waitsFor(function() {\r | |
847 | return plugin.activeEditor && plugin.activeEditor.up('grid') === grid;\r | |
848 | });\r | |
849 | });\r | |
850 | \r | |
851 | describe('positioning the editor', function () {\r | |
852 | it('should default to "l-l!"', function () {\r | |
853 | field = column.field;\r | |
854 | \r | |
855 | expect(field.xtype).toBe('textfield');\r | |
856 | waitsFor(function() {\r | |
857 | return plugin.activeEditor && plugin.activeEditor.alignment === 'l-l!';\r | |
858 | });\r | |
859 | });\r | |
860 | \r | |
861 | it('should constrain to the view if the editor goes out of bounds', function () {\r | |
862 | // Wait for the beforeEach's startEdit to get started\r | |
863 | waitsFor(function() {\r | |
864 | return plugin.activeEditor && plugin.activeEditor.field.hasFocus;\r | |
865 | }, 'editor to focus', 1000);\r | |
866 | \r | |
867 | // Need to be able to correctly startEdit while editing to move edit location\r | |
868 | runs(function() {\r | |
869 | startEdit(0, 1);\r | |
870 | });\r | |
871 | \r | |
872 | waitsFor(function() {\r | |
873 | return field.hasFocus && field.getRegion().top === Ext.fly(plugin.activeEditor.container).getRegion().top;\r | |
874 | }, 'something funky to happen', 1000);\r | |
875 | });\r | |
876 | \r | |
877 | it('should not reposition when shown', function () {\r | |
878 | plugin.completeEdit();\r | |
879 | \r | |
880 | spyOn(Ext.AbstractComponent.prototype, 'setPosition');\r | |
881 | \r | |
882 | startEdit(0, 1);\r | |
883 | \r | |
884 | expect(plugin.activeEditor.setPosition).not.toHaveBeenCalled();\r | |
885 | });\r | |
886 | \r | |
887 | it('should not reposition when within a draggable container', function () {\r | |
888 | // See EXTJS-15532.\r | |
889 | var win;\r | |
890 | \r | |
891 | tearDown();\r | |
892 | \r | |
893 | makeGrid(null, {\r | |
894 | renderTo: null\r | |
895 | });\r | |
896 | \r | |
897 | win = new Ext.window.Window({\r | |
898 | items: grid\r | |
899 | }).show();\r | |
900 | \r | |
901 | startEdit();\r | |
902 | \r | |
903 | spyOn(plugin.activeEditor, 'setPosition');\r | |
904 | \r | |
905 | jasmine.fireMouseEvent(win.el.dom, 'mousedown');\r | |
906 | jasmine.fireMouseEvent(win.el.dom, 'mousemove', win.x, win.y);\r | |
907 | jasmine.fireMouseEvent(win.el.dom, 'mousemove', (win.x - 100), (win.y - 100));\r | |
908 | jasmine.fireMouseEvent(win.el.dom, 'mouseup', 400);\r | |
909 | \r | |
910 | expect(plugin.activeEditor.setPosition).not.toHaveBeenCalled();\r | |
911 | \r | |
912 | win.destroy();\r | |
913 | });\r | |
914 | });\r | |
915 | \r | |
916 | describe('as textfield', function () {\r | |
917 | it('should start the edit when ENTER is pressed', function () {\r | |
918 | var node = view.body.query('td', true)[0];\r | |
919 | \r | |
920 | // Wait for the beforeEach's startEdit to take effect\r | |
921 | waitsFor(function() {\r | |
922 | return plugin.activeEditor && plugin.activeEditor.field.hasFocus;\r | |
923 | }, 'beforeEach startEdit to take effect');\r | |
924 | \r | |
925 | // First complete the edit (we start an edit in the top-level beforeEach).\r | |
926 | runs(function() {\r | |
927 | grid.setActionableMode(false);\r | |
928 | });\r | |
929 | \r | |
930 | // Wait for it to clear itself up and focus to return to the cell\r | |
931 | waitsFor(function() {\r | |
932 | return plugin.activeEditor == null && plugin.editing === false && Ext.Element.getActiveElement() === node;\r | |
933 | }, 'actionable mode to end and cell to regain focus');\r | |
934 | \r | |
935 | runs(function() {\r | |
936 | jasmine.fireKeyEvent(node, 'keydown', 13);\r | |
937 | });\r | |
938 | \r | |
939 | waitsFor(function() {\r | |
940 | return plugin.activeEditor && plugin.editing === true;\r | |
941 | }, 'editing to start on the focused cell');\r | |
942 | });\r | |
943 | \r | |
944 | describe('when currently editing', function() {\r | |
945 | it('should complete the edit when ENTER is pressed', function() {\r | |
946 | var str = 'Utley is Top Dog',\r | |
947 | model = store.getAt(0);\r | |
948 | \r | |
949 | expect(model.get('name')).toBe('Lisa');\r | |
950 | field.setValue(str);\r | |
951 | \r | |
952 | jasmine.fireKeyEvent(field.inputEl.dom, 'keydown', 13);\r | |
953 | \r | |
954 | waitsFor(function() {\r | |
955 | return model.get('name') === str;\r | |
956 | }, 'model to be set', 1000);\r | |
957 | \r | |
958 | runs(function() {\r | |
959 | expect(model.get('name')).toBe(str);\r | |
960 | });\r | |
961 | });\r | |
962 | \r | |
963 | it('should cancel the edit when ESCAPE is pressed', function() {\r | |
964 | jasmine.pressKey(field, 'esc');\r | |
965 | \r | |
966 | waitsFor(function() {\r | |
967 | return !plugin.editing;\r | |
968 | }, 'editing to stop', 1000);\r | |
969 | \r | |
970 | runs(function() {\r | |
971 | expect(plugin.editing).toBe(false);\r | |
972 | });\r | |
973 | });\r | |
974 | });\r | |
975 | });\r | |
976 | \r | |
977 | describe('as textarea', function () {\r | |
978 | beforeEach(function () {\r | |
979 | startEdit(0, 1);\r | |
980 | });\r | |
981 | \r | |
982 | it('should start the edit when ENTER is pressed', function () {\r | |
983 | var node = view.body.query('td', true)[1];\r | |
984 | \r | |
985 | // Wait for the beforeEach's startEdit to take effect\r | |
986 | waitsFor(function() {\r | |
987 | return plugin.activeEditor && plugin.activeEditor.field.hasFocus && view.actionableMode === true;\r | |
988 | }, 'beforeEach startEdit to take effect');\r | |
989 | \r | |
990 | // First complete the edit (we start an edit in the top-level beforeEach).\r | |
991 | runs(function() {\r | |
992 | grid.setActionableMode(false);\r | |
993 | });\r | |
994 | \r | |
995 | // Wait for it to clear itself up and focus to return to the cell\r | |
996 | waitsFor(function() {\r | |
997 | return plugin.activeEditor == null && plugin.editing === false && Ext.Element.getActiveElement() === node;\r | |
998 | }, 'actionable mode to end and cell to regain focus');\r | |
999 | \r | |
1000 | runs(function() {\r | |
1001 | jasmine.fireKeyEvent(node, 'keydown', 13);\r | |
1002 | });\r | |
1003 | \r | |
1004 | waitsFor(function() {\r | |
1005 | return plugin.activeEditor && plugin.editing === true;\r | |
1006 | }, 'editing to start on the focused cell');\r | |
1007 | });\r | |
1008 | \r | |
1009 | describe('when currently editing', function () {\r | |
1010 | it('should not complete the edit when ENTER is pressed', function () {\r | |
1011 | spyOn(plugin, 'completeEdit');\r | |
1012 | \r | |
1013 | // Wait for the beforeEach's startEdit to take effect\r | |
1014 | waitsFor(function() {\r | |
1015 | return plugin.activeEditor && plugin.activeEditor.field.hasFocus;\r | |
1016 | }, 'beforeEach startEdit to take effect');\r | |
1017 | \r | |
1018 | // First complete the edit (we start an edit in the top-level beforeEach).\r | |
1019 | runs(function() {\r | |
1020 | triggerEditorKey(field.inputEl, 13);\r | |
1021 | \r | |
1022 | expect(plugin.completeEdit).not.toHaveBeenCalled();\r | |
1023 | });\r | |
1024 | });\r | |
1025 | \r | |
1026 | it('should not cancel the edit when ENTER is pressed', function () {\r | |
1027 | spyOn(plugin, 'cancelEdit');\r | |
1028 | \r | |
1029 | // Wait for the beforeEach's startEdit to take effect\r | |
1030 | waitsFor(function() {\r | |
1031 | return plugin.activeEditor && plugin.activeEditor.field.hasFocus;\r | |
1032 | }, 'beforeEach startEdit to take effect');\r | |
1033 | \r | |
1034 | // First complete the edit (we start an edit in the top-level beforeEach).\r | |
1035 | runs(function() {\r | |
1036 | triggerEditorKey(field.inputEl, 13);\r | |
1037 | \r | |
1038 | expect(plugin.cancelEdit).not.toHaveBeenCalled();\r | |
1039 | });\r | |
1040 | });\r | |
1041 | \r | |
1042 | it('should cancel the edit when ESCAPE is pressed', function () {\r | |
1043 | spyOn(plugin, 'cancelEdit');\r | |
1044 | \r | |
1045 | // Wait for the beforeEach's startEdit to take effect\r | |
1046 | waitsFor(function() {\r | |
1047 | return plugin.activeEditor && plugin.activeEditor.field.hasFocus;\r | |
1048 | }, 'beforeEach startEdit to take effect');\r | |
1049 | \r | |
1050 | // First complete the edit (we start an edit in the top-level beforeEach).\r | |
1051 | runs(function() {\r | |
1052 | triggerEditorKey(field.inputEl, 27);\r | |
1053 | });\r | |
1054 | \r | |
1055 | waitsFor(function () {\r | |
1056 | return !plugin.editing;\r | |
1057 | }, 'ESC keydown to have terminated editing');\r | |
1058 | \r | |
1059 | runs(function () {\r | |
1060 | expect(plugin.editing).toBe(false);\r | |
1061 | });\r | |
1062 | });\r | |
1063 | \r | |
1064 | describe('grow and auto-sizing', function () {\r | |
1065 | var str = 'Attention all planets of the Solar Federation!\nAttention all planets of the Solar Federation!\nWe have assumed control!';\r | |
1066 | \r | |
1067 | it('should auto-size when written to', function () {\r | |
1068 | spyOn(field, 'autoSize');\r | |
1069 | \r | |
1070 | field.setValue(str);\r | |
1071 | \r | |
1072 | expect(field.autoSize).toHaveBeenCalled();\r | |
1073 | });\r | |
1074 | \r | |
1075 | it('should grow', function () {\r | |
1076 | var previousHeight = field.getHeight();\r | |
1077 | \r | |
1078 | field.setValue(str);\r | |
1079 | \r | |
1080 | expect(field.getHeight()).toBeGreaterThan(previousHeight);\r | |
1081 | });\r | |
1082 | });\r | |
1083 | });\r | |
1084 | });\r | |
1085 | });\r | |
1086 | \r | |
1087 | describe('key mappings', function () {\r | |
1088 | it('should not stop propagation on the enter key', function () {\r | |
1089 | var EM = Ext.EventManager;\r | |
1090 | \r | |
1091 | spyOn(EM, 'stopPropagation');\r | |
1092 | spyOn(EM, 'preventDefault');\r | |
1093 | \r | |
1094 | makeGrid();\r | |
1095 | startEdit(0, 1);\r | |
1096 | \r | |
1097 | triggerEditorKey(column.field.inputEl, 13);\r | |
1098 | \r | |
1099 | expect(EM.stopPropagation).not.toHaveBeenCalled();\r | |
1100 | expect(EM.preventDefault).not.toHaveBeenCalled();\r | |
1101 | });\r | |
1102 | });\r | |
1103 | \r | |
1104 | describe('in a collapsed container', function () {\r | |
1105 | // To reproduce the bug:\r | |
1106 | // 1. Start edit\r | |
1107 | // 2. Collapse the fieldset\r | |
1108 | // 3. Create the new editor (or any component that contains an editor)\r | |
1109 | // 4. Show the fieldset\r | |
1110 | // 5. Try to start edit\r | |
1111 | //\r | |
1112 | // See EXTJS-12752.\r | |
1113 | var fieldset, editor_1, editor_2;\r | |
1114 | \r | |
1115 | beforeEach(function () {\r | |
1116 | fieldset = new Ext.form.FieldSet({\r | |
1117 | collapsible: true,\r | |
1118 | items: makeGrid({\r | |
1119 | renderTo: null\r | |
1120 | }),\r | |
1121 | width: 500,\r | |
1122 | renderTo: Ext.getBody()\r | |
1123 | });\r | |
1124 | \r | |
1125 | startEdit();\r | |
1126 | });\r | |
1127 | \r | |
1128 | afterEach(function () {\r | |
1129 | Ext.destroy(fieldset, editor_1, editor_2);\r | |
1130 | fieldset = editor_1 = editor_2 = null;\r | |
1131 | });\r | |
1132 | \r | |
1133 | it('should not set its hierarchicallyHidden property in response to any hierarchyEvents', function () {\r | |
1134 | waitsFor(function() {\r | |
1135 | return (editor_1 = plugin.activeEditor) && editor_1.field.hasFocus;\r | |
1136 | }, 'editing to start');\r | |
1137 | \r | |
1138 | runs(function() {\r | |
1139 | \r | |
1140 | // We have to fake a blur here.\r | |
1141 | plugin.completeEdit();\r | |
1142 | \r | |
1143 | fieldset.toggle();\r | |
1144 | \r | |
1145 | editor_2 = new Ext.grid.CellEditor({\r | |
1146 | field: 'textfield',\r | |
1147 | renderTo: Ext.getBody()\r | |
1148 | });\r | |
1149 | \r | |
1150 | fieldset.toggle();\r | |
1151 | \r | |
1152 | plugin.startEdit(record, column);\r | |
1153 | });\r | |
1154 | \r | |
1155 | waitsFor(function() {\r | |
1156 | return editor_1.hidden === false;\r | |
1157 | }, 'editor_1 to show');\r | |
1158 | \r | |
1159 | runs(function() {\r | |
1160 | expect(editor_1.hierarchicallyHidden).toBe(false);\r | |
1161 | });\r | |
1162 | });\r | |
1163 | \r | |
1164 | it('should show the CellEditor when the edit is started', function () {\r | |
1165 | waitsFor(function() {\r | |
1166 | return (editor_1 = plugin.activeEditor) && editor_1.field.hasFocus;\r | |
1167 | }, 'editing to start');\r | |
1168 | \r | |
1169 | runs(function() {\r | |
1170 | \r | |
1171 | // We have to fake a blur here.\r | |
1172 | plugin.completeEdit();\r | |
1173 | \r | |
1174 | fieldset.toggle();\r | |
1175 | \r | |
1176 | editor_2 = new Ext.grid.CellEditor({\r | |
1177 | field: 'textfield',\r | |
1178 | renderTo: Ext.getBody()\r | |
1179 | });\r | |
1180 | \r | |
1181 | fieldset.toggle();\r | |
1182 | \r | |
1183 | plugin.startEdit(record, column);\r | |
1184 | });\r | |
1185 | \r | |
1186 | waitsFor(function() {\r | |
1187 | return editor_1.hidden === false;\r | |
1188 | }, 'editor_1 to show');\r | |
1189 | });\r | |
1190 | });\r | |
1191 | \r | |
1192 | describe('selectOnFocus', function () {\r | |
1193 | // I could not get the following spec to pass in the following browsers, although the test case does work.\r | |
1194 | // The dom.select() method in FF seems to be asynchronous (possibly for Opera as well), and IE 11 always\r | |
1195 | // returned an empty string for the text selection even though it claims to support window.getSelection().\r | |
1196 | ((Ext.isGecko || Ext.isOpera || Ext.isIE11) ? xit : it)('should select the text in the cell when initiating an edit', function () {\r | |
1197 | // See EXTJS-12364.\r | |
1198 | var node;\r | |
1199 | \r | |
1200 | function getSelectionText() {\r | |
1201 | var text;\r | |
1202 | \r | |
1203 | if (!Ext.isIE) {\r | |
1204 | text = window.getSelection().toString();\r | |
1205 | } else if (document.selection) {\r | |
1206 | text = document.selection.createRange().text;\r | |
1207 | }\r | |
1208 | \r | |
1209 | return text;\r | |
1210 | }\r | |
1211 | \r | |
1212 | makeGrid(null, {\r | |
1213 | columns: [\r | |
1214 | {header: 'Name', dataIndex: 'name',\r | |
1215 | editor: {\r | |
1216 | xtype: 'textfield',\r | |
1217 | selectOnFocus: true\r | |
1218 | }\r | |
1219 | },\r | |
1220 | {header: 'Email', dataIndex: 'email', flex:1,\r | |
1221 | editor: {\r | |
1222 | xtype: 'textfield',\r | |
1223 | selectOnFocus: true\r | |
1224 | }\r | |
1225 | },\r | |
1226 | {header: 'Phone', dataIndex: 'phone', editor: 'textfield'},\r | |
1227 | {header: 'Age', dataIndex: 'age', editor: 'textfield'}\r | |
1228 | ]\r | |
1229 | });\r | |
1230 | \r | |
1231 | node = grid.view.getNode(grid.store.getAt(1));\r | |
1232 | jasmine.fireMouseEvent(node.getElementsByTagName('td')[0], 'dblclick');\r | |
1233 | \r | |
1234 | expect(getSelectionText()).toBe('Bart');\r | |
1235 | });\r | |
1236 | });\r | |
1237 | \r | |
1238 | describe('not completing the edit', function () {\r | |
1239 | beforeEach(function() {\r | |
1240 | \r | |
1241 | // Must wait for async focus events from previous suite to complete.\r | |
1242 | waits(10);\r | |
1243 | });\r | |
1244 | it('should preserve the correct editing context', function () {\r | |
1245 | var listener = function () {\r | |
1246 | return false;\r | |
1247 | }, ed, context;\r | |
1248 | \r | |
1249 | makeGrid(null, {\r | |
1250 | columns: [\r | |
1251 | {header: 'Name', dataIndex: 'name',\r | |
1252 | editor: {\r | |
1253 | xtype: 'textfield',\r | |
1254 | selectOnFocus: true\r | |
1255 | }\r | |
1256 | },\r | |
1257 | {header: 'Email', dataIndex: 'email', flex:1,\r | |
1258 | editor: {\r | |
1259 | xtype: 'textfield',\r | |
1260 | selectOnFocus: true\r | |
1261 | }\r | |
1262 | },\r | |
1263 | {header: 'Phone', dataIndex: 'phone', editor: 'textfield'},\r | |
1264 | {header: 'Age', dataIndex: 'age', editor: 'textfield'}\r | |
1265 | ]\r | |
1266 | });\r | |
1267 | \r | |
1268 | startEdit(0, 1);\r | |
1269 | waitsFor(function() {\r | |
1270 | ed = plugin.activeEditor;\r | |
1271 | return !!ed;\r | |
1272 | }, 'editing to start at cell(0, 1)');\r | |
1273 | runs(function() {\r | |
1274 | context = plugin.context;\r | |
1275 | \r | |
1276 | ed.on('beforecomplete', listener);\r | |
1277 | ed.setValue('derp');\r | |
1278 | // Cancel edit.\r | |
1279 | triggerEditorKey(ed.field.inputEl, 27);\r | |
1280 | \r | |
1281 | expect(plugin.context).toBe(context);\r | |
1282 | });\r | |
1283 | });\r | |
1284 | });\r | |
1285 | \r | |
1286 | describe('operations that refresh the view', function () {\r | |
1287 | var ed;\r | |
1288 | \r | |
1289 | afterEach(function () {\r | |
1290 | ed = null;\r | |
1291 | });\r | |
1292 | \r | |
1293 | describe('when editing and tabbing', function () {\r | |
1294 | function doIt(autoSync) {\r | |
1295 | it('should not complete the edit in the new position, autoSync ' + autoSync, function () {\r | |
1296 | makeGrid(null, null, {\r | |
1297 | autoSync: autoSync\r | |
1298 | });\r | |
1299 | \r | |
1300 | record = grid.store.getAt(0);\r | |
1301 | column = grid.columns[0];\r | |
1302 | \r | |
1303 | plugin.startEdit(record, column);\r | |
1304 | ed = plugin.activeEditor;\r | |
1305 | ed.setValue('Pete the Dog was here');\r | |
1306 | \r | |
1307 | // Now let's tab and check that the editor is still shown and active.\r | |
1308 | jasmine.fireKeyEvent(ed.field.inputEl, 'keydown', 9);\r | |
1309 | \r | |
1310 | waitsFor(function () {\r | |
1311 | return !!plugin.activeEditor.editing;\r | |
1312 | }, 'editing to start', 1000);\r | |
1313 | \r | |
1314 | runs(function () {\r | |
1315 | // ed is the old editor\r | |
1316 | expect(ed.editing).toBe(false);\r | |
1317 | expect(plugin.activeEditor.editing).toBe(true);\r | |
1318 | expect(plugin.activeColumn.dataIndex).toBe('email');\r | |
1319 | });\r | |
1320 | });\r | |
1321 | }\r | |
1322 | \r | |
1323 | doIt(true);\r | |
1324 | doIt(false);\r | |
1325 | });\r | |
1326 | \r | |
1327 | describe('when editing and syncing', function () {\r | |
1328 | it('should not complete the edit in the current position', function () {\r | |
1329 | makeGrid();\r | |
1330 | \r | |
1331 | record = grid.store.getAt(0);\r | |
1332 | column = grid.columns[0];\r | |
1333 | \r | |
1334 | plugin.startEdit(record, column);\r | |
1335 | ed = plugin.activeEditor;\r | |
1336 | ed.setValue('Pete the Dog was here');\r | |
1337 | store.sync();\r | |
1338 | \r | |
1339 | waitsFor(function () {\r | |
1340 | return !!plugin.activeEditor.editing;\r | |
1341 | }, 'editing to start', 1000);\r | |
1342 | \r | |
1343 | runs(function () {\r | |
1344 | expect(ed.editing).toBe(true);\r | |
1345 | expect(plugin.activeColumn.dataIndex).toBe('name');\r | |
1346 | });\r | |
1347 | });\r | |
1348 | });\r | |
1349 | });\r | |
1350 | });\r |