slickgrid 2.3.16.1 → 2.4.5

Sign up to get free protection for your applications and to get access to all the features.
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);