canvas-datagrid 0.3.24 → 0.4.2

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.
@@ -130,6 +130,8 @@ export default function (self) {
130
130
  l = (self.viewData || []).length,
131
131
  columnHeaderCellHeight = self.getColumnHeaderCellHeight(),
132
132
  rowHeaderCellWidth = self.getRowHeaderCellWidth(),
133
+ topGroupAreaHeight = self.getColumnGroupAreaHeight(),
134
+ leftGroupAreaWidth = self.getRowGroupAreaWidth(),
133
135
  ch = self.style.cellHeight,
134
136
  s = self.getSchema();
135
137
  // sets actual DOM canvas element
@@ -148,8 +150,10 @@ export default function (self) {
148
150
  self.scrollBox.verticalBoxVisible = dataHeight > self.scrollBox.height;
149
151
  }
150
152
  function setScrollBoxSize() {
151
- self.scrollBox.width = self.width - rowHeaderCellWidth;
152
- self.scrollBox.height = self.height - columnHeaderCellHeight;
153
+ self.scrollBox.width =
154
+ self.width - rowHeaderCellWidth - leftGroupAreaWidth;
155
+ self.scrollBox.height =
156
+ self.height - columnHeaderCellHeight - topGroupAreaHeight;
153
157
  }
154
158
  function setCanvasSize() {
155
159
  if (self.isChildGrid) {
@@ -157,8 +161,13 @@ export default function (self) {
157
161
  }
158
162
  dims = {
159
163
  // HACK +1 ? maybe it's a magic cell border? Required to line up properly in auto height mode.
160
- height: columnHeaderCellHeight + dataHeight + cellBorder + 1,
161
- width: dataWidth + rowHeaderCellWidth + cellBorder,
164
+ height:
165
+ columnHeaderCellHeight +
166
+ topGroupAreaHeight +
167
+ dataHeight +
168
+ cellBorder +
169
+ 1,
170
+ width: dataWidth + rowHeaderCellWidth + cellBorder + leftGroupAreaWidth,
162
171
  };
163
172
  ['width', 'height'].forEach(function (dim) {
164
173
  //TODO: support inherit
@@ -190,18 +199,31 @@ export default function (self) {
190
199
  if (l > 1) {
191
200
  self.scrollCache.y[x] = dataHeight;
192
201
  }
202
+ const collapsedColumnGroups = self.getCollapsedColumnGroups();
203
+ const isColumnCollapsed = (columnIndex) =>
204
+ collapsedColumnGroups.findIndex(
205
+ (group) => columnIndex >= group.from && columnIndex <= group.to,
206
+ ) >= 0;
207
+ /** @type {number} it will be used in `reduceSchema` only */
208
+ let frozenWidth = 0;
193
209
  dataWidth =
194
210
  s.reduce(function reduceSchema(accumulator, column, columnIndex) {
195
211
  // intentional redefintion of column. This causes scrollCache to be in the correct order
196
- column = s[self.orders.columns[columnIndex]];
197
- if (column.hidden) {
212
+ const schemaIndex = self.orders.columns[columnIndex];
213
+ const columnWidth = self.getColumnWidth(schemaIndex);
214
+ column = s[schemaIndex];
215
+ if (!column.hidden && !isColumnCollapsed(columnIndex))
216
+ accumulator += columnWidth;
217
+ if (columnIndex < self.frozenColumn) {
198
218
  self.scrollCache.x[columnIndex] = accumulator;
199
- return accumulator;
219
+ frozenWidth = accumulator;
220
+ } else {
221
+ self.scrollCache.x[columnIndex] = Math.max(
222
+ frozenWidth + columnWidth,
223
+ accumulator,
224
+ );
200
225
  }
201
- var va =
202
- accumulator + self.getColumnWidth(self.orders.columns[columnIndex]);
203
- self.scrollCache.x[columnIndex] = va;
204
- return va;
226
+ return accumulator;
205
227
  }, 0) || 0;
206
228
  if (self.attributes.showNewRow) {
207
229
  dataHeight += ch;
@@ -224,8 +246,9 @@ export default function (self) {
224
246
  }
225
247
  /// calculate scroll bar dimensions
226
248
  // non-controversial
227
- self.scrollBox.top = columnHeaderCellHeight + columnHeaderCellBorder;
228
- self.scrollBox.left = rowHeaderCellWidth;
249
+ self.scrollBox.top =
250
+ columnHeaderCellHeight + topGroupAreaHeight + columnHeaderCellBorder;
251
+ self.scrollBox.left = rowHeaderCellWidth + leftGroupAreaWidth;
229
252
  // width and height of scroll box
230
253
  setScrollBoxSize();
231
254
  // is the data larger than the scroll box
@@ -274,6 +297,7 @@ export default function (self) {
274
297
  self.scrollBox.heightBoxRatio =
275
298
  (self.scrollBox.height -
276
299
  columnHeaderCellHeight -
300
+ topGroupAreaHeight -
277
301
  self.scrollCache.y[self.frozenRow]) /
278
302
  dataHeight;
279
303
  self.scrollBox.scrollBoxHeight =
@@ -291,9 +315,14 @@ export default function (self) {
291
315
  );
292
316
  // horizontal
293
317
  n.x += rowHeaderCellWidth;
294
- n.y += self.height - self.style.scrollBarWidth - d;
318
+ n.y += self.height - self.style.scrollBarWidth - d - topGroupAreaHeight;
295
319
  n.width =
296
- self.width - self.style.scrollBarWidth - rowHeaderCellWidth - d - m;
320
+ self.width -
321
+ self.style.scrollBarWidth -
322
+ rowHeaderCellWidth -
323
+ leftGroupAreaWidth -
324
+ d -
325
+ m;
297
326
  n.height = self.style.scrollBarWidth + self.style.scrollBarBorderWidth + d;
298
327
  // horizontal box
299
328
  nb.y = n.y + self.style.scrollBarBoxMargin;
@@ -302,13 +331,19 @@ export default function (self) {
302
331
  // vertical
303
332
  v.x +=
304
333
  self.width -
334
+ leftGroupAreaWidth -
305
335
  self.style.scrollBarWidth -
306
336
  self.style.scrollBarBorderWidth -
307
337
  d;
308
338
  v.y += columnHeaderCellHeight + self.scrollCache.y[self.frozenRow];
309
339
  v.width = self.style.scrollBarWidth + self.style.scrollBarBorderWidth + d;
310
340
  v.height =
311
- self.height - columnHeaderCellHeight - self.style.scrollBarWidth - d - m;
341
+ self.height -
342
+ columnHeaderCellHeight -
343
+ topGroupAreaHeight -
344
+ self.style.scrollBarWidth -
345
+ d -
346
+ m;
312
347
  // vertical box
313
348
  vb.x = v.x + self.style.scrollBarBoxMargin;
314
349
  vb.y += self.scrollCache.y[self.frozenRow];
@@ -420,6 +455,14 @@ export default function (self) {
420
455
  if (self.contextMenu || self.input) {
421
456
  return;
422
457
  }
458
+
459
+ // Cancel dragging action if user ventures outside grid
460
+ if (self.draggingItem && e.which === 0) {
461
+ self.stopFreezeMove(e);
462
+ self.mouseup(e);
463
+ return;
464
+ }
465
+
423
466
  self.mouse = overridePos || self.getLayerPos(e);
424
467
  var ctrl =
425
468
  (e.ctrlKey || e.metaKey || self.attributes.persistantSelectionMode) &&
@@ -469,6 +512,7 @@ export default function (self) {
469
512
  rowIndex: cell.rowIndex,
470
513
  columnIndex: cell.columnIndex,
471
514
  onFilterButton: false,
515
+ onCellTreeIcon: false,
472
516
  };
473
517
  if (
474
518
  cell.isFilterable &&
@@ -488,6 +532,26 @@ export default function (self) {
488
532
  self.hovers.onFilterButton = true;
489
533
  self.draw();
490
534
  }
535
+ if (cell.isRowTree || cell.isColumnTree) {
536
+ const pc = cell.isRowTree
537
+ ? self.cellTree.rows[cell.rowIndex].parentCount
538
+ : 0;
539
+ const rc = self.style.cellTreeIconWidth * self.scale,
540
+ rx =
541
+ cell.x +
542
+ cell.paddingLeft +
543
+ self.canvasOffsetLeft +
544
+ self.style.cellTreeIconMarginLeft +
545
+ pc * (rc + cell.paddingLeft),
546
+ ry =
547
+ cell.y +
548
+ self.canvasOffsetTop +
549
+ self.style.cellTreeIconMarginTop * self.scale;
550
+ if (x >= rx && x <= rx + rc && y >= ry && y < ry + rc) {
551
+ self.hovers.onCellTreeIcon = true;
552
+ self.draw();
553
+ }
554
+ }
491
555
  }
492
556
  if (self.selecting || self.reorderObject) {
493
557
  delta = {
@@ -512,7 +576,24 @@ export default function (self) {
512
576
  dragBounds.right = s.length - 1;
513
577
  dragBounds.top = Math.min(sBounds.top, cell.rowIndex);
514
578
  dragBounds.bottom = Math.max(sBounds.bottom, cell.rowIndex);
579
+ if (dragBounds.top < 0) dragBounds.top = 0;
515
580
  }
581
+
582
+ if (self.dragStartObject.rowIndex === -1) {
583
+ sBounds = self.getSelectionBounds();
584
+ dragBounds.left =
585
+ cell.columnIndex === undefined
586
+ ? sBounds.left
587
+ : Math.min(sBounds.left, cell.columnIndex);
588
+ dragBounds.right =
589
+ cell.columnIndex === undefined
590
+ ? sBounds.right
591
+ : Math.max(sBounds.right, cell.columnIndex);
592
+ dragBounds.top = -1;
593
+ dragBounds.bottom = self.viewData.length - 1;
594
+ if (dragBounds.left < 0) dragBounds.left = 0;
595
+ }
596
+
516
597
  if (
517
598
  self.dragStartObject.rowIndex !== cell.rowIndex ||
518
599
  self.dragStartObject.columnIndex !== cell.columnIndex
@@ -525,11 +606,31 @@ export default function (self) {
525
606
  self.attributes.selectionMode === 'row'
526
607
  ) {
527
608
  if (
609
+ cell.rowIndex !== undefined &&
528
610
  (self.attributes.selectionMode === 'row' ||
529
611
  self.dragStartObject.columnIndex === -1) &&
530
612
  self.rowBoundaryCrossed
531
613
  ) {
532
- self.selectRow(cell.rowIndex, ctrl, null, true);
614
+ if (self.dragStartObject.rowIndex < cell.rowIndex) {
615
+ dragBounds.top = self.dragStartObject.rowIndex;
616
+ dragBounds.bottom = cell.rowIndex;
617
+ } else {
618
+ dragBounds.top = cell.rowIndex;
619
+ dragBounds.bottom = self.dragStartObject.rowIndex;
620
+ }
621
+ } else if (
622
+ cell.rowIndex !== undefined &&
623
+ (self.attributes.selectionMode === 'column' ||
624
+ self.dragStartObject.rowIndex === -1) &&
625
+ self.columnBoundaryCrossed
626
+ ) {
627
+ if (self.dragStartObject.columnIndex < cell.columnIndex) {
628
+ dragBounds.left = self.dragStartObject.columnIndex;
629
+ dragBounds.right = cell.columnIndex;
630
+ } else {
631
+ dragBounds.left = cell.columnIndex;
632
+ dragBounds.right = self.dragStartObject.columnIndex;
633
+ }
533
634
  } else if (self.attributes.selectionMode !== 'row') {
534
635
  if (cell.hovered && self.hovers.onFilterButton) {
535
636
  if (cell.openedFilter) {
@@ -549,12 +650,20 @@ export default function (self) {
549
650
  }
550
651
  self.draw();
551
652
  return;
653
+ } else if (
654
+ cell.hovered &&
655
+ self.hovers.onCellTreeIcon &&
656
+ e.type == 'mousedown'
657
+ ) {
658
+ self.toggleCollapseTree(cell.rowIndex, cell.columnIndex);
659
+ return;
552
660
  } else {
553
661
  self.selectedFilterButton = {
554
662
  columnIndex: -1,
555
663
  rowIndex: -1,
556
664
  };
557
665
  if (self.hovers.onFilterButton) return;
666
+ if (self.hovers.onCellTreeIcon) return;
558
667
  if (!self.dragAddToSelection && cell.rowIndex !== undefined) {
559
668
  if (
560
669
  self.selections[cell.rowIndex] &&
@@ -627,6 +736,12 @@ export default function (self) {
627
736
  }
628
737
  }
629
738
  }
739
+ const columnGroup = self.getColumnGroupAt(self.mouse.x, self.mouse.y);
740
+ if (columnGroup) self.cursor = 'pointer';
741
+
742
+ const rowGroup = self.getRowGroupAt(self.mouse.x, self.mouse.y);
743
+ if (rowGroup) self.cursor = 'pointer';
744
+
630
745
  self.cellBoundaryCrossed = false;
631
746
  self.rowBoundaryCrossed = false;
632
747
  self.columnBoundaryCrossed = false;
@@ -675,9 +790,25 @@ export default function (self) {
675
790
  ) {
676
791
  return;
677
792
  }
793
+
794
+ let group = self.getColumnGroupAt(pos.x, pos.y);
795
+ if (!group) group = self.getRowGroupAt(pos.x, pos.y);
796
+ if (group) {
797
+ if (self.toggleGroup(group)) {
798
+ self.setStorageData();
799
+ self.refresh();
800
+ return;
801
+ }
802
+ }
803
+
678
804
  if (!self.hasFocus) {
679
805
  return;
680
806
  }
807
+
808
+ const leftOffset = self.getRowGroupAreaWidth();
809
+ const topOffset = self.getColumnGroupAreaHeight();
810
+ const xInGrid = pos.x - leftOffset;
811
+ const yInGrid = pos.y - topOffset;
681
812
  if (
682
813
  ['rowHeaderCell', 'columnHeaderCell'].indexOf(self.currentCell.style) ===
683
814
  -1 &&
@@ -715,17 +846,17 @@ export default function (self) {
715
846
  if (
716
847
  self.currentCell.style === 'rowHeaderCell' &&
717
848
  self.attributes.tree &&
718
- pos.x > 0 &&
719
- pos.x - self.currentCell.x <
849
+ xInGrid > 0 &&
850
+ xInGrid - self.currentCell.x <
720
851
  self.style.treeArrowWidth +
721
852
  self.style.treeArrowMarginLeft +
722
853
  self.style.treeArrowMarginRight +
723
854
  self.style.treeArrowClickRadius &&
724
- pos.y - self.currentCell.y <
855
+ yInGrid - self.currentCell.y <
725
856
  self.style.treeArrowHeight +
726
857
  self.style.treeArrowMarginTop +
727
858
  self.style.treeArrowClickRadius &&
728
- pos.y > 0
859
+ yInGrid > 0
729
860
  ) {
730
861
  self.toggleTree(i.rowIndex);
731
862
  return;
@@ -765,7 +896,6 @@ export default function (self) {
765
896
  self.dragMode === 'ew-resize'
766
897
  ) {
767
898
  self.resize(true);
768
- self.scrollBox.scrollLeft += x;
769
899
  }
770
900
  if (self.dragMode === 'ew-resize') {
771
901
  self.sizes.columns[
@@ -975,6 +1105,7 @@ export default function (self) {
975
1105
  -1,
976
1106
  self.activeCell.rowIndex,
977
1107
  );
1108
+ if (!self.reorderObject) return;
978
1109
  self.reorderTarget = self.currentCell;
979
1110
  self.reorderObject.dragOffset = {
980
1111
  x: x,
@@ -1126,6 +1257,8 @@ export default function (self) {
1126
1257
 
1127
1258
  self.ignoreNextClick = true;
1128
1259
  self.freezeMarkerPosition = pos;
1260
+ pos.x -= self.getRowGroupAreaWidth();
1261
+ pos.y -= self.getColumnGroupAreaHeight();
1129
1262
  if (
1130
1263
  self.currentCell &&
1131
1264
  self.currentCell.rowIndex !== undefined &&
@@ -1284,6 +1417,12 @@ export default function (self) {
1284
1417
  self.dragStartObject.rowIndex > -1
1285
1418
  ) {
1286
1419
  self.selectRow(self.dragStartObject.rowIndex, ctrl, null);
1420
+ } else if (
1421
+ (self.attributes.selectionMode === 'column' ||
1422
+ self.dragStartObject.rowIndex === -1) &&
1423
+ self.dragStartObject.columnIndex > -1
1424
+ ) {
1425
+ self.selectColumn(self.currentCell.header.index, ctrl, e.shiftKey);
1287
1426
  } else if (self.attributes.selectionMode !== 'row') {
1288
1427
  self.mousemove(e);
1289
1428
  }
@@ -1646,9 +1785,21 @@ export default function (self) {
1646
1785
  self.autosize();
1647
1786
  } else if (
1648
1787
  ['cell', 'activeCell'].includes(self.currentCell.style) &&
1649
- !self.hovers.onFilterButton
1788
+ !self.hovers.onFilterButton &&
1789
+ !self.hovers.onCellTreeIcon
1650
1790
  ) {
1651
- self.beginEditAt(self.currentCell.columnIndex, self.currentCell.rowIndex);
1791
+ if (self.currentCell.isRowTree || self.currentCell.isColumnTree) {
1792
+ self.cellTreeExpandCollapse(
1793
+ self.currentCell.rowIndex,
1794
+ self.currentCell.columnIndex,
1795
+ );
1796
+ self.draw();
1797
+ } else {
1798
+ self.beginEditAt(
1799
+ self.currentCell.columnIndex,
1800
+ self.currentCell.rowIndex,
1801
+ );
1802
+ }
1652
1803
  }
1653
1804
  };
1654
1805
  self.scrollWheel = function (e) {
@@ -87,7 +87,8 @@ const parseData = function (data, mimeType) {
87
87
  };
88
88
 
89
89
  const htmlSafe = function (value) {
90
- if (typeof value === 'number') return value;
90
+ if (typeof value !== 'string') return value;
91
+
91
92
  return value.replace(/</g, '&lt;').replace(/>/g, '&gt;');
92
93
  };
93
94
 
@@ -111,7 +112,7 @@ const createHTMLString = function (selectedData, isNeat) {
111
112
  (row) =>
112
113
  '<tr>' +
113
114
  Object.values(row)
114
- .map((value) => '<td>' + htmlSafe(value) + '</td>')
115
+ .map((value) => ['<td>', htmlSafe(value), '</td>'].join(''))
115
116
  .join('') +
116
117
  '</tr>',
117
118
  )