]>
git.proxmox.com Git - extjs.git/blob - extjs/classic/classic/test/specs/grid/plugin/CellEditing.js
1 describe('Ext.grid.plugin.CellEditing', function () {
2 var store
, plugin
, grid
, view
, record
, column
, field
,
4 synchronousLoad
= true,
5 proxyStoreLoad
= Ext
.data
.ProxyStore
.prototype.load
,
8 function makeGrid(pluginCfg
, gridCfg
, storeCfg
, locked
) {
9 store
= new Ext
.data
.Store(Ext
.apply({
10 fields
: ['name', 'email', 'phone'],
12 {'name': 'Lisa', 'email': 'lisa@simpsons.com', 'phone': '555-111-1224', 'age': 14},
13 {'name': 'Bart', 'email': 'bart@simpsons.com', 'phone': '555-222-1234', 'age': 12},
14 {'name': 'Homer', 'email': 'homer@simpsons.com', 'phone': '555-222-1244', 'age': 44},
15 {'name': 'Marge', 'email': 'marge@simpsons.com', 'phone': '555-222-1254', 'age': 41}
20 plugin
= new Ext
.grid
.plugin
.CellEditing(pluginCfg
);
22 grid
= new Ext
.grid
.Panel(Ext
.apply({
24 {header
: 'Name', dataIndex
: 'name', editor
: 'textfield', locked
: locked
},
25 {header
: 'Email', dataIndex
: 'email', flex
:1,
27 xtype
: 'textareafield',
32 {header
: 'Phone', dataIndex
: 'phone', editor
: 'textfield'},
33 {header
: 'Age', dataIndex
: 'age', editor
: 'textfield'}
36 selModel
: 'cellmodel',
40 renderTo
: Ext
.getBody()
46 function startEdit(recId
, colId
) {
47 record
= store
.getAt(recId
|| 0);
48 column
= grid
.columns
[colId
|| 0];
49 plugin
.startEdit(record
, column
);
53 function triggerEditorKey(target
, key
) {
54 // Ext.supports.SpecialKeyDownRepeat changes the event Ext.form.field.Base listens for!
55 jasmine
.fireKeyEvent(target
, Ext
.supports
.SpecialKeyDownRepeat
? 'keydown' : 'keypress', key
);
58 beforeEach(function() {
59 // Override so that we can control asynchronous loading
60 loadStore
= Ext
.data
.ProxyStore
.prototype.load = function() {
61 proxyStoreLoad
.apply(this, arguments
);
62 if (synchronousLoad
) {
63 this.flushLoad
.apply(this, arguments
);
68 MockAjaxManager
.addMethods();
71 afterEach(function() {
72 // Undo the overrides.
73 Ext
.data
.ProxyStore
.prototype.load
= proxyStoreLoad
;
76 MockAjaxManager
.removeMethods();
80 store
= plugin
= grid
= view
= record
= column
= field
= Ext
.destroy(grid
);
83 describe('finding the cell editing plugin in a locking grid', function() {
84 beforeEach(function() {
85 makeGrid({pluginId
:'test-cell-editing'}, null, null, true);
88 it('should find it by id', function() {
89 expect(grid
.getPlugin('test-cell-editing')).toBe(plugin
);
91 it('should find it by ptype', function() {
92 expect(grid
.findPlugin('cellediting')).toBe(plugin
);
96 describe('effect of hiding columns on cell editing selection', function () {
97 // These specs show that hiding columns pre- or post- cell edit will not place the x-grid-cell-selected class on the wrong
98 // cell in the wrong column when the row is updated since Ext.view.Table:renderCell is now looking up the cell context by
99 // header rather than by index. See EXTJSIV-11653.
100 var wasEdited
= false,
103 beforeEach(function () {
106 edit: function (editor
) {
114 columnManager
= grid
.getColumnManager();
117 afterEach(function () {
119 columnManager
= null;
122 it('should give the edited cell the selected class after initially hiding columns', function () {
123 // First hide the columns.
124 columnManager
.getColumns()[0].hide();
125 columnManager
.getColumns()[1].hide();
128 record
= grid
.store
.getAt(0);
129 column
= columnManager
.getColumns()[2];
130 cell
= grid
.view
.getCell(record
, column
);
132 jasmine
.fireMouseEvent(cell
, 'dblclick');
133 plugin
.getEditor(record
, column
).setValue('111-111-1111');
134 plugin
.completeEdit();
136 waitsFor(function () {
141 // Finally show that the selected cell is in the correct column.
142 cell
= Ext
.fly(grid
.view
.getNode(record
)).down('.x-grid-cell-selected');
143 expect(cell
.hasCls('x-grid-cell-' + column
.id
)).toBe(true);
147 it('should move the selected cell along with its column when other columns are hidden', function () {
148 record
= grid
.store
.getAt(0);
149 column
= columnManager
.columns
[2];
150 cell
= grid
.view
.getCell(record
, column
);
152 jasmine
.fireMouseEvent(cell
, 'dblclick');
153 plugin
.getEditor(record
, column
).setValue('111-111-1111');
154 plugin
.completeEdit();
156 waitsFor(function () {
161 // First simply show that the selected cell is in the correct column.
162 cell
= Ext
.fly(grid
.view
.getNode(record
)).down('.x-grid-cell-selected');
163 expect(cell
.hasCls('x-grid-cell-' + column
.id
)).toBe(true);
165 columnManager
.columns
[0].hide();
167 // Now show that the selected cell is still in the correct column.
168 cell
= Ext
.fly(grid
.view
.getNode(record
)).down('.x-grid-cell-selected');
169 expect(cell
.hasCls('x-grid-cell-' + column
.id
)).toBe(true);
174 describe('events', function () {
175 var editorContext
, cancelEditFired
;
177 afterEach(function () {
178 editorContext
= null;
181 describe('beforeedit', function () {
182 it('should retain changes to the editing context in the event handler', function () {
183 // See EXTJSIV-11643.
186 beforeedit: function (editor
, context
) {
187 context
.value
= 'motley';
188 editorContext
= context
;
195 expect(editorContext
.value
).toBe('motley');
199 describe('canceledit', function () {
200 beforeEach(function () {
202 // Must wait for async focus events from previous suite to complete.
206 cancelEditFired
= false;
210 canceledit: function (editor
, context
) {
211 cancelEditFired
= true;
212 editorContext
= context
;
221 it('should be able to get the original value when canceling the edit by the plugin', function() {
222 expect(plugin
.editing
).toBe(true);
224 // Note that the columnmove and columnresize events go through plugin.cancelEdit().
225 column
.getEditor().setValue('baz');
228 expect(cancelEditFired
).toBe(true);
229 expect(editorContext
.originalValue
).toBe('Lisa');
232 it('should be able to get the edited value when canceling the edit by the plugin', function() {
233 expect(plugin
.editing
).toBe(true);
235 // Note that the columnmove and columnresize events go through plugin.cancelEdit().
236 column
.getEditor().setValue('foo');
239 expect(cancelEditFired
).toBe(true);
240 expect(editorContext
.value
).toBe('foo');
243 it('should have different values for edited value and original value when canceling', function() {
244 expect(plugin
.editing
).toBe(true);
246 column
.getEditor().setValue('foo');
249 expect(cancelEditFired
).toBe(true);
250 expect(editorContext
.value
).not
.toBe(editorContext
.originalValue
);
253 it('should be able to get the edited value when canceling the edit by the editor', function() {
254 expect(plugin
.editing
).toBe(true);
256 // Note that the canceledit event goes through editor.cancelEdit().
257 column
.getEditor().setValue('bar');
258 plugin
.getEditor(record
, column
).cancelEdit();
260 expect(cancelEditFired
).toBe(true);
261 expect(editorContext
.value
).not
.toBe(editorContext
.originalValue
);
262 expect(editorContext
.value
).toBe('bar');
265 describe('falsey values', function () {
266 it('should be able to capture falsey values when canceled by the plugin', function() {
267 expect(plugin
.editing
).toBe(true);
269 // Note that the columnmove and columnresize events go through plugin.cancelEdit().
270 column
.getEditor().setValue('');
273 expect(cancelEditFired
).toBe(true);
274 expect(editorContext
.value
).toBe('');
277 it('should be able to capture falsey values for the editedValue when canceled by the editor', function() {
278 expect(plugin
.editing
).toBe(true);
280 // Note that the canceledit event goes through editor.cancelEdit().
281 column
.getEditor().setValue('');
282 plugin
.getEditor(record
, column
).cancelEdit();
284 waitsFor(function() {
285 return cancelEditFired
;
288 expect(editorContext
.value
).toBe('');
294 describe('selecting ranges', function () {
298 function fireEvent(rowNum
, eventName
, shift
) {
299 jasmine
.fireMouseEvent(view
.getNode(rowNum
).getElementsByTagName('td')[0],eventName
, null, null, null, !!shift
);
302 function expectSelected(rec
) {
305 if (arguments
.length
=== 1) {
306 if (typeof rec
== 'number') {
307 rec
= store
.getAt(rec
);
309 expect(selModel
.isSelected(rec
)).toBe(true);
311 for (i
= 0, len
= arguments
.length
; i
< len
; ++i
) {
312 expectSelected(arguments
[i
]);
317 afterEach(function () {
321 function selectRange(eventName
) {
322 describe('MULTI', function () {
323 beforeEach(function () {
325 clicksToEdit
: eventName
=== 'click' ? 1: 2
333 selModel
= grid
.selModel
;
336 it('should select a range if we have a selection start point and shift is pressed', function () {
337 fireEvent(0, eventName
);
338 fireEvent(3, eventName
, true);
339 expectSelected(0, 1, 2, 3);
342 it('should maintain selection with a complex sequence', function() {
343 fireEvent(0, eventName
);
345 fireEvent(2, eventName
, true);
346 expectSelected(0, 1, 2);
347 fireEvent(3, eventName
);
349 fireEvent(1, eventName
, true);
350 expectSelected(1, 2, 3);
352 fireEvent(2, eventName
);
354 fireEvent(0, eventName
, true);
355 expectSelected(0, 1, 2);
356 fireEvent(3, eventName
, true);
357 expectSelected(2, 3);
362 selectRange('click');
363 selectRange('dblclick');
367 describe('sorting', function () {
368 it('should complete the edit when focusing the column', function () {
373 expect(plugin
.editing
).toBe(false);
377 describe('making multiple selections with checkbox model', function () {
380 afterEach(function () {
381 store
= selModel
= null;
384 it('should keep existing selections when editing a cell in an previously-selected row', function () {
386 selModel
: new Ext
.selection
.CheckboxModel({})
390 selModel
= grid
.selModel
;
392 // Select all models in the store.
393 selModel
.select(store
.data
.items
);
398 // All the previous selections should still be selected.
399 expect(selModel
.getSelection().length
).toBe(store
.data
.length
);
402 it('should expect that the correct records have been selected', function () {
403 var contains
= Ext
.Array
.contains
,
407 selModel
: new Ext
.selection
.CheckboxModel({})
411 selModel
= grid
.selModel
;
413 // Make some selections.
414 selModel
.select([store
.getAt(1), store
.getAt(3)]);
416 // Now edit a cell in an unselected row.
417 // As of 5.0.1, it should NOT select, but should preserve existing MULTI selections: https://sencha.jira.com/browse/EXTJS-14472
420 selections
= selModel
.getSelection();
422 expect(contains(selections
, store
.getAt(0))).toBe(false);
423 expect(contains(selections
, store
.getAt(1))).toBe(true);
424 expect(contains(selections
, store
.getAt(2))).toBe(false);
425 expect(contains(selections
, store
.getAt(3))).toBe(true);
428 it('should keep existing selections when editing a cell in an unselected row', function () {
430 selModel
: new Ext
.selection
.CheckboxModel({})
434 selModel
= grid
.selModel
;
436 // Make some selections.
437 selModel
.select([store
.getAt(0), store
.getAt(1)]);
439 // Now edit a cell in an unselected row.
440 // As of 5.0.1, it should NOT select, but should preserve existing MULTI selections: https://sencha.jira.com/browse/EXTJS-14472
443 // The selections should now also include the row that contains the cell being edited.
444 expect(selModel
.getSelection().length
).toBe(2);
448 describe('setting value while remote querying', function () {
449 // These tests simulates a test case where a value is entered in the editor (either as .value or .rawValue) and then
450 // is tabbed out of the editor (and completing the edit) before the response returns and the combo store is loaded.
453 // There is a lot of coverage for combos, but we also needed to test the behavior of combos as cell editors. There have
454 // been bugs where raw values have been retained by the editor across tabs, i.e., if 'foo' is entered in the editor that
455 // same value will be retained as the user tabs through the grid (although this only seems to happen in grids where only
456 // a single column is editable, as tested below). Also, there have been bugs where the same editor value (.value) has been
457 // been written to each model as the user tabs (obviously not good). The following tests cover both of these scenarios.
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,
460 // both when forceSelection is on and off. In either case (of forceSelection), we have decided that the value should be
461 // allowed because the combo store hasn't been loaded yet. The contract with forceSelection is with the combo store, and if
462 // the user chooses to enter a value before said store is loaded then we cannot do anything about that as we cannot look
467 function createUI(forceSelection
) {
468 comboStore
= new Ext
.data
.Store({
469 fields
: ['id', 'state', 'nickname'],
483 renderer: function (value
, metaData
, record
) {
484 return record
.get('state');
492 displayField
: 'state',
494 forceSelection
: forceSelection
498 fields
: ['id', 'state', 'nickname'],
500 ['AL', 'Alabama', 'The Heart of Dixie'],
501 ['AK', 'Alaska', 'The Land of the Midnight Sun'],
502 ['AR', 'Arkansas', 'The Natural State'],
503 ['AZ', 'Arizona', 'The Grand Canyon State']
514 describe('only one editable column', function () {
515 function initiateTests(expectation
, loadStore
) {
516 describe(expectation
, function () {
517 function forceSelection(force
) {
518 describe('forceSelection = ' + force
, function () {
519 beforeEach(function () {
523 afterEach(function () {
524 Ext
.destroy(comboStore
);
525 comboStore
= ed
= null;
528 function setup(force
, method
) {
529 // Initiate the edit.
530 jasmine
.fireMouseEvent(grid
.view
.getNode(store
.getAt(0)).getElementsByTagName('td')[0], 'dblclick');
531 ed
= plugin
.getActiveEditor();
538 // Simulate the load which happens when text is typed into the editor.
539 // Let's then tab out to complete the edit.
540 if (method
=== 'setRawValue') {
541 ed
.field
.setRawValue('ben');
546 jasmine
.fireKeyEvent(ed
.field
.inputEl
, 'keydown', 9);
549 function setValue(raw
) {
550 var method
= raw
? 'setRawValue' : 'setValue';
552 describe(method
, function () {
553 it('should write the value to the model', function () {
556 setup(force
, method
);
558 if (force
&& method
=== 'setRawValue') {
562 record
= store
.getAt(0);
563 expect(record
.get('id')).toBe(val
);
564 expect(record
.get('state')).toBe('Alabama');
567 it('should not set any other fields in the model across tabs', function () {
568 // There have been bugs which caused the same value to be set in different models across tabs.
569 setup(force
, method
);
571 record
= store
.getAt(1);
572 expect(record
.get('id')).toBe('AK');
573 expect(record
.get('state')).toBe('Alaska');
575 record
= store
.getAt(2);
576 jasmine
.fireKeyEvent(ed
.field
.inputEl
, 'keydown', 9);
577 expect(record
.get('state')).toBe('Arkansas');
578 expect(record
.get('nickname')).toBe('The Natural State');
580 record
= store
.getAt(3);
581 jasmine
.fireKeyEvent(ed
.field
.inputEl
, 'keydown', 9);
582 expect(record
.get('state')).toBe('Arizona');
583 expect(record
.get('nickname')).toBe('The Grand Canyon State');
586 it('should give the editor different values across tabs', function () {
587 // There have been bugs which caused the editor to keep the same value across tabs.
588 setup(force
, method
);
590 // It should not propagate the user-inputted value.
592 // Let's make sure the editor has the correct value...
593 expect(ed
.getValue()).toBe('AK');
594 expect(ed
.field
.getRawValue()).toBe('');
596 jasmine
.fireKeyEvent(ed
.field
.inputEl
, 'keydown', 9);
597 expect(ed
.getValue()).toBe('AR');
599 jasmine
.fireKeyEvent(ed
.field
.inputEl
, 'keydown', 9);
600 expect(ed
.getValue()).toBe('AZ');
603 it('should not give the editor a raw value because the combo store has not been loaded', function () {
604 // There have been bugs which caused the editor to keep the same raw value across tabs.
605 setup(force
, method
);
607 expect(ed
.field
.getRawValue()).toBe('');
609 jasmine
.fireKeyEvent(ed
.field
.inputEl
, 'keydown', 9);
610 expect(ed
.field
.getRawValue()).toBe('');
612 jasmine
.fireKeyEvent(ed
.field
.inputEl
, 'keydown', 9);
613 expect(ed
.field
.getRawValue()).toBe('');
623 forceSelection(false);
624 forceSelection(true);
628 initiateTests('before store load is initiated', false);
629 initiateTests('while store is loading', true);
631 describe('when tabbing (down/up to the contiguous row)', function () {
634 beforeEach(function () {
639 {header
: 'Name', dataIndex
: 'name', editor
: 'textfield'},
640 {header
: 'Email', dataIndex
: 'email', flex
:1},
641 {header
: 'Phone', dataIndex
: 'phone'},
642 {header
: 'Age', dataIndex
: 'age'}
649 activeEditor
= plugin
.activeEditor
;
651 // Spy on afterHide to count *successful* hides.
652 // hide may be called when already hidden during CellEditing tabbing sequence.
653 spyOn(activeEditor
, 'afterHide').andCallThrough();
655 jasmine
.fireKeyEvent(column
.field
.inputEl
, 'keydown', 9);
658 afterEach(function () {
662 it('should not complete', function () {
663 expect(activeEditor
).not
.toBe(null);
664 expect(plugin
.activeColumn
).not
.toBe(null);
665 expect(plugin
.activeRecord
).not
.toBe(null);
668 it('should hide the editor', function () {
669 expect(activeEditor
).not
.toBe(null);
670 expect(activeEditor
.isVisible()).toBe(true);
672 // CellEditing is just part of actionable mode.
673 // Actionable mode does not know that you are going to focus to the same editor.
674 // It just desctivates the old row, activates the new row, and focuses the first tabbable element.
675 // Deactivating a row will hide the editors.
676 // So the "name" editor will have been hidden when that row was deactivated.
677 expect(activeEditor
.afterHide
.callCount
).toBe(1);
683 describe('clicksToEdit', function () {
684 describe('2 clicks', function () {
685 beforeEach(function () {
689 it('should default to 2', function () {
690 expect(plugin
.clicksToEdit
).toBe(2);
693 it('should begin editing when double-clicked', function () {
694 record
= grid
.store
.getAt(0);
695 node
= grid
.view
.getNodeByRecord(record
);
696 jasmine
.fireMouseEvent(Ext
.fly(node
).down('.x-grid-cell'), 'dblclick');
698 expect(plugin
.activeEditor
).not
.toBeFalsy();
701 it('should not begin editing when single-clicked', function () {
702 record
= grid
.store
.getAt(0);
703 node
= grid
.view
.getNodeByRecord(record
);
704 jasmine
.fireMouseEvent(Ext
.fly(node
).down('.x-grid-cell'), 'click');
706 expect(plugin
.activeEditor
).toBeFalsy();
709 describe('editing a new cell', function () {
712 afterEach(function () {
713 cells
= boundEl
= null;
716 it('should update the activeEditor to point to the new cell, adjacent', function () {
717 record
= grid
.store
.getAt(0);
718 node
= grid
.view
.getNodeByRecord(record
);
719 cells
= Ext
.fly(node
).query('.x-grid-cell');
722 jasmine
.fireMouseEvent(boundEl
, 'dblclick');
724 expect(plugin
.activeEditor
.boundEl
.dom
).toBe(boundEl
);
726 // Update the boundEl to our new cell.
728 jasmine
.fireMouseEvent(boundEl
, 'dblclick');
730 expect(plugin
.activeEditor
.boundEl
.dom
).toBe(boundEl
);
733 it('should update the activeEditor to point to the new cell, below', function () {
734 record
= grid
.store
.getAt(0);
735 node
= grid
.view
.getNodeByRecord(record
);
736 boundEl
= Ext
.fly(node
).down('.x-grid-cell').dom
;
738 jasmine
.fireMouseEvent(boundEl
, 'dblclick');
740 expect(plugin
.activeEditor
.boundEl
.dom
).toBe(boundEl
);
742 record
= grid
.store
.getAt(1);
743 node
= grid
.view
.getNodeByRecord(record
);
745 // Update the boundEl to our new cell.
746 boundEl
= Ext
.fly(node
).down('.x-grid-cell').dom
;
748 jasmine
.fireMouseEvent(boundEl
, 'dblclick');
750 expect(plugin
.activeEditor
.boundEl
.dom
).toBe(boundEl
);
755 describe('1 click', function () {
756 beforeEach(function () {
762 it('should honor a different number than the default', function () {
763 expect(plugin
.clicksToEdit
).toBe(1);
766 it('should begin editing when single-clicked', function () {
767 record
= grid
.store
.getAt(0);
768 node
= grid
.view
.getNodeByRecord(record
);
769 jasmine
.fireMouseEvent(Ext
.fly(node
).down('.x-grid-cell'), 'click');
771 expect(plugin
.activeEditor
).not
.toBeFalsy();
774 // Note: I'm disabling this for IE b/c certain versions (esp. 10 & 11) could not distinguish
775 // between single- and double-click.
777 it('should not begin editing when double-clicked', function () {
778 record
= grid
.store
.getAt(0);
779 node
= grid
.view
.getNodeByRecord(record
);
780 jasmine
.fireMouseEvent(Ext
.fly(node
).down('.x-grid-cell'), 'dblclick');
782 expect(plugin
.activeEditor
).toBeFalsy();
786 describe('editing a new cell', function () {
789 afterEach(function () {
790 cells
= boundEl
= null;
793 it('should update the activeEditor to point to the new cell, adjacent', function () {
794 record
= grid
.store
.getAt(0);
795 node
= grid
.view
.getNodeByRecord(record
);
796 cells
= Ext
.fly(node
).query('.x-grid-cell');
799 jasmine
.fireMouseEvent(boundEl
, 'click');
801 expect(plugin
.activeEditor
.boundEl
.dom
).toBe(boundEl
);
803 // Update the boundEl to our new cell.
805 jasmine
.fireMouseEvent(boundEl
, 'click');
807 expect(plugin
.activeEditor
.boundEl
.dom
).toBe(boundEl
);
810 it('should update the activeEditor to point to the new cell, below', function () {
811 record
= grid
.store
.getAt(0);
812 node
= grid
.view
.getNodeByRecord(record
);
813 boundEl
= Ext
.fly(node
).down('.x-grid-cell').dom
;
815 jasmine
.fireMouseEvent(boundEl
, 'click');
817 expect(plugin
.activeEditor
.boundEl
.dom
).toBe(boundEl
);
819 record
= grid
.store
.getAt(1);
820 node
= grid
.view
.getNodeByRecord(record
);
822 // Update the boundEl to our new cell.
823 boundEl
= Ext
.fly(node
).down('.x-grid-cell').dom
;
825 jasmine
.fireMouseEvent(boundEl
, 'click');
827 expect(plugin
.activeEditor
.boundEl
.dom
).toBe(boundEl
);
833 describe('the CellEditor', function () {
834 beforeEach(function () {
839 it('should get an ownerCmp reference to the grid', function () {
840 waitsFor(function() {
841 return plugin
.activeEditor
&& plugin
.activeEditor
.ownerCmp
=== grid
;
845 it('should be able to lookup up its owner in the component hierarchy chain', function () {
846 waitsFor(function() {
847 return plugin
.activeEditor
&& plugin
.activeEditor
.up('grid') === grid
;
851 describe('positioning the editor', function () {
852 it('should default to "l-l!"', function () {
853 field
= column
.field
;
855 expect(field
.xtype
).toBe('textfield');
856 waitsFor(function() {
857 return plugin
.activeEditor
&& plugin
.activeEditor
.alignment
=== 'l-l!';
861 it('should constrain to the view if the editor goes out of bounds', function () {
862 // Wait for the beforeEach's startEdit to get started
863 waitsFor(function() {
864 return plugin
.activeEditor
&& plugin
.activeEditor
.field
.hasFocus
;
865 }, 'editor to focus', 1000);
867 // Need to be able to correctly startEdit while editing to move edit location
872 waitsFor(function() {
873 return field
.hasFocus
&& field
.getRegion().top
=== Ext
.fly(plugin
.activeEditor
.container
).getRegion().top
;
874 }, 'something funky to happen', 1000);
877 it('should not reposition when shown', function () {
878 plugin
.completeEdit();
880 spyOn(Ext
.AbstractComponent
.prototype, 'setPosition');
884 expect(plugin
.activeEditor
.setPosition
).not
.toHaveBeenCalled();
887 it('should not reposition when within a draggable container', function () {
897 win
= new Ext
.window
.Window({
903 spyOn(plugin
.activeEditor
, 'setPosition');
905 jasmine
.fireMouseEvent(win
.el
.dom
, 'mousedown');
906 jasmine
.fireMouseEvent(win
.el
.dom
, 'mousemove', win
.x
, win
.y
);
907 jasmine
.fireMouseEvent(win
.el
.dom
, 'mousemove', (win
.x
- 100), (win
.y
- 100));
908 jasmine
.fireMouseEvent(win
.el
.dom
, 'mouseup', 400);
910 expect(plugin
.activeEditor
.setPosition
).not
.toHaveBeenCalled();
916 describe('as textfield', function () {
917 it('should start the edit when ENTER is pressed', function () {
918 var node
= view
.body
.query('td', true)[0];
920 // Wait for the beforeEach's startEdit to take effect
921 waitsFor(function() {
922 return plugin
.activeEditor
&& plugin
.activeEditor
.field
.hasFocus
;
923 }, 'beforeEach startEdit to take effect');
925 // First complete the edit (we start an edit in the top-level beforeEach).
927 grid
.setActionableMode(false);
930 // Wait for it to clear itself up and focus to return to the cell
931 waitsFor(function() {
932 return plugin
.activeEditor
== null && plugin
.editing
=== false && Ext
.Element
.getActiveElement() === node
;
933 }, 'actionable mode to end and cell to regain focus');
936 jasmine
.fireKeyEvent(node
, 'keydown', 13);
939 waitsFor(function() {
940 return plugin
.activeEditor
&& plugin
.editing
=== true;
941 }, 'editing to start on the focused cell');
944 describe('when currently editing', function() {
945 it('should complete the edit when ENTER is pressed', function() {
946 var str
= 'Utley is Top Dog',
947 model
= store
.getAt(0);
949 expect(model
.get('name')).toBe('Lisa');
952 jasmine
.fireKeyEvent(field
.inputEl
.dom
, 'keydown', 13);
954 waitsFor(function() {
955 return model
.get('name') === str
;
956 }, 'model to be set', 1000);
959 expect(model
.get('name')).toBe(str
);
963 it('should cancel the edit when ESCAPE is pressed', function() {
964 jasmine
.pressKey(field
, 'esc');
966 waitsFor(function() {
967 return !plugin
.editing
;
968 }, 'editing to stop', 1000);
971 expect(plugin
.editing
).toBe(false);
977 describe('as textarea', function () {
978 beforeEach(function () {
982 it('should start the edit when ENTER is pressed', function () {
983 var node
= view
.body
.query('td', true)[1];
985 // Wait for the beforeEach's startEdit to take effect
986 waitsFor(function() {
987 return plugin
.activeEditor
&& plugin
.activeEditor
.field
.hasFocus
&& view
.actionableMode
=== true;
988 }, 'beforeEach startEdit to take effect');
990 // First complete the edit (we start an edit in the top-level beforeEach).
992 grid
.setActionableMode(false);
995 // Wait for it to clear itself up and focus to return to the cell
996 waitsFor(function() {
997 return plugin
.activeEditor
== null && plugin
.editing
=== false && Ext
.Element
.getActiveElement() === node
;
998 }, 'actionable mode to end and cell to regain focus');
1001 jasmine
.fireKeyEvent(node
, 'keydown', 13);
1004 waitsFor(function() {
1005 return plugin
.activeEditor
&& plugin
.editing
=== true;
1006 }, 'editing to start on the focused cell');
1009 describe('when currently editing', function () {
1010 it('should not complete the edit when ENTER is pressed', function () {
1011 spyOn(plugin
, 'completeEdit');
1013 // Wait for the beforeEach's startEdit to take effect
1014 waitsFor(function() {
1015 return plugin
.activeEditor
&& plugin
.activeEditor
.field
.hasFocus
;
1016 }, 'beforeEach startEdit to take effect');
1018 // First complete the edit (we start an edit in the top-level beforeEach).
1020 triggerEditorKey(field
.inputEl
, 13);
1022 expect(plugin
.completeEdit
).not
.toHaveBeenCalled();
1026 it('should not cancel the edit when ENTER is pressed', function () {
1027 spyOn(plugin
, 'cancelEdit');
1029 // Wait for the beforeEach's startEdit to take effect
1030 waitsFor(function() {
1031 return plugin
.activeEditor
&& plugin
.activeEditor
.field
.hasFocus
;
1032 }, 'beforeEach startEdit to take effect');
1034 // First complete the edit (we start an edit in the top-level beforeEach).
1036 triggerEditorKey(field
.inputEl
, 13);
1038 expect(plugin
.cancelEdit
).not
.toHaveBeenCalled();
1042 it('should cancel the edit when ESCAPE is pressed', function () {
1043 spyOn(plugin
, 'cancelEdit');
1045 // Wait for the beforeEach's startEdit to take effect
1046 waitsFor(function() {
1047 return plugin
.activeEditor
&& plugin
.activeEditor
.field
.hasFocus
;
1048 }, 'beforeEach startEdit to take effect');
1050 // First complete the edit (we start an edit in the top-level beforeEach).
1052 triggerEditorKey(field
.inputEl
, 27);
1055 waitsFor(function () {
1056 return !plugin
.editing
;
1057 }, 'ESC keydown to have terminated editing');
1060 expect(plugin
.editing
).toBe(false);
1064 describe('grow and auto-sizing', function () {
1065 var str
= 'Attention all planets of the Solar Federation!\nAttention all planets of the Solar Federation!\nWe have assumed control!';
1067 it('should auto-size when written to', function () {
1068 spyOn(field
, 'autoSize');
1070 field
.setValue(str
);
1072 expect(field
.autoSize
).toHaveBeenCalled();
1075 it('should grow', function () {
1076 var previousHeight
= field
.getHeight();
1078 field
.setValue(str
);
1080 expect(field
.getHeight()).toBeGreaterThan(previousHeight
);
1087 describe('key mappings', function () {
1088 it('should not stop propagation on the enter key', function () {
1089 var EM
= Ext
.EventManager
;
1091 spyOn(EM
, 'stopPropagation');
1092 spyOn(EM
, 'preventDefault');
1097 triggerEditorKey(column
.field
.inputEl
, 13);
1099 expect(EM
.stopPropagation
).not
.toHaveBeenCalled();
1100 expect(EM
.preventDefault
).not
.toHaveBeenCalled();
1104 describe('in a collapsed container', function () {
1105 // To reproduce the bug:
1107 // 2. Collapse the fieldset
1108 // 3. Create the new editor (or any component that contains an editor)
1109 // 4. Show the fieldset
1110 // 5. Try to start edit
1113 var fieldset
, editor_1
, editor_2
;
1115 beforeEach(function () {
1116 fieldset
= new Ext
.form
.FieldSet({
1122 renderTo
: Ext
.getBody()
1128 afterEach(function () {
1129 Ext
.destroy(fieldset
, editor_1
, editor_2
);
1130 fieldset
= editor_1
= editor_2
= null;
1133 it('should not set its hierarchicallyHidden property in response to any hierarchyEvents', function () {
1134 waitsFor(function() {
1135 return (editor_1
= plugin
.activeEditor
) && editor_1
.field
.hasFocus
;
1136 }, 'editing to start');
1140 // We have to fake a blur here.
1141 plugin
.completeEdit();
1145 editor_2
= new Ext
.grid
.CellEditor({
1147 renderTo
: Ext
.getBody()
1152 plugin
.startEdit(record
, column
);
1155 waitsFor(function() {
1156 return editor_1
.hidden
=== false;
1157 }, 'editor_1 to show');
1160 expect(editor_1
.hierarchicallyHidden
).toBe(false);
1164 it('should show the CellEditor when the edit is started', function () {
1165 waitsFor(function() {
1166 return (editor_1
= plugin
.activeEditor
) && editor_1
.field
.hasFocus
;
1167 }, 'editing to start');
1171 // We have to fake a blur here.
1172 plugin
.completeEdit();
1176 editor_2
= new Ext
.grid
.CellEditor({
1178 renderTo
: Ext
.getBody()
1183 plugin
.startEdit(record
, column
);
1186 waitsFor(function() {
1187 return editor_1
.hidden
=== false;
1188 }, 'editor_1 to show');
1192 describe('selectOnFocus', function () {
1193 // I could not get the following spec to pass in the following browsers, although the test case does work.
1194 // The dom.select() method in FF seems to be asynchronous (possibly for Opera as well), and IE 11 always
1195 // returned an empty string for the text selection even though it claims to support window.getSelection().
1196 ((Ext
.isGecko
|| Ext
.isOpera
|| Ext
.isIE11
) ? xit
: it
)('should select the text in the cell when initiating an edit', function () {
1200 function getSelectionText() {
1204 text
= window
.getSelection().toString();
1205 } else if (document
.selection
) {
1206 text
= document
.selection
.createRange().text
;
1214 {header
: 'Name', dataIndex
: 'name',
1220 {header
: 'Email', dataIndex
: 'email', flex
:1,
1226 {header
: 'Phone', dataIndex
: 'phone', editor
: 'textfield'},
1227 {header
: 'Age', dataIndex
: 'age', editor
: 'textfield'}
1231 node
= grid
.view
.getNode(grid
.store
.getAt(1));
1232 jasmine
.fireMouseEvent(node
.getElementsByTagName('td')[0], 'dblclick');
1234 expect(getSelectionText()).toBe('Bart');
1238 describe('not completing the edit', function () {
1239 beforeEach(function() {
1241 // Must wait for async focus events from previous suite to complete.
1244 it('should preserve the correct editing context', function () {
1245 var listener = function () {
1251 {header
: 'Name', dataIndex
: 'name',
1257 {header
: 'Email', dataIndex
: 'email', flex
:1,
1263 {header
: 'Phone', dataIndex
: 'phone', editor
: 'textfield'},
1264 {header
: 'Age', dataIndex
: 'age', editor
: 'textfield'}
1269 waitsFor(function() {
1270 ed
= plugin
.activeEditor
;
1272 }, 'editing to start at cell(0, 1)');
1274 context
= plugin
.context
;
1276 ed
.on('beforecomplete', listener
);
1277 ed
.setValue('derp');
1279 triggerEditorKey(ed
.field
.inputEl
, 27);
1281 expect(plugin
.context
).toBe(context
);
1286 describe('operations that refresh the view', function () {
1289 afterEach(function () {
1293 describe('when editing and tabbing', function () {
1294 function doIt(autoSync
) {
1295 it('should not complete the edit in the new position, autoSync ' + autoSync
, function () {
1296 makeGrid(null, null, {
1300 record
= grid
.store
.getAt(0);
1301 column
= grid
.columns
[0];
1303 plugin
.startEdit(record
, column
);
1304 ed
= plugin
.activeEditor
;
1305 ed
.setValue('Pete the Dog was here');
1307 // Now let's tab and check that the editor is still shown and active.
1308 jasmine
.fireKeyEvent(ed
.field
.inputEl
, 'keydown', 9);
1310 waitsFor(function () {
1311 return !!plugin
.activeEditor
.editing
;
1312 }, 'editing to start', 1000);
1315 // ed is the old editor
1316 expect(ed
.editing
).toBe(false);
1317 expect(plugin
.activeEditor
.editing
).toBe(true);
1318 expect(plugin
.activeColumn
.dataIndex
).toBe('email');
1327 describe('when editing and syncing', function () {
1328 it('should not complete the edit in the current position', function () {
1331 record
= grid
.store
.getAt(0);
1332 column
= grid
.columns
[0];
1334 plugin
.startEdit(record
, column
);
1335 ed
= plugin
.activeEditor
;
1336 ed
.setValue('Pete the Dog was here');
1339 waitsFor(function () {
1340 return !!plugin
.activeEditor
.editing
;
1341 }, 'editing to start', 1000);
1344 expect(ed
.editing
).toBe(true);
1345 expect(plugin
.activeColumn
.dataIndex
).toBe('name');