canvas-datagrid 0.3.18 → 0.3.22
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 +1079 -207
- 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 +19 -0
- package/lib/button.js +326 -0
- package/lib/contextMenu.js +47 -8
- package/lib/defaults.js +27 -0
- package/lib/docs.js +9 -1
- package/lib/dom.js +90 -0
- package/lib/draw.js +98 -6
- package/lib/events/index.js +254 -136
- package/lib/events/util.js +39 -1
- package/lib/intf.js +116 -0
- package/lib/main.js +2 -0
- package/lib/publicMethods.js +107 -5
- package/package.json +1 -1
package/lib/intf.js
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
/*globals HTMLElement: false, Reflect: false, define: true, MutationObserver: false, requestAnimationFrame: false, performance: false, btoa: false*/
|
|
3
3
|
'use strict';
|
|
4
4
|
|
|
5
|
+
import { createHTMLString, createTextString } from './events/util';
|
|
6
|
+
|
|
5
7
|
export default function (self, ctor) {
|
|
6
8
|
self.scale = 1;
|
|
7
9
|
self.orders = {
|
|
@@ -61,6 +63,14 @@ export default function (self, ctor) {
|
|
|
61
63
|
trees: {},
|
|
62
64
|
};
|
|
63
65
|
self.selections = [];
|
|
66
|
+
self.filterable = {
|
|
67
|
+
rows: [],
|
|
68
|
+
columns: [],
|
|
69
|
+
};
|
|
70
|
+
self.selectedFilterButton = {
|
|
71
|
+
columnIndex: -1,
|
|
72
|
+
rowIndex: -1,
|
|
73
|
+
};
|
|
64
74
|
self.hovers = {};
|
|
65
75
|
self.attributes = {};
|
|
66
76
|
self.style = {};
|
|
@@ -88,6 +98,7 @@ export default function (self, ctor) {
|
|
|
88
98
|
self.eventNames = [
|
|
89
99
|
'afterdraw',
|
|
90
100
|
'afterrendercell',
|
|
101
|
+
'afterrenderfilterbutton',
|
|
91
102
|
'attributechanged',
|
|
92
103
|
'beforebeginedit',
|
|
93
104
|
'beforecreatecellgrid',
|
|
@@ -95,6 +106,7 @@ export default function (self, ctor) {
|
|
|
95
106
|
'beforeendedit',
|
|
96
107
|
'beforerendercell',
|
|
97
108
|
'beforerendercellgrid',
|
|
109
|
+
'beforerenderfilterbutton',
|
|
98
110
|
'beginedit',
|
|
99
111
|
'cellmouseout',
|
|
100
112
|
'cellmouseover',
|
|
@@ -232,6 +244,89 @@ export default function (self, ctor) {
|
|
|
232
244
|
|
|
233
245
|
return selectedCells;
|
|
234
246
|
};
|
|
247
|
+
self.copySelectedCellsToClipboard = function (clipboardData) {
|
|
248
|
+
const selectedData = [];
|
|
249
|
+
const schema = self.getSchema();
|
|
250
|
+
let firstRowAsString;
|
|
251
|
+
let isNeat = true; // Selected like [[0, 1], [0, 1]] of [[0, 3]] is neat; Selected like [[0, 1], [1, 2]] is untidy
|
|
252
|
+
|
|
253
|
+
for (const [rowIndex, row] of self.selections.entries()) {
|
|
254
|
+
// If no cells are selected for a particular rowIndex the selections array will contain an empty element for that rowIndex.
|
|
255
|
+
if (!row) continue;
|
|
256
|
+
|
|
257
|
+
// Convert to string for easy comparison to the first row.
|
|
258
|
+
const rowAsString = row.join(',').toString();
|
|
259
|
+
const rowDict = {};
|
|
260
|
+
|
|
261
|
+
if (!firstRowAsString) firstRowAsString = row.join(',').toString();
|
|
262
|
+
if (isNeat && rowAsString !== firstRowAsString) isNeat = false;
|
|
263
|
+
|
|
264
|
+
const boundRowIndex = self.getBoundRowIndexFromViewRowIndex(rowIndex);
|
|
265
|
+
|
|
266
|
+
for (let columnIndex of row) {
|
|
267
|
+
// If the whole row is selected the columnIndex for the rowHeader is -1.
|
|
268
|
+
if (columnIndex < 0) continue;
|
|
269
|
+
|
|
270
|
+
const boundColumnIndex = self.getBoundColumnIndexFromViewColumnIndex(
|
|
271
|
+
columnIndex,
|
|
272
|
+
);
|
|
273
|
+
const columnName = schema[boundColumnIndex].name;
|
|
274
|
+
|
|
275
|
+
const value = self.originalData[boundRowIndex][columnName];
|
|
276
|
+
|
|
277
|
+
rowDict[columnName] = value;
|
|
278
|
+
}
|
|
279
|
+
selectedData.push(rowDict);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
if (selectedData.length > 0) {
|
|
283
|
+
const textString = createTextString(selectedData, isNeat);
|
|
284
|
+
const htmlString = createHTMLString(selectedData, isNeat);
|
|
285
|
+
|
|
286
|
+
const copiedData = {
|
|
287
|
+
'text/plain': textString,
|
|
288
|
+
'text/html': htmlString,
|
|
289
|
+
'text/csv': textString,
|
|
290
|
+
'application/json': JSON.stringify(selectedData),
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
for (const [mimeType, data] of Object.entries(copiedData)) {
|
|
294
|
+
clipboardData.setData(mimeType, data);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
self.clearSelectedCells = function () {
|
|
299
|
+
const schema = self.getSchema();
|
|
300
|
+
const affectedCells = [];
|
|
301
|
+
|
|
302
|
+
for (const [rowIndex, row] of self.selections.entries()) {
|
|
303
|
+
// If no cells are selected for a particular rowIndex the selections array will contain an empty element for that rowIndex.
|
|
304
|
+
if (!row) continue;
|
|
305
|
+
|
|
306
|
+
const boundRowIndex = self.getBoundRowIndexFromViewRowIndex(rowIndex);
|
|
307
|
+
|
|
308
|
+
for (let columnIndex of row) {
|
|
309
|
+
// If the whole row is selected the columnIndex for the rowHeader is -1.
|
|
310
|
+
if (columnIndex < 0) continue;
|
|
311
|
+
|
|
312
|
+
const boundColumnIndex = self.getBoundColumnIndexFromViewColumnIndex(
|
|
313
|
+
columnIndex,
|
|
314
|
+
);
|
|
315
|
+
const columnName = schema[boundColumnIndex].name;
|
|
316
|
+
|
|
317
|
+
self.viewData[boundRowIndex][columnName] = '';
|
|
318
|
+
|
|
319
|
+
affectedCells.push([
|
|
320
|
+
rowIndex,
|
|
321
|
+
columnIndex,
|
|
322
|
+
boundRowIndex,
|
|
323
|
+
boundColumnIndex,
|
|
324
|
+
]);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return affectedCells;
|
|
329
|
+
};
|
|
235
330
|
self.getBoundRowIndexFromViewRowIndex = function (viewRowIndex) {
|
|
236
331
|
if (self.boundRowIndexMap && self.boundRowIndexMap.has(viewRowIndex)) {
|
|
237
332
|
return self.boundRowIndexMap.get(viewRowIndex);
|
|
@@ -301,6 +396,18 @@ export default function (self, ctor) {
|
|
|
301
396
|
self.createRowOrders = function () {
|
|
302
397
|
self.orders.rows = fillArray(0, self.originalData.length - 1);
|
|
303
398
|
};
|
|
399
|
+
self.fitSelectedColumns = function () {
|
|
400
|
+
const selectedColumns = self.selections[0];
|
|
401
|
+
const schema = self.getSchema();
|
|
402
|
+
|
|
403
|
+
for (const selectedColumn of selectedColumns) {
|
|
404
|
+
// Make sure the column is not the row header and that the whole column has in fact been selected.
|
|
405
|
+
if (selectedColumn >= 0 && self.isColumnSelected(selectedColumn)) {
|
|
406
|
+
const column = schema[self.orders.columns[selectedColumn]];
|
|
407
|
+
self.fitColumnToValues(column.name);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
};
|
|
304
411
|
self.getVisibleSchema = function () {
|
|
305
412
|
return self.getSchema().filter(function (col) {
|
|
306
413
|
return !col.hidden;
|
|
@@ -547,6 +654,7 @@ export default function (self, ctor) {
|
|
|
547
654
|
self.controlInput.removeEventListener('keypress', self.keypress, false);
|
|
548
655
|
self.controlInput.removeEventListener('keyup', self.keyup, false);
|
|
549
656
|
self.controlInput.removeEventListener('keydown', self.keydown, false);
|
|
657
|
+
document.body.removeEventListener('mousemove', self.mousemove);
|
|
550
658
|
window.removeEventListener('resize', self.resize);
|
|
551
659
|
if (self.observer && self.observer.disconnect) {
|
|
552
660
|
self.observer.disconnect();
|
|
@@ -724,6 +832,7 @@ export default function (self, ctor) {
|
|
|
724
832
|
self.pointerLockPosition = { x: 0, y: 0 };
|
|
725
833
|
Object.keys(self.style).forEach(self.parseStyleValue);
|
|
726
834
|
self.intf.moveSelection = self.moveSelection;
|
|
835
|
+
self.intf.deleteSelectedData = self.deleteSelectedData;
|
|
727
836
|
self.intf.moveTo = self.moveTo;
|
|
728
837
|
self.intf.addEventListener = self.addEventListener;
|
|
729
838
|
self.intf.removeEventListener = self.removeEventListener;
|
|
@@ -755,6 +864,7 @@ export default function (self, ctor) {
|
|
|
755
864
|
self.intf.clearChangeLog = self.clearChangeLog;
|
|
756
865
|
self.intf.gotoCell = self.gotoCell;
|
|
757
866
|
self.intf.gotoRow = self.gotoRow;
|
|
867
|
+
self.intf.addButton = self.addButton;
|
|
758
868
|
self.intf.getHeaderByName = self.getHeaderByName;
|
|
759
869
|
self.intf.findColumnScrollLeft = self.findColumnScrollLeft;
|
|
760
870
|
self.intf.findRowScrollTop = self.findRowScrollTop;
|
|
@@ -1534,6 +1644,9 @@ export default function (self, ctor) {
|
|
|
1534
1644
|
if (!preventScrollEvent) {
|
|
1535
1645
|
self.scroll();
|
|
1536
1646
|
}
|
|
1647
|
+
if (self.button) {
|
|
1648
|
+
self.moveButtonPos();
|
|
1649
|
+
}
|
|
1537
1650
|
}
|
|
1538
1651
|
function setScrollLeft(value, preventScrollEvent) {
|
|
1539
1652
|
if (isNaN(value)) {
|
|
@@ -1552,6 +1665,9 @@ export default function (self, ctor) {
|
|
|
1552
1665
|
if (!preventScrollEvent) {
|
|
1553
1666
|
self.scroll();
|
|
1554
1667
|
}
|
|
1668
|
+
if (self.button) {
|
|
1669
|
+
self.moveButtonPos();
|
|
1670
|
+
}
|
|
1555
1671
|
}
|
|
1556
1672
|
self.scrollBox.toString = function () {
|
|
1557
1673
|
return (
|
package/lib/main.js
CHANGED
|
@@ -9,6 +9,7 @@ import events from './events';
|
|
|
9
9
|
import touch from './touch';
|
|
10
10
|
import intf from './intf';
|
|
11
11
|
import contextMenu from './contextMenu';
|
|
12
|
+
import button from './button';
|
|
12
13
|
import dom from './dom';
|
|
13
14
|
import publicMethods from './publicMethods';
|
|
14
15
|
|
|
@@ -21,6 +22,7 @@ var modules = [
|
|
|
21
22
|
touch,
|
|
22
23
|
intf,
|
|
23
24
|
contextMenu,
|
|
25
|
+
button,
|
|
24
26
|
dom,
|
|
25
27
|
publicMethods,
|
|
26
28
|
];
|
package/lib/publicMethods.js
CHANGED
|
@@ -206,6 +206,18 @@ export default function (self) {
|
|
|
206
206
|
delete self.columnFilters[column];
|
|
207
207
|
} else {
|
|
208
208
|
self.columnFilters[column] = value;
|
|
209
|
+
if (self.attributes.showFilterInCell) {
|
|
210
|
+
self.filterable.rows.push(0);
|
|
211
|
+
self.orders.columns.forEach(function (value, index) {
|
|
212
|
+
self.filterable.columns.push(index);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!Object.keys(self.columnFilters).length) {
|
|
217
|
+
self.filterable = {
|
|
218
|
+
rows: [],
|
|
219
|
+
columns: [],
|
|
220
|
+
};
|
|
209
221
|
}
|
|
210
222
|
self.refresh();
|
|
211
223
|
};
|
|
@@ -294,6 +306,31 @@ export default function (self) {
|
|
|
294
306
|
self.gotoRow = function (y) {
|
|
295
307
|
self.gotoCell(0, y);
|
|
296
308
|
};
|
|
309
|
+
/**
|
|
310
|
+
* Add a button into the cell.
|
|
311
|
+
* @memberof canvasDatagrid
|
|
312
|
+
* @name addButton
|
|
313
|
+
* @method
|
|
314
|
+
* @param {number} columnIndex The column index of the cell to to add a button.
|
|
315
|
+
* @param {number} rowIndex The row index of the cell to to add a button.
|
|
316
|
+
* @param {object} offset Offset how far go away from cell.
|
|
317
|
+
* @param {object} items a list of items to add into button menu.
|
|
318
|
+
* @param {string} imgSrc icon path to add into button.
|
|
319
|
+
*/
|
|
320
|
+
self.addButton = function (columnIndex, rowIndex, offset, items, imgSrc) {
|
|
321
|
+
var cells = self.visibleCells.filter(function (c) {
|
|
322
|
+
return c.sortColumnIndex === columnIndex && c.sortRowIndex === rowIndex;
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
self.attachButton(
|
|
326
|
+
{
|
|
327
|
+
top: cells[0].y + cells[0].height + offset.y,
|
|
328
|
+
left: cells[0].x + cells[0].width + offset.x,
|
|
329
|
+
},
|
|
330
|
+
items,
|
|
331
|
+
imgSrc,
|
|
332
|
+
);
|
|
333
|
+
};
|
|
297
334
|
/**
|
|
298
335
|
* Scrolls the cell at cell x, row y into view if it is not already.
|
|
299
336
|
* @memberof canvasDatagrid
|
|
@@ -379,6 +416,37 @@ export default function (self) {
|
|
|
379
416
|
}
|
|
380
417
|
self.draw();
|
|
381
418
|
};
|
|
419
|
+
/**
|
|
420
|
+
* Returns true if indices of columns next to the selected columnIndex is selected on every row.
|
|
421
|
+
* @memberof canvasDatagrid
|
|
422
|
+
* @name isMultiColumnsSelected
|
|
423
|
+
* @method
|
|
424
|
+
* @param {number} columnIndex The column index to check.
|
|
425
|
+
*/
|
|
426
|
+
self.isMultiColumnsSelected = function (columnIndex) {
|
|
427
|
+
var multiColIsSelected = true;
|
|
428
|
+
self.viewData.forEach(function (row, rowIndex) {
|
|
429
|
+
var columnIndices = self.selections[rowIndex];
|
|
430
|
+
if (
|
|
431
|
+
!columnIndices ||
|
|
432
|
+
columnIndices.length <= 1 ||
|
|
433
|
+
columnIndices.indexOf(columnIndex) === -1
|
|
434
|
+
) {
|
|
435
|
+
multiColIsSelected = false;
|
|
436
|
+
} else if (columnIndices.length > 1) {
|
|
437
|
+
if (columnIndices[0] != columnIndex) multiColIsSelected = false;
|
|
438
|
+
else {
|
|
439
|
+
for (var i = 0; i < columnIndices.length - 1; i++) {
|
|
440
|
+
if (columnIndices[i] + 1 != columnIndices[i + 1]) {
|
|
441
|
+
multiColIsSelected = false;
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
});
|
|
448
|
+
return multiColIsSelected;
|
|
449
|
+
};
|
|
382
450
|
/**
|
|
383
451
|
* Returns true if the selected columnIndex is selected on every row.
|
|
384
452
|
* @memberof canvasDatagrid
|
|
@@ -391,8 +459,7 @@ export default function (self) {
|
|
|
391
459
|
self.viewData.forEach(function (row, rowIndex) {
|
|
392
460
|
if (
|
|
393
461
|
!self.selections[rowIndex] ||
|
|
394
|
-
self.selections[rowIndex].indexOf(
|
|
395
|
-
-1
|
|
462
|
+
self.selections[rowIndex].indexOf(columnIndex) === -1
|
|
396
463
|
) {
|
|
397
464
|
colIsSelected = false;
|
|
398
465
|
}
|
|
@@ -504,6 +571,7 @@ export default function (self) {
|
|
|
504
571
|
st,
|
|
505
572
|
en,
|
|
506
573
|
s = self.getVisibleSchema();
|
|
574
|
+
self.isMultiRowsSelected = false;
|
|
507
575
|
function de() {
|
|
508
576
|
if (supressEvent) {
|
|
509
577
|
return;
|
|
@@ -666,9 +734,23 @@ export default function (self) {
|
|
|
666
734
|
if (!self.canvas) {
|
|
667
735
|
return;
|
|
668
736
|
}
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
737
|
+
|
|
738
|
+
const columnIndex =
|
|
739
|
+
name === 'cornerCell' ? -1 : self.getHeaderByName(name).index;
|
|
740
|
+
|
|
741
|
+
const newSize = Math.max(
|
|
742
|
+
self.findColumnMaxTextLength(name),
|
|
743
|
+
self.style.minColumnWidth,
|
|
744
|
+
);
|
|
745
|
+
|
|
746
|
+
self.sizes.columns[columnIndex] = newSize;
|
|
747
|
+
|
|
748
|
+
self.dispatchEvent('resizecolumn', {
|
|
749
|
+
x: newSize,
|
|
750
|
+
y: self.resizingStartingHeight,
|
|
751
|
+
draggingItem: self.currentCell,
|
|
752
|
+
});
|
|
753
|
+
|
|
672
754
|
if (!internal) {
|
|
673
755
|
self.resize();
|
|
674
756
|
self.draw(true);
|
|
@@ -788,6 +870,26 @@ export default function (self) {
|
|
|
788
870
|
});
|
|
789
871
|
self.selections = sel;
|
|
790
872
|
};
|
|
873
|
+
/**
|
|
874
|
+
* Deletes currently selected data.
|
|
875
|
+
* @memberof canvasDatagrid
|
|
876
|
+
* @name deleteSelectedData
|
|
877
|
+
* @method
|
|
878
|
+
* @param {boolean} dontDraw Suppress the draw method after the selection change.
|
|
879
|
+
*/
|
|
880
|
+
self.deleteSelectedData = function (dontDraw) {
|
|
881
|
+
const affectedCells = self.clearSelectedCells();
|
|
882
|
+
|
|
883
|
+
self.dispatchEvent('afterdelete', {
|
|
884
|
+
cells: affectedCells,
|
|
885
|
+
});
|
|
886
|
+
|
|
887
|
+
if (dontDraw) {
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
requestAnimationFrame(() => self.draw());
|
|
892
|
+
};
|
|
791
893
|
/**
|
|
792
894
|
* Moves data in the provided selection to another position in the grid. Moving data off the edge of the schema (columns/x) will truncate data.
|
|
793
895
|
* @memberof canvasDatagrid
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "canvas-datagrid",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.22",
|
|
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",
|