glassy
21 Nov 2006, 12:52 AM
Thanks to the original NavEditorSelectionModel (http://www.yui-ext.com/forum/viewtopic.php?t=667), I had a good starting point to implement the selection "model" that I had in mind.
This selection model, which also borrows some code from EditorSelectionModel, has many features including:
- Single click to edit
- F2 or Space to edit (and Esc to cancel editing, Enter to save as usual)
- Tab/Shift-Tab to navigate cells while editing
- Up/Down arrow keys to navigate rows (both when editing and not editing)
- Left/Right not used for navigation
- Multiple selection with shift keys
- No more losing focus of keyboard!
- Can support drag/drop
(Tested on Firefox 2.0, IE 7, Opera 9.0)
An improvement that could be made to this is to support cell highlighting/selecting.
YAHOO.ext.grid.NavEditorSelectionModel = function(){
YAHOO.ext.grid.NavEditorSelectionModel.superclass.constructor.call(this);
this.events['cellactivate'] = new YAHOO.util.CustomEvent('cellactivate');
};
YAHOO.extendX(YAHOO.ext.grid.NavEditorSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
YAHOO.ext.grid.NavEditorSelectionModel.prototype.initEvents = function(){
YAHOO.ext.grid.NavEditorSelectionModel.superclass.initEvents.call(this);
this.grid.addListener("cellclick", this.onCellClick, this, true);
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.onCellClick = function(grid, rowIndex, colIndex){
var row = this.grid.getRow(rowIndex);
var cell = row.childNodes[colIndex];
if (cell) {
this.activate(row, cell);
}
this.selectRow(row, false);
this.lastSelectedRow = row;
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.activate = function(row, cell){
this.fireEvent('cellactivate', this, row, cell);
this.grid.doEdit(row, cell);
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.getEditorCellAfter = function(cell, spanRows){
var g = this.grid;
var next = g.getCellAfter(cell);
while(next && !g.colModel.isCellEditable(next.columnIndex)){
next = g.getCellAfter(next);
}
if(!next && spanRows){
var row = g.getRowAfter(g.getRowFromChild(cell));
if(row){
next = g.getFirstCell(row);
if(!g.colModel.isCellEditable(next.columnIndex)){
next = this.getEditorCellAfter(next);
}
}
}
return next;
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.getEditorCellBefore = function(cell, spanRows){
var g = this.grid;
var prev = g.getCellBefore(cell);
while(prev && !g.colModel.isCellEditable(prev.columnIndex)){
prev = g.getCellBefore(prev);
}
if(!prev && spanRows){
var row = g.getRowBefore(g.getRowFromChild(cell));
if(row){
prev = g.getLastCell(row);
if(!g.colModel.isCellEditable(prev.columnIndex)){
prev = this.getEditorCellBefore(prev);
}
}
}
return prev;
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.keyDown = function(e){
var g = this.grid, cm = g.colModel, cell = g.getEditingCell();
var m = YAHOO.ext.grid.NavEditorSelectionModel;
var superclass = null;
var newCell;
if (cell) {
if (!this.gridHasActiveEditor()) {
switch (e.browserEvent.keyCode) {
case 113:
row = this.lastSelectedRow;
next = g.getFirstCell(row, false);
while(next && !g.colModel.isCellEditable(next.columnIndex)){
next = g.getCellAfter(next);
}
this.activate(row, next);
break;
default:
cell.focus();
break;
}
}
else {
switch (e.browserEvent.keyCode) {
case e.TAB:
if (e.shiftKey) {
newCell = this.getEditorCellBefore(cell, true);
}
else {
newCell = this.getEditorCellAfter(cell, true);
}
if (newCell) {
row = g.getRowFromChild(newCell);
this.activate(row, newCell);
this.selectRow(row, false);
e.stopEvent();
}
e.preventDefault();
break;
case e.DOWN:
var next = g.getRowAfter(g.getRowFromChild(cell));
if(next){
newCell = next.childNodes[cell.columnIndex];
}
if (newCell) {
row = g.getRowFromChild(newCell);
this.activate(row, newCell);
e.stopEvent();
}
break;
case e.UP:
var prev = g.getRowBefore(g.getRowFromChild(cell));
if(prev){
newCell = prev.childNodes[cell.columnIndex];
}
if (newCell) {
row = g.getRowFromChild(newCell);
this.activate(row, newCell);
e.stopEvent();
}
break;
}
}
}
YAHOO.ext.grid.DefaultSelectionModel.prototype.keyDown.call(this, e);
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.gridHasActiveEditor = function(){
// hack
var colConfigs = this.grid.getColumnModel().config;
var editing = false;
for (var i = 0; i < colConfigs.length && !editing; ++i)
{
var c = colConfigs[i];
editing = c.editor && c.editor.editing;
}
return editing;
}
This selection model, which also borrows some code from EditorSelectionModel, has many features including:
- Single click to edit
- F2 or Space to edit (and Esc to cancel editing, Enter to save as usual)
- Tab/Shift-Tab to navigate cells while editing
- Up/Down arrow keys to navigate rows (both when editing and not editing)
- Left/Right not used for navigation
- Multiple selection with shift keys
- No more losing focus of keyboard!
- Can support drag/drop
(Tested on Firefox 2.0, IE 7, Opera 9.0)
An improvement that could be made to this is to support cell highlighting/selecting.
YAHOO.ext.grid.NavEditorSelectionModel = function(){
YAHOO.ext.grid.NavEditorSelectionModel.superclass.constructor.call(this);
this.events['cellactivate'] = new YAHOO.util.CustomEvent('cellactivate');
};
YAHOO.extendX(YAHOO.ext.grid.NavEditorSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
YAHOO.ext.grid.NavEditorSelectionModel.prototype.initEvents = function(){
YAHOO.ext.grid.NavEditorSelectionModel.superclass.initEvents.call(this);
this.grid.addListener("cellclick", this.onCellClick, this, true);
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.onCellClick = function(grid, rowIndex, colIndex){
var row = this.grid.getRow(rowIndex);
var cell = row.childNodes[colIndex];
if (cell) {
this.activate(row, cell);
}
this.selectRow(row, false);
this.lastSelectedRow = row;
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.activate = function(row, cell){
this.fireEvent('cellactivate', this, row, cell);
this.grid.doEdit(row, cell);
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.getEditorCellAfter = function(cell, spanRows){
var g = this.grid;
var next = g.getCellAfter(cell);
while(next && !g.colModel.isCellEditable(next.columnIndex)){
next = g.getCellAfter(next);
}
if(!next && spanRows){
var row = g.getRowAfter(g.getRowFromChild(cell));
if(row){
next = g.getFirstCell(row);
if(!g.colModel.isCellEditable(next.columnIndex)){
next = this.getEditorCellAfter(next);
}
}
}
return next;
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.getEditorCellBefore = function(cell, spanRows){
var g = this.grid;
var prev = g.getCellBefore(cell);
while(prev && !g.colModel.isCellEditable(prev.columnIndex)){
prev = g.getCellBefore(prev);
}
if(!prev && spanRows){
var row = g.getRowBefore(g.getRowFromChild(cell));
if(row){
prev = g.getLastCell(row);
if(!g.colModel.isCellEditable(prev.columnIndex)){
prev = this.getEditorCellBefore(prev);
}
}
}
return prev;
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.keyDown = function(e){
var g = this.grid, cm = g.colModel, cell = g.getEditingCell();
var m = YAHOO.ext.grid.NavEditorSelectionModel;
var superclass = null;
var newCell;
if (cell) {
if (!this.gridHasActiveEditor()) {
switch (e.browserEvent.keyCode) {
case 113:
row = this.lastSelectedRow;
next = g.getFirstCell(row, false);
while(next && !g.colModel.isCellEditable(next.columnIndex)){
next = g.getCellAfter(next);
}
this.activate(row, next);
break;
default:
cell.focus();
break;
}
}
else {
switch (e.browserEvent.keyCode) {
case e.TAB:
if (e.shiftKey) {
newCell = this.getEditorCellBefore(cell, true);
}
else {
newCell = this.getEditorCellAfter(cell, true);
}
if (newCell) {
row = g.getRowFromChild(newCell);
this.activate(row, newCell);
this.selectRow(row, false);
e.stopEvent();
}
e.preventDefault();
break;
case e.DOWN:
var next = g.getRowAfter(g.getRowFromChild(cell));
if(next){
newCell = next.childNodes[cell.columnIndex];
}
if (newCell) {
row = g.getRowFromChild(newCell);
this.activate(row, newCell);
e.stopEvent();
}
break;
case e.UP:
var prev = g.getRowBefore(g.getRowFromChild(cell));
if(prev){
newCell = prev.childNodes[cell.columnIndex];
}
if (newCell) {
row = g.getRowFromChild(newCell);
this.activate(row, newCell);
e.stopEvent();
}
break;
}
}
}
YAHOO.ext.grid.DefaultSelectionModel.prototype.keyDown.call(this, e);
};
YAHOO.ext.grid.NavEditorSelectionModel.prototype.gridHasActiveEditor = function(){
// hack
var colConfigs = this.grid.getColumnModel().config;
var editing = false;
for (var i = 0; i < colConfigs.length && !editing; ++i)
{
var c = colConfigs[i];
editing = c.editor && c.editor.editing;
}
return editing;
}