slickgrid 2.4.5 → 2.4.14

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