canvas-datagrid 0.3.22 → 0.4.0
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/CHANGELOG.md +33 -0
- package/dist/canvas-datagrid.debug.js +2272 -157
- package/dist/canvas-datagrid.debug.map +1 -1
- package/dist/canvas-datagrid.js +1 -1
- package/dist/canvas-datagrid.module.js +1 -1
- package/dist/canvas-datagrid.module.js.map +1 -1
- package/dist/types.d.ts +114 -0
- package/lib/contextMenu.js +283 -0
- package/lib/defaults.js +35 -0
- package/lib/docs.js +18 -0
- package/lib/dom.js +27 -5
- package/lib/draw.js +626 -30
- package/lib/events/index.js +145 -50
- package/lib/events/util.js +6 -5
- package/lib/intf.js +584 -3
- package/lib/publicMethods.js +378 -12
- package/package.json +1 -1
package/lib/events/index.js
CHANGED
|
@@ -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 =
|
|
152
|
-
|
|
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:
|
|
161
|
-
|
|
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
|
-
|
|
197
|
-
|
|
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
|
-
|
|
219
|
+
frozenWidth = accumulator;
|
|
220
|
+
} else {
|
|
221
|
+
self.scrollCache.x[columnIndex] = Math.max(
|
|
222
|
+
frozenWidth + columnWidth,
|
|
223
|
+
accumulator,
|
|
224
|
+
);
|
|
200
225
|
}
|
|
201
|
-
|
|
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 =
|
|
228
|
-
|
|
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 -
|
|
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 -
|
|
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];
|
|
@@ -469,6 +504,7 @@ export default function (self) {
|
|
|
469
504
|
rowIndex: cell.rowIndex,
|
|
470
505
|
columnIndex: cell.columnIndex,
|
|
471
506
|
onFilterButton: false,
|
|
507
|
+
onCellTreeIcon: false,
|
|
472
508
|
};
|
|
473
509
|
if (
|
|
474
510
|
cell.isFilterable &&
|
|
@@ -488,6 +524,26 @@ export default function (self) {
|
|
|
488
524
|
self.hovers.onFilterButton = true;
|
|
489
525
|
self.draw();
|
|
490
526
|
}
|
|
527
|
+
if (cell.isRowTree || cell.isColumnTree) {
|
|
528
|
+
const pc = cell.isRowTree
|
|
529
|
+
? self.cellTree.rows[cell.rowIndex].parentCount
|
|
530
|
+
: 0;
|
|
531
|
+
const rc = self.style.cellTreeIconWidth * self.scale,
|
|
532
|
+
rx =
|
|
533
|
+
cell.x +
|
|
534
|
+
cell.paddingLeft +
|
|
535
|
+
self.canvasOffsetLeft +
|
|
536
|
+
self.style.cellTreeIconMarginLeft +
|
|
537
|
+
pc * (rc + cell.paddingLeft),
|
|
538
|
+
ry =
|
|
539
|
+
cell.y +
|
|
540
|
+
self.canvasOffsetTop +
|
|
541
|
+
self.style.cellTreeIconMarginTop * self.scale;
|
|
542
|
+
if (x >= rx && x <= rx + rc && y >= ry && y < ry + rc) {
|
|
543
|
+
self.hovers.onCellTreeIcon = true;
|
|
544
|
+
self.draw();
|
|
545
|
+
}
|
|
546
|
+
}
|
|
491
547
|
}
|
|
492
548
|
if (self.selecting || self.reorderObject) {
|
|
493
549
|
delta = {
|
|
@@ -549,12 +605,20 @@ export default function (self) {
|
|
|
549
605
|
}
|
|
550
606
|
self.draw();
|
|
551
607
|
return;
|
|
608
|
+
} else if (
|
|
609
|
+
cell.hovered &&
|
|
610
|
+
self.hovers.onCellTreeIcon &&
|
|
611
|
+
e.type == 'mousedown'
|
|
612
|
+
) {
|
|
613
|
+
self.toggleCollapseTree(cell.rowIndex, cell.columnIndex);
|
|
614
|
+
return;
|
|
552
615
|
} else {
|
|
553
616
|
self.selectedFilterButton = {
|
|
554
617
|
columnIndex: -1,
|
|
555
618
|
rowIndex: -1,
|
|
556
619
|
};
|
|
557
620
|
if (self.hovers.onFilterButton) return;
|
|
621
|
+
if (self.hovers.onCellTreeIcon) return;
|
|
558
622
|
if (!self.dragAddToSelection && cell.rowIndex !== undefined) {
|
|
559
623
|
if (
|
|
560
624
|
self.selections[cell.rowIndex] &&
|
|
@@ -627,6 +691,12 @@ export default function (self) {
|
|
|
627
691
|
}
|
|
628
692
|
}
|
|
629
693
|
}
|
|
694
|
+
const columnGroup = self.getColumnGroupAt(self.mouse.x, self.mouse.y);
|
|
695
|
+
if (columnGroup) self.cursor = 'pointer';
|
|
696
|
+
|
|
697
|
+
const rowGroup = self.getRowGroupAt(self.mouse.x, self.mouse.y);
|
|
698
|
+
if (rowGroup) self.cursor = 'pointer';
|
|
699
|
+
|
|
630
700
|
self.cellBoundaryCrossed = false;
|
|
631
701
|
self.rowBoundaryCrossed = false;
|
|
632
702
|
self.columnBoundaryCrossed = false;
|
|
@@ -675,9 +745,25 @@ export default function (self) {
|
|
|
675
745
|
) {
|
|
676
746
|
return;
|
|
677
747
|
}
|
|
748
|
+
|
|
749
|
+
let group = self.getColumnGroupAt(pos.x, pos.y);
|
|
750
|
+
if (!group) group = self.getRowGroupAt(pos.x, pos.y);
|
|
751
|
+
if (group) {
|
|
752
|
+
if (self.toggleGroup(group)) {
|
|
753
|
+
self.setStorageData();
|
|
754
|
+
self.refresh();
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
758
|
+
|
|
678
759
|
if (!self.hasFocus) {
|
|
679
760
|
return;
|
|
680
761
|
}
|
|
762
|
+
|
|
763
|
+
const leftOffset = self.getRowGroupAreaWidth();
|
|
764
|
+
const topOffset = self.getColumnGroupAreaHeight();
|
|
765
|
+
const xInGrid = pos.x - leftOffset;
|
|
766
|
+
const yInGrid = pos.y - topOffset;
|
|
681
767
|
if (
|
|
682
768
|
['rowHeaderCell', 'columnHeaderCell'].indexOf(self.currentCell.style) ===
|
|
683
769
|
-1 &&
|
|
@@ -715,17 +801,17 @@ export default function (self) {
|
|
|
715
801
|
if (
|
|
716
802
|
self.currentCell.style === 'rowHeaderCell' &&
|
|
717
803
|
self.attributes.tree &&
|
|
718
|
-
|
|
719
|
-
|
|
804
|
+
xInGrid > 0 &&
|
|
805
|
+
xInGrid - self.currentCell.x <
|
|
720
806
|
self.style.treeArrowWidth +
|
|
721
807
|
self.style.treeArrowMarginLeft +
|
|
722
808
|
self.style.treeArrowMarginRight +
|
|
723
809
|
self.style.treeArrowClickRadius &&
|
|
724
|
-
|
|
810
|
+
yInGrid - self.currentCell.y <
|
|
725
811
|
self.style.treeArrowHeight +
|
|
726
812
|
self.style.treeArrowMarginTop +
|
|
727
813
|
self.style.treeArrowClickRadius &&
|
|
728
|
-
|
|
814
|
+
yInGrid > 0
|
|
729
815
|
) {
|
|
730
816
|
self.toggleTree(i.rowIndex);
|
|
731
817
|
return;
|
|
@@ -765,7 +851,6 @@ export default function (self) {
|
|
|
765
851
|
self.dragMode === 'ew-resize'
|
|
766
852
|
) {
|
|
767
853
|
self.resize(true);
|
|
768
|
-
self.scrollBox.scrollLeft += x;
|
|
769
854
|
}
|
|
770
855
|
if (self.dragMode === 'ew-resize') {
|
|
771
856
|
self.sizes.columns[
|
|
@@ -797,30 +882,24 @@ export default function (self) {
|
|
|
797
882
|
}
|
|
798
883
|
self.ellipsisCache = {};
|
|
799
884
|
};
|
|
800
|
-
self.stopDragResize = function (
|
|
801
|
-
const pos = self.getLayerPos(
|
|
802
|
-
const hasMoved = !!(pos.x - self.dragStart.x);
|
|
803
|
-
const width = self.resizingStartingWidth + pos.x - self.dragStart.x;
|
|
885
|
+
self.stopDragResize = function (event) {
|
|
886
|
+
const pos = self.getLayerPos(event);
|
|
804
887
|
|
|
805
888
|
if (self.dragMode === 'ew-resize') {
|
|
806
|
-
const
|
|
889
|
+
const hasMoved = !!(pos.x - self.dragStart.x);
|
|
890
|
+
// Check that dragItem is selected or part of selection.
|
|
807
891
|
const dragItemIsSelected = self.isColumnSelected(
|
|
808
892
|
self.dragItem.columnIndex,
|
|
809
893
|
);
|
|
810
894
|
|
|
811
|
-
if (dragItemIsSelected)
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
dragItemIsSelected &&
|
|
820
|
-
self.isColumnSelected(selectedColumnIndex)
|
|
821
|
-
)
|
|
822
|
-
self.sizes.columns[boundColumnIndex] = width;
|
|
823
|
-
}
|
|
895
|
+
if (hasMoved && dragItemIsSelected) {
|
|
896
|
+
const width = Math.max(
|
|
897
|
+
self.resizingStartingWidth + pos.x - self.dragStart.x,
|
|
898
|
+
self.style.minColumnWidth,
|
|
899
|
+
);
|
|
900
|
+
// If the column is selected, resize it to width plus any other selected columns.
|
|
901
|
+
self.fitSelectedColumns(width);
|
|
902
|
+
}
|
|
824
903
|
}
|
|
825
904
|
|
|
826
905
|
self.resize();
|
|
@@ -981,6 +1060,7 @@ export default function (self) {
|
|
|
981
1060
|
-1,
|
|
982
1061
|
self.activeCell.rowIndex,
|
|
983
1062
|
);
|
|
1063
|
+
if (!self.reorderObject) return;
|
|
984
1064
|
self.reorderTarget = self.currentCell;
|
|
985
1065
|
self.reorderObject.dragOffset = {
|
|
986
1066
|
x: x,
|
|
@@ -1132,6 +1212,8 @@ export default function (self) {
|
|
|
1132
1212
|
|
|
1133
1213
|
self.ignoreNextClick = true;
|
|
1134
1214
|
self.freezeMarkerPosition = pos;
|
|
1215
|
+
pos.x -= self.getRowGroupAreaWidth();
|
|
1216
|
+
pos.y -= self.getColumnGroupAreaHeight();
|
|
1135
1217
|
if (
|
|
1136
1218
|
self.currentCell &&
|
|
1137
1219
|
self.currentCell.rowIndex !== undefined &&
|
|
@@ -1652,9 +1734,21 @@ export default function (self) {
|
|
|
1652
1734
|
self.autosize();
|
|
1653
1735
|
} else if (
|
|
1654
1736
|
['cell', 'activeCell'].includes(self.currentCell.style) &&
|
|
1655
|
-
!self.hovers.onFilterButton
|
|
1737
|
+
!self.hovers.onFilterButton &&
|
|
1738
|
+
!self.hovers.onCellTreeIcon
|
|
1656
1739
|
) {
|
|
1657
|
-
|
|
1740
|
+
if (self.currentCell.isRowTree || self.currentCell.isColumnTree) {
|
|
1741
|
+
self.cellTreeExpandCollapse(
|
|
1742
|
+
self.currentCell.rowIndex,
|
|
1743
|
+
self.currentCell.columnIndex,
|
|
1744
|
+
);
|
|
1745
|
+
self.draw();
|
|
1746
|
+
} else {
|
|
1747
|
+
self.beginEditAt(
|
|
1748
|
+
self.currentCell.columnIndex,
|
|
1749
|
+
self.currentCell.rowIndex,
|
|
1750
|
+
);
|
|
1751
|
+
}
|
|
1658
1752
|
}
|
|
1659
1753
|
};
|
|
1660
1754
|
self.scrollWheel = function (e) {
|
|
@@ -1876,17 +1970,17 @@ export default function (self) {
|
|
|
1876
1970
|
self.draw();
|
|
1877
1971
|
});
|
|
1878
1972
|
};
|
|
1879
|
-
self.cut = function (
|
|
1880
|
-
if (self.dispatchEvent('cut', { NativeEvent:
|
|
1973
|
+
self.cut = function (event) {
|
|
1974
|
+
if (self.dispatchEvent('cut', { NativeEvent: event })) {
|
|
1881
1975
|
return;
|
|
1882
1976
|
}
|
|
1883
1977
|
|
|
1884
1978
|
// Expecting instance of `ClipboardEvent` with `clipboardData` attribute
|
|
1885
|
-
if (!self.hasFocus || !
|
|
1979
|
+
if (!self.hasFocus || !event.clipboardData) {
|
|
1886
1980
|
return;
|
|
1887
1981
|
}
|
|
1888
1982
|
|
|
1889
|
-
self.copySelectedCellsToClipboard(
|
|
1983
|
+
self.copySelectedCellsToClipboard(event.clipboardData);
|
|
1890
1984
|
|
|
1891
1985
|
const affectedCells = self.clearSelectedCells();
|
|
1892
1986
|
|
|
@@ -1895,20 +1989,21 @@ export default function (self) {
|
|
|
1895
1989
|
});
|
|
1896
1990
|
|
|
1897
1991
|
requestAnimationFrame(() => self.draw());
|
|
1992
|
+
event.preventDefault();
|
|
1898
1993
|
};
|
|
1899
|
-
self.copy = function (
|
|
1900
|
-
if (self.dispatchEvent('copy', { NativeEvent:
|
|
1994
|
+
self.copy = function (event) {
|
|
1995
|
+
if (self.dispatchEvent('copy', { NativeEvent: event })) {
|
|
1901
1996
|
return;
|
|
1902
1997
|
}
|
|
1903
1998
|
|
|
1904
1999
|
// Expecting instance of `ClipboardEvent` with `clipboardData` attribute
|
|
1905
|
-
if (!self.hasFocus || !
|
|
2000
|
+
if (!self.hasFocus || !event.clipboardData) {
|
|
1906
2001
|
return;
|
|
1907
2002
|
}
|
|
1908
2003
|
|
|
1909
|
-
self.copySelectedCellsToClipboard(
|
|
2004
|
+
self.copySelectedCellsToClipboard(event.clipboardData);
|
|
1910
2005
|
|
|
1911
|
-
|
|
2006
|
+
event.preventDefault();
|
|
1912
2007
|
};
|
|
1913
2008
|
return;
|
|
1914
2009
|
}
|
package/lib/events/util.js
CHANGED
|
@@ -86,12 +86,13 @@ const parseData = function (data, mimeType) {
|
|
|
86
86
|
return parseText(data);
|
|
87
87
|
};
|
|
88
88
|
|
|
89
|
-
const htmlSafe = (value)
|
|
90
|
-
if (typeof value
|
|
89
|
+
const htmlSafe = function (value) {
|
|
90
|
+
if (typeof value !== 'string') return value;
|
|
91
|
+
|
|
91
92
|
return value.replace(/</g, '<').replace(/>/g, '>');
|
|
92
93
|
};
|
|
93
94
|
|
|
94
|
-
const createTextString = (selectedData, isNeat)
|
|
95
|
+
const createTextString = function (selectedData, isNeat) {
|
|
95
96
|
// Selected like [[0, 1], [0, 1]] of [[0, 3]] is neat; Selected like [[0, 1], [1, 2]] is untidy.
|
|
96
97
|
// If not isNeat we just return a simple string of concatenated values.
|
|
97
98
|
if (!isNeat)
|
|
@@ -101,7 +102,7 @@ const createTextString = (selectedData, isNeat) => {
|
|
|
101
102
|
return selectedData.map((row) => Object.values(row).join('\t')).join('\n');
|
|
102
103
|
};
|
|
103
104
|
|
|
104
|
-
const createHTMLString = (selectedData, isNeat)
|
|
105
|
+
const createHTMLString = function (selectedData, isNeat) {
|
|
105
106
|
if (!isNeat) return createTextString(selectedData, isNeat);
|
|
106
107
|
|
|
107
108
|
// If isNeat, we can create a HTML table with the selected data.
|
|
@@ -111,7 +112,7 @@ const createHTMLString = (selectedData, isNeat) => {
|
|
|
111
112
|
(row) =>
|
|
112
113
|
'<tr>' +
|
|
113
114
|
Object.values(row)
|
|
114
|
-
.map((value) => '<td>'
|
|
115
|
+
.map((value) => ['<td>', htmlSafe(value), '</td>'].join(''))
|
|
115
116
|
.join('') +
|
|
116
117
|
'</tr>',
|
|
117
118
|
)
|