PDA

View Full Version : Excel style cell editing in EditorGridPanel



mohaaron
22 Sep 2009, 3:13 PM
Hello all,

I have been working on writing an override for the CellSelectionModel to provide a more Excel style way of editing cells in the EditorGridPanel. Some of these features are different then Excel and I think make a better editing experience for a data grid.

The main set of features that the standard EditorGridPanel does not have which I would like are the following.

1. When a cell is selected typing automatically starts editing of the cell with the characters typed entered into the cell.
2. When a cell is in edit mode the up/down arrow keys move the curser and cell being edited up/down one row completing the edit in the previous cell/row.
3. Copy/Paste functionality so that I can paste directly into a highlighted cell without having to be in edit mode.
4. A future feature that I would really like to have is the ability to have a RowCellSelectionModel like this (http://www.extjswithrails.com/2008/06/extuxrowwithcellselectionmodel.html) except that I would like a click on the RowNumber column to select the row. Any other click in the EditorGridPanel would work using the CellSelectionModel.

I'm currently overriding the CellSelectionModel to create what I want although I don't know if it's really thie best way to solve this problem. After looking over the standard EditorGridPanel as well as the CellSelectionModel source it looks like the functionality of moving around cells and editing them is in both. I decided to try and put everything in one place so that is why I chose to override the CellSelectionModel to make this happen.

1. I have mostly completed. I continue to have a problem with it when I enter a bunch of key down events all at once the cell stops editing and loses focus. It seems like some times the keyboard events stop working completely when this happens.
2. This is completed and works well. When the up/down arrow is pressed the current cell editing is completed and the next cell starting editing and the text in the cell is selected so typing overwrites the current value in the cell.
3. I have not started this yet. After doing some research it looks like this is difficult to implement so it will probably be a while before this happens.

Please let me know if you think there is a better way to solve this.



Ext.override(Ext.grid.CellSelectionModel, {
handleKeyDown : function(e){
// Original code commented out so standard keys can be used to start editing cells.
// if(!e.isNavKeyPress()){
// return;
// }

var g = this.grid, s = this.selection;

// If the cell is not selected and it's selectable then select it.
// When does this happen?
if(!s){
console.log('select none-selected cell.');
e.stopEvent();
var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
if(cell){
this.select(cell[0], cell[1]);
}
return;
}
var sm = this;
var walk = function(row, col, step){
return g.walkCells(row, col, step, sm.isSelectable, sm);
};
var k = e.getKey(), r = s.cell[0], c = s.cell[1];
var newCell;

if (!e.isNavKeyPress() && !e.isSpecialKey()) {
// Added BY: Aaron Prohaska, 2009.09.21.14:15
// Allow regular keys to start editing so we can type directly into cells.

var keyCode = k;
/*
The String.fromCharCode method is return the charactor in upper case so I'm converting
it back to lower case then later checking if the shiftKey was used and converting to upper case.
*/
var keyValue = String.fromCharCode(keyCode).toLowerCase();
var record = g.getStore().getAt(r);
var field = g.colModel.getDataIndex(c);

// Shift + charector should be upper case charector.
if (e.shiftKey) {
console.log('e.shiftKey');
keyValue = keyValue.toUpperCase();
}

g.startEditing(r, c);
record.data[field] = keyValue;
} else {
switch(k){
case e.TAB:
if(e.shiftKey){
newCell = walk(r, c-1, -1);
}else{
newCell = walk(r, c+1, 1);
}
break;
case e.DOWN:
newCell = walk(r+1, c, 1);
break;
case e.UP:
newCell = walk(r-1, c, -1);
break;
case e.RIGHT:
newCell = walk(r, c+1, 1);
break;
case e.LEFT:
newCell = walk(r, c-1, -1);
break;
case e.ENTER:
if(g.isEditor && !g.editing){
g.startEditing(r, c);
e.stopEvent();
// Added BY: Aaron Prohaska, 2009.09.21.14:15
// Set focus back to cell after pressing ENTER key.
g.getView().focusCell(r, c);
return;
}
break;
}
}

if (newCell) {
this.select(newCell[0], newCell[1]);
e.stopEvent();
}
},
onEditorKey : function(field, e){
var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
if(k == e.TAB){
if(e.shiftKey){
newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
}else{
newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
}
e.stopEvent();
}else if(k == e.ENTER){
ed.completeEdit();
e.stopEvent();
}else if(k == e.ESC){
e.stopEvent();
ed.cancelEdit();
// Added BY: Aaron Prohaska, 2009.09.16.15:30
// Set focus back to cell after pressing ESC key.
g.getView().focusCell(ed.row, ed.col);
}else if(k == e.DOWN){
// Added BY: Aaron Prohaska, 2009.09.17.11:30
// When in edit mode and down arrow is pressed navigate to the cell on the next row down.
ed.completeEdit();
e.stopEvent();
newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
ed.field.focus(true);
//ed.field.selectOnFocus = true;
}else if(k == e.UP){
// Added BY: Aaron Prohaska, 2009.09.17.11:30
// When in edit mode and down arrow is pressed navigate to the cell on the next row up.
ed.completeEdit();
e.stopEvent();
newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
ed.field.focus(true);
//ed.field.selectOnFocus = true;
}
if(newCell){
g.startEditing(newCell[0], newCell[1]);
}
}
});

mpereda
27 May 2010, 6:11 PM
Hi, I had a similar code that is working fine in extjs 2, but because Im having problems to refresh the grid after I change the record ( ext.grid.getview().refreshrow(record) method is not working ) I tried to upgrade to version 3.2.1, unfortunally the row ed = g.activeEditor is returning ed as Null.
In the API doc I found activeEditor as a property of the Ext.grid.EditorGridPanel but when you go inside the EditorGridPanel documentation there is no reference to it. Is the activeEditor still valid ?

sosy
11 Sep 2010, 11:25 AM
I changed some parts in the code, since i would like to have a loop untill the user leaves the key.

So if the arrow down key reaches the last cell, it continues at the first cell,
and on arrow up if the first cell is reached, it continues with the last cell.

I also modified the behavior of the tab key, it stays now in the same row,
and on enter the next cell is choosen. Same on shift+tab and shift+enter.

I hope it is of some use for somebody.

One thing remains, if you continue to press the arrow, enter or tab key,
it sudden stops. I cant find an solution yet.

Tried with an defer on it, but it did not work out. So if anybody knows an solution for that?

Here is the code..


onEditorKey: function (field, e) {
var k = e.getKey(),
newCell, g = this.grid,
ed = g.activeEditor;
var numberOfRows = grid.getStore().getCount();
var maxrow = numberOfRows - 1;
var shift = e.shiftKey;
var last = g.lastEdit;
if (k == e.TAB) {
if (e.shiftKey) {
var newrow = ed.row - 1;
if (newrow < 0) {
var newrow = maxrow;
}
newCell = g.walkCells(newrow, ed.col, -1, this.acceptsNav, this);
}
else {
var newrow = ed.row + 1;
if (newrow > maxrow) {
var newrow = 0;
}
newCell = g.walkCells(newrow, ed.col, 1, this.acceptsNav, this);
}
e.stopEvent();
}
else if (k == e.ENTER) {
var nexrow = last.row + 1;
var prerow = last.row - 1;
if (nexrow > maxrow) {
var nexrow = 0;
}
if (prerow < 0) {
var prerow = maxrow;
}
if (this.moveEditorOnEnter !== false) {
if (shift) {
newCell = g.walkCells(prerow, last.col, -1, this.acceptsNav, this);
}
else {
newCell = g.walkCells(nexrow, last.col, 1, this.acceptsNav, this);
}
}
}
else if (k == e.ESC) {
e.stopEvent();
ed.cancelEdit();
g.getView().focusCell(ed.row, ed.col);
}
else if (k == e.DOWN) {
ed.completeEdit();
e.stopEvent();
var newrow = ed.row + 1;
if (newrow > maxrow) {
var newrow = 0;
}
newCell = g.walkCells(newrow, ed.col, 1, this.acceptsNav, this);
ed.field.focus(true);
}
else if (k == e.UP) {
ed.completeEdit();
e.stopEvent();
var newrow = ed.row - 1;
if (newrow < 0) {
var newrow = maxrow;
}
newCell = g.walkCells(newrow, ed.col, -1, this.acceptsNav, this);
ed.field.focus(true);
}
if (newCell) {
g.startEditing(newCell[0], newCell[1]);
}
}