|
19 | 19 | * editable - (default false) If false, no cells will be switched into edit mode. |
20 | 20 | * autoEdit - (default true) Cell will not automatically go into edit mode when selected. |
21 | 21 | * 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. |
22 | 23 | * defaultColumnWidth - (default 80px) Default column width in pixels (if columns[cell].width is not specified). |
23 | 24 | * enableColumnReorder - (default true) Allows the user to reorder columns. |
24 | 25 | * asyncEditorLoading - (default false) Makes cell editors load asynchronously after a small delay. |
|
81 | 82 | * onBeforeCellEditorDestroy - Raised before a cell editor is destroyed. Args: current cell editor. |
82 | 83 | * onBeforeDestroy - Raised just before the grid control is destroyed (part of the destroy() method). |
83 | 84 | * 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}}. |
84 | 86 | * |
85 | 87 | * NOTES: |
86 | 88 | * Cell/row DOM manipulations are done directly bypassing jQuery's DOM manipulation methods. |
@@ -221,6 +223,7 @@ if (!jQuery.fn.drag) { |
221 | 223 | editable: false, |
222 | 224 | autoEdit: true, |
223 | 225 | enableCellNavigation: true, |
| 226 | + enableCellRangeSelection: false, |
224 | 227 | enableColumnReorder: true, |
225 | 228 | asyncEditorLoading: false, |
226 | 229 | asyncEditorLoadDelay: 100, |
@@ -255,7 +258,7 @@ if (!jQuery.fn.drag) { |
255 | 258 | var cj; // "jumpiness" coefficient |
256 | 259 |
|
257 | 260 | var page = 0; // current page |
258 | | - var offset=0; // current page offset |
| 261 | + var offset = 0; // current page offset |
259 | 262 | var scrollDir = 1; |
260 | 263 |
|
261 | 264 | // private |
@@ -389,7 +392,7 @@ if (!jQuery.fn.drag) { |
389 | 392 |
|
390 | 393 | createColumnHeaders(); |
391 | 394 | setupColumnSort(); |
392 | | - setupRowReordering(); |
| 395 | + setupDragEvents(); |
393 | 396 | createCssRules(); |
394 | 397 |
|
395 | 398 | resizeAndRender(); |
@@ -749,61 +752,123 @@ if (!jQuery.fn.drag) { |
749 | 752 | }); |
750 | 753 | } |
751 | 754 |
|
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 | + |
753 | 770 | $canvas |
754 | 771 | .bind("draginit", function(e,dd) { |
755 | 772 | var $cell = $(e.target).closest(".slick-cell"); |
756 | 773 | 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 | + |
758 | 777 | 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; |
760 | 786 | }) |
761 | 787 | .bind("dragstart", function(e,dd) { |
762 | 788 | if (!options.editorLock.commitCurrentEdit()) { return false; } |
763 | 789 | var row = parseInt($(e.target).closest(".slick-row").attr("row"), 10); |
764 | 790 |
|
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; |
767 | 811 | } |
768 | 812 |
|
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 | + } |
784 | 821 | }) |
785 | 822 | .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; |
798 | 838 | } |
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 | + }); |
800 | 856 | } |
801 | 857 | }) |
802 | 858 | .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)); |
807 | 872 | } |
808 | 873 | }); |
809 | 874 | } |
@@ -1758,19 +1823,43 @@ if (!jQuery.fn.drag) { |
1758 | 1823 | } |
1759 | 1824 | } |
1760 | 1825 |
|
| 1826 | + function cellExists(row,cell) { |
| 1827 | + return !(row < 0 || row >= gridDataGetLength() || cell < 0 || cell >= columns.length); |
| 1828 | + } |
| 1829 | + |
1761 | 1830 | function getCellFromPoint(x,y) { |
1762 | | - var row = Math.floor(y/options.rowHeight); |
| 1831 | + var row = Math.floor((y+offset)/options.rowHeight); |
1763 | 1832 | var cell = 0; |
1764 | 1833 |
|
1765 | 1834 | 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++) { |
1767 | 1836 | w += columns[i].width; |
1768 | 1837 | cell++; |
1769 | 1838 | } |
1770 | 1839 |
|
1771 | 1840 | return {row:row,cell:cell-1}; |
1772 | 1841 | } |
1773 | 1842 |
|
| 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 | + |
1774 | 1863 |
|
1775 | 1864 | ////////////////////////////////////////////////////////////////////////////////////////////// |
1776 | 1865 | // Cell switching |
@@ -2270,7 +2359,7 @@ if (!jQuery.fn.drag) { |
2270 | 2359 | // a debug helper to be able to access private members |
2271 | 2360 | this.eval = function(expr) { |
2272 | 2361 | return eval(expr); |
2273 | | - } |
| 2362 | + }; |
2274 | 2363 |
|
2275 | 2364 | init(); |
2276 | 2365 |
|
@@ -2302,6 +2391,7 @@ if (!jQuery.fn.drag) { |
2302 | 2391 | "onBeforeDestroy": null, |
2303 | 2392 | "onCurrentCellChanged": null, |
2304 | 2393 | "onCurrentCellPositionChanged": null, |
| 2394 | + "onCellRangeSelected": null, |
2305 | 2395 |
|
2306 | 2396 | // Methods |
2307 | 2397 | "getColumns": getColumns, |
|
0 commit comments