slickgrid 2.3.16.1 → 2.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. checksums.yaml +4 -4
  2. data/slickgrid.gemspec +1 -1
  3. data/vendor/assets/javascripts/slickgrid/controls/columnpicker.js +49 -34
  4. data/vendor/assets/javascripts/slickgrid/controls/gridmenu.js +32 -13
  5. data/vendor/assets/javascripts/slickgrid/core.js +174 -0
  6. data/vendor/assets/javascripts/slickgrid/dataview.js +47 -18
  7. data/vendor/assets/javascripts/slickgrid/editors.js +49 -27
  8. data/vendor/assets/javascripts/slickgrid/grid.js +5357 -3990
  9. data/vendor/assets/javascripts/slickgrid/groupitemmetadataprovider.js +4 -4
  10. data/vendor/assets/javascripts/slickgrid/plugins/autotooltips.js +2 -1
  11. data/vendor/assets/javascripts/slickgrid/plugins/cellcopymanager.js +2 -0
  12. data/vendor/assets/javascripts/slickgrid/plugins/cellexternalcopymanager.js +29 -9
  13. data/vendor/assets/javascripts/slickgrid/plugins/cellrangedecorator.js +2 -1
  14. data/vendor/assets/javascripts/slickgrid/plugins/cellrangeselector.js +70 -9
  15. data/vendor/assets/javascripts/slickgrid/plugins/cellselectionmodel.js +27 -5
  16. data/vendor/assets/javascripts/slickgrid/plugins/checkboxselectcolumn.js +157 -26
  17. data/vendor/assets/javascripts/slickgrid/plugins/draggablegrouping.js +145 -19
  18. data/vendor/assets/javascripts/slickgrid/plugins/headerbuttons.js +1 -0
  19. data/vendor/assets/javascripts/slickgrid/plugins/headermenu.js +8 -2
  20. data/vendor/assets/javascripts/slickgrid/plugins/rowdetailview.js +542 -231
  21. data/vendor/assets/javascripts/slickgrid/plugins/rowmovemanager.js +2 -1
  22. data/vendor/assets/javascripts/slickgrid/plugins/rowselectionmodel.js +1 -0
  23. data/vendor/assets/stylesheets/slickgrid/controls/draggablegrouping.scss +52 -0
  24. data/vendor/assets/stylesheets/slickgrid/controls/gridmenu.css +17 -3
  25. data/vendor/assets/stylesheets/slickgrid/grid.scss +54 -5
  26. data/vendor/assets/stylesheets/slickgrid/plugins/headermenu.scss +14 -0
  27. data/vendor/assets/stylesheets/slickgrid/plugins/rowdetailview.scss +9 -11
  28. metadata +3 -2
@@ -44,7 +44,7 @@
44
44
  options = $.extend(true, {}, _defaults, options);
45
45
 
46
46
 
47
- function defaultGroupCellFormatter(row, cell, value, columnDef, item) {
47
+ function defaultGroupCellFormatter(row, cell, value, columnDef, item, grid) {
48
48
  if (!options.enableExpandCollapse) {
49
49
  return item.title;
50
50
  }
@@ -62,8 +62,8 @@
62
62
  "</span>";
63
63
  }
64
64
 
65
- function defaultTotalsCellFormatter(row, cell, value, columnDef, item) {
66
- return (columnDef.groupTotalsFormatter && columnDef.groupTotalsFormatter(item, columnDef)) || "";
65
+ function defaultTotalsCellFormatter(row, cell, value, columnDef, item, grid) {
66
+ return (columnDef.groupTotalsFormatter && columnDef.groupTotalsFormatter(item, columnDef, grid)) || "";
67
67
  }
68
68
 
69
69
 
@@ -112,7 +112,7 @@
112
112
 
113
113
  // TODO: add -/+ handling
114
114
  function handleGridKeyDown(e, args) {
115
- if (options.enableExpandCollapse && (e.which == $.ui.keyCode.SPACE)) {
115
+ if (options.enableExpandCollapse && (e.which == Slick.keyCode.SPACE)) {
116
116
  var activeCell = this.getActiveCell();
117
117
  if (activeCell) {
118
118
  var item = this.getDataItem(activeCell.row);
@@ -77,7 +77,8 @@
77
77
  // Public API
78
78
  $.extend(this, {
79
79
  "init": init,
80
- "destroy": destroy
80
+ "destroy": destroy,
81
+ "pluginName": "AutoTooltips"
81
82
  });
82
83
  }
83
84
  })(jQuery);
@@ -78,6 +78,8 @@
78
78
  $.extend(this, {
79
79
  "init": init,
80
80
  "destroy": destroy,
81
+ "pluginName": "CellCopyManager",
82
+
81
83
  "clearCopySelection": clearCopySelection,
82
84
 
83
85
  "onCopyCells": new Slick.Event(),
@@ -28,6 +28,7 @@
28
28
  onCopySuccess: optional handler to run when copy action is complete
29
29
  newRowCreator: function to add rows to table if paste overflows bottom of table, if this function is not provided new rows will be ignored.
30
30
  readOnlyMode: suppresses paste
31
+ headerColumnValueExtractor : option to specify a custom column header value extractor function
31
32
  */
32
33
  var _grid;
33
34
  var _self = this;
@@ -67,12 +68,21 @@
67
68
  _grid.onKeyDown.unsubscribe(handleKeyDown);
68
69
  }
69
70
 
70
- function getDataItemValueForColumn(item, columnDef) {
71
+ function getHeaderValueForColumn(columnDef) {
72
+ if (_options.headerColumnValueExtractor) {
73
+ var val = _options.headerColumnValueExtractor(columnDef);
74
+
75
+ if (val) { return val; }
76
+ }
77
+
78
+ return columnDef.name;
79
+ }
80
+
81
+ function getDataItemValueForColumn(item, columnDef, e) {
71
82
  if (_options.dataItemColumnValueExtractor) {
72
- var dataItemColumnValueExtractorValue = _options.dataItemColumnValueExtractor(item, columnDef);
83
+ var val = _options.dataItemColumnValueExtractor(item, columnDef);
73
84
 
74
- if (dataItemColumnValueExtractorValue)
75
- return dataItemColumnValueExtractorValue;
85
+ if (val) { return val; }
76
86
  }
77
87
 
78
88
  var retVal = '';
@@ -83,7 +93,8 @@
83
93
  'container':$("<p>"), // a dummy container
84
94
  'column':columnDef,
85
95
  'position':{'top':0, 'left':0}, // a dummy position required by some editors
86
- 'grid':_grid
96
+ 'grid':_grid,
97
+ 'event':e
87
98
  };
88
99
  var editor = new columnDef.editor(editorArgs);
89
100
  editor.loadValue(item);
@@ -97,6 +108,8 @@
97
108
  }
98
109
 
99
110
  function setDataItemValueForColumn(item, columnDef, value) {
111
+ if (columnDef.denyPaste) { return null; }
112
+
100
113
  if (_options.dataItemColumnValueSetter) {
101
114
  return _options.dataItemColumnValueSetter(item, columnDef, value);
102
115
  }
@@ -348,13 +361,13 @@
348
361
  var clipTextHeaders = [];
349
362
  for (var j = range.fromCell; j < range.toCell + 1 ; j++) {
350
363
  if (columns[j].name.length > 0)
351
- clipTextHeaders.push(columns[j].name);
364
+ clipTextHeaders.push(getHeaderValueForColumn(columns[j]));
352
365
  }
353
366
  clipTextRows.push(clipTextHeaders.join("\t"));
354
367
  }
355
368
 
356
369
  for (var j=range.fromCell; j< range.toCell+1 ; j++){
357
- clipTextCells.push(getDataItemValueForColumn(dt, columns[j]));
370
+ clipTextCells.push(getDataItemValueForColumn(dt, columns[j], e));
358
371
  }
359
372
  clipTextRows.push(clipTextCells.join("\t"));
360
373
  }
@@ -438,15 +451,22 @@
438
451
  _grid.removeCellCssStyles(_copiedCellStyleLayerKey);
439
452
  }
440
453
 
454
+ function setIncludeHeaderWhenCopying(includeHeaderWhenCopying) {
455
+ _options.includeHeaderWhenCopying = includeHeaderWhenCopying;
456
+ }
457
+
441
458
  $.extend(this, {
442
459
  "init": init,
443
460
  "destroy": destroy,
461
+ "pluginName": "CellExternalCopyManager",
462
+
444
463
  "clearCopySelection": clearCopySelection,
445
464
  "handleKeyDown":handleKeyDown,
446
465
 
447
466
  "onCopyCells": new Slick.Event(),
448
467
  "onCopyCancelled": new Slick.Event(),
449
- "onPasteCells": new Slick.Event()
468
+ "onPasteCells": new Slick.Event(),
469
+ "setIncludeHeaderWhenCopying" : setIncludeHeaderWhenCopying
450
470
  });
451
471
  }
452
- })(jQuery);
472
+ })(jQuery);
@@ -41,7 +41,7 @@
41
41
  _elem = $("<div></div>", {css: options.selectionCss})
42
42
  .addClass(options.selectionCssClass)
43
43
  .css("position", "absolute")
44
- .appendTo(grid.getCanvasNode());
44
+ .appendTo(grid.getActiveCanvasNode());
45
45
  }
46
46
 
47
47
  var from = grid.getCellNodeBox(range.fromRow, range.fromCell);
@@ -65,6 +65,7 @@
65
65
  }
66
66
 
67
67
  $.extend(this, {
68
+ "pluginName": "CellRangeDecorator",
68
69
  "show": show,
69
70
  "hide": hide
70
71
  });
@@ -10,6 +10,8 @@
10
10
  var _grid;
11
11
  var _currentlySelectedRange;
12
12
  var _canvas;
13
+ var _gridOptions;
14
+ var _$activeCanvas;
13
15
  var _dragging;
14
16
  var _decorator;
15
17
  var _self = this;
@@ -20,12 +22,24 @@
20
22
  }
21
23
  };
22
24
 
25
+ // Frozen row & column variables
26
+ var _rowOffset;
27
+ var _columnOffset;
28
+ var _isRightCanvas;
29
+ var _isBottomCanvas;
30
+
31
+ // Scrollings
32
+ var _scrollTop = 0;
33
+ var _scrollLeft = 0;
34
+
23
35
  function init(grid) {
24
36
  options = $.extend(true, {}, _defaults, options);
25
37
  _decorator = options.cellDecorator || new Slick.CellRangeDecorator(grid, options);
26
38
  _grid = grid;
27
39
  _canvas = _grid.getCanvasNode();
40
+ _gridOptions = _grid.getOptions();
28
41
  _handler
42
+ .subscribe(_grid.onScroll, handleScroll)
29
43
  .subscribe(_grid.onDragInit, handleDragInit)
30
44
  .subscribe(_grid.onDragStart, handleDragStart)
31
45
  .subscribe(_grid.onDrag, handleDrag)
@@ -40,7 +54,32 @@
40
54
  return _decorator;
41
55
  }
42
56
 
57
+ function handleScroll(e, args) {
58
+ _scrollTop = args.scrollTop;
59
+ _scrollLeft = args.scrollLeft;
60
+ }
61
+
43
62
  function handleDragInit(e, dd) {
63
+ // Set the active canvas node because the decorator needs to append its
64
+ // box to the correct canvas
65
+ _$activeCanvas = $(_grid.getActiveCanvasNode(e));
66
+
67
+ var c = _$activeCanvas.offset();
68
+
69
+ _rowOffset = 0;
70
+ _columnOffset = 0;
71
+ _isBottomCanvas = _$activeCanvas.hasClass('grid-canvas-bottom');
72
+
73
+ if (_gridOptions.frozenRow > -1 && _isBottomCanvas) {
74
+ _rowOffset = (_gridOptions.frozenBottom) ? $('.grid-canvas-bottom').height() : $('.grid-canvas-top').height();
75
+ }
76
+
77
+ _isRightCanvas = _$activeCanvas.hasClass('grid-canvas-right');
78
+
79
+ if (_gridOptions.frozenColumn > -1 && _isRightCanvas) {
80
+ _columnOffset = $('.grid-canvas-left').width();
81
+ }
82
+
44
83
  // prevent the grid from cancelling drag'n'drop by default
45
84
  e.stopImmediatePropagation();
46
85
  }
@@ -59,11 +98,19 @@
59
98
 
60
99
  _grid.focus();
61
100
 
62
- var start = _grid.getCellFromPoint(
63
- dd.startX - $(_canvas).offset().left,
64
- dd.startY - $(_canvas).offset().top);
101
+ var startX = dd.startX - $(_canvas).offset().left;
102
+ if (_gridOptions.frozenColumn >= 0 && _isRightCanvas) {
103
+ startX += _scrollLeft;
104
+ }
105
+
106
+ var startY = dd.startY - $(_canvas).offset().top;
107
+ if (_gridOptions.frozenRow >= 0 && _isBottomCanvas) {
108
+ startY += _scrollTop;
109
+ }
110
+
111
+ var start = _grid.getCellFromPoint(startX, startY);
65
112
 
66
- dd.range = {start: start, end: {}};
113
+ dd.range = { start: start, end: {} };
67
114
  _currentlySelectedRange = dd.range;
68
115
  return _decorator.show(new Slick.Range(start.row, start.cell));
69
116
  }
@@ -75,15 +122,27 @@
75
122
  e.stopImmediatePropagation();
76
123
 
77
124
  var end = _grid.getCellFromPoint(
78
- e.pageX - $(_canvas).offset().left,
79
- e.pageY - $(_canvas).offset().top);
125
+ e.pageX - _$activeCanvas.offset().left + _columnOffset,
126
+ e.pageY - _$activeCanvas.offset().top + _rowOffset
127
+ );
80
128
 
129
+ // ... frozen column(s),
130
+ if ( _gridOptions.frozenColumn >= 0 && (!_isRightCanvas && (end.cell > _gridOptions.frozenColumn)) || (_isRightCanvas && (end.cell <= _gridOptions.frozenColumn)) ) {
131
+ return;
132
+ }
133
+
134
+ // ... or frozen row(s)
135
+ if ( _gridOptions.frozenRow >= 0 && (!_isBottomCanvas && (end.row >= _gridOptions.frozenRow)) || (_isBottomCanvas && (end.row < _gridOptions.frozenRow)) ) {
136
+ return;
137
+ }
138
+
139
+ // ... or regular grid (without any frozen options)
81
140
  if (!_grid.canCellBeSelected(end.row, end.cell)) {
82
141
  return;
83
142
  }
84
143
 
85
144
  dd.range.end = end;
86
- _currentlySelectedRange = dd.range;
145
+
87
146
  _decorator.show(new Slick.Range(dd.range.start.row, dd.range.start.cell, end.row, end.cell));
88
147
  }
89
148
 
@@ -105,7 +164,7 @@
105
164
  )
106
165
  });
107
166
  }
108
-
167
+
109
168
  function getCurrentRange() {
110
169
  return _currentlySelectedRange;
111
170
  }
@@ -113,6 +172,8 @@
113
172
  $.extend(this, {
114
173
  "init": init,
115
174
  "destroy": destroy,
175
+ "pluginName": "CellRangeSelector",
176
+
116
177
  "getCellDecorator": getCellDecorator,
117
178
  "getCurrentRange": getCurrentRange,
118
179
 
@@ -120,4 +181,4 @@
120
181
  "onCellRangeSelected": new Slick.Event()
121
182
  });
122
183
  }
123
- })(jQuery);
184
+ })(jQuery);
@@ -13,7 +13,7 @@
13
13
  var _self = this;
14
14
  var _selector;
15
15
 
16
- if (typeof options === "undefined" || typeof options.cellRangeSelector === "undefined") {
16
+ if (typeof options === "undefined" || typeof options.cellRangeSelector === "undefined") {
17
17
  _selector = new Slick.CellRangeSelector({
18
18
  "selectionCss": {
19
19
  "border": "2px solid black"
@@ -60,12 +60,33 @@
60
60
  return result;
61
61
  }
62
62
 
63
+ function rangesAreEqual(range1, range2) {
64
+ var areDifferent = (range1.length !== range2.length);
65
+ if (!areDifferent) {
66
+ for (var i = 0; i < range1.length; i++) {
67
+ if (
68
+ range1[i].fromCell !== range2[i].fromCell
69
+ || range1[i].fromRow !== range2[i].fromRow
70
+ || range1[i].toCell !== range2[i].toCell
71
+ || range1[i].toRow !== range2[i].toRow
72
+ ) {
73
+ areDifferent = true;
74
+ break;
75
+ }
76
+ }
77
+ }
78
+ return !areDifferent;
79
+ }
80
+
63
81
  function setSelectedRanges(ranges) {
64
82
  // simple check for: empty selection didn't change, prevent firing onSelectedRangesChanged
65
83
  if ((!_ranges || _ranges.length === 0) && (!ranges || ranges.length === 0)) { return; }
66
84
 
85
+ // if range has not changed, don't fire onSelectedRangesChanged
86
+ var rangeHasChanged = !rangesAreEqual(_ranges, ranges);
87
+
67
88
  _ranges = removeInvalidRanges(ranges);
68
- _self.onSelectedRangesChanged.notify(_ranges);
89
+ if (rangeHasChanged) { _self.onSelectedRangesChanged.notify(_ranges); }
69
90
  }
70
91
 
71
92
  function getSelectedRanges() {
@@ -109,11 +130,11 @@
109
130
  if (active && e.shiftKey && !metaKey && !e.altKey &&
110
131
  (e.which == 37 || e.which == 39 || e.which == 38 || e.which == 40)) {
111
132
 
112
- ranges = getSelectedRanges();
133
+ ranges = getSelectedRanges().slice();
113
134
  if (!ranges.length)
114
135
  ranges.push(new Slick.Range(active.row, active.cell));
115
136
 
116
- // keyboard can work with last range only
137
+ // keyboard can work with last range only
117
138
  last = ranges.pop();
118
139
 
119
140
  // can't handle selection out of active cell
@@ -136,7 +157,7 @@
136
157
  dRow += dirRow;
137
158
  }
138
159
 
139
- // define new selection range
160
+ // define new selection range
140
161
  var new_last = new Slick.Range(active.row, active.cell, active.row + dirRow * dRow, active.cell + dirCell * dCell);
141
162
  if (removeInvalidRanges([new_last]).length) {
142
163
  ranges.push(new_last);
@@ -161,6 +182,7 @@
161
182
 
162
183
  "init": init,
163
184
  "destroy": destroy,
185
+ "pluginName": "CellSelectionModel",
164
186
 
165
187
  "onSelectedRangesChanged": new Slick.Event()
166
188
  });
@@ -9,15 +9,20 @@
9
9
 
10
10
  function CheckboxSelectColumn(options) {
11
11
  var _grid;
12
- var _self = this;
12
+ var _selectableOverride = null;
13
+ var _selectAll_UID = createUID();
13
14
  var _handler = new Slick.EventHandler();
14
15
  var _selectedRowsLookup = {};
15
16
  var _defaults = {
16
17
  columnId: "_checkbox_selector",
17
18
  cssClass: null,
19
+ hideSelectAllCheckbox: false,
18
20
  toolTip: "Select/Deselect All",
19
- width: 30
21
+ width: 30,
22
+ hideInColumnTitleRow: false,
23
+ hideInFilterHeaderRow: true
20
24
  };
25
+ var _isSelectAllChecked = false;
21
26
 
22
27
  var _options = $.extend(true, {}, _defaults, options);
23
28
 
@@ -26,24 +31,85 @@
26
31
  _handler
27
32
  .subscribe(_grid.onSelectedRowsChanged, handleSelectedRowsChanged)
28
33
  .subscribe(_grid.onClick, handleClick)
29
- .subscribe(_grid.onHeaderClick, handleHeaderClick)
30
34
  .subscribe(_grid.onKeyDown, handleKeyDown);
35
+
36
+ if (!_options.hideInFilterHeaderRow) {
37
+ addCheckboxToFilterHeaderRow(grid);
38
+ }
39
+ if (!_options.hideInColumnTitleRow) {
40
+ _handler.subscribe(_grid.onHeaderClick, handleHeaderClick)
41
+ }
31
42
  }
32
43
 
33
44
  function destroy() {
34
45
  _handler.unsubscribeAll();
35
46
  }
36
47
 
48
+ function getOptions() {
49
+ return _options;
50
+ }
51
+
52
+ function setOptions(options) {
53
+ _options = $.extend(true, {}, _options, options);
54
+
55
+ if (_options.hideSelectAllCheckbox) {
56
+ hideSelectAllFromColumnHeaderTitleRow();
57
+ hideSelectAllFromColumnHeaderFilterRow();
58
+ } else {
59
+ if (!_options.hideInColumnTitleRow) {
60
+ renderSelectAllCheckbox(_isSelectAllChecked);
61
+ _handler.subscribe(_grid.onHeaderClick, handleHeaderClick);
62
+ } else {
63
+ hideSelectAllFromColumnHeaderTitleRow();
64
+ }
65
+
66
+ if (!_options.hideInFilterHeaderRow) {
67
+ var selectAllContainer = $("#filter-checkbox-selectall-container");
68
+ selectAllContainer.show();
69
+ selectAllContainer.find('input[type="checkbox"]').prop("checked", _isSelectAllChecked);
70
+ } else {
71
+ hideSelectAllFromColumnHeaderFilterRow();
72
+ }
73
+ }
74
+ }
75
+
76
+ function hideSelectAllFromColumnHeaderTitleRow() {
77
+ _grid.updateColumnHeader(_options.columnId, "", "");
78
+ }
79
+
80
+ function hideSelectAllFromColumnHeaderFilterRow() {
81
+ $("#filter-checkbox-selectall-container").hide();
82
+ }
83
+
37
84
  function handleSelectedRowsChanged(e, args) {
38
- var UID = createUID();
39
85
  var selectedRows = _grid.getSelectedRows();
40
86
  var lookup = {}, row, i;
87
+ var disabledCount = 0;
88
+ if (typeof _selectableOverride === 'function') {
89
+ for (k = 0; k < _grid.getDataLength(); k++) {
90
+ // If we are allowed to select the row
91
+ var dataItem = _grid.getDataItem(k);
92
+ if (!checkSelectableOverride(i, dataItem, _grid)) {
93
+ disabledCount++;
94
+ }
95
+ }
96
+ }
97
+
98
+ var removeList = [];
41
99
  for (i = 0; i < selectedRows.length; i++) {
42
100
  row = selectedRows[i];
43
- lookup[row] = true;
44
- if (lookup[row] !== _selectedRowsLookup[row]) {
45
- _grid.invalidateRow(row);
46
- delete _selectedRowsLookup[row];
101
+
102
+ // If we are allowed to select the row
103
+ var rowItem = _grid.getDataItem(row);
104
+ if (checkSelectableOverride(i, rowItem, _grid)) {
105
+ lookup[row] = true;
106
+ if (lookup[row] !== _selectedRowsLookup[row]) {
107
+ _grid.invalidateRow(row);
108
+ delete _selectedRowsLookup[row];
109
+ }
110
+ }
111
+ else {
112
+ removeList.push(row);
47
113
  }
48
114
  }
49
115
  for (i in _selectedRowsLookup) {
@@ -51,11 +117,22 @@
51
117
  }
52
118
  _selectedRowsLookup = lookup;
53
119
  _grid.render();
120
+ _isSelectAllChecked = selectedRows.length && selectedRows.length + disabledCount >= _grid.getDataLength();
54
121
 
55
- if (selectedRows.length && selectedRows.length == _grid.getDataLength()) {
56
- _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + UID + "' type='checkbox' checked='checked'><label for='header-selector" + UID + "'></label>", _options.toolTip);
57
- } else {
58
- _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + UID + "' type='checkbox'><label for='header-selector" + UID + "'></label>", _options.toolTip);
122
+ if (!_options.hideInColumnTitleRow && !_options.hideSelectAllCheckbox) {
123
+ renderSelectAllCheckbox(_isSelectAllChecked);
124
+ }
125
+ if (!_options.hideInFilterHeaderRow) {
126
+ var selectAllElm = $("#header-filter-selector" + _selectAll_UID);
127
+ selectAllElm.prop("checked", _isSelectAllChecked);
128
+ }
129
+ // Remove items that shouln't of been selected in the first place (Got here Ctrl + click)
130
+ if (removeList.length > 0) {
131
+ for (i = 0; i < removeList.length; i++) {
132
+ var remIdx = selectedRows.indexOf(removeList[i]);
133
+ selectedRows.splice(remIdx, 1);
134
+ }
135
+ _grid.setSelectedRows(selectedRows);
59
136
  }
60
137
  }
61
138
 
@@ -89,6 +166,11 @@
89
166
  }
90
167
 
91
168
  function toggleRowSelection(row) {
169
+ var dataContext = _grid.getDataItem(row);
170
+ if (!checkSelectableOverride(row, dataContext, _grid)) {
171
+ return;
172
+ }
173
+
92
174
  if (_selectedRowsLookup[row]) {
93
175
  _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
94
176
  return n != row
@@ -97,12 +179,11 @@
97
179
  _grid.setSelectedRows(_grid.getSelectedRows().concat(row));
98
180
  }
99
181
  _grid.setActiveCell(row, getCheckboxColumnCellIndex());
100
- _grid.focus();
101
182
  }
102
183
 
103
184
  function selectRows(rowArray) {
104
- var i, l=rowArray.length, addRows = [];
105
- for(i=0; i<l; i++) {
185
+ var i, l = rowArray.length, addRows = [];
186
+ for (i = 0; i < l; i++) {
106
187
  if (!_selectedRowsLookup[rowArray[i]]) {
107
188
  addRows[addRows.length] = rowArray[i];
108
189
  }
@@ -111,14 +192,14 @@
111
192
  }
112
193
 
113
194
  function deSelectRows(rowArray) {
114
- var i, l=rowArray.length, removeRows = [];
115
- for(i=0; i<l; i++) {
195
+ var i, l = rowArray.length, removeRows = [];
196
+ for (i = 0; i < l; i++) {
116
197
  if (_selectedRowsLookup[rowArray[i]]) {
117
198
  removeRows[removeRows.length] = rowArray[i];
118
199
  }
119
200
  }
120
201
  _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
121
- return removeRows.indexOf(n)<0
202
+ return removeRows.indexOf(n) < 0
122
203
  }));
123
204
  }
124
205
 
@@ -134,7 +215,11 @@
134
215
  if ($(e.target).is(":checked")) {
135
216
  var rows = [];
136
217
  for (var i = 0; i < _grid.getDataLength(); i++) {
137
- rows.push(i);
218
+ // Get the row and check it's a selectable row before pushing it onto the stack
219
+ var rowItem = _grid.getDataItem(i);
220
+ if (rowItem.selectableRow !== false) {
221
+ rows.push(i);
222
+ }
138
223
  }
139
224
  _grid.setSelectedRows(rows);
140
225
  } else {
@@ -151,7 +236,7 @@
151
236
  if (_checkboxColumnCellIndex === null) {
152
237
  _checkboxColumnCellIndex = 0;
153
238
  var colArr = _grid.getColumns();
154
- for (var i=0; i < colArr.length; i++) {
239
+ for (var i = 0; i < colArr.length; i++) {
155
240
  if (colArr[i].id == _options.columnId) {
156
241
  _checkboxColumnCellIndex = i;
157
242
  }
@@ -161,42 +246,88 @@
161
246
  }
162
247
 
163
248
  function getColumnDefinition() {
164
- var UID = createUID();
165
-
166
249
  return {
167
250
  id: _options.columnId,
168
- name: "<input id='header-selector" + UID + "' type='checkbox'><label for='header-selector" + UID + "'></label>",
251
+ name: (_options.hideSelectAllCheckbox || _options.hideInColumnTitleRow) ? "" : "<input id='header-selector" + _selectAll_UID + "' type='checkbox'><label for='header-selector" + _selectAll_UID + "'></label>",
169
252
  toolTip: _options.toolTip,
170
253
  field: "sel",
171
254
  width: _options.width,
172
255
  resizable: false,
173
256
  sortable: false,
174
257
  cssClass: _options.cssClass,
258
+ hideSelectAllCheckbox: _options.hideSelectAllCheckbox,
175
259
  formatter: checkboxSelectionFormatter
176
260
  };
177
261
  }
178
262
 
263
+ function addCheckboxToFilterHeaderRow(grid) {
264
+ grid.onHeaderRowCellRendered.subscribe(function (e, args) {
265
+ if (args.column.field === "sel") {
266
+ $(args.node).empty();
267
+ $("<span id='filter-checkbox-selectall-container'><input id='header-filter-selector" + _selectAll_UID + "' type='checkbox'><label for='header-filter-selector" + _selectAll_UID + "'></label></span>")
268
+ .appendTo(args.node)
269
+ .on('click', function (evnt) {
270
+ handleHeaderClick(evnt, args)
271
+ });
272
+ }
273
+ });
274
+ }
275
+
179
276
  function createUID() {
180
277
  return Math.round(10000000 * Math.random());
181
278
  }
182
279
 
183
- function checkboxSelectionFormatter(row, cell, value, columnDef, dataContext) {
280
+ function checkboxSelectionFormatter(row, cell, value, columnDef, dataContext, grid) {
184
281
  var UID = createUID() + row;
185
282
 
186
283
  if (dataContext) {
187
- return _selectedRowsLookup[row]
284
+ if (!checkSelectableOverride(row, dataContext, grid)) {
285
+ return null;
286
+ } else {
287
+ return _selectedRowsLookup[row]
188
288
  ? "<input id='selector" + UID + "' type='checkbox' checked='checked'><label for='selector" + UID + "'></label>"
189
289
  : "<input id='selector" + UID + "' type='checkbox'><label for='selector" + UID + "'></label>";
290
+ }
190
291
  }
191
292
  return null;
192
293
  }
193
294
 
295
+ function checkSelectableOverride(row, dataContext, grid) {
296
+ if (typeof _selectableOverride === 'function') {
297
+ return _selectableOverride(row, dataContext, grid);
298
+ }
299
+ return true;
300
+ }
301
+
302
+ function renderSelectAllCheckbox(isSelectAllChecked) {
303
+ if (isSelectAllChecked) {
304
+ _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox' checked='checked'><label for='header-selector" + _selectAll_UID + "'></label>", _options.toolTip);
305
+ } else {
306
+ _grid.updateColumnHeader(_options.columnId, "<input id='header-selector" + _selectAll_UID + "' type='checkbox'><label for='header-selector" + _selectAll_UID + "'></label>", _options.toolTip);
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Method that user can pass to override the default behavior or making every row a selectable row.
312
+ * In order word, user can choose which rows to be selectable or not by providing his own logic.
313
+ * @param overrideFn: override function callback
314
+ */
315
+ function selectableOverride(overrideFn) {
316
+ _selectableOverride = overrideFn;
317
+ }
318
+
319
+
194
320
  $.extend(this, {
195
321
  "init": init,
196
322
  "destroy": destroy,
323
+ "pluginName": "CheckboxSelectColumn",
324
+
197
325
  "deSelectRows": deSelectRows,
198
326
  "selectRows": selectRows,
199
- "getColumnDefinition": getColumnDefinition
327
+ "getColumnDefinition": getColumnDefinition,
328
+ "getOptions": getOptions,
329
+ "selectableOverride": selectableOverride,
330
+ "setOptions": setOptions,
200
331
  });
201
332
  }
202
333
  })(jQuery);