canvas-datagrid 0.3.11 → 0.3.15

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.
package/dist/types.d.ts CHANGED
@@ -66,6 +66,8 @@
66
66
  * @param [args.autoScrollMargin = 5] - Number of pixels of mouse movement to trigger auto scroll.
67
67
  * @param [args.allowFreezingRows = false] - When true, the UI provides a drag-able cutter to freeze rows.
68
68
  * @param [args.allowFreezingColumns = false] - When true, the UI provides a drag-able cutter to freeze columns.
69
+ * @param [args.filterFrozenRows = true] - When false, rows on and above {@link canvasDatagrid#property:frozenRow}` will be ignored by filters when {@link canvasDatagrid#param:allowFreezingRows} is true.
70
+ * @param [args.sortFrozenRows = true] - When false, rows on and above {@link canvasDatagrid#property:frozenRow}` will be ignored by sorters when {@link canvasDatagrid#param:allowSorting} is true.
69
71
  * @param [args.allowColumnReordering = true] - When true columns can be reordered.
70
72
  * @param [args.allowMovingSelection = false] - When true selected data can be moved by clicking and dragging on the border of the selection.
71
73
  * @param [args.allowRowReordering = false] - When true rows can be reordered.
@@ -76,6 +78,7 @@
76
78
  * @param [args.pageUpDownOverlap = 1] - Amount of rows to overlap when pageup/pagedown is used.
77
79
  * @param [args.persistantSelectionMode = false] - When true, selections will behave as if the command/control key is held down at all times. Conflicts with singleSelectionMode.
78
80
  * @param [args.singleSelectionMode = false] - When true, selections will ignore the command/control key. Conflicts with persistantSelectionMode.
81
+ * @param [args.keepFocusOnMouseOut = false] - When true, grid will continue to handle keydown events when mouse is outside of the grid.
79
82
  * @param [args.selectionMode = 'cell'] - Can be 'cell', or 'row'. This setting dictates what will be selected when the user clicks a cell. The cell, or the entire row respectively.
80
83
  * @param [args.hoverMode = 'cell'] - Can be 'cell', or 'row'. This setting dictates whether to highlight either the individual cell, or the entire row when hovering over a cell.
81
84
  * @param [args.autoResizeColumns = false] - When true, all columns will be automatically resized to fit the data in them. Warning! Expensive for large (>100k ~2 seconds) datasets.
@@ -152,6 +155,8 @@ declare class canvasDatagrid {
152
155
  autoScrollMargin?: number;
153
156
  allowFreezingRows?: boolean;
154
157
  allowFreezingColumns?: boolean;
158
+ filterFrozenRows?: boolean;
159
+ sortFrozenRows?: boolean;
155
160
  allowColumnReordering?: boolean;
156
161
  allowMovingSelection?: boolean;
157
162
  allowRowReordering?: boolean;
@@ -162,6 +167,7 @@ declare class canvasDatagrid {
162
167
  pageUpDownOverlap?: number;
163
168
  persistantSelectionMode?: boolean;
164
169
  singleSelectionMode?: boolean;
170
+ keepFocusOnMouseOut?: boolean;
165
171
  selectionMode?: string;
166
172
  hoverMode?: string;
167
173
  autoResizeColumns?: boolean;
package/lib/defaults.js CHANGED
@@ -38,9 +38,11 @@ export default function (self) {
38
38
  ['ellipsisText', '...'],
39
39
  ['filterOptionText', 'Filter %s'],
40
40
  ['filterTextPrefix', '(filtered) '],
41
+ ['filterFrozenRows', true],
41
42
  ['globalRowResize', false],
42
43
  ['hideColumnText', 'Hide %s'],
43
44
  ['hoverMode', 'cell'],
45
+ ['keepFocusOnMouseOut', false],
44
46
  ['maxAutoCompleteItems', 200],
45
47
  ['multiLine', false],
46
48
  ['name', ''],
@@ -76,6 +78,7 @@ export default function (self) {
76
78
  ['showRowNumberGaps', true],
77
79
  ['singleSelectionMode', false],
78
80
  ['snapToRow', false],
81
+ ['sortFrozenRows', true],
79
82
  ['touchContextMenuTimeMs', 800],
80
83
  ['touchDeadZone', 3],
81
84
  ['touchEasingMethod', 'easeOutQuad'],
package/lib/docs.js CHANGED
@@ -29,6 +29,8 @@
29
29
  * @param {number} [args.autoScrollMargin=5] - Number of pixels of mouse movement to trigger auto scroll.
30
30
  * @param {boolean} [args.allowFreezingRows=false] - When true, the UI provides a drag-able cutter to freeze rows.
31
31
  * @param {boolean} [args.allowFreezingColumns=false] - When true, the UI provides a drag-able cutter to freeze columns.
32
+ * @param {boolean} [args.filterFrozenRows=true] - When false, rows on and above {@link canvasDatagrid#property:frozenRow}` will be ignored by filters when {@link canvasDatagrid#param:allowFreezingRows} is true.
33
+ * @param {boolean} [args.sortFrozenRows=true] - When false, rows on and above {@link canvasDatagrid#property:frozenRow}` will be ignored by sorters when {@link canvasDatagrid#param:allowSorting} is true.
32
34
  * @param {boolean} [args.allowColumnReordering=true] - When true columns can be reordered.
33
35
  * @param {boolean} [args.allowMovingSelection=false] - When true selected data can be moved by clicking and dragging on the border of the selection.
34
36
  * @param {boolean} [args.allowRowReordering=false] - When true rows can be reordered.
@@ -39,6 +41,7 @@
39
41
  * @param {number} [args.pageUpDownOverlap=1] - Amount of rows to overlap when pageup/pagedown is used.
40
42
  * @param {boolean} [args.persistantSelectionMode=false] - When true, selections will behave as if the command/control key is held down at all times. Conflicts with singleSelectionMode.
41
43
  * @param {boolean} [args.singleSelectionMode=false] - When true, selections will ignore the command/control key. Conflicts with persistantSelectionMode.
44
+ * @param {boolean} [args.keepFocusOnMouseOut=false] - When true, grid will continue to handle keydown events when mouse is outside of the grid.
42
45
  * @param {string} [args.selectionMode='cell'] - Can be 'cell', or 'row'. This setting dictates what will be selected when the user clicks a cell. The cell, or the entire row respectively.
43
46
  * @param {string} [args.hoverMode='cell'] - Can be 'cell', or 'row'. This setting dictates whether to highlight either the individual cell, or the entire row when hovering over a cell.
44
47
  * @param {boolean} [args.autoResizeColumns=false] - When true, all columns will be automatically resized to fit the data in them. Warning! Expensive for large (>100k ~2 seconds) datasets.
@@ -454,6 +457,8 @@
454
457
  * @param {object} e.selectedData Selected data.
455
458
  * @param {array} e.selections Selections object. 2D matrix of selections.
456
459
  * @param {rectangle} e.selectionBounds rectangle object describing the selection bounds.
460
+ * @param {object} e.boundRowIndexMap Mapping of view data row to bound data row index.
461
+ * @param {object} e.boundColumnIndexMap Mapping of view column order to bound column order.
457
462
  */
458
463
  /**
459
464
  * Fires when the user clicks on the "drill in" arrow. When the arrow is clicked a new
package/lib/draw.js CHANGED
@@ -122,15 +122,15 @@ export default function (self) {
122
122
  x = x + ml;
123
123
  y = y + mt;
124
124
  if (self.orderDirection === 'asc') {
125
- self.ctx.moveTo(x, y);
126
- self.ctx.lineTo(x + aw, y);
127
- self.ctx.lineTo(x + aw * 0.5, y + ah);
128
- self.ctx.moveTo(x, y);
129
- } else {
130
125
  self.ctx.lineTo(x, y + ah);
131
126
  self.ctx.lineTo(x + aw, y + ah);
132
127
  self.ctx.lineTo(x + aw * 0.5, y);
133
128
  self.ctx.lineTo(x, y + ah);
129
+ } else {
130
+ self.ctx.moveTo(x, y);
131
+ self.ctx.lineTo(x + aw, y);
132
+ self.ctx.lineTo(x + aw * 0.5, y + ah);
133
+ self.ctx.moveTo(x, y);
134
134
  }
135
135
  self.ctx.stroke();
136
136
  self.ctx.fill();
@@ -911,7 +911,9 @@ export default function (self) {
911
911
  viewColumnIndex: columnOrderIndex,
912
912
 
913
913
  boundRowIndex: self.getBoundRowIndexFromViewRowIndex(rowOrderIndex),
914
- boundColumnIndex: columnOrderIndex,
914
+ boundColumnIndex: self.getBoundColumnIndexFromViewColumnIndex(
915
+ columnOrderIndex,
916
+ ),
915
917
 
916
918
  sortColumnIndex: headerIndex,
917
919
  sortRowIndex: rowIndex,
@@ -3,6 +3,7 @@
3
3
  'use strict';
4
4
 
5
5
  import isPrintableKeyEvent from 'is-printable-key-event';
6
+ import { isSupportedHtml, parseData } from './util';
6
7
 
7
8
  export default function (self) {
8
9
  var wheeling;
@@ -518,13 +519,12 @@ export default function (self) {
518
519
  self.selections[cell.rowIndex].indexOf(cell.columnIndex) === -1
519
520
  ) {
520
521
  self.selections[cell.rowIndex].push(cell.columnIndex);
521
-
522
522
  const event = {
523
523
  selections: self.selections,
524
524
  selectedData: self.getSelectedData(),
525
+ selectedCells: self.getSelectedCells(),
525
526
  selectionBounds: self.getSelectionBounds(),
526
527
  };
527
-
528
528
  self.dispatchEvent('selectionchanged', event);
529
529
  }
530
530
  }
@@ -583,12 +583,14 @@ export default function (self) {
583
583
  function checkSelectionChange() {
584
584
  var ev,
585
585
  sb = self.getSelectionBounds();
586
+
586
587
  if (startingBounds === JSON.stringify(sb)) {
587
588
  return;
588
589
  }
589
590
  ev = {
590
591
  selections: self.selections,
591
592
  selectionBounds: self.getSelectionBounds(),
593
+ selectedCells: self.getSelectedCells(),
592
594
  };
593
595
  Object.defineProperty(ev, 'selectedData', {
594
596
  get: function () {
@@ -897,6 +899,7 @@ export default function (self) {
897
899
  self.stopDragReorder = function (e) {
898
900
  var oIndex,
899
901
  tIndex,
902
+ odata,
900
903
  cr = {
901
904
  'row-reorder': self.orders.rows,
902
905
  'column-reorder': self.orders.columns,
@@ -927,12 +930,15 @@ export default function (self) {
927
930
  self.ignoreNextClick = true;
928
931
  oIndex = cr[self.dragMode].indexOf(self.reorderObject[i]);
929
932
  tIndex = cr[self.dragMode].indexOf(self.reorderTarget[i]);
930
- cr[self.dragMode].splice(oIndex, 1);
931
- cr[self.dragMode].splice(tIndex, 0, self.reorderObject[i]);
932
933
  if (self.dragMode === 'column-reorder') {
934
+ cr[self.dragMode].splice(oIndex, 1);
935
+ cr[self.dragMode].splice(tIndex, 0, self.reorderObject[i]);
933
936
  self.orders.columns = cr[self.dragMode];
934
937
  } else {
935
- self.orders.rows = cr[self.dragMode];
938
+ // self.orders.rows = cr[self.dragMode];
939
+ odata = self.viewData[oIndex];
940
+ self.viewData[oIndex] = self.viewData[tIndex];
941
+ self.viewData[tIndex] = odata;
936
942
  }
937
943
  self.resize();
938
944
  self.setStorageData();
@@ -1167,6 +1173,13 @@ export default function (self) {
1167
1173
  }
1168
1174
  if (['row-reorder', 'column-reorder'].indexOf(self.dragMode) !== -1) {
1169
1175
  self.draggingItem = self.dragStartObject;
1176
+ if (
1177
+ self.dragMode === 'column-reorder' &&
1178
+ self.attributes.columnHeaderClickBehavior === 'select'
1179
+ ) {
1180
+ self.selectColumn(self.currentCell.header.index, ctrl, e.shiftKey);
1181
+ self.draw();
1182
+ }
1170
1183
  document.body.addEventListener('mousemove', self.dragReorder, false);
1171
1184
  document.body.addEventListener('mouseup', self.stopDragReorder, false);
1172
1185
  return;
@@ -1174,9 +1187,14 @@ export default function (self) {
1174
1187
  };
1175
1188
  self.mouseup = function (e) {
1176
1189
  clearTimeout(self.scrollTimer);
1190
+ var ctrl = e.ctrlKey || e.metaKey;
1177
1191
  self.cellBoundaryCrossed = true;
1178
1192
  self.rowBoundaryCrossed = true;
1179
1193
  self.columnBoundaryCrossed = true;
1194
+ if (self.draggingItem) {
1195
+ self.selectColumn(self.currentCell.header.index, ctrl, e.shiftKey);
1196
+ self.draw();
1197
+ }
1180
1198
  self.selecting = undefined;
1181
1199
  self.draggingItem = undefined;
1182
1200
  self.dragStartObject = undefined;
@@ -1246,7 +1264,7 @@ export default function (self) {
1246
1264
  return;
1247
1265
  }
1248
1266
 
1249
- if (!self.hasFocus) {
1267
+ if (!self.attributes.keepFocusOnMouseOut && !self.hasFocus) {
1250
1268
  return;
1251
1269
  }
1252
1270
 
@@ -1401,6 +1419,7 @@ export default function (self) {
1401
1419
  selectedData: self.getSelectedData(),
1402
1420
  selections: self.selections,
1403
1421
  selectionBounds: self.getSelectionBounds(),
1422
+ selectedCells: self.getSelectedCells(),
1404
1423
  };
1405
1424
  Object.defineProperty(ev, 'selectedData', {
1406
1425
  get: function () {
@@ -1497,24 +1516,13 @@ export default function (self) {
1497
1516
  }, 1);
1498
1517
  }
1499
1518
  };
1500
-
1501
1519
  self.pasteData = function (
1502
1520
  pasteValue,
1503
1521
  mimeType,
1504
1522
  startRowIndex,
1505
1523
  startColIndex,
1506
1524
  ) {
1507
- var schema = self.getSchema();
1508
- const isSupportedHtmlTable = (htmlString) =>
1509
- /(?:^(<meta[^>]+>)?<table.*?>)|(?:<!--StartFragment-->\s*<table.*?>)/.test(
1510
- htmlString,
1511
- );
1512
-
1513
- // TODO: support pasting tables from Excel
1514
- if (
1515
- mimeType === 'text/html' &&
1516
- isSupportedHtmlTable(pasteValue) === false
1517
- ) {
1525
+ if (mimeType === 'text/html' && !isSupportedHtml(pasteValue)) {
1518
1526
  console.warn(
1519
1527
  'Unrecognized HTML format. HTML must be a simple table, e.g.: <table><tr><td>data</td></tr></table>.',
1520
1528
  );
@@ -1524,48 +1532,12 @@ export default function (self) {
1524
1532
 
1525
1533
  return;
1526
1534
  }
1527
-
1528
- function parseData(data, mimeType) {
1529
- // TODO: use DOMParser
1530
- if (mimeType === 'text/html') {
1531
- const doc = new DOMParser().parseFromString(data, 'text/html');
1532
- const trs = doc.querySelectorAll('table tr');
1533
- const rows = [];
1534
- trs.forEach((tr) => {
1535
- const row = [];
1536
- tr.childNodes.forEach((td) => {
1537
- if (td.nodeName === '#text') return;
1538
- const col = {
1539
- // style: {}, // keep style if need
1540
- value: [],
1541
- };
1542
- td.childNodes.forEach((ele) => {
1543
- col.value.push({
1544
- // style: {}, // keep style if need
1545
- value: ele.nodeType === 1 ? ele.innerText : ele.data,
1546
- });
1547
- });
1548
- row.push(col);
1549
- });
1550
- rows.push(row);
1551
- });
1552
- return rows;
1553
- }
1554
-
1555
- // Default data format is string, so split on new line,
1556
- // and then enclose in an array (a row with one cell):
1557
- return data
1558
- .split('\n')
1559
- .map((item) =>
1560
- item.split('\t').map((value) => ({ value: [{ value }] })),
1561
- );
1562
- }
1563
-
1535
+ var schema = self.getSchema();
1564
1536
  var rows = parseData(pasteValue, mimeType);
1565
1537
 
1566
1538
  // selected cell. This mimics Excel's paste functionality, and works
1567
1539
  // as a poor-man's fill-down.
1568
- if (rows.length === 1) {
1540
+ if (rows.length === 1 && rows[0].length === 1) {
1569
1541
  var cellData = rows[0][0].value.map((item) => item.value).join();
1570
1542
 
1571
1543
  self.forEachSelectedCell(function (data, rowIndex, colName) {
@@ -1627,7 +1599,8 @@ export default function (self) {
1627
1599
  affectedCells.push([
1628
1600
  rowIndex,
1629
1601
  columnIndex,
1630
- self.getVisibleCellByIndex(columnIndex, rowIndex),
1602
+ self.getBoundRowIndexFromViewRowIndex(rowIndex),
1603
+ self.getBoundColumnIndexFromViewColumnIndex(columnIndex),
1631
1604
  ]);
1632
1605
  });
1633
1606
  });
@@ -1722,9 +1695,34 @@ export default function (self) {
1722
1695
  };
1723
1696
  self.cut = function (e) {
1724
1697
  self.copy(e);
1725
- self.forEachSelectedCell(function (data, index, colName) {
1726
- data[index][colName] = '';
1727
- });
1698
+ const schema = self.getSchema();
1699
+
1700
+ var affectedCells = [];
1701
+ for (const [rowIndex, row] of self.selections.entries()) {
1702
+ if (!row) continue;
1703
+
1704
+ const boundRowIndex = self.getBoundRowIndexFromViewRowIndex(rowIndex);
1705
+
1706
+ for (const columnIndex of row) {
1707
+ const boundColumnIndex = self.getBoundColumnIndexFromViewColumnIndex(
1708
+ columnIndex,
1709
+ );
1710
+ const colName = schema[boundColumnIndex].name;
1711
+
1712
+ self.viewData[rowIndex][colName] = '';
1713
+
1714
+ affectedCells.push([
1715
+ rowIndex,
1716
+ columnIndex,
1717
+ boundRowIndex,
1718
+ boundColumnIndex,
1719
+ ]);
1720
+ }
1721
+ }
1722
+
1723
+ if (self.dispatchEvent('cut', { NativeEvent: e, cells: affectedCells })) {
1724
+ return;
1725
+ }
1728
1726
  };
1729
1727
  self.copy = function (e) {
1730
1728
  if (self.dispatchEvent('copy', { NativeEvent: e })) {
@@ -0,0 +1,96 @@
1
+ 'use strict';
2
+
3
+ const isSupportedHtml = function (pasteValue) {
4
+ // We need to match new lines in the HTML, .* won't match new line characters.
5
+ // `s` regex modifier can't be used with `ecmaVersion === 2017`.
6
+ // As a workaround using [\s\S]*. Fix when we upgrade `ecmaVersion`.
7
+ const genericDiv = /(?:^(<meta[^>]*>)?[\s\S]*<div[^>]*>)/;
8
+ const genericSpan = /(?:^(<meta[^>]*>)?[\s\S]*<span[^>]*>)/;
9
+ const genericTable = /(?:^(<meta[^>]*>)?[\s\S]*<table[^>]*>)/; // Matches Google Sheets format clipboard data format too.
10
+ const excelTable = /(?:<!--StartFragment-->[\s\S]*<tr[^>]*>)/;
11
+ const excelTableRow = /(?:<!--StartFragment-->[\s\S]*<td[^>]*>)/;
12
+
13
+ return [
14
+ genericDiv,
15
+ genericTable,
16
+ genericSpan,
17
+ excelTable,
18
+ excelTableRow,
19
+ ].some((expression) => expression.test(pasteValue));
20
+ };
21
+
22
+ // Explanation of nodeType here: https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
23
+ const IGNORE_NODETYPES = [8, 3]; // '#text' and '#comment'
24
+
25
+ const isHtmlTable = function (pasteValue) {
26
+ return /(?:<table[^>]*>)|(?:<tr[^]*>)/.test(pasteValue);
27
+ };
28
+
29
+ const sanitizeElementData = function (element) {
30
+ // It is not entirely clear if this check on nodeType is required.
31
+ let elementData = element.nodeType === 1 ? element.innerText : element.data;
32
+
33
+ return String(elementData).replace(/\s+/g, ' ').trim();
34
+ };
35
+
36
+ const parseHtmlText = function (data) {
37
+ const doc = new DOMParser().parseFromString(data, 'text/html');
38
+ const element = doc.querySelector('div') || doc.querySelector('span');
39
+ const elementData = sanitizeElementData(element);
40
+
41
+ return elementData
42
+ .split('\n')
43
+ .map((item) => item.split('\t').map((value) => ({ value: [{ value }] })));
44
+ };
45
+
46
+ const parseHtmlTable = function (data) {
47
+ const doc = new DOMParser().parseFromString(data, 'text/html');
48
+ const trs = doc.querySelectorAll('table tr');
49
+ const rows = [];
50
+
51
+ for (const tr of trs) {
52
+ const row = [];
53
+
54
+ for (const childNode of tr.childNodes) {
55
+ if (IGNORE_NODETYPES.includes(childNode.nodeType)) continue;
56
+
57
+ const col = { value: [] };
58
+ const value = sanitizeElementData(childNode);
59
+
60
+ if (value) col.value.push({ value });
61
+
62
+ row.push(col);
63
+ }
64
+
65
+ rows.push(row);
66
+ }
67
+
68
+ return rows;
69
+ };
70
+
71
+ const parseText = function (data) {
72
+ return data
73
+ .split('\n')
74
+ .map((item) => item.split('\t').map((value) => ({ value: [{ value }] })));
75
+ };
76
+
77
+ const parseData = function (data, mimeType) {
78
+ if (mimeType === 'text/html' && isHtmlTable(data)) {
79
+ return parseHtmlTable(data);
80
+ } else if (mimeType === 'text/html') {
81
+ return parseHtmlText(data);
82
+ }
83
+
84
+ // Default data format is string, so split on new line,
85
+ // and then enclose in an array (a row with one cell):
86
+ return parseText(data);
87
+ };
88
+
89
+ export {
90
+ isSupportedHtml,
91
+ sanitizeElementData,
92
+ parseData,
93
+ parseHtmlTable,
94
+ parseHtmlText,
95
+ parseText,
96
+ };
package/lib/intf.js CHANGED
@@ -184,6 +184,54 @@ export default function (self, ctor) {
184
184
 
185
185
  return selectedData;
186
186
  };
187
+ self.getSelectedCells = function (expandToRow) {
188
+ const selectedCells = [];
189
+ const schema = self.getSchema();
190
+ const viewDataLength = self.viewData.length;
191
+
192
+ if (viewDataLength === 0) {
193
+ return [];
194
+ }
195
+
196
+ for (const [viewRowIndex, row] of self.selections.entries()) {
197
+ if (!row || row.length === 0) continue;
198
+
199
+ for (const [, viewColumnIndex] of row.entries()) {
200
+ if (viewColumnIndex === -1 || !schema[viewColumnIndex]) {
201
+ continue;
202
+ }
203
+
204
+ const boundColumnIndex = self.getBoundColumnIndexFromViewColumnIndex(
205
+ viewColumnIndex,
206
+ );
207
+
208
+ if (!expandToRow && schema[boundColumnIndex].hidden) {
209
+ continue;
210
+ }
211
+
212
+ if (self.viewData[viewRowIndex]) {
213
+ const header = schema[boundColumnIndex];
214
+ const value = self.viewData[viewRowIndex][header.name];
215
+ const boundRowIndex = self.getBoundRowIndexFromViewRowIndex(
216
+ viewRowIndex,
217
+ );
218
+
219
+ const cell = {
220
+ value,
221
+ header,
222
+ boundRowIndex,
223
+ boundColumnIndex,
224
+ viewRowIndex,
225
+ viewColumnIndex,
226
+ };
227
+
228
+ selectedCells.push(cell);
229
+ }
230
+ }
231
+ }
232
+
233
+ return selectedCells;
234
+ };
187
235
  self.getBoundRowIndexFromViewRowIndex = function (viewRowIndex) {
188
236
  if (self.boundRowIndexMap && self.boundRowIndexMap.has(viewRowIndex)) {
189
237
  return self.boundRowIndexMap.get(viewRowIndex);
@@ -191,6 +239,9 @@ export default function (self, ctor) {
191
239
 
192
240
  return undefined;
193
241
  };
242
+ self.getBoundColumnIndexFromViewColumnIndex = function (viewColumnIndex) {
243
+ return self.orders.columns[viewColumnIndex];
244
+ };
194
245
  self.getColumnHeaderCellHeight = function () {
195
246
  if (!self.attributes.showColumnHeaders) {
196
247
  return 0;
@@ -320,11 +371,15 @@ export default function (self, ctor) {
320
371
  const currentFilterFunction =
321
372
  header.filter || self.filter(header.type || 'string');
322
373
 
323
- newViewData = newViewData.filter(function ([row]) {
324
- const cellValue = row[headerName];
325
- const shouldIncludeRow = currentFilterFunction(cellValue, filterText);
374
+ newViewData = newViewData.filter(function ([row, originalRowIndex]) {
375
+ if (
376
+ self.attributes.allowFreezingRows &&
377
+ !self.attributes.filterFrozenRows &&
378
+ originalRowIndex < self.frozenRow
379
+ )
380
+ return true;
326
381
 
327
- return shouldIncludeRow;
382
+ return currentFilterFunction(row[headerName], filterText);
328
383
  });
329
384
  }
330
385
 
@@ -332,7 +387,15 @@ export default function (self, ctor) {
332
387
  for (const column of self.orderings.columns) {
333
388
  const sortFn = column.sortFunction(column.orderBy, column.orderDirection);
334
389
 
335
- newViewData.sort(([rowA], [rowB]) => sortFn(rowA, rowB));
390
+ newViewData.sort(([rowA], [rowB, rowIndexB]) => {
391
+ if (
392
+ self.attributes.allowFreezingRows &&
393
+ !self.attributes.sortFrozenRows &&
394
+ rowIndexB < self.frozenRow
395
+ )
396
+ return 0;
397
+ return sortFn(rowA, rowB);
398
+ });
336
399
  }
337
400
 
338
401
  return {
@@ -738,6 +801,7 @@ export default function (self, ctor) {
738
801
  self.intf.clearPxColorAssertions = self.clearPxColorAssertions;
739
802
  self.intf.integerToAlpha = self.integerToAlpha;
740
803
  self.intf.copy = self.copy;
804
+ self.intf.cut = self.cut;
741
805
  self.intf.paste = self.paste;
742
806
  self.intf.setStyleProperty = self.setStyleProperty;
743
807
  Object.defineProperty(self.intf, 'defaults', {
@@ -353,6 +353,7 @@ export default function (self) {
353
353
  selectedData: self.getSelectedData(),
354
354
  selections: self.selections,
355
355
  selectionBounds: self.selectionBounds,
356
+ selectedCells: self.getSelectedCells(),
356
357
  });
357
358
  if (dontDraw) {
358
359
  return;
@@ -485,6 +486,7 @@ export default function (self) {
485
486
  selectedData: self.getSelectedData(),
486
487
  selections: self.selections,
487
488
  selectionBounds: self.getSelectionBounds(),
489
+ selectedCells: self.getSelectedCells(),
488
490
  });
489
491
  };
490
492
  /**
@@ -510,6 +512,7 @@ export default function (self) {
510
512
  selectedData: self.getSelectedData(),
511
513
  selections: self.selections,
512
514
  selectionBounds: self.selectionBounds,
515
+ selectedCells: self.getSelectedCells(),
513
516
  });
514
517
  }
515
518
  function addRow(ri) {
@@ -1252,6 +1255,7 @@ export default function (self) {
1252
1255
  ev = {
1253
1256
  selections: self.selections,
1254
1257
  selectionBounds: self.selectionBounds,
1258
+ selectedCells: self.getSelectedCells(),
1255
1259
  };
1256
1260
  Object.defineProperty(ev, 'selectedData', {
1257
1261
  get: function () {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "canvas-datagrid",
3
- "version": "0.3.11",
3
+ "version": "0.3.15",
4
4
  "description": "Canvas based data grid web component. Capable of displaying millions of contiguous hierarchical rows and columns without paging or loading, on a single canvas element.",
5
5
  "main": "./dist/canvas-datagrid.js",
6
6
  "module": "./dist/canvas-datagrid.module.js",