Skip to content
Browse files

Fixed the onDragInit event handlers interfering with each other on cl…

…ick.

Added CellRangeSelector and refactored CellSelectionModel to make use of it.
Added a sample FormulaEditor cell editor that uses CellRangeSelector to let the user drag-select a range of cells and have them appended to the currently edited cell.
  • Loading branch information...
1 parent d14636a commit 17b1bb8f3c43022ee6aec89dcab185cd368b8785 @mleibman committed Nov 26, 2010
View
45 examples/example3-editing.html
@@ -42,6 +42,8 @@
<script language="JavaScript" src="../lib/jquery.event.drag-2.0.min.js"></script>
<script language="JavaScript" src="../slick.core.js"></script>
+ <script language="JavaScript" src="../plugins/slick.cellrangeselector.js"></script>
+ <script language="JavaScript" src="../plugins/slick.cellselectionmodel.js"></script>
<script language="JavaScript" src="../slick.editors.js"></script>
<script language="JavaScript" src="../slick.grid.js"></script>
@@ -58,7 +60,7 @@
var columns = [
{id:"title", name:"Title", field:"title", width:120, cssClass:"cell-title", editor:TextCellEditor, validator:requiredFieldValidator},
{id:"desc", name:"Description", field:"description", width:100, editor:LongTextCellEditor},
- {id:"duration", name:"Duration", field:"duration", editor:TextCellEditor},
+ {id:"duration", name:"Duration", field:"duration", editor:FormulaEditor},
{id:"%", name:"% Complete", field:"percentComplete", width:80, resizable:false, formatter:GraphicalPercentCompleteCellFormatter, editor:PercentCompleteCellEditor},
{id:"start", name:"Start", field:"start", minWidth:60, editor:DateCellEditor},
{id:"finish", name:"Finish", field:"finish", minWidth:60, editor:DateCellEditor},
@@ -72,6 +74,43 @@
autoEdit: false
};
+
+ /***
+ * A proof-of-concept cell editor with Excel-like range selection and insertion.
+ */
+ function FormulaEditor(args) {
+ var _self = this;
+ var _editor = new TextCellEditor(args);
+ var _selector;
+
+ $.extend(this, _editor);
+
+ function init() {
+ // register a plugin to select a range and append it to the textbox
+ // since events are fired in reverse order (most recently added are executed first),
+ // this will override other plugins like moverows or selection model and will
+ // not require the grid to not be in the edit mode
+ _selector = new Slick.CellRangeSelector();
+ _selector.onCellRangeSelected.subscribe(_self.handleCellRangeSelected);
+ args.grid.registerPlugin(_selector);
+ }
+
+ this.destroy = function() {
+ _selector.onCellRangeSelected.unsubscribe(_self.handleCellRangeSelected);
+ grid.unregisterPlugin(_selector);
+ _editor.destroy();
+ };
+
+ this.handleCellRangeSelected = function(e, args) {
+ _editor.setValue(_editor.getValue() + args.range);
+ };
+
+
+ init();
+ }
+
+
+
$(function()
{
for (var i=0; i<500; i++) {
@@ -88,6 +127,10 @@
grid = new Slick.Grid("#myGrid", data, columns, options);
+ //grid.registerPlugin(new Slick.CellRangeSelector());
+
+ grid.setSelectionModel(new Slick.CellSelectionModel());
+
grid.onAddNewRow.subscribe(function(e, args) {
var item = args.item;
var column = args.column;
View
127 plugins/slick.cellrangeselector.js
@@ -0,0 +1,127 @@
+(function($) {
+ // register namespace
+ $.extend(true, window, {
+ "Slick": {
+ "CellRangeSelector": CellRangeSelector
+ }
+ });
+
+
+ function CellRangeSelector(options) {
+ var _grid;
+ var _canvas;
+ var _dragging;
+ var _self = this;
+ var _defaults = {
+ selectionCss: {
+ "border": "2px dashed blue"
+ }
+ };
+
+
+ function init(grid) {
+ options = $.extend(true, {}, _defaults, options);
+ _grid = grid;
+ _canvas = _grid.getCanvasNode();
+ _grid.onDragStart.subscribe(handleDragStart);
+ _grid.onDrag.subscribe(handleDrag);
+ _grid.onDragEnd.subscribe(handleDragEnd);
+ }
+
+ function destroy() {
+ _grid.onDragStart.unsubscribe(handleDragStart);
+ _grid.onDrag.unsubscribe(handleDrag);
+ _grid.onDragEnd.unsubscribe(handleDragEnd);
+ }
+
+ function fixUpRange(range) {
+ var r1 = Math.min(range.start.row,range.end.row);
+ var c1 = Math.min(range.start.cell,range.end.cell);
+ var r2 = Math.max(range.start.row,range.end.row);
+ var c2 = Math.max(range.start.cell,range.end.cell);
+ return {
+ start: {row:r1, cell:c1},
+ end: {row:r2, cell:c2}
+ };
+ }
+
+ function handleDragStart(e,dd) {
+ var cell = _grid.getCellFromEvent(e);
+ if (_self.onBeforeCellRangeSelected.notify(cell) !== false) {
+ if (_grid.canCellBeSelected(cell.row,cell.cell)) {
+ _dragging = true;
+ e.stopImmediatePropagation();
+ }
+ }
+ if (!_dragging) {
+ return;
+ }
+
+ var start = _grid.getCellFromPoint(
+ dd.startX - $(_canvas).offset().left,
+ dd.startY - $(_canvas).offset().top);
+
+ dd.range = {start:start,end:{}};
+
+ // TODO: use a decorator
+ return $("<div></div>", {css: options.selectionCss})
+ .css("position", "absolute")
+ .appendTo(_canvas);
+ }
+
+ function handleDrag(e,dd) {
+ if (!_dragging) {
+ return;
+ }
+
+ e.stopImmediatePropagation();
+
+ var end = _grid.getCellFromPoint(
+ e.pageX - $(_canvas).offset().left,
+ e.pageY - $(_canvas).offset().top);
+
+ if (!_grid.canCellBeSelected(end.row,end.cell)) {
+ return;
+ }
+
+ dd.range.end = end;
+ var r = fixUpRange(dd.range);
+ var from = _grid.getCellNodeBox(r.start.row,r.start.cell);
+ var to = _grid.getCellNodeBox(r.end.row,r.end.cell);
+
+ $(dd.proxy).css({
+ top: from.top - 1,
+ left: from.left - 1,
+ height: to.bottom - from.top - 2,
+ width: to.right - from.left - 2
+ });
+ }
+
+ function handleDragEnd(e,dd) {
+ if (!_dragging) {
+ return;
+ }
+
+ _dragging = false;
+ e.stopImmediatePropagation();
+ $(dd.proxy).remove();
+
+ _self.onCellRangeSelected.notify({
+ range: new Slick.Range(
+ dd.range.start.row,
+ dd.range.start.cell,
+ dd.range.end.row,
+ dd.range.end.cell
+ )
+ });
+ }
+
+ $.extend(this, {
+ "init": init,
+ "destroy": destroy,
+
+ "onBeforeCellRangeSelected": new Slick.Event(),
+ "onCellRangeSelected": new Slick.Event()
+ });
+ }
+})(jQuery);
View
117 plugins/slick.cellselectionmodel.js
@@ -11,29 +11,27 @@
var _grid;
var _canvas;
var _ranges = [];
- var _dragging;
var _self = this;
-
- function returnFalse() {
- return false;
- }
+ var _selector = new Slick.CellRangeSelector({
+ "selectionCss": {
+ "border": "2px solid black"
+ }
+ });
function init(grid) {
_grid = grid;
_canvas = _grid.getCanvasNode();
_grid.onActiveCellChanged.subscribe(handleActiveCellChange);
- _grid.onDragInit.subscribe(handleDragInit);
- _grid.onDragStart.subscribe(handleDragStart);
- _grid.onDrag.subscribe(handleDrag);
- _grid.onDragEnd.subscribe(handleDragEnd);
+ grid.registerPlugin(_selector);
+ _selector.onCellRangeSelected.subscribe(handleCellRangeSelected);
+ _selector.onBeforeCellRangeSelected.subscribe(handleBeforeCellRangeSelected);
}
function destroy() {
_grid.onActiveCellChanged.unsubscribe(handleActiveCellChange);
- _grid.onDragInit.unsubscribe(handleDragInit);
- _grid.onDragStart.unsubscribe(handleDragStart);
- _grid.onDrag.unsubscribe(handleDrag);
- _grid.onDragEnd.unsubscribe(handleDragEnd);
+ _selector.onCellRangeSelected.unsubscribe(handleCellRangeSelected);
+ _selector.onBeforeCellRangeSelected.unsubscribe(handleBeforeCellRangeSelected);
+ _grid.unregisterPlugin(_selector);
}
function removeInvalidRanges(ranges) {
@@ -51,99 +49,26 @@
function setSelectedRanges(ranges) {
_ranges = removeInvalidRanges(ranges);
- _self.onSelectedRangesChanged.notify(_ranges); }
+ _self.onSelectedRangesChanged.notify(_ranges);
+ }
function getSelectedRanges() {
return _ranges;
}
- function fixUpRange(range) {
- var r1 = Math.min(range.start.row,range.end.row);
- var c1 = Math.min(range.start.cell,range.end.cell);
- var r2 = Math.max(range.start.row,range.end.row);
- var c2 = Math.max(range.start.cell,range.end.cell);
- return {
- start: {row:r1, cell:c1},
- end: {row:r2, cell:c2}
- };
- }
-
- function handleDragInit(e,dd) {
- var cell = _grid.getCellFromEvent(e);
-
- if (!_grid.getEditorLock().isActive()) {
- if (_grid.canCellBeSelected(cell.row,cell.cell)/* && e.ctrlKey*/) {
- _dragging = true;
- e.stopImmediatePropagation();
- }
- }
- }
-
- function handleDragStart(e,dd) {
- if (!_dragging) {
- return;
- }
-
- var start = _grid.getCellFromPoint(
- dd.startX - $(_canvas).offset().left,
- dd.startY - $(_canvas).offset().top);
-
- e.stopImmediatePropagation();
-
- dd.range = {start:start,end:{}};
-
- return $("<div class='slick-selection'></div>").appendTo(_canvas);
- }
-
- function handleDrag(e,dd) {
- if (!_dragging) {
- return;
- }
-
- e.stopImmediatePropagation();
-
- var end = _grid.getCellFromPoint(
- e.pageX - $(_canvas).offset().left,
- e.pageY - $(_canvas).offset().top);
-
- if (!_grid.canCellBeSelected(end.row,end.cell)) {
- return;
+ function handleBeforeCellRangeSelected(e, args) {
+ if (_grid.getEditorLock().isActive()) {
+ e.stopPropagation();
+ return false;
}
-
- dd.range.end = end;
- var r = fixUpRange(dd.range);
- var from = _grid.getCellNodeBox(r.start.row,r.start.cell);
- var to = _grid.getCellNodeBox(r.end.row,r.end.cell);
-
- $(dd.proxy).css({
- top: from.top - 1,
- left: from.left - 1,
- height: to.bottom - from.top - 2,
- width: to.right - from.left - 2
- });
}
- function handleDragEnd(e,dd) {
- if (!_dragging) {
- return;
- }
-
- _dragging = false;
- e.stopImmediatePropagation();
- $(dd.proxy).remove();
-
- setSelectedRanges([
- new Slick.Range(
- dd.range.start.row,
- dd.range.start.cell,
- dd.range.end.row,
- dd.range.end.cell
- )
- ]);
+ function handleCellRangeSelected(e, args) {
+ setSelectedRanges([args.range]);
}
- function handleActiveCellChange(e, data) {
- setSelectedRanges([new Slick.Range(data.row,data.cell)]);
+ function handleActiveCellChange(e, args) {
+ setSelectedRanges([new Slick.Range(args.row,args.cell)]);
}
$.extend(this, {
View
20 plugins/slick.rowmovemanager.js
@@ -15,38 +15,26 @@
function init(grid) {
_grid = grid;
_canvas = _grid.getCanvasNode();
- _grid.onDragInit.subscribe(handleDragInit);
_grid.onDragStart.subscribe(handleDragStart);
_grid.onDrag.subscribe(handleDrag);
_grid.onDragEnd.subscribe(handleDragEnd);
}
function destroy() {
- _grid.onDragInit.unsubscribe(handleDragInit);
_grid.onDragStart.unsubscribe(handleDragStart);
_grid.onDrag.unsubscribe(handleDrag);
_grid.onDragEnd.unsubscribe(handleDragEnd);
}
- function handleDragInit(e,dd) {
- var cell = _grid.getCellFromEvent(e);
-
- if (!_grid.getEditorLock().isActive()) {
- if (/move|selectAndMove/.test(_grid.getColumns()[cell.cell].behavior)) {
- _dragging = true;
- e.stopImmediatePropagation();
- }
- }
- }
-
function handleDragStart(e,dd) {
- if (!_dragging) {
- return;
+ var cell = _grid.getCellFromEvent(e);
+ if (_grid.getEditorLock().isActive() || !/move|selectAndMove/.test(_grid.getColumns()[cell.cell].behavior)) {
+ return false;
}
+ _dragging = true;
e.stopImmediatePropagation();
- var cell = _grid.getCellFromEvent(e);
var selectedRows = _grid.getSelectedRows();
if (selectedRows.length == 0 || $.inArray(cell.row, selectedRows) == -1) {
View
8 slick.editors.js
@@ -90,6 +90,14 @@
$input.focus();
};
+ this.getValue = function() {
+ return $input.val();
+ };
+
+ this.setValue = function(val) {
+ $input.val(val);
+ };
+
this.loadValue = function(item) {
defaultValue = item[args.column.field] || "";
$input.val(defaultValue);
View
2 slick.grid.js
@@ -1391,8 +1391,6 @@ if (typeof Slick === "undefined") {
if (e.isImmediatePropagationStopped()) {
return retval;
}
-
- return false;
}
function handleDragStart(e,dd) {

0 comments on commit 17b1bb8

Please sign in to comment.
Something went wrong with that request. Please try again.