Skip to content

Commit ef6d928

Browse files
committed
- ADDED: preliminary support for cell range selection ("enableCellRangeSelection" option, "onCellRangeSelected" event)
1 parent 2ac42e6 commit ef6d928

2 files changed

Lines changed: 144 additions & 42 deletions

File tree

‎slick.grid.css‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,15 @@ classes should alter those!
139139
opacity: 0.7;
140140
filter: alpha(opacity=70);
141141
}
142+
143+
.slick-selection {
144+
z-index: 10;
145+
position: absolute;
146+
background: gray;
147+
border: 1px solid black;
148+
opacity: 0.3;
149+
filter: alpha(opacity=30);
150+
-webkit-box-shadow: 0px 0px 10px black;
151+
-moz-box-shadow: 0px 0px 10px black;
152+
box-shadow: 0px 0px 10px black;
153+
}

‎slick.grid.js‎

Lines changed: 132 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
* editable - (default false) If false, no cells will be switched into edit mode.
2020
* autoEdit - (default true) Cell will not automatically go into edit mode when selected.
2121
* enableCellNavigation - (default true) If false, no cells will be selectable.
22+
* enableCellRangeSelection - (default false) If true, user will be able to select a cell range. onCellRangeSelected event will be fired.
2223
* defaultColumnWidth - (default 80px) Default column width in pixels (if columns[cell].width is not specified).
2324
* enableColumnReorder - (default true) Allows the user to reorder columns.
2425
* asyncEditorLoading - (default false) Makes cell editors load asynchronously after a small delay.
@@ -81,6 +82,7 @@
8182
* onBeforeCellEditorDestroy - Raised before a cell editor is destroyed. Args: current cell editor.
8283
* onBeforeDestroy - Raised just before the grid control is destroyed (part of the destroy() method).
8384
* onCurrentCellChanged - Raised when the selected (active) cell changed. Args: {row:currentRow, cell:currentCell}.
85+
* onCellRangeSelected - Raised when a user selects a range of cells. Args: {from:{row,cell}, to:{row,cell}}.
8486
*
8587
* NOTES:
8688
* Cell/row DOM manipulations are done directly bypassing jQuery's DOM manipulation methods.
@@ -221,6 +223,7 @@ if (!jQuery.fn.drag) {
221223
editable: false,
222224
autoEdit: true,
223225
enableCellNavigation: true,
226+
enableCellRangeSelection: false,
224227
enableColumnReorder: true,
225228
asyncEditorLoading: false,
226229
asyncEditorLoadDelay: 100,
@@ -255,7 +258,7 @@ if (!jQuery.fn.drag) {
255258
var cj; // "jumpiness" coefficient
256259

257260
var page = 0; // current page
258-
var offset=0; // current page offset
261+
var offset = 0; // current page offset
259262
var scrollDir = 1;
260263

261264
// private
@@ -389,7 +392,7 @@ if (!jQuery.fn.drag) {
389392

390393
createColumnHeaders();
391394
setupColumnSort();
392-
setupRowReordering();
395+
setupDragEvents();
393396
createCssRules();
394397

395398
resizeAndRender();
@@ -749,61 +752,123 @@ if (!jQuery.fn.drag) {
749752
});
750753
}
751754

752-
function setupRowReordering() {
755+
function setupDragEvents() {
756+
var MOVE_ROWS = 1;
757+
var SELECT_CELLS = 2;
758+
759+
function fixUpRange(range) {
760+
var r1 = Math.min(range.start.row,range.end.row);
761+
var c1 = Math.min(range.start.cell,range.end.cell);
762+
var r2 = Math.max(range.start.row,range.end.row);
763+
var c2 = Math.max(range.start.cell,range.end.cell);
764+
return {
765+
start: {row:r1, cell:c1},
766+
end: {row:r2, cell:c2}
767+
};
768+
}
769+
753770
$canvas
754771
.bind("draginit", function(e,dd) {
755772
var $cell = $(e.target).closest(".slick-cell");
756773
if ($cell.length === 0) { return false; }
757-
if (parseInt($cell.parent().attr("row"), 10) >= gridDataGetLength()) { return false; }
774+
if (parseInt($cell.parent().attr("row"), 10) >= gridDataGetLength())
775+
return false;
776+
758777
var colDef = columns[getSiblingIndex($cell[0])];
759-
if (colDef.behavior !== "move" && colDef.behavior !== "selectAndMove") { return false; }
778+
if (colDef.behavior == "move" || colDef.behavior == "selectAndMove") {
779+
dd.mode = MOVE_ROWS;
780+
}
781+
else if (options.enableCellRangeSelection) {
782+
dd.mode = SELECT_CELLS;
783+
}
784+
else
785+
return false;
760786
})
761787
.bind("dragstart", function(e,dd) {
762788
if (!options.editorLock.commitCurrentEdit()) { return false; }
763789
var row = parseInt($(e.target).closest(".slick-row").attr("row"), 10);
764790

765-
if (!selectedRowsLookup[row]) {
766-
setSelectedRows([row]);
791+
if (dd.mode == MOVE_ROWS) {
792+
if (!selectedRowsLookup[row]) {
793+
setSelectedRows([row]);
794+
}
795+
796+
dd.selectionProxy = $("<div class='slick-reorder-proxy'/>")
797+
.css("position", "absolute")
798+
.css("zIndex", "99999")
799+
.css("width", $(this).innerWidth())
800+
.css("height", options.rowHeight*selectedRows.length)
801+
.appendTo($viewport);
802+
803+
dd.guide = $("<div class='slick-reorder-guide'/>")
804+
.css("position", "absolute")
805+
.css("zIndex", "99998")
806+
.css("width", $(this).innerWidth())
807+
.css("top", -1000)
808+
.appendTo($viewport);
809+
810+
dd.insertBefore = -1;
767811
}
768812

769-
dd.selectionProxy = $("<div class='slick-reorder-proxy'/>")
770-
.css("position", "absolute")
771-
.css("zIndex", "99999")
772-
.css("width", $(this).innerWidth())
773-
.css("height", options.rowHeight*selectedRows.length)
774-
.appendTo($viewport);
775-
776-
dd.guide = $("<div class='slick-reorder-guide'/>")
777-
.css("position", "absolute")
778-
.css("zIndex", "99998")
779-
.css("width", $(this).innerWidth())
780-
.css("top", -1000)
781-
.appendTo($viewport);
782-
783-
dd.insertBefore = -1;
813+
if (dd.mode == SELECT_CELLS) {
814+
var start = getCellFromPoint(dd.startX - $canvas.offset().left, dd.startY - $canvas.offset().top);
815+
if (!cellExists(start.row,start.cell))
816+
return false;
817+
818+
dd.range = {start:start,end:{}};
819+
return $("<div class='slick-selection'></div>").appendTo($canvas);
820+
}
784821
})
785822
.bind("drag", function(e,dd) {
786-
var top = e.clientY - $(this).offset().top;
787-
dd.selectionProxy.css("top",top-5);
788-
789-
var insertBefore = Math.max(0,Math.min(Math.round(top/options.rowHeight),gridDataGetLength()));
790-
if (insertBefore !== dd.insertBefore) {
791-
if (self.onBeforeMoveRows && self.onBeforeMoveRows(getSelectedRows(),insertBefore) === false) {
792-
dd.guide.css("top", -1000);
793-
dd.canMove = false;
794-
}
795-
else {
796-
dd.guide.css("top",insertBefore*options.rowHeight);
797-
dd.canMove = true;
823+
if (dd.mode == MOVE_ROWS) {
824+
var top = e.clientY - $(this).offset().top;
825+
dd.selectionProxy.css("top",top-5);
826+
827+
var insertBefore = Math.max(0,Math.min(Math.round(top/options.rowHeight),gridDataGetLength()));
828+
if (insertBefore !== dd.insertBefore) {
829+
if (self.onBeforeMoveRows && self.onBeforeMoveRows(getSelectedRows(),insertBefore) === false) {
830+
dd.guide.css("top", -1000);
831+
dd.canMove = false;
832+
}
833+
else {
834+
dd.guide.css("top",insertBefore*options.rowHeight);
835+
dd.canMove = true;
836+
}
837+
dd.insertBefore = insertBefore;
798838
}
799-
dd.insertBefore = insertBefore;
839+
}
840+
841+
if (dd.mode == SELECT_CELLS) {
842+
var end = getCellFromPoint(e.clientX - $canvas.offset().left, e.clientY - $canvas.offset().top);
843+
if (!cellExists(end.row,end.cell))
844+
return;
845+
846+
dd.range.end = end;
847+
var r = fixUpRange(dd.range);
848+
var from = getCellNodeBox(r.start.row,r.start.cell);
849+
var to = getCellNodeBox(r.end.row,r.end.cell);
850+
$(dd.proxy).css({
851+
top: from.top,
852+
left: from.left,
853+
height: to.bottom - from.top - 2,
854+
width: to.right - from.left - 2
855+
});
800856
}
801857
})
802858
.bind("dragend", function(e,dd) {
803-
dd.guide.remove();
804-
dd.selectionProxy.remove();
805-
if (self.onMoveRows && dd.canMove) {
806-
self.onMoveRows(getSelectedRows(),dd.insertBefore);
859+
if (dd.mode == MOVE_ROWS) {
860+
dd.guide.remove();
861+
dd.selectionProxy.remove();
862+
if (self.onMoveRows && dd.canMove) {
863+
self.onMoveRows(getSelectedRows(),dd.insertBefore);
864+
}
865+
}
866+
867+
if (dd.mode == SELECT_CELLS) {
868+
$(dd.proxy).remove();
869+
870+
if (self.onCellRangeSelected)
871+
self.onCellRangeSelected(fixUpRange(dd.range));
807872
}
808873
});
809874
}
@@ -1758,19 +1823,43 @@ if (!jQuery.fn.drag) {
17581823
}
17591824
}
17601825

1826+
function cellExists(row,cell) {
1827+
return !(row < 0 || row >= gridDataGetLength() || cell < 0 || cell >= columns.length);
1828+
}
1829+
17611830
function getCellFromPoint(x,y) {
1762-
var row = Math.floor(y/options.rowHeight);
1831+
var row = Math.floor((y+offset)/options.rowHeight);
17631832
var cell = 0;
17641833

17651834
var w = 0;
1766-
for (var i=0; i<columns.length && w<y; i++) {
1835+
for (var i=0; i<columns.length && w<x; i++) {
17671836
w += columns[i].width;
17681837
cell++;
17691838
}
17701839

17711840
return {row:row,cell:cell-1};
17721841
}
17731842

1843+
function getCellNodeBox(row,cell) {
1844+
if (!cellExists(row,cell))
1845+
return null;
1846+
1847+
var y1 = row * options.rowHeight - offset;
1848+
var y2 = y1 + options.rowHeight - 1;
1849+
var x1 = 0;
1850+
for (var i=0; i<cell; i++) {
1851+
x1 += columns[i].width;
1852+
}
1853+
var x2 = x1 + columns[cell].width;
1854+
1855+
return {
1856+
top: y1,
1857+
left: x1,
1858+
bottom: y2,
1859+
right: x2
1860+
};
1861+
}
1862+
17741863

17751864
//////////////////////////////////////////////////////////////////////////////////////////////
17761865
// Cell switching
@@ -2270,7 +2359,7 @@ if (!jQuery.fn.drag) {
22702359
// a debug helper to be able to access private members
22712360
this.eval = function(expr) {
22722361
return eval(expr);
2273-
}
2362+
};
22742363

22752364
init();
22762365

@@ -2302,6 +2391,7 @@ if (!jQuery.fn.drag) {
23022391
"onBeforeDestroy": null,
23032392
"onCurrentCellChanged": null,
23042393
"onCurrentCellPositionChanged": null,
2394+
"onCellRangeSelected": null,
23052395

23062396
// Methods
23072397
"getColumns": getColumns,

0 commit comments

Comments
 (0)