canvas-datagrid 0.3.16 → 0.3.20

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/lib/draw.js CHANGED
@@ -164,6 +164,34 @@ export default function (self) {
164
164
  self.ctx.fill();
165
165
  return ml + aw + mr;
166
166
  }
167
+ function drawFilterButtonArrow(x, y) {
168
+ var mt =
169
+ ((self.style.filterButtonHeight - self.style.filterButtonArrowHeight) /
170
+ 2) *
171
+ self.scale,
172
+ ml =
173
+ ((self.style.filterButtonWidth - self.style.filterButtonArrowWidth) /
174
+ 2) *
175
+ self.scale,
176
+ aw = self.style.filterButtonArrowWidth * self.scale,
177
+ ah = self.style.filterButtonArrowHeight * self.scale;
178
+ x += self.canvasOffsetLeft;
179
+ y += self.canvasOffsetTop;
180
+ self.ctx.fillStyle = self.style.filterButtonArrowColor;
181
+ self.ctx.strokeStyle = self.style.filterButtonArrowBorderColor;
182
+ self.ctx.beginPath();
183
+ x = x + ml;
184
+ y = y + mt;
185
+
186
+ self.ctx.moveTo(x, y);
187
+ self.ctx.lineTo(x + aw, y);
188
+ self.ctx.lineTo(x + aw * 0.5, y + ah);
189
+ self.ctx.moveTo(x, y);
190
+
191
+ self.ctx.stroke();
192
+ self.ctx.fill();
193
+ return ml + aw;
194
+ }
167
195
  function radiusRect(x, y, w, h, radius) {
168
196
  x += self.canvasOffsetLeft;
169
197
  y += self.canvasOffsetTop;
@@ -601,15 +629,29 @@ export default function (self) {
601
629
  m = self.style.scrollBarBoxMargin * 2;
602
630
  self.ctx.strokeStyle = self.style.scrollBarBorderColor;
603
631
  self.ctx.lineWidth = self.style.scrollBarBorderWidth;
604
- en.horizontalBox.x =
605
- rowHeaderCellWidth +
606
- self.style.scrollBarBoxMargin +
607
- (en.horizontalBar.width - self.scrollBox.scrollBoxWidth) *
608
- (self.scrollBox.scrollLeft / self.scrollBox.scrollWidth);
632
+ if (self.frozenColumn > 0) {
633
+ en.horizontalBox.x =
634
+ rowHeaderCellWidth +
635
+ self.style.scrollBarBoxMargin +
636
+ self.scrollCache.x[self.frozenColumn - 1] +
637
+ (en.horizontalBar.width -
638
+ self.scrollCache.x[self.frozenColumn - 1] -
639
+ self.scrollBox.scrollBoxWidth) *
640
+ (self.scrollBox.scrollLeft / self.scrollBox.scrollWidth);
641
+ } else {
642
+ en.horizontalBox.x =
643
+ rowHeaderCellWidth +
644
+ self.style.scrollBarBoxMargin +
645
+ (en.horizontalBar.width - self.scrollBox.scrollBoxWidth) *
646
+ (self.scrollBox.scrollLeft / self.scrollBox.scrollWidth);
647
+ }
609
648
  en.verticalBox.y =
610
649
  columnHeaderCellHeight +
611
650
  self.style.scrollBarBoxMargin +
612
- (en.verticalBar.height - self.scrollBox.scrollBoxHeight) *
651
+ self.scrollCache.y[self.frozenRow] +
652
+ (en.verticalBar.height -
653
+ self.scrollBox.scrollBoxHeight -
654
+ self.scrollCache.y[self.frozenRow]) *
613
655
  (self.scrollBox.scrollTop / self.scrollBox.scrollHeight);
614
656
  if (self.scrollBox.horizontalBarVisible) {
615
657
  self.ctx.fillStyle = self.style.scrollBarBackgroundColor;
@@ -802,6 +844,9 @@ export default function (self) {
802
844
  isCorner = /cornerCell/.test(cellStyle),
803
845
  isRowHeader = 'rowHeaderCell' === cellStyle,
804
846
  isColumnHeader = 'columnHeaderCell' === cellStyle,
847
+ isFilterable =
848
+ self.filterable.rows.includes(rowIndex) &&
849
+ self.filterable.columns.includes(headerIndex),
805
850
  wrap = self.style.cellWhiteSpace !== 'nowrap',
806
851
  selected =
807
852
  self.selections[rowOrderIndex] &&
@@ -810,6 +855,9 @@ export default function (self) {
810
855
  self.hovers.rowIndex === rowOrderIndex &&
811
856
  (self.attributes.hoverMode === 'row' ||
812
857
  self.hovers.columnIndex === columnOrderIndex),
858
+ openedFilter =
859
+ self.selectedFilterButton.rowIndex == rowIndex &&
860
+ self.selectedFilterButton.columnIndex == headerIndex,
813
861
  active =
814
862
  self.activeCell.rowIndex === rowOrderIndex &&
815
863
  self.activeCell.columnIndex === columnOrderIndex,
@@ -901,6 +949,8 @@ export default function (self) {
901
949
  isColumnHeader: isColumnHeader,
902
950
  isColumnHeaderCellCap: isColumnHeaderCellCap,
903
951
  isRowHeader: isRowHeader,
952
+ isFilterable: isFilterable,
953
+ openedFilter: openedFilter,
904
954
  rowOpen: rowOpen,
905
955
  header: header,
906
956
 
@@ -1100,13 +1150,23 @@ export default function (self) {
1100
1150
  }
1101
1151
  self.ctx.restore();
1102
1152
 
1153
+ if (isFilterable) {
1154
+ drawFilterButton(cell);
1155
+ }
1156
+
1103
1157
  // Gaps may occur in row numbers between consecutively rendered rows
1104
1158
  // when we are filtering. We draw attention to this by drawing a thick
1105
- // border overlapping the two consecutive row headers.
1159
+ // border overlapping the two consecutive row headers. If sorting, visible
1160
+ // row numbers stay the same (i.e. they don't correspond to the underlying
1161
+ // data's row number), so we do not show row gaps in that case.
1162
+ const isSorting =
1163
+ self.orderings.columns && self.orderings.columns.length > 0;
1164
+
1106
1165
  if (
1107
1166
  isRowHeader &&
1108
1167
  self.attributes.showRowNumbers &&
1109
- self.attributes.showRowNumberGaps
1168
+ self.attributes.showRowNumberGaps &&
1169
+ isSorting === false
1110
1170
  ) {
1111
1171
  const previousRowNumber = self.getBoundRowIndexFromViewRowIndex(
1112
1172
  rowOrderIndex - 1,
@@ -1134,6 +1194,34 @@ export default function (self) {
1134
1194
  return cell.width;
1135
1195
  };
1136
1196
  }
1197
+ function drawFilterButton(cell, ev) {
1198
+ var posX = cell.x + cell.width - self.style.filterButtonWidth - 1;
1199
+ var posY = cell.y + cell.height - self.style.filterButtonHeight - 2;
1200
+ if (self.dispatchEvent('beforerenderfilterbutton', ev)) {
1201
+ return;
1202
+ }
1203
+ self.ctx.save();
1204
+ self.ctx.strokeStyle = self.style.filterButtonBorderColor;
1205
+ self.ctx.fillStyle = self.style.filterButtonBackgroundColor;
1206
+ if (cell.openedFilter) {
1207
+ self.ctx.fillStyle = self.style.filterButtonActiveBackgroundColor;
1208
+ } else if (cell.hovered && self.hovers.onFilterButton) {
1209
+ self.ctx.fillStyle = self.style.filterButtonHoverBackgroundColor;
1210
+ }
1211
+ radiusRect(
1212
+ posX,
1213
+ posY,
1214
+ self.style.filterButtonWidth,
1215
+ self.style.filterButtonHeight,
1216
+ self.style.filterButtonBorderRadius,
1217
+ );
1218
+ self.ctx.stroke();
1219
+ self.ctx.fill();
1220
+ drawFilterButtonArrow(posX, posY);
1221
+ self.ctx.clip();
1222
+ self.dispatchEvent('afterrenderfilterbutton', ev);
1223
+ self.ctx.restore();
1224
+ }
1137
1225
  function drawRowHeader(rowData, rowIndex, rowOrderIndex) {
1138
1226
  if (self.attributes.showRowHeaders) {
1139
1227
  x = 0;
@@ -1514,6 +1602,10 @@ export default function (self) {
1514
1602
  self.ctx.lineWidth = self.style.reorderMarkerBorderWidth;
1515
1603
  self.ctx.strokeStyle = self.style.reorderMarkerBorderColor;
1516
1604
  if (self.dragMode === 'row-reorder') {
1605
+ for (var k = 0; k < self.selections.length; k++) {
1606
+ if (!self.selections[k] || k == self.reorderObject.rowIndex) continue;
1607
+ b.height += self.getRowHeight(k);
1608
+ }
1517
1609
  b.width = w;
1518
1610
  b.x = 0;
1519
1611
  m.width = w;
@@ -1536,6 +1628,12 @@ export default function (self) {
1536
1628
  );
1537
1629
  }
1538
1630
  } else if (self.dragMode === 'column-reorder' && self.reorderObject) {
1631
+ var selectedColumns = self.selections[0];
1632
+ for (var k = 1; k < selectedColumns.length; k++) {
1633
+ b.width += self.getColumnWidth(
1634
+ self.orders.columns[selectedColumns[k]],
1635
+ );
1636
+ }
1539
1637
  b.height = h;
1540
1638
  b.y = 0;
1541
1639
  m.height = h;
@@ -254,7 +254,13 @@ export default function (self) {
254
254
  setScrollBoxSize();
255
255
  self.scrollBox.scrollWidth = dataWidth - self.scrollBox.width;
256
256
  self.scrollBox.scrollHeight = dataHeight - self.scrollBox.height;
257
- self.scrollBox.widthBoxRatio = self.scrollBox.width / dataWidth;
257
+ if (self.frozenColumn > 0) {
258
+ self.scrollBox.widthBoxRatio =
259
+ (self.scrollBox.width - self.scrollCache.x[self.frozenColumn - 1]) /
260
+ dataWidth;
261
+ } else {
262
+ self.scrollBox.widthBoxRatio = self.scrollBox.width / dataWidth;
263
+ }
258
264
  self.scrollBox.scrollBoxWidth =
259
265
  self.scrollBox.width * self.scrollBox.widthBoxRatio -
260
266
  self.style.scrollBarWidth -
@@ -266,7 +272,10 @@ export default function (self) {
266
272
  // the dragged mouse.
267
273
  // https://github.com/TonyGermaneri/canvas-datagrid/issues/97
268
274
  self.scrollBox.heightBoxRatio =
269
- (self.scrollBox.height - columnHeaderCellHeight) / dataHeight;
275
+ (self.scrollBox.height -
276
+ columnHeaderCellHeight -
277
+ self.scrollCache.y[self.frozenRow]) /
278
+ dataHeight;
270
279
  self.scrollBox.scrollBoxHeight =
271
280
  self.scrollBox.height * self.scrollBox.heightBoxRatio -
272
281
  self.style.scrollBarWidth -
@@ -296,12 +305,13 @@ export default function (self) {
296
305
  self.style.scrollBarWidth -
297
306
  self.style.scrollBarBorderWidth -
298
307
  d;
299
- v.y += columnHeaderCellHeight;
308
+ v.y += columnHeaderCellHeight + self.scrollCache.y[self.frozenRow];
300
309
  v.width = self.style.scrollBarWidth + self.style.scrollBarBorderWidth + d;
301
310
  v.height =
302
311
  self.height - columnHeaderCellHeight - self.style.scrollBarWidth - d - m;
303
312
  // vertical box
304
313
  vb.x = v.x + self.style.scrollBarBoxMargin;
314
+ vb.y += self.scrollCache.y[self.frozenRow];
305
315
  vb.width = self.style.scrollBarBoxWidth;
306
316
  vb.height = self.scrollBox.scrollBoxHeight;
307
317
  // corner
@@ -458,7 +468,18 @@ export default function (self) {
458
468
  self.hovers = {
459
469
  rowIndex: cell.rowIndex,
460
470
  columnIndex: cell.columnIndex,
471
+ onFilterButton: false,
461
472
  };
473
+ if (
474
+ cell.isFilterable &&
475
+ x > cell.x + cell.width - self.style.filterButtonWidth &&
476
+ x < cell.x + cell.width &&
477
+ y > cell.y + cell.height - self.style.filterButtonHeight &&
478
+ y < cell.y + cell.height
479
+ ) {
480
+ self.hovers.onFilterButton = true;
481
+ self.draw();
482
+ }
462
483
  }
463
484
  if (self.selecting || self.reorderObject) {
464
485
  delta = {
@@ -502,30 +523,57 @@ export default function (self) {
502
523
  ) {
503
524
  self.selectRow(cell.rowIndex, ctrl, null, true);
504
525
  } else if (self.attributes.selectionMode !== 'row') {
505
- if (!self.dragAddToSelection && cell.rowIndex !== undefined) {
506
- if (
507
- self.selections[cell.rowIndex] &&
508
- self.selections[cell.rowIndex].indexOf(cell.columnIndex) !== -1
509
- ) {
510
- self.selections[cell.rowIndex].splice(
511
- self.selections[cell.rowIndex].indexOf(cell.columnIndex),
512
- 1,
513
- );
526
+ if (cell.hovered && self.hovers.onFilterButton) {
527
+ if (cell.openedFilter) {
528
+ cell.openedFilter = false;
529
+ self.selectedFilterButton = {
530
+ columnIndex: -1,
531
+ rowIndex: -1,
532
+ };
533
+ } else {
534
+ self.selectedFilterButton.rowIndex = cell.rowIndex;
535
+ self.selectedFilterButton.columnIndex = cell.columnIndex;
536
+ self.contextmenuEvent(e, {
537
+ x: cell.x + cell.width - self.style.filterButtonWidth,
538
+ y: cell.y + cell.height,
539
+ rect: { left: 0, top: 0 },
540
+ });
514
541
  }
542
+ self.draw();
543
+ return;
515
544
  } else {
516
- self.selections[cell.rowIndex] =
517
- self.selections[cell.rowIndex] || [];
518
- if (
519
- self.selections[cell.rowIndex].indexOf(cell.columnIndex) === -1
520
- ) {
521
- self.selections[cell.rowIndex].push(cell.columnIndex);
522
- const event = {
523
- selections: self.selections,
524
- selectedData: self.getSelectedData(),
525
- selectedCells: self.getSelectedCells(),
526
- selectionBounds: self.getSelectionBounds(),
527
- };
528
- self.dispatchEvent('selectionchanged', event);
545
+ self.selectedFilterButton = {
546
+ columnIndex: -1,
547
+ rowIndex: -1,
548
+ };
549
+ if (self.hovers.onFilterButton) return;
550
+ if (!self.dragAddToSelection && cell.rowIndex !== undefined) {
551
+ if (
552
+ self.selections[cell.rowIndex] &&
553
+ self.selections[cell.rowIndex].indexOf(cell.columnIndex) !==
554
+ -1
555
+ ) {
556
+ self.selections[cell.rowIndex].splice(
557
+ self.selections[cell.rowIndex].indexOf(cell.columnIndex),
558
+ 1,
559
+ );
560
+ }
561
+ } else {
562
+ self.selections[cell.rowIndex] =
563
+ self.selections[cell.rowIndex] || [];
564
+ if (
565
+ self.selections[cell.rowIndex].indexOf(cell.columnIndex) ===
566
+ -1
567
+ ) {
568
+ self.selections[cell.rowIndex].push(cell.columnIndex);
569
+ var event = {
570
+ selections: self.selections,
571
+ selectedData: self.getSelectedData(),
572
+ selectedCells: self.getSelectedCells(),
573
+ selectionBounds: self.getSelectionBounds(),
574
+ };
575
+ self.dispatchEvent('selectionchanged', event);
576
+ }
529
577
  }
530
578
  }
531
579
  }
@@ -538,14 +586,21 @@ export default function (self) {
538
586
  dragBounds.right !== self.selectionBounds.right) &&
539
587
  !ctrl
540
588
  ) {
541
- self.selections = [];
589
+ if (!(cell.hovered && self.hovers.onFilterButton)) {
590
+ self.selections = [];
591
+ }
592
+ if (dragBounds.top === -1) {
593
+ dragBounds.top = 0;
594
+ }
542
595
  sBounds = dragBounds;
543
596
  if (self.attributes.selectionMode === 'row') {
544
597
  for (i = sBounds.top; i <= sBounds.bottom; i += 1) {
545
598
  self.selectRow(i, true, null, true);
546
599
  }
547
- } else if (dragBounds.top !== -1) {
600
+ } else {
548
601
  self.selectArea(sBounds, true);
602
+ if (sBounds.left == -1 && sBounds.top !== sBounds.bottom)
603
+ self.isMultiRowsSelected = true;
549
604
  }
550
605
  }
551
606
 
@@ -620,7 +675,9 @@ export default function (self) {
620
675
  -1 &&
621
676
  !ctrl
622
677
  ) {
623
- self.setActiveCell(i.columnIndex, i.rowIndex);
678
+ if (!self.hovers.onFilterButton) {
679
+ self.setActiveCell(i.columnIndex, i.rowIndex);
680
+ }
624
681
  }
625
682
  if (self.currentCell.context === 'cell') {
626
683
  if (self.currentCell.style === 'cornerCell') {
@@ -641,11 +698,6 @@ export default function (self) {
641
698
  checkSelectionChange();
642
699
  return;
643
700
  }
644
- if (self.attributes.columnHeaderClickBehavior === 'select') {
645
- self.selectColumn(i.header.index, ctrl, e.shiftKey);
646
- self.draw();
647
- return;
648
- }
649
701
  }
650
702
  self.selections[i.rowIndex] = self.selections[i.rowIndex] || [];
651
703
  if (
@@ -868,6 +920,14 @@ export default function (self) {
868
920
  if (!self.attributes.allowRowReordering && rowReorder) {
869
921
  return;
870
922
  }
923
+ if ((e.ctrlKey || e.metaKey || e.shiftKey) && self.reorderObject) {
924
+ if (
925
+ self.dragMode === 'column-reorder' &&
926
+ !self.isMultiColumnsSelected(self.draggingItem.header.index)
927
+ ) {
928
+ self.selectColumn(self.draggingItem.header.index, false, false);
929
+ }
930
+ }
871
931
  if (
872
932
  self.dispatchEvent('reordering', {
873
933
  NativeEvent: e,
@@ -883,6 +943,11 @@ export default function (self) {
883
943
  Math.abs(y) > self.attributes.reorderDeadZone
884
944
  ) {
885
945
  self.reorderObject = self.draggingItem;
946
+ if (self.isMultiRowsSelected)
947
+ self.reorderObject = self.getVisibleCellByIndex(
948
+ -1,
949
+ self.activeCell.rowIndex,
950
+ );
886
951
  self.reorderTarget = self.currentCell;
887
952
  self.reorderObject.dragOffset = {
888
953
  x: x,
@@ -899,7 +964,7 @@ export default function (self) {
899
964
  self.stopDragReorder = function (e) {
900
965
  var oIndex,
901
966
  tIndex,
902
- odata,
967
+ odata = [],
903
968
  cr = {
904
969
  'row-reorder': self.orders.rows,
905
970
  'column-reorder': self.orders.columns,
@@ -931,14 +996,40 @@ export default function (self) {
931
996
  oIndex = cr[self.dragMode].indexOf(self.reorderObject[i]);
932
997
  tIndex = cr[self.dragMode].indexOf(self.reorderTarget[i]);
933
998
  if (self.dragMode === 'column-reorder') {
934
- cr[self.dragMode].splice(oIndex, 1);
935
- cr[self.dragMode].splice(tIndex, 0, self.reorderObject[i]);
999
+ var sortColumnIndices = [];
1000
+ var seletedColumnIndices = [];
1001
+ if (self.selections[0]) {
1002
+ self.selections[0].forEach(function (value) {
1003
+ sortColumnIndices.push(self.orders.columns[value]);
1004
+ });
1005
+ }
1006
+ var deleteCount = sortColumnIndices.length;
1007
+ cr[self.dragMode].splice(oIndex, deleteCount);
1008
+ if (tIndex > oIndex) tIndex = tIndex - (deleteCount - 1);
1009
+ for (var i = 0; i < sortColumnIndices.length; i++) {
1010
+ seletedColumnIndices.push(tIndex + i);
1011
+ cr[self.dragMode].splice(tIndex + i, 0, sortColumnIndices[i]);
1012
+ }
936
1013
  self.orders.columns = cr[self.dragMode];
1014
+ self.viewData.forEach(function (row, rowIndex) {
1015
+ self.selections[rowIndex] = seletedColumnIndices;
1016
+ });
937
1017
  } else {
938
- // self.orders.rows = cr[self.dragMode];
939
- odata = self.viewData[oIndex];
940
- self.viewData[oIndex] = self.viewData[tIndex];
941
- self.viewData[tIndex] = odata;
1018
+ var selectedRows = [];
1019
+ self.selections.forEach(function (row, rowIndex) {
1020
+ if (row) {
1021
+ selectedRows.push(row);
1022
+ odata.push(self.viewData[rowIndex]);
1023
+ }
1024
+ });
1025
+ self.viewData.splice(oIndex, odata.length);
1026
+ self.selections = [];
1027
+ if (tIndex > oIndex) tIndex = tIndex - (odata.length - 1);
1028
+ self.activeCell.rowIndex = tIndex;
1029
+ for (var i = 0; i < odata.length; i++) {
1030
+ self.viewData.splice(tIndex + i, 0, odata[i]);
1031
+ self.selections[tIndex + i] = selectedRows[i];
1032
+ }
942
1033
  }
943
1034
  self.resize();
944
1035
  self.setStorageData();
@@ -1000,7 +1091,12 @@ export default function (self) {
1000
1091
  ) {
1001
1092
  return;
1002
1093
  }
1003
- var pos = self.getLayerPos(e);
1094
+ var pos = self.getLayerPos(e),
1095
+ bm = self.style.gridBorderCollapse === 'collapse' ? 1 : 2,
1096
+ columnHeaderCellBorder = self.style.columnHeaderCellBorderWidth * bm,
1097
+ columnHeaderCellHeight = self.getColumnHeaderCellHeight(),
1098
+ rowHeaderCellWidth = self.getRowHeaderCellWidth();
1099
+
1004
1100
  self.ignoreNextClick = true;
1005
1101
  self.freezeMarkerPosition = pos;
1006
1102
  if (
@@ -1010,6 +1106,28 @@ export default function (self) {
1010
1106
  ) {
1011
1107
  self.scrollBox.scrollTop = 0;
1012
1108
  self.frozenRow = self.currentCell.rowIndex + 1;
1109
+ self.scrollBox.bar.v.y =
1110
+ columnHeaderCellHeight +
1111
+ columnHeaderCellBorder +
1112
+ self.scrollCache.y[self.frozenRow];
1113
+ self.scrollBox.box.v.y =
1114
+ columnHeaderCellHeight +
1115
+ columnHeaderCellBorder +
1116
+ self.scrollCache.y[self.frozenRow];
1117
+ var dataHeight = self.scrollCache.y[self.scrollCache.y.length - 1];
1118
+ self.scrollBox.heightBoxRatio =
1119
+ (self.scrollBox.height -
1120
+ columnHeaderCellHeight -
1121
+ self.scrollCache.y[self.frozenRow]) /
1122
+ dataHeight;
1123
+ self.scrollBox.scrollBoxHeight =
1124
+ self.scrollBox.height * self.scrollBox.heightBoxRatio -
1125
+ self.style.scrollBarWidth;
1126
+ self.scrollBox.scrollBoxHeight = Math.max(
1127
+ self.scrollBox.scrollBoxHeight,
1128
+ self.style.scrollBarBoxMinSize,
1129
+ );
1130
+ self.scrollBox.box.v.height = self.scrollBox.scrollBoxHeight;
1013
1131
  }
1014
1132
  if (
1015
1133
  self.currentCell &&
@@ -1018,6 +1136,22 @@ export default function (self) {
1018
1136
  ) {
1019
1137
  self.scrollBox.scrollLeft = 0;
1020
1138
  self.frozenColumn = self.currentCell.columnIndex + 1;
1139
+ self.scrollBox.bar.h.x =
1140
+ rowHeaderCellWidth + self.scrollCache.x[self.frozenColumn - 1];
1141
+ self.scrollBox.box.h.x =
1142
+ rowHeaderCellWidth + self.scrollCache.x[self.frozenColumn - 1];
1143
+ var dataWidth = self.scrollCache.x[self.scrollCache.x.length - 1];
1144
+ self.scrollBox.widthBoxRatio =
1145
+ (self.scrollBox.width - self.scrollCache.x[self.frozenColumn - 1]) /
1146
+ dataWidth;
1147
+ self.scrollBox.scrollBoxWidth =
1148
+ self.scrollBox.width * self.scrollBox.widthBoxRatio -
1149
+ self.style.scrollBarWidth;
1150
+ self.scrollBox.scrollBoxWidth = Math.max(
1151
+ self.scrollBox.scrollBoxWidth,
1152
+ self.style.scrollBarBoxMinSize,
1153
+ );
1154
+ self.scrollBox.box.h.width = self.scrollBox.scrollBoxWidth;
1021
1155
  }
1022
1156
  if (
1023
1157
  Math.abs(pos.x) > self.attributes.reorderDeadZone ||
@@ -1084,7 +1218,12 @@ export default function (self) {
1084
1218
  !freeze &&
1085
1219
  !resize
1086
1220
  ) {
1087
- self.selections = [];
1221
+ if (
1222
+ !(self.dragMode == 'row-reorder' && self.isMultiRowsSelected) &&
1223
+ !(self.currentCell.hovered && self.hovers.onFilterButton)
1224
+ ) {
1225
+ self.selections = [];
1226
+ }
1088
1227
  }
1089
1228
  if (self.dragStartObject.isGrid) {
1090
1229
  return;
@@ -1175,10 +1314,11 @@ export default function (self) {
1175
1314
  self.draggingItem = self.dragStartObject;
1176
1315
  if (
1177
1316
  self.dragMode === 'column-reorder' &&
1178
- self.attributes.columnHeaderClickBehavior === 'select'
1317
+ !self.isMultiColumnsSelected(self.currentCell.header.index)
1179
1318
  ) {
1180
1319
  self.selectColumn(self.currentCell.header.index, ctrl, e.shiftKey);
1181
- self.draw();
1320
+ } else if (self.dragMode === 'row-reorder' && !self.isMultiRowsSelected) {
1321
+ self.selectRow(self.dragStartObject.rowIndex, ctrl, null);
1182
1322
  }
1183
1323
  document.body.addEventListener('mousemove', self.dragReorder, false);
1184
1324
  document.body.addEventListener('mouseup', self.stopDragReorder, false);
@@ -1187,14 +1327,9 @@ export default function (self) {
1187
1327
  };
1188
1328
  self.mouseup = function (e) {
1189
1329
  clearTimeout(self.scrollTimer);
1190
- var ctrl = e.ctrlKey || e.metaKey;
1191
1330
  self.cellBoundaryCrossed = true;
1192
1331
  self.rowBoundaryCrossed = true;
1193
1332
  self.columnBoundaryCrossed = true;
1194
- if (self.draggingItem) {
1195
- self.selectColumn(self.currentCell.header.index, ctrl, e.shiftKey);
1196
- self.draw();
1197
- }
1198
1333
  self.selecting = undefined;
1199
1334
  self.draggingItem = undefined;
1200
1335
  self.dragStartObject = undefined;
@@ -1470,7 +1605,10 @@ export default function (self) {
1470
1605
  self.currentCell.style === 'cornerCell'
1471
1606
  ) {
1472
1607
  self.autosize();
1473
- } else if (['cell', 'activeCell'].indexOf(self.currentCell.style) !== -1) {
1608
+ } else if (
1609
+ ['cell', 'activeCell'].includes(self.currentCell.style) &&
1610
+ !self.hovers.onFilterButton
1611
+ ) {
1474
1612
  self.beginEditAt(self.currentCell.columnIndex, self.currentCell.rowIndex);
1475
1613
  }
1476
1614
  };
@@ -1740,6 +1878,7 @@ export default function (self) {
1740
1878
  firstRowKeys,
1741
1879
  isNeat = true; // Selected like [[0, 1], [0, 1]] of [[0, 3]] is neat; Selected like [[0, 1], [1, 2]] is untidy
1742
1880
  function htmlSafe(v) {
1881
+ if (typeof v === 'number') return v;
1743
1882
  return v.replace(/</g, '&lt;').replace(/>/g, '&gt;');
1744
1883
  }
1745
1884
  s.forEach(function (column, columnIndex) {
@@ -1753,8 +1892,8 @@ export default function (self) {
1753
1892
  if (!firstRowKeys) firstRowKeys = Object.keys(row);
1754
1893
  if (isNeat && rowKeys.length !== firstRowKeys.length) isNeat = false;
1755
1894
  sSorted.forEach(function (column, columnIndex) {
1756
- if (rowKeys.indexOf(column.name) < 0) {
1757
- if (firstRowKeys.indexOf(column.name) < 0) {
1895
+ if (rowKeys.indexOf(String(column.name)) < 0) {
1896
+ if (firstRowKeys.indexOf(String(column.name)) < 0) {
1758
1897
  return;
1759
1898
  } else if (isNeat) {
1760
1899
  isNeat = false;
package/lib/intf.js CHANGED
@@ -61,6 +61,14 @@ export default function (self, ctor) {
61
61
  trees: {},
62
62
  };
63
63
  self.selections = [];
64
+ self.filterable = {
65
+ rows: [],
66
+ columns: [],
67
+ };
68
+ self.selectedFilterButton = {
69
+ columnIndex: -1,
70
+ rowIndex: -1,
71
+ };
64
72
  self.hovers = {};
65
73
  self.attributes = {};
66
74
  self.style = {};
@@ -88,6 +96,7 @@ export default function (self, ctor) {
88
96
  self.eventNames = [
89
97
  'afterdraw',
90
98
  'afterrendercell',
99
+ 'afterrenderfilterbutton',
91
100
  'attributechanged',
92
101
  'beforebeginedit',
93
102
  'beforecreatecellgrid',
@@ -95,6 +104,7 @@ export default function (self, ctor) {
95
104
  'beforeendedit',
96
105
  'beforerendercell',
97
106
  'beforerendercellgrid',
107
+ 'beforerenderfilterbutton',
98
108
  'beginedit',
99
109
  'cellmouseout',
100
110
  'cellmouseover',
@@ -755,6 +765,7 @@ export default function (self, ctor) {
755
765
  self.intf.clearChangeLog = self.clearChangeLog;
756
766
  self.intf.gotoCell = self.gotoCell;
757
767
  self.intf.gotoRow = self.gotoRow;
768
+ self.intf.addButton = self.addButton;
758
769
  self.intf.getHeaderByName = self.getHeaderByName;
759
770
  self.intf.findColumnScrollLeft = self.findColumnScrollLeft;
760
771
  self.intf.findRowScrollTop = self.findRowScrollTop;
@@ -1534,6 +1545,9 @@ export default function (self, ctor) {
1534
1545
  if (!preventScrollEvent) {
1535
1546
  self.scroll();
1536
1547
  }
1548
+ if (self.button) {
1549
+ self.moveButtonPos();
1550
+ }
1537
1551
  }
1538
1552
  function setScrollLeft(value, preventScrollEvent) {
1539
1553
  if (isNaN(value)) {
@@ -1552,6 +1566,9 @@ export default function (self, ctor) {
1552
1566
  if (!preventScrollEvent) {
1553
1567
  self.scroll();
1554
1568
  }
1569
+ if (self.button) {
1570
+ self.moveButtonPos();
1571
+ }
1555
1572
  }
1556
1573
  self.scrollBox.toString = function () {
1557
1574
  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
  ];