slickgrid 2.4.5 → 2.4.14

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.
@@ -38,7 +38,8 @@
38
38
  toggleCollapsedCssClass: "collapsed",
39
39
  enableExpandCollapse: true,
40
40
  groupFormatter: defaultGroupCellFormatter,
41
- totalsFormatter: defaultTotalsCellFormatter
41
+ totalsFormatter: defaultTotalsCellFormatter,
42
+ includeHeaderTotals: false
42
43
  };
43
44
 
44
45
  options = $.extend(true, {}, _defaults, options);
@@ -137,13 +138,15 @@
137
138
  }
138
139
 
139
140
  function getGroupRowMetadata(item) {
141
+ var groupLevel = item && item.level;
140
142
  return {
141
143
  selectable: false,
142
144
  focusable: options.groupFocusable,
143
- cssClasses: options.groupCssClass,
145
+ cssClasses: options.groupCssClass + ' slick-group-level-' + groupLevel,
146
+ formatter: options.includeHeaderTotals && options.totalsFormatter,
144
147
  columns: {
145
148
  0: {
146
- colspan: "*",
149
+ colspan: options.includeHeaderTotals?"1":"*",
147
150
  formatter: options.groupFormatter,
148
151
  editor: null
149
152
  }
@@ -152,10 +155,11 @@
152
155
  }
153
156
 
154
157
  function getTotalsRowMetadata(item) {
158
+ var groupLevel = item && item.group && item.group.level;
155
159
  return {
156
160
  selectable: false,
157
161
  focusable: options.totalsFocusable,
158
- cssClasses: options.totalsCssClass,
162
+ cssClasses: options.totalsCssClass + ' slick-group-level-' + groupLevel,
159
163
  formatter: options.totalsFormatter,
160
164
  editor: null
161
165
  };
@@ -35,7 +35,7 @@
35
35
 
36
36
  if (e.which == 67 && (e.ctrlKey || e.metaKey)) {
37
37
  ranges = _grid.getSelectionModel().getSelectedRanges();
38
- if (ranges.length != 0) {
38
+ if (ranges.length !== 0) {
39
39
  e.preventDefault();
40
40
  _copiedRanges = ranges;
41
41
  markCopySelection(ranges);
@@ -149,14 +149,14 @@
149
149
  var clipText = ta.value;
150
150
  var clipRows = clipText.split(/[\n\f\r]/);
151
151
  // trim trailing CR if present
152
- if (clipRows[clipRows.length - 1]=="") { clipRows.pop(); }
152
+ if (clipRows[clipRows.length - 1]==="") { clipRows.pop(); }
153
153
 
154
154
  var clippedRange = [];
155
155
  var j = 0;
156
156
 
157
157
  _bodyElement.removeChild(ta);
158
158
  for (var i=0; i<clipRows.length; i++) {
159
- if (clipRows[i]!="")
159
+ if (clipRows[i]!=="")
160
160
  clippedRange[j++] = clipRows[i].split("\t");
161
161
  else
162
162
  clippedRange[i] = [""];
@@ -264,7 +264,7 @@
264
264
  'fromRow': activeRow,
265
265
  'toCell': activeCell+this.w-1,
266
266
  'toRow': activeRow+this.h-1
267
- }
267
+ };
268
268
 
269
269
  this.markCopySelection([bRange]);
270
270
  _grid.getSelectionModel().setSelectedRanges([bRange]);
@@ -300,7 +300,7 @@
300
300
  'fromRow': activeRow,
301
301
  'toCell': activeCell+this.w-1,
302
302
  'toRow': activeRow+this.h-1
303
- }
303
+ };
304
304
 
305
305
  this.markCopySelection([bRange]);
306
306
  _grid.getSelectionModel().setSelectedRanges([bRange]);
@@ -342,7 +342,7 @@
342
342
  _onCopyInit.call();
343
343
  }
344
344
  ranges = _grid.getSelectionModel().getSelectedRanges();
345
- if (ranges.length != 0) {
345
+ if (ranges.length !== 0) {
346
346
  _copiedRanges = ranges;
347
347
  markCopySelection(ranges);
348
348
  _self.onCopyCells.notify({ranges: ranges});
@@ -357,7 +357,7 @@
357
357
  var clipTextCells = [];
358
358
  var dt = _grid.getDataItem(i);
359
359
 
360
- if (clipTextRows == "" && _options.includeHeaderWhenCopying) {
360
+ if (clipTextRows === "" && _options.includeHeaderWhenCopying) {
361
361
  var clipTextHeaders = [];
362
362
  for (var j = range.fromCell; j < range.toCell + 1 ; j++) {
363
363
  if (columns[j].name.length > 0)
@@ -26,6 +26,11 @@
26
26
 
27
27
  var _options = $.extend(true, {}, _defaults, options);
28
28
 
29
+ // user could override the checkbox icon logic from within the options or after instantiating the plugin
30
+ if(typeof _options.selectableOverride === 'function') {
31
+ selectableOverride(_options.selectableOverride);
32
+ }
33
+
29
34
  function init(grid) {
30
35
  _grid = grid;
31
36
  _handler
@@ -37,7 +42,7 @@
37
42
  addCheckboxToFilterHeaderRow(grid);
38
43
  }
39
44
  if (!_options.hideInColumnTitleRow) {
40
- _handler.subscribe(_grid.onHeaderClick, handleHeaderClick)
45
+ _handler.subscribe(_grid.onHeaderClick, handleHeaderClick);
41
46
  }
42
47
  }
43
48
 
@@ -83,7 +88,7 @@
83
88
 
84
89
  function handleSelectedRowsChanged(e, args) {
85
90
  var selectedRows = _grid.getSelectedRows();
86
- var lookup = {}, row, i;
91
+ var lookup = {}, row, i, k;
87
92
  var disabledCount = 0;
88
93
  if (typeof _selectableOverride === 'function') {
89
94
  for (k = 0; k < _grid.getDataLength(); k++) {
@@ -173,7 +178,7 @@
173
178
 
174
179
  if (_selectedRowsLookup[row]) {
175
180
  _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
176
- return n != row
181
+ return n != row;
177
182
  }));
178
183
  } else {
179
184
  _grid.setSelectedRows(_grid.getSelectedRows().concat(row));
@@ -199,7 +204,7 @@
199
204
  }
200
205
  }
201
206
  _grid.setSelectedRows($.grep(_grid.getSelectedRows(), function (n) {
202
- return removeRows.indexOf(n) < 0
207
+ return removeRows.indexOf(n) < 0;
203
208
  }));
204
209
  }
205
210
 
@@ -267,7 +272,7 @@
267
272
  $("<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
273
  .appendTo(args.node)
269
274
  .on('click', function (evnt) {
270
- handleHeaderClick(evnt, args)
275
+ handleHeaderClick(evnt, args);
271
276
  });
272
277
  }
273
278
  });
@@ -81,11 +81,11 @@
81
81
  var node = args.node;
82
82
  if (!$.isEmptyObject(column.grouping)) {
83
83
  var groupableIcon = $("<span class='slick-column-groupable' />");
84
- if(options.groupIconCssClass) groupableIcon.addClass(options.groupIconCssClass)
85
- if(options.groupIconImage) groupableIcon.css("background", "url(" + options.groupIconImage + ") no-repeat center center");
84
+ if(options.groupIconCssClass) { groupableIcon.addClass(options.groupIconCssClass); }
85
+ if(options.groupIconImage) { groupableIcon.css("background", "url(" + options.groupIconImage + ") no-repeat center center"); }
86
86
  $(node).css('cursor', 'pointer').append(groupableIcon);
87
87
  }
88
- })
88
+ });
89
89
 
90
90
  for (var i = 0; i < _gridColumns.length; i++) {
91
91
  var columnId = _gridColumns[i].field;
@@ -227,9 +227,9 @@
227
227
  if (e.id == columnid) {
228
228
  if (e.grouping != null && !$.isEmptyObject(e.grouping)) {
229
229
  var entry = $("<div id='" + _gridUid + e.id + "_entry' data-id='" + e.id + "' class='slick-dropped-grouping'>");
230
- var groupText = $("<div style='display: inline-flex'>" + column.text() + "</div>")
230
+ var groupText = $("<div style='display: inline-flex'>" + column.text() + "</div>");
231
231
  groupText.appendTo(entry);
232
- var groupRemoveIcon = $("<div class='slick-groupby-remove'>&nbsp;</div>")
232
+ var groupRemoveIcon = $("<div class='slick-groupby-remove'>&nbsp;</div>");
233
233
  if(options.deleteIconCssClass) groupRemoveIcon.addClass(options.deleteIconCssClass);
234
234
  if(options.deleteIconImage) groupRemoveIcon.css("background", "url(" + options.deleteIconImage + ") no-repeat center right");
235
235
  if(!options.deleteIconCssClass && !options.deleteIconImage) groupRemoveIcon.addClass('slick-groupby-remove-image');
@@ -260,8 +260,8 @@
260
260
  }
261
261
 
262
262
  function setDroppedGroups(groupingInfo) {
263
- groupingInfos = (groupingInfo instanceof Array) ? groupingInfo : [groupingInfo];
264
- dropboxPlaceholder.hide()
263
+ var groupingInfos = (groupingInfo instanceof Array) ? groupingInfo : [groupingInfo];
264
+ dropboxPlaceholder.hide();
265
265
  for (var i = 0; i < groupingInfos.length; i++) {
266
266
  var column = $(_grid.getHeaderColumn(groupingInfos[i]));
267
267
  handleGroupByDrop(dropbox, column);
@@ -272,7 +272,7 @@
272
272
  updateGroupBy("clear-all");
273
273
  dropbox.find(".slick-dropped-grouping").remove();
274
274
  groupToggler.css("display", "none");
275
- dropboxPlaceholder.show()
275
+ dropboxPlaceholder.show();
276
276
  }
277
277
 
278
278
  function removeFromArray(arr) {
@@ -295,14 +295,14 @@
295
295
  groupby[e.id] = e;
296
296
  });
297
297
  removeFromArray(columnsGroupBy, groupby[id]);
298
- if(columnsGroupBy.length == 0){
298
+ if(columnsGroupBy.length === 0){
299
299
  dropboxPlaceholder.show();
300
300
  }
301
301
  updateGroupBy("remove-group");
302
302
  }
303
303
 
304
304
  function updateGroupBy(originator) {
305
- if (columnsGroupBy.length == 0) {
305
+ if (columnsGroupBy.length === 0) {
306
306
  _dataView.setGrouping([]);
307
307
  onGroupChanged.notify({ caller: originator, groupColumns: [] });
308
308
  return;
@@ -315,7 +315,7 @@
315
315
  /*
316
316
  collapseAllGroups();
317
317
  */
318
- onGroupChanged.notify({ caller: originator, groupColumns: groupingArray})
318
+ onGroupChanged.notify({ caller: originator, groupColumns: groupingArray});
319
319
  }
320
320
 
321
321
  // Public API
@@ -275,7 +275,7 @@
275
275
 
276
276
  hideMenu();
277
277
 
278
- if (command != null && command != '') {
278
+ if (command != null && command !== '') {
279
279
  _self.onCommand.notify({
280
280
  "grid": _grid,
281
281
  "column": columnDef,
@@ -10,19 +10,21 @@
10
10
  * AVAILABLE ROW DETAIL OPTIONS:
11
11
  * cssClass: A CSS class to be added to the row detail
12
12
  * expandedClass: Extra classes to be added to the expanded Toggle
13
+ * expandableOverride: callback method that user can override the default behavior of making every row an expandable row (the logic to show or not the expandable icon).
13
14
  * collapsedClass: Extra classes to be added to the collapse Toggle
14
15
  * loadOnce: Defaults to false, when set to True it will load the data once and then reuse it.
15
16
  * preTemplate: Template that will be used before the async process (typically used to show a spinner/loading)
16
17
  * postTemplate: Template that will be loaded once the async function finishes
17
18
  * process: Async server function call
18
19
  * panelRows: Row count to use for the template panel
20
+ * singleRowExpand: Defaults to false, limit expanded row to 1 at a time.
19
21
  * useRowClick: Boolean flag, when True will open the row detail on a row click (from any column), default to False
20
22
  * keyPrefix: Defaults to '_', prefix used for all the plugin metadata added to the item object (meta e.g.: padding, collapsed, parent)
21
23
  * collapseAllOnSort: Defaults to true, which will collapse all row detail views when user calls a sort. Unless user implements a sort to deal with padding
22
24
  * saveDetailViewOnScroll: Defaults to true, which will save the row detail view in a cache when it detects that it will become out of the viewport buffer
23
25
  * useSimpleViewportCalc: Defaults to false, which will use simplified calculation of out or back of viewport visibility
24
26
  *
25
- * AVAILABLE PUBLIC OPTIONS:
27
+ * AVAILABLE PUBLIC METHODS:
26
28
  * init: initiliaze the plugin
27
29
  * expandableOverride: callback method that user can override the default behavior of making every row an expandable row (the logic to show or not the expandable icon).
28
30
  * destroy: destroy the plugin and it's events
@@ -92,6 +94,7 @@
92
94
  var _grid;
93
95
  var _gridOptions;
94
96
  var _gridUid;
97
+ var _dataView;
95
98
  var _expandableOverride = null;
96
99
  var _self = this;
97
100
  var _lastRange = null;
@@ -108,6 +111,7 @@
108
111
  loadOnce: false,
109
112
  collapseAllOnSort: true,
110
113
  saveDetailViewOnScroll: true,
114
+ singleRowExpand: false,
111
115
  useSimpleViewportCalc: false,
112
116
  alwaysRenderColumn: true,
113
117
  toolTip: '',
@@ -119,6 +123,11 @@
119
123
  var _rowIdsOutOfViewport = [];
120
124
  var _options = $.extend(true, {}, _defaults, options);
121
125
 
126
+ // user could override the expandable icon logic from within the options or after instantiating the plugin
127
+ if(typeof _options.expandableOverride === 'function') {
128
+ expandableOverride(_options.expandableOverride);
129
+ }
130
+
122
131
  /**
123
132
  * Initialize the plugin, which requires user to pass the SlickGrid Grid object
124
133
  * @param grid: SlickGrid Grid object
@@ -192,6 +201,9 @@
192
201
  /** set or change some of the plugin options */
193
202
  function setOptions(options) {
194
203
  _options = $.extend(true, {}, _options, options);
204
+ if (_options && _options.singleRowExpand) {
205
+ collapseAll();
206
+ }
195
207
  }
196
208
 
197
209
  /** Find a value in an array and return the index when (or -1 when not found) */
@@ -453,6 +465,10 @@
453
465
 
454
466
  /** Expand a row given the dataview item that is to be expanded */
455
467
  function expandDetailView(item) {
468
+ if (_options && _options.singleRowExpand) {
469
+ collapseAll();
470
+ }
471
+
456
472
  item[_keyPrefix + 'collapsed'] = false;
457
473
  _expandedRows.push(item);
458
474
 
@@ -499,7 +515,7 @@
499
515
  function subscribeToOnAsyncResponse() {
500
516
  _self.onAsyncResponse.subscribe(function (e, args) {
501
517
  if (!args || (!args.item && !args.itemDetail)) {
502
- throw 'Slick.RowDetailView plugin requires the onAsyncResponse() to supply "args.item" property.'
518
+ throw 'Slick.RowDetailView plugin requires the onAsyncResponse() to supply "args.item" property.';
503
519
  }
504
520
 
505
521
  // we accept item/itemDetail, just get the one which has data
@@ -554,7 +570,7 @@
554
570
  item[_keyPrefix + 'offset'] = offset;
555
571
 
556
572
  return item;
557
- }
573
+ };
558
574
 
559
575
  //////////////////////////////////////////////////////////////
560
576
  // create the detail ctr node. this belongs to the dev & can be custom-styled as per
@@ -596,20 +612,20 @@
596
612
  }
597
613
 
598
614
  /** The Formatter of the toggling icon of the Row Detail */
599
- function detailSelectionFormatter(row, cell, value, columnDef, dataContext) {
615
+ function detailSelectionFormatter(row, cell, value, columnDef, dataContext, grid) {
600
616
  if (!checkExpandableOverride(row, dataContext, grid)) {
601
617
  return null;
602
618
  } else {
603
619
  if (dataContext[_keyPrefix + 'collapsed'] == undefined) {
604
- dataContext[_keyPrefix + 'collapsed'] = true,
605
- dataContext[_keyPrefix + 'sizePadding'] = 0, //the required number of pading rows
606
- dataContext[_keyPrefix + 'height'] = 0, //the actual height in pixels of the detail field
607
- dataContext[_keyPrefix + 'isPadding'] = false,
608
- dataContext[_keyPrefix + 'parent'] = undefined,
609
- dataContext[_keyPrefix + 'offset'] = 0
620
+ dataContext[_keyPrefix + 'collapsed'] = true;
621
+ dataContext[_keyPrefix + 'sizePadding'] = 0; //the required number of pading rows
622
+ dataContext[_keyPrefix + 'height'] = 0; //the actual height in pixels of the detail field
623
+ dataContext[_keyPrefix + 'isPadding'] = false;
624
+ dataContext[_keyPrefix + 'parent'] = undefined;
625
+ dataContext[_keyPrefix + 'offset'] = 0;
610
626
  }
611
627
 
612
- if (dataContext[_keyPrefix + 'isPadding'] == true) {
628
+ if (dataContext[_keyPrefix + 'isPadding']) {
613
629
  // render nothing
614
630
  }
615
631
  else if (dataContext[_keyPrefix + 'collapsed']) {
@@ -645,7 +661,7 @@
645
661
  html.push('<div class="dynamic-cell-detail cellDetailView_', dataContext.id, '" '); //apply custom css to detail
646
662
  html.push('style="height:', outterHeight, 'px;'); //set total height of padding
647
663
  html.push('top:', rowHeight, 'px">'); //shift detail below 1st row
648
- html.push('<div class="detail-container detailViewContainer_', dataContext.id, '" style="min-height:' + dataContext[_keyPrefix + 'height'] + 'px">'); //sub ctr for custom styling
664
+ html.push('<div class="detail-container detailViewContainer_', dataContext.id, '">'); //sub ctr for custom styling
649
665
  html.push('<div class="innerDetailView_', dataContext.id, '">', dataContext[_keyPrefix + 'detailContent'], '</div></div>');
650
666
  // &omit a final closing detail container </div> that would come next
651
667
 
@@ -52,7 +52,7 @@
52
52
 
53
53
  var selectedRows = _grid.getSelectedRows();
54
54
 
55
- if (selectedRows.length == 0 || $.inArray(cell.row, selectedRows) == -1) {
55
+ if (selectedRows.length === 0 || $.inArray(cell.row, selectedRows) == -1) {
56
56
  selectedRows = [cell.row];
57
57
  _grid.setSelectedRows(selectedRows);
58
58
  }
@@ -104,7 +104,7 @@
104
104
  && (e.which == Slick.keyCode.UP || e.which == Slick.keyCode.DOWN)) {
105
105
  var selectedRows = getSelectedRows();
106
106
  selectedRows.sort(function (x, y) {
107
- return x - y
107
+ return x - y;
108
108
  });
109
109
 
110
110
  if (!selectedRows.length) {
@@ -0,0 +1,153 @@
1
+ (function ($) {
2
+ // register namespace
3
+ $.extend(true, window, {
4
+ Slick: {
5
+ State: State
6
+ }
7
+ });
8
+
9
+ var localStorageWrapper = function() {
10
+ var localStorage = window.localStorage;
11
+
12
+ if (typeof localStorage === 'undefined') {
13
+ console.error('localStorage is not available. slickgrid statepersistor disabled.');
14
+ }
15
+
16
+ return {
17
+ get: function(key) {
18
+ return $.Deferred(function(dfd) {
19
+ if (!localStorage) return dfd.reject("missing localStorage");
20
+ try {
21
+ var d = localStorage.getItem(key);
22
+ if (d) {
23
+ return dfd.resolve(JSON.parse(d));
24
+ }
25
+ dfd.resolve();
26
+ }
27
+ catch (exc) {
28
+ dfd.reject(exc);
29
+ }
30
+ });
31
+ },
32
+ set: function(key, obj) {
33
+ if (!localStorage) return;
34
+ if (typeof obj !== 'undefined') {
35
+ obj = JSON.stringify(obj);
36
+ }
37
+ localStorage.setItem(key, obj);
38
+ }
39
+ };
40
+ };
41
+
42
+ var defaults = {
43
+ key_prefix: "slickgrid:",
44
+ storage: new localStorageWrapper()
45
+ };
46
+
47
+ function State(options) {
48
+ options = $.extend(true, {}, defaults, options);
49
+
50
+ var _grid, _cid,
51
+ _store = options.storage,
52
+ onStateChanged = new Slick.Event();
53
+
54
+ function init(grid) {
55
+ _grid = grid;
56
+ _cid = grid.cid || options.cid;
57
+ if (_cid) {
58
+ grid.onColumnsResized.subscribe(save);
59
+ grid.onColumnsReordered.subscribe(save);
60
+ grid.onSort.subscribe(save);
61
+ } else {
62
+ console.warn("grid has no client id. state persisting is disabled.");
63
+ }
64
+ }
65
+
66
+ function destroy() {
67
+ grid.onSort.unsubscribe(save);
68
+ grid.onColumnsReordered.unsubscribe(save);
69
+ grid.onColumnsResized.unsubscribe(save);
70
+ save();
71
+ }
72
+
73
+ function save() {
74
+ if (_cid && _store) {
75
+ var state = {
76
+ sortcols: getSortColumns(),
77
+ viewport: _grid.getViewport(),
78
+ columns: getColumns()
79
+ };
80
+ onStateChanged.notify(state);
81
+ return _store.set(options.key_prefix + _cid, state);
82
+ }
83
+ }
84
+
85
+ function restore() {
86
+ return $.Deferred(function(dfd) {
87
+ if (!_cid) { return dfd.reject("missing client id"); }
88
+ if (!_store) { return dfd.reject("missing store"); }
89
+
90
+ _store.get(options.key_prefix + _cid)
91
+ .then(function success(state) {
92
+ if (state) {
93
+ if (state.sortcols) {
94
+ _grid.setSortColumns(state.sortcols);
95
+ }
96
+ if (state.viewport) {
97
+ _grid.scrollRowIntoView(state.viewport.top, true);
98
+ }
99
+ if (state.columns) {
100
+ var defaultColumns = options.defaultColumns;
101
+ if (defaultColumns) {
102
+ var defaultColumnsLookup = {};
103
+ $.each(defaultColumns, function(idx, colDef) {
104
+ defaultColumnsLookup[colDef.id] = colDef;
105
+ });
106
+
107
+ var cols = [];
108
+ $.each(state.columns, function(idx, columnDef) {
109
+ if (defaultColumnsLookup[columnDef.id]) {
110
+ cols.push($.extend(true, {}, defaultColumnsLookup[columnDef.id], {
111
+ width: columnDef.width,
112
+ headerCssClass: columnDef.headerCssClass
113
+ }));
114
+ }
115
+ });
116
+
117
+ state.columns = cols;
118
+ }
119
+
120
+ _grid.setColumns(state.columns);
121
+ }
122
+ }
123
+ dfd.resolve(state);
124
+ }, dfd.reject);
125
+ });
126
+ }
127
+
128
+ function getColumns() {
129
+ return $.map(_grid.getColumns(), function(col) {
130
+ return {
131
+ id: col.id,
132
+ width: col.width
133
+ };
134
+ });
135
+ }
136
+
137
+ function getSortColumns() {
138
+ var sortCols = _grid.getSortColumns();
139
+ return sortCols;
140
+ }
141
+
142
+ /*
143
+ * API
144
+ */
145
+ $.extend(this, {
146
+ "init": init,
147
+ "destroy": destroy,
148
+ "save": save,
149
+ "restore": restore,
150
+ "onStateChanged": onStateChanged
151
+ });
152
+ }
153
+ })(jQuery);