Skip to content

Instantly share code, notes, and snippets.

@gjuggler
Created June 30, 2010 06:56
Show Gist options
  • Save gjuggler/458337 to your computer and use it in GitHub Desktop.
Save gjuggler/458337 to your computer and use it in GitHub Desktop.
Ext.override(Ext.grid.RowSelectionModel, {
initEvents: function() {
// Create an event which only fires after a selection is DONE changing in response
// to a user interaction (i.e., when we shift-click to select 10 items, this only fires ONCE).
this.addEvents('afterselectionchange');
// Make the grid respond to click events.
this.grid.on('rowclick', this.handleMouseDown, this);
// Even if we're using drag and drop, respond to mouse-down events.
// if (!this.grid.enableDragDrop && !this.grid.enableDrag) {
this.grid.on('rowmousedown', this.handleMouseDown, this);
// }
this.rowNav = new Ext.KeyNav(this.grid.getGridEl(), {
'up': function(e) {
this.keyNavMove(-1, e);
},
'down': function(e) {
this.keyNavMove(1, e);
},
'pageDown': function(e) {
var pageDistance = this.grid.getPageSize();
this.keyNavMove(pageDistance, e);
},
'pageUp': function(e) {
var pageDistance = this.grid.getPageSize();
this.keyNavMove(-pageDistance, e);
},
'j': function(e) {
this.keyNavMove(1, e);
},
'k': function(e) {
this.keyNavMove(-1, e);
},
'n': function(e) {
this.keyNavMove(1, e);
},
'p': function(e) {
this.keyNavMove(-1, e);
},
scope: this
});
this.rowNav.keyToHandler['74'] = 'j';
this.rowNav.keyToHandler['75'] = 'k';
this.rowNav.keyToHandler['78'] = 'n';
this.rowNav.keyToHandler['80'] = 'p';
this.grid.getView().on({
scope: this,
refresh: this.onRefresh,
rowupdated: this.onRowUpdated,
rowremoved: this.onRemove
});
},
keyNavMove: function(distance, e) {
if (!e.shiftKey || this.singleSelect) {
this.selectDistance(distance);
} else if (this.last !== false && this.lastActive !== false) {
var anchor = this.lastActive;
var cursor = this.constraintToGrid(this.last + distance);
this.selectRange(anchor, cursor);
this.grid.getView().focusRow(cursor);
this.last = cursor;
this.lastActive = anchor;
} else {
this.selectFirstRow();
}
this.fireEvent('afterselectionchange', this);
},
constraintToGrid: function(value) {
if (value < 0) {
value = 0;
}
if (value >= this.grid.store.getCount()) {
value = this.grid.store.getCount() - 1;
}
return value;
},
selectDistance: function(dist, keepExisting) {
var cursor = this.constraintToGrid(this.last + dist);
this.selectRow(cursor, keepExisting);
this.grid.getView().focusRow(this.last);
return true;
},
hasDistance: function(dist) {
return (this.last !== false && (this.last + dist) < this.grid.store.getCount() && (this.last + dist) >= 0);
},
looksLikeDuplicateEvents: function(a, b) {
if (a !== undefined && b !== undefined && a.type === b.type &&
a.target === b.target &&
a.ctrlKey === b.ctrlKey &&
a.shiftKey === b.shiftKey &&
a.source === b.source && a.browserEvent === b.browserEvent) {
return true;
} else {
return false;
}
},
cacheEvent: {},
// private
handleMouseDown: function(g, rowIndex, e) {
if (e.button !== 0 || this.isLocked()) {
return;
}
// We cache a shallow copy of the most recent event and compare it to the current
// event to avoid handling duplicate events.
if (this.looksLikeDuplicateEvents(this.cacheEvent, e)) {
return;
}
Ext.apply(this.cacheEvent, e); // Store the cache by applying the event's properties to a hash.
var view = this.grid.getView();
var isSelected = this.isSelected(rowIndex);
var type = e.type;
var ctrl = e.ctrlKey;
var shift = e.shiftKey;
if (shift) {
if (type === 'mousedown' && !this.singleSelect && this.last !== false) {
var last = this.last;
this.selectRange(last, rowIndex, ctrl);
this.last = last; // reset the cursor point.
view.focusRow(rowIndex);
}
} else if (ctrl) {
if (type === 'mousedown') {
if (isSelected) {
this.deselectRow(rowIndex);
} else {
this.selectRow(rowIndex, true);
view.focusRow(rowIndex);
}
}
} else {
if (type === 'mousedown' && !isSelected) {
this.selectRow(rowIndex, false);
view.focusRow(rowIndex);
} else {
if (isSelected) {
this.selectRow(rowIndex, false);
}
}
}
this.fireEvent('afterselectionchange', this);
},
selectFirstRow: function() {
this.selectRow(0);
this.fireEvent('afterselectionchange', this);
},
selectRow: function(index, keepExisting, preventViewNotify) {
if (this.isLocked() || (index < 0 || index >= this.grid.store.getCount()) || (keepExisting && this.isSelected(index))) {
return;
}
var r = this.grid.store.getAt(index);
if (r && this.fireEvent('beforerowselect', this, index, keepExisting, r) !== false) {
if (!keepExisting || this.singleSelect) {
this.clearSelections();
}
this.selections.add(r);
this.last = this.lastActive = index;
if (!preventViewNotify) {
this.grid.getView().onRowSelect(index);
}
this.fireEvent('rowselect', this, index, r);
this.fireEvent('selectionchange', this);
// Adding this here to always focus the view when the next row is selected -- TODO, check if this causes any unforeseen problems.
this.grid.getView().focusRow(index);
}
},
onRefresh: function() {
this.suspendEvents();
var ds = this.grid.store,
index;
var s = this.getSelections();
this.clearSelections(true);
for (var i = 0, len = s.length; i < len; i++) {
var r = s[i];
if ((index = ds.indexOfId(r.id)) != -1) {
this.selectRow(index, true);
}
}
this.resumeEvents();
if (s.length != this.selections.getCount()) {
this.fireEvent('selectionchange', this);
this.fireEvent('afterselectionchange', this);
}
},
selectAll: function() {
if (this.isLocked()) {
return;
}
this.clearSelections(true);
for (var i = 0, len = this.grid.store.getCount(); i < len; i++) {
this.selectRow(i, true);
}
this.fireEvent('afterselectionchange', this);
},
clearSelections: function(fast) {
if (this.isLocked()) {
return;
}
if (fast !== true) {
var ds = this.grid.store;
var s = this.selections;
s.each(function(r) {
this.deselectRow(ds.indexOfId(r.id));
},
this);
s.clear();
} else {
this.selections.clear();
}
this.last = false;
// DO NOT fire an 'afterselectionchange' event here!
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment