handsontable 15.2.0 → 15.3.0-next-6f5f494-20250424
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/3rdparty/walkontable/src/cell/range.js +14 -0
- package/3rdparty/walkontable/src/cell/range.mjs +14 -0
- package/3rdparty/walkontable/src/core/_base.js +2 -2
- package/3rdparty/walkontable/src/core/_base.mjs +3 -3
- package/3rdparty/walkontable/src/overlay/_base.js +0 -2
- package/3rdparty/walkontable/src/overlay/_base.mjs +0 -2
- package/3rdparty/walkontable/src/overlay/bottom.js +9 -6
- package/3rdparty/walkontable/src/overlay/bottom.mjs +9 -6
- package/3rdparty/walkontable/src/overlay/inlineStart.js +8 -5
- package/3rdparty/walkontable/src/overlay/inlineStart.mjs +8 -5
- package/3rdparty/walkontable/src/overlay/top.js +11 -6
- package/3rdparty/walkontable/src/overlay/top.mjs +11 -6
- package/3rdparty/walkontable/src/overlays.js +15 -11
- package/3rdparty/walkontable/src/overlays.mjs +15 -11
- package/3rdparty/walkontable/src/renderer/rowHeaders.js +4 -1
- package/3rdparty/walkontable/src/renderer/rowHeaders.mjs +4 -1
- package/3rdparty/walkontable/src/selection/border/border.js +5 -0
- package/3rdparty/walkontable/src/selection/border/border.mjs +5 -0
- package/3rdparty/walkontable/src/table/mixin/stickyColumnsStart.js +3 -4
- package/3rdparty/walkontable/src/table/mixin/stickyColumnsStart.mjs +3 -4
- package/3rdparty/walkontable/src/table/mixin/stickyRowsBottom.js +8 -10
- package/3rdparty/walkontable/src/table/mixin/stickyRowsBottom.mjs +8 -10
- package/3rdparty/walkontable/src/table/mixin/stickyRowsTop.js +3 -4
- package/3rdparty/walkontable/src/table/mixin/stickyRowsTop.mjs +3 -4
- package/3rdparty/walkontable/src/table.js +5 -2
- package/3rdparty/walkontable/src/table.mjs +5 -2
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.js +0 -2
- package/3rdparty/walkontable/src/utils/orderView/viewDiffer/viewOrder.mjs +0 -2
- package/CHANGELOG.md +45 -1
- package/README.md +1 -1
- package/base.js +2 -2
- package/base.mjs +2 -2
- package/core/focusCatcher/focusDetector.js +1 -1
- package/core/focusCatcher/focusDetector.mjs +2 -2
- package/core/hooks/constants.js +8 -0
- package/core/hooks/constants.mjs +8 -0
- package/core/hooks/index.d.ts +1 -0
- package/core/viewportScroll/scrollStrategies/columnHeaderScroll.js +7 -5
- package/core/viewportScroll/scrollStrategies/columnHeaderScroll.mjs +7 -5
- package/core/viewportScroll/scrollStrategies/focusScroll.js +8 -1
- package/core/viewportScroll/scrollStrategies/focusScroll.mjs +8 -1
- package/core/viewportScroll/scrollStrategies/multipleScroll.js +13 -1
- package/core/viewportScroll/scrollStrategies/multipleScroll.mjs +13 -1
- package/core/viewportScroll/scrollStrategies/noncontiguousScroll.js +13 -1
- package/core/viewportScroll/scrollStrategies/noncontiguousScroll.mjs +13 -1
- package/core/viewportScroll/scrollStrategies/rowHeaderScroll.js +7 -5
- package/core/viewportScroll/scrollStrategies/rowHeaderScroll.mjs +7 -5
- package/core/viewportScroll/scrollStrategies/singleScroll.js +8 -4
- package/core/viewportScroll/scrollStrategies/singleScroll.mjs +8 -4
- package/core/viewportScroll/utils.js +111 -0
- package/core/viewportScroll/utils.mjs +106 -0
- package/core.d.ts +2 -3
- package/core.js +125 -71
- package/core.mjs +126 -72
- package/dataMap/dataMap.js +0 -7
- package/dataMap/dataMap.mjs +0 -7
- package/dataMap/metaManager/index.js +8 -9
- package/dataMap/metaManager/index.mjs +8 -9
- package/dataMap/metaManager/mods/dynamicCellMeta.js +4 -1
- package/dataMap/metaManager/mods/dynamicCellMeta.mjs +4 -1
- package/dist/handsontable.css +4 -15
- package/dist/handsontable.full.css +4 -17
- package/dist/handsontable.full.js +4573 -4013
- package/dist/handsontable.full.min.css +3 -3
- package/dist/handsontable.full.min.js +148 -148
- package/dist/handsontable.js +4287 -3730
- package/dist/handsontable.min.css +3 -3
- package/dist/handsontable.min.js +19 -19
- package/editorManager.js +1 -7
- package/editorManager.mjs +1 -7
- package/editors/autocompleteEditor/autocompleteEditor.js +31 -7
- package/editors/autocompleteEditor/autocompleteEditor.mjs +31 -7
- package/focusManager.js +4 -2
- package/focusManager.mjs +4 -2
- package/helpers/browser.js +1 -1
- package/helpers/browser.mjs +1 -1
- package/helpers/dom/element.d.ts +1 -0
- package/helpers/dom/element.js +20 -0
- package/helpers/dom/element.mjs +19 -0
- package/helpers/mixed.js +2 -2
- package/helpers/mixed.mjs +2 -2
- package/helpers/object.js +3 -0
- package/helpers/object.mjs +3 -0
- package/package.json +1 -1
- package/plugins/autoColumnSize/autoColumnSize.js +38 -17
- package/plugins/autoColumnSize/autoColumnSize.mjs +38 -17
- package/plugins/autoRowSize/autoRowSize.js +12 -6
- package/plugins/autoRowSize/autoRowSize.mjs +12 -6
- package/plugins/columnSorting/columnSorting.js +0 -4
- package/plugins/columnSorting/columnSorting.mjs +0 -4
- package/plugins/comments/comments.js +1 -0
- package/plugins/comments/comments.mjs +1 -0
- package/plugins/contextMenu/menu/defaultShortcutsList.js +2 -2
- package/plugins/contextMenu/menu/defaultShortcutsList.mjs +2 -2
- package/plugins/contextMenu/menu/menu.js +1 -0
- package/plugins/contextMenu/menu/menu.mjs +1 -0
- package/plugins/contextMenu/menu/positioner.js +10 -2
- package/plugins/contextMenu/menu/positioner.mjs +10 -2
- package/plugins/contextMenu/predefinedItems/redo.js +3 -3
- package/plugins/contextMenu/predefinedItems/redo.mjs +3 -3
- package/plugins/contextMenu/predefinedItems/undo.js +3 -3
- package/plugins/contextMenu/predefinedItems/undo.mjs +3 -3
- package/plugins/copyPaste/copyPaste.js +12 -9
- package/plugins/copyPaste/copyPaste.mjs +12 -9
- package/plugins/copyPaste/pasteEvent.js +3 -0
- package/plugins/copyPaste/pasteEvent.mjs +3 -0
- package/plugins/exportFile/exportFile.d.ts +1 -0
- package/plugins/exportFile/exportFile.js +2 -1
- package/plugins/exportFile/exportFile.mjs +2 -1
- package/plugins/exportFile/types/csv.js +76 -11
- package/plugins/exportFile/types/csv.mjs +76 -11
- package/plugins/filters/filters.js +24 -23
- package/plugins/filters/filters.mjs +24 -23
- package/plugins/filters/ui/multipleSelect.js +7 -1
- package/plugins/filters/ui/multipleSelect.mjs +7 -1
- package/plugins/formulas/formulas.d.ts +1 -1
- package/plugins/formulas/formulas.js +57 -60
- package/plugins/formulas/formulas.mjs +59 -62
- package/plugins/formulas/indexSyncer/axisSyncer.js +5 -1
- package/plugins/formulas/indexSyncer/axisSyncer.mjs +5 -1
- package/plugins/hiddenColumns/hiddenColumns.js +1 -1
- package/plugins/hiddenColumns/hiddenColumns.mjs +1 -1
- package/plugins/hiddenRows/hiddenRows.js +1 -1
- package/plugins/hiddenRows/hiddenRows.mjs +1 -1
- package/plugins/manualColumnResize/manualColumnResize.js +4 -6
- package/plugins/manualColumnResize/manualColumnResize.mjs +4 -6
- package/plugins/manualRowResize/manualRowResize.js +4 -6
- package/plugins/manualRowResize/manualRowResize.mjs +4 -6
- package/plugins/mergeCells/mergeCells.js +10 -30
- package/plugins/mergeCells/mergeCells.mjs +10 -30
- package/plugins/mergeCells/renderer.js +15 -0
- package/plugins/mergeCells/renderer.mjs +15 -0
- package/plugins/mergeCells/utils.js +31 -0
- package/plugins/mergeCells/utils.mjs +27 -0
- package/plugins/nestedRows/data/dataManager.js +2 -2
- package/plugins/nestedRows/data/dataManager.mjs +2 -2
- package/plugins/undoRedo/actions/index.js +0 -2
- package/plugins/undoRedo/actions/index.mjs +0 -2
- package/plugins/undoRedo/actions/removeColumn.js +19 -14
- package/plugins/undoRedo/actions/removeColumn.mjs +19 -14
- package/plugins/undoRedo/actions/removeRow.js +12 -4
- package/plugins/undoRedo/actions/removeRow.mjs +12 -4
- package/selection/selection.js +3 -1
- package/selection/selection.mjs +3 -1
- package/shortcutContexts/commands/extendCellsSelection/down.js +7 -2
- package/shortcutContexts/commands/extendCellsSelection/down.mjs +7 -2
- package/shortcutContexts/commands/extendCellsSelection/downByViewportHeight.js +8 -2
- package/shortcutContexts/commands/extendCellsSelection/downByViewportHeight.mjs +8 -2
- package/shortcutContexts/commands/extendCellsSelection/left.js +7 -2
- package/shortcutContexts/commands/extendCellsSelection/left.mjs +7 -2
- package/shortcutContexts/commands/extendCellsSelection/right.js +7 -2
- package/shortcutContexts/commands/extendCellsSelection/right.mjs +7 -2
- package/shortcutContexts/commands/extendCellsSelection/toColumns.js +7 -2
- package/shortcutContexts/commands/extendCellsSelection/toColumns.mjs +7 -2
- package/shortcutContexts/commands/extendCellsSelection/toMostBottom.js +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostBottom.mjs +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostInlineEnd.js +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostInlineEnd.mjs +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostInlineStart.js +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostInlineStart.mjs +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostLeft.js +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostLeft.mjs +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostRight.js +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostRight.mjs +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostTop.js +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toMostTop.mjs +3 -1
- package/shortcutContexts/commands/extendCellsSelection/toRows.js +7 -2
- package/shortcutContexts/commands/extendCellsSelection/toRows.mjs +7 -2
- package/shortcutContexts/commands/extendCellsSelection/up.js +7 -2
- package/shortcutContexts/commands/extendCellsSelection/up.mjs +7 -2
- package/shortcutContexts/commands/extendCellsSelection/upByViewportHeight.js +8 -2
- package/shortcutContexts/commands/extendCellsSelection/upByViewportHeight.mjs +8 -2
- package/shortcutContexts/commands/index.js +0 -2
- package/shortcutContexts/commands/index.mjs +0 -2
- package/shortcutContexts/commands/moveCellSelection/down.js +2 -0
- package/shortcutContexts/commands/moveCellSelection/down.mjs +2 -0
- package/shortcutContexts/commands/moveCellSelection/downByViewportHeight.js +6 -1
- package/shortcutContexts/commands/moveCellSelection/downByViewportHeight.mjs +6 -1
- package/shortcutContexts/commands/moveCellSelection/inlineEnd.js +8 -3
- package/shortcutContexts/commands/moveCellSelection/inlineEnd.mjs +8 -3
- package/shortcutContexts/commands/moveCellSelection/inlineStart.js +8 -3
- package/shortcutContexts/commands/moveCellSelection/inlineStart.mjs +8 -3
- package/shortcutContexts/commands/moveCellSelection/left.js +6 -1
- package/shortcutContexts/commands/moveCellSelection/left.mjs +6 -1
- package/shortcutContexts/commands/moveCellSelection/right.js +6 -1
- package/shortcutContexts/commands/moveCellSelection/right.mjs +6 -1
- package/shortcutContexts/commands/moveCellSelection/toMostBottom.js +4 -1
- package/shortcutContexts/commands/moveCellSelection/toMostBottom.mjs +4 -1
- package/shortcutContexts/commands/moveCellSelection/toMostBottomInlineEnd.js +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostBottomInlineEnd.mjs +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostInlineEnd.js +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostInlineEnd.mjs +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostInlineStart.js +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostInlineStart.mjs +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostLeft.js +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostLeft.mjs +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostRight.js +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostRight.mjs +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostTop.js +6 -1
- package/shortcutContexts/commands/moveCellSelection/toMostTop.mjs +6 -1
- package/shortcutContexts/commands/moveCellSelection/toMostTopInlineStart.js +2 -0
- package/shortcutContexts/commands/moveCellSelection/toMostTopInlineStart.mjs +2 -0
- package/shortcutContexts/commands/moveCellSelection/up.js +2 -0
- package/shortcutContexts/commands/moveCellSelection/up.mjs +2 -0
- package/shortcutContexts/commands/moveCellSelection/upByViewportHeight.js +6 -1
- package/shortcutContexts/commands/moveCellSelection/upByViewportHeight.mjs +6 -1
- package/shortcutContexts/commands/selectAllCells.js +7 -2
- package/shortcutContexts/commands/selectAllCells.mjs +7 -2
- package/shortcutContexts/commands/selectAllCellsAndHeaders.js +7 -2
- package/shortcutContexts/commands/selectAllCellsAndHeaders.mjs +7 -2
- package/shortcutContexts/index.js +2 -2
- package/shortcutContexts/index.mjs +0 -2
- package/styles/handsontable.css +15 -17
- package/styles/handsontable.min.css +3 -3
- package/styles/ht-theme-horizon.css +2 -2
- package/styles/ht-theme-horizon.min.css +2 -2
- package/styles/ht-theme-main.css +2 -2
- package/styles/ht-theme-main.min.css +2 -2
- package/tableView.js +5 -8
- package/tableView.mjs +5 -8
- package/translations/indexMapper.js +0 -1
- package/translations/indexMapper.mjs +0 -1
- package/utils/ghostTable.js +3 -0
- package/utils/ghostTable.mjs +3 -0
@@ -113,6 +113,7 @@ const ROW_WIDTHS_MAP_NAME = 'autoRowSize';
|
|
113
113
|
*/
|
114
114
|
/* eslint-enable jsdoc/require-description-complete-sentence */
|
115
115
|
var _visualRowsToRefresh = /*#__PURE__*/new WeakMap();
|
116
|
+
var _isInitialized = /*#__PURE__*/new WeakMap();
|
116
117
|
var _AutoRowSize_brand = /*#__PURE__*/new WeakSet();
|
117
118
|
class AutoRowSize extends _base.BasePlugin {
|
118
119
|
static get PLUGIN_KEY() {
|
@@ -215,6 +216,12 @@ class AutoRowSize extends _base.BasePlugin {
|
|
215
216
|
* @type {number[]}
|
216
217
|
*/
|
217
218
|
_classPrivateFieldInitSpec(this, _visualRowsToRefresh, []);
|
219
|
+
/**
|
220
|
+
* `true` value indicates that the #onInit() function has been already called.
|
221
|
+
*
|
222
|
+
* @type {boolean}
|
223
|
+
*/
|
224
|
+
_classPrivateFieldInitSpec(this, _isInitialized, false);
|
218
225
|
this.hot.rowIndexMapper.registerMap(ROW_WIDTHS_MAP_NAME, this.rowHeightsMap);
|
219
226
|
|
220
227
|
// Leave the listener active to allow auto-sizing the rows when the plugin is disabled.
|
@@ -297,7 +304,7 @@ class AutoRowSize extends _base.BasePlugin {
|
|
297
304
|
if (firstVisibleRow === -1 || lastVisibleRow === -1) {
|
298
305
|
return;
|
299
306
|
}
|
300
|
-
const overwriteCache = this.hot.
|
307
|
+
const overwriteCache = this.hot.forceFullRender;
|
301
308
|
this.calculateRowsHeight({
|
302
309
|
from: firstVisibleRow,
|
303
310
|
to: lastVisibleRow
|
@@ -398,11 +405,6 @@ class AutoRowSize extends _base.BasePlugin {
|
|
398
405
|
|
399
406
|
// @TODO Should call once per render cycle, currently fired separately in different plugins
|
400
407
|
this.hot.view.adjustElementsSize();
|
401
|
-
|
402
|
-
// tmp
|
403
|
-
if (this.hot.view._wt.wtOverlays.inlineStartOverlay.needFullRender) {
|
404
|
-
this.hot.view._wt.wtOverlays.inlineStartOverlay.clone.draw();
|
405
|
-
}
|
406
408
|
}
|
407
409
|
};
|
408
410
|
const syncLimit = this.getSyncCalculationLimit();
|
@@ -645,6 +647,7 @@ function _onBeforeChange(changes) {
|
|
645
647
|
*/
|
646
648
|
function _onInit() {
|
647
649
|
this.recalculateAllRowsHeight();
|
650
|
+
_classPrivateFieldSet(_isInitialized, this, true);
|
648
651
|
}
|
649
652
|
/**
|
650
653
|
* After formulas values updated listener.
|
@@ -652,6 +655,9 @@ function _onInit() {
|
|
652
655
|
* @param {Array} changes An array of modified data.
|
653
656
|
*/
|
654
657
|
function _onAfterFormulasValuesUpdate(changes) {
|
658
|
+
if (!_classPrivateFieldGet(_isInitialized, this)) {
|
659
|
+
return;
|
660
|
+
}
|
655
661
|
const changedRows = changes.reduce((acc, change) => {
|
656
662
|
var _change$address;
|
657
663
|
const physicalRow = (_change$address = change.address) === null || _change$address === void 0 ? void 0 : _change$address.row;
|
@@ -109,6 +109,7 @@ const ROW_WIDTHS_MAP_NAME = 'autoRowSize';
|
|
109
109
|
*/
|
110
110
|
/* eslint-enable jsdoc/require-description-complete-sentence */
|
111
111
|
var _visualRowsToRefresh = /*#__PURE__*/new WeakMap();
|
112
|
+
var _isInitialized = /*#__PURE__*/new WeakMap();
|
112
113
|
var _AutoRowSize_brand = /*#__PURE__*/new WeakSet();
|
113
114
|
export class AutoRowSize extends BasePlugin {
|
114
115
|
static get PLUGIN_KEY() {
|
@@ -211,6 +212,12 @@ export class AutoRowSize extends BasePlugin {
|
|
211
212
|
* @type {number[]}
|
212
213
|
*/
|
213
214
|
_classPrivateFieldInitSpec(this, _visualRowsToRefresh, []);
|
215
|
+
/**
|
216
|
+
* `true` value indicates that the #onInit() function has been already called.
|
217
|
+
*
|
218
|
+
* @type {boolean}
|
219
|
+
*/
|
220
|
+
_classPrivateFieldInitSpec(this, _isInitialized, false);
|
214
221
|
this.hot.rowIndexMapper.registerMap(ROW_WIDTHS_MAP_NAME, this.rowHeightsMap);
|
215
222
|
|
216
223
|
// Leave the listener active to allow auto-sizing the rows when the plugin is disabled.
|
@@ -293,7 +300,7 @@ export class AutoRowSize extends BasePlugin {
|
|
293
300
|
if (firstVisibleRow === -1 || lastVisibleRow === -1) {
|
294
301
|
return;
|
295
302
|
}
|
296
|
-
const overwriteCache = this.hot.
|
303
|
+
const overwriteCache = this.hot.forceFullRender;
|
297
304
|
this.calculateRowsHeight({
|
298
305
|
from: firstVisibleRow,
|
299
306
|
to: lastVisibleRow
|
@@ -394,11 +401,6 @@ export class AutoRowSize extends BasePlugin {
|
|
394
401
|
|
395
402
|
// @TODO Should call once per render cycle, currently fired separately in different plugins
|
396
403
|
this.hot.view.adjustElementsSize();
|
397
|
-
|
398
|
-
// tmp
|
399
|
-
if (this.hot.view._wt.wtOverlays.inlineStartOverlay.needFullRender) {
|
400
|
-
this.hot.view._wt.wtOverlays.inlineStartOverlay.clone.draw();
|
401
|
-
}
|
402
404
|
}
|
403
405
|
};
|
404
406
|
const syncLimit = this.getSyncCalculationLimit();
|
@@ -640,6 +642,7 @@ function _onBeforeChange(changes) {
|
|
640
642
|
*/
|
641
643
|
function _onInit() {
|
642
644
|
this.recalculateAllRowsHeight();
|
645
|
+
_classPrivateFieldSet(_isInitialized, this, true);
|
643
646
|
}
|
644
647
|
/**
|
645
648
|
* After formulas values updated listener.
|
@@ -647,6 +650,9 @@ function _onInit() {
|
|
647
650
|
* @param {Array} changes An array of modified data.
|
648
651
|
*/
|
649
652
|
function _onAfterFormulasValuesUpdate(changes) {
|
653
|
+
if (!_classPrivateFieldGet(_isInitialized, this)) {
|
654
|
+
return;
|
655
|
+
}
|
650
656
|
const changedRows = changes.reduce((acc, change) => {
|
651
657
|
var _change$address;
|
652
658
|
const physicalRow = (_change$address = change.address) === null || _change$address === void 0 ? void 0 : _change$address.row;
|
@@ -304,10 +304,6 @@ class ColumnSorting extends _base.BasePlugin {
|
|
304
304
|
this.hot.runHooks('afterColumnSort', currentSortConfig, sortPossible ? destinationSortConfigs : currentSortConfig, sortPossible);
|
305
305
|
if (sortPossible) {
|
306
306
|
this.hot.render();
|
307
|
-
// TODO: Workaround? This triggers fast redraw. One test won't pass after removal.
|
308
|
-
// It should be refactored / described.
|
309
|
-
this.hot.forceFullRender = false;
|
310
|
-
this.hot.view.render();
|
311
307
|
}
|
312
308
|
}
|
313
309
|
|
@@ -301,10 +301,6 @@ export class ColumnSorting extends BasePlugin {
|
|
301
301
|
this.hot.runHooks('afterColumnSort', currentSortConfig, sortPossible ? destinationSortConfigs : currentSortConfig, sortPossible);
|
302
302
|
if (sortPossible) {
|
303
303
|
this.hot.render();
|
304
|
-
// TODO: Workaround? This triggers fast redraw. One test won't pass after removal.
|
305
|
-
// It should be refactored / described.
|
306
|
-
this.hot.forceFullRender = false;
|
307
|
-
this.hot.view.render();
|
308
304
|
}
|
309
305
|
}
|
310
306
|
|
@@ -234,6 +234,7 @@ class Comments extends _base.BasePlugin {
|
|
234
234
|
this.addHook('afterScroll', () => _assertClassBrand(_Comments_brand, this, _onAfterScroll).call(this));
|
235
235
|
this.addHook('afterBeginEditing', () => this.hide());
|
236
236
|
this.addHook('afterDocumentKeyDown', event => _assertClassBrand(_Comments_brand, this, _onAfterDocumentKeyDown).call(this, event));
|
237
|
+
this.addHook('beforeCompositionStart', event => _assertClassBrand(_Comments_brand, this, _onAfterDocumentKeyDown).call(this, event));
|
237
238
|
this.addHook('afterSetTheme', function () {
|
238
239
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
239
240
|
args[_key2] = arguments[_key2];
|
@@ -230,6 +230,7 @@ export class Comments extends BasePlugin {
|
|
230
230
|
this.addHook('afterScroll', () => _assertClassBrand(_Comments_brand, this, _onAfterScroll).call(this));
|
231
231
|
this.addHook('afterBeginEditing', () => this.hide());
|
232
232
|
this.addHook('afterDocumentKeyDown', event => _assertClassBrand(_Comments_brand, this, _onAfterDocumentKeyDown).call(this, event));
|
233
|
+
this.addHook('beforeCompositionStart', event => _assertClassBrand(_Comments_brand, this, _onAfterDocumentKeyDown).call(this, event));
|
233
234
|
this.addHook('afterSetTheme', function () {
|
234
235
|
for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
235
236
|
args[_key2] = arguments[_key2];
|
@@ -39,7 +39,7 @@ function createDefaultShortcutsList(menu) {
|
|
39
39
|
keys: [['ArrowUp']],
|
40
40
|
callback: () => menu.getNavigator().toPreviousItem()
|
41
41
|
}, {
|
42
|
-
keys: [['ArrowRight']],
|
42
|
+
keys: [[hot.isRtl() ? 'ArrowLeft' : 'ArrowRight']],
|
43
43
|
callback: () => {
|
44
44
|
const selection = hotMenu.getSelectedLast();
|
45
45
|
if (selection) {
|
@@ -50,7 +50,7 @@ function createDefaultShortcutsList(menu) {
|
|
50
50
|
}
|
51
51
|
}
|
52
52
|
}, {
|
53
|
-
keys: [['ArrowLeft']],
|
53
|
+
keys: [[hot.isRtl() ? 'ArrowRight' : 'ArrowLeft']],
|
54
54
|
callback: () => {
|
55
55
|
const selection = hotMenu.getSelectedLast();
|
56
56
|
if (selection && menu.isSubMenu()) {
|
@@ -35,7 +35,7 @@ export function createDefaultShortcutsList(menu) {
|
|
35
35
|
keys: [['ArrowUp']],
|
36
36
|
callback: () => menu.getNavigator().toPreviousItem()
|
37
37
|
}, {
|
38
|
-
keys: [['ArrowRight']],
|
38
|
+
keys: [[hot.isRtl() ? 'ArrowLeft' : 'ArrowRight']],
|
39
39
|
callback: () => {
|
40
40
|
const selection = hotMenu.getSelectedLast();
|
41
41
|
if (selection) {
|
@@ -46,7 +46,7 @@ export function createDefaultShortcutsList(menu) {
|
|
46
46
|
}
|
47
47
|
}
|
48
48
|
}, {
|
49
|
-
keys: [['ArrowLeft']],
|
49
|
+
keys: [[hot.isRtl() ? 'ArrowRight' : 'ArrowLeft']],
|
50
50
|
callback: () => {
|
51
51
|
const selection = hotMenu.getSelectedLast();
|
52
52
|
if (selection && menu.isSubMenu()) {
|
@@ -293,6 +293,7 @@ class Menu {
|
|
293
293
|
layoutDirection: this.hot.isRtl() ? 'rtl' : 'ltr',
|
294
294
|
ariaTags: false,
|
295
295
|
themeName: this.hot.getCurrentThemeName(),
|
296
|
+
beforeRefreshDimensions: () => false,
|
296
297
|
beforeOnCellMouseOver: (event, coords) => {
|
297
298
|
_classPrivateFieldGet(_navigator, this).setCurrentPage(coords.row);
|
298
299
|
},
|
@@ -289,6 +289,7 @@ export class Menu {
|
|
289
289
|
layoutDirection: this.hot.isRtl() ? 'rtl' : 'ltr',
|
290
290
|
ariaTags: false,
|
291
291
|
themeName: this.hot.getCurrentThemeName(),
|
292
|
+
beforeRefreshDimensions: () => false,
|
292
293
|
beforeOnCellMouseOver: (event, coords) => {
|
293
294
|
_classPrivateFieldGet(_navigator, this).setCurrentPage(coords.row);
|
294
295
|
},
|
@@ -143,7 +143,11 @@ class Positioner {
|
|
143
143
|
setPositionAboveCursor() {
|
144
144
|
let top = _classPrivateFieldGet(_offset, this).above + _classPrivateFieldGet(_cursor, this).top - _classPrivateFieldGet(_container, this).offsetHeight;
|
145
145
|
if (_classPrivateFieldGet(_parentContainer, this)) {
|
146
|
-
|
146
|
+
const rootWindow = _classPrivateFieldGet(_parentContainer, this).ownerDocument.defaultView;
|
147
|
+
const style = rootWindow.getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.ht_master'));
|
148
|
+
const paddingTop = Number.parseInt(style.paddingTop, 10);
|
149
|
+
const borderTop = Number.parseInt(style.borderTop, 10);
|
150
|
+
top = _classPrivateFieldGet(_cursor, this).top + _classPrivateFieldGet(_cursor, this).cellHeight - _classPrivateFieldGet(_container, this).scrollHeight + paddingTop + borderTop;
|
147
151
|
}
|
148
152
|
_classPrivateFieldGet(_container, this).style.top = `${top}px`;
|
149
153
|
}
|
@@ -154,7 +158,11 @@ class Positioner {
|
|
154
158
|
setPositionBelowCursor() {
|
155
159
|
let top = _classPrivateFieldGet(_offset, this).below + _classPrivateFieldGet(_cursor, this).top + 1;
|
156
160
|
if (_classPrivateFieldGet(_parentContainer, this)) {
|
157
|
-
|
161
|
+
const rootWindow = _classPrivateFieldGet(_parentContainer, this).ownerDocument.defaultView;
|
162
|
+
const style = rootWindow.getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.ht_master'));
|
163
|
+
const paddingTop = Number.parseInt(style.paddingTop, 10);
|
164
|
+
const borderTop = Number.parseInt(style.borderTop, 10);
|
165
|
+
top = _classPrivateFieldGet(_cursor, this).top - paddingTop - borderTop - 1;
|
158
166
|
}
|
159
167
|
_classPrivateFieldGet(_container, this).style.top = `${top}px`;
|
160
168
|
}
|
@@ -140,7 +140,11 @@ export class Positioner {
|
|
140
140
|
setPositionAboveCursor() {
|
141
141
|
let top = _classPrivateFieldGet(_offset, this).above + _classPrivateFieldGet(_cursor, this).top - _classPrivateFieldGet(_container, this).offsetHeight;
|
142
142
|
if (_classPrivateFieldGet(_parentContainer, this)) {
|
143
|
-
|
143
|
+
const rootWindow = _classPrivateFieldGet(_parentContainer, this).ownerDocument.defaultView;
|
144
|
+
const style = rootWindow.getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.ht_master'));
|
145
|
+
const paddingTop = Number.parseInt(style.paddingTop, 10);
|
146
|
+
const borderTop = Number.parseInt(style.borderTop, 10);
|
147
|
+
top = _classPrivateFieldGet(_cursor, this).top + _classPrivateFieldGet(_cursor, this).cellHeight - _classPrivateFieldGet(_container, this).scrollHeight + paddingTop + borderTop;
|
144
148
|
}
|
145
149
|
_classPrivateFieldGet(_container, this).style.top = `${top}px`;
|
146
150
|
}
|
@@ -151,7 +155,11 @@ export class Positioner {
|
|
151
155
|
setPositionBelowCursor() {
|
152
156
|
let top = _classPrivateFieldGet(_offset, this).below + _classPrivateFieldGet(_cursor, this).top + 1;
|
153
157
|
if (_classPrivateFieldGet(_parentContainer, this)) {
|
154
|
-
|
158
|
+
const rootWindow = _classPrivateFieldGet(_parentContainer, this).ownerDocument.defaultView;
|
159
|
+
const style = rootWindow.getComputedStyle(_classPrivateFieldGet(_parentContainer, this).querySelector('.ht_master'));
|
160
|
+
const paddingTop = Number.parseInt(style.paddingTop, 10);
|
161
|
+
const borderTop = Number.parseInt(style.borderTop, 10);
|
162
|
+
top = _classPrivateFieldGet(_cursor, this).top - paddingTop - borderTop - 1;
|
155
163
|
}
|
156
164
|
_classPrivateFieldGet(_container, this).style.top = `${top}px`;
|
157
165
|
}
|
@@ -17,11 +17,11 @@ function redoItem() {
|
|
17
17
|
return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_REDO);
|
18
18
|
},
|
19
19
|
callback() {
|
20
|
-
this.redo();
|
20
|
+
this.getPlugin('undoRedo').redo();
|
21
21
|
},
|
22
22
|
hidden() {
|
23
|
-
const
|
24
|
-
return !
|
23
|
+
const undoRedoPlugin = this.getPlugin('undoRedo');
|
24
|
+
return !undoRedoPlugin || !undoRedoPlugin.isEnabled();
|
25
25
|
},
|
26
26
|
disabled() {
|
27
27
|
return !this.getPlugin('undoRedo').isRedoAvailable();
|
@@ -11,11 +11,11 @@ export default function redoItem() {
|
|
11
11
|
return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_REDO);
|
12
12
|
},
|
13
13
|
callback() {
|
14
|
-
this.redo();
|
14
|
+
this.getPlugin('undoRedo').redo();
|
15
15
|
},
|
16
16
|
hidden() {
|
17
|
-
const
|
18
|
-
return !
|
17
|
+
const undoRedoPlugin = this.getPlugin('undoRedo');
|
18
|
+
return !undoRedoPlugin || !undoRedoPlugin.isEnabled();
|
19
19
|
},
|
20
20
|
disabled() {
|
21
21
|
return !this.getPlugin('undoRedo').isRedoAvailable();
|
@@ -17,11 +17,11 @@ function undoItem() {
|
|
17
17
|
return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_UNDO);
|
18
18
|
},
|
19
19
|
callback() {
|
20
|
-
this.undo();
|
20
|
+
this.getPlugin('undoRedo').undo();
|
21
21
|
},
|
22
22
|
hidden() {
|
23
|
-
const
|
24
|
-
return !
|
23
|
+
const undoRedoPlugin = this.getPlugin('undoRedo');
|
24
|
+
return !undoRedoPlugin || !undoRedoPlugin.isEnabled();
|
25
25
|
},
|
26
26
|
disabled() {
|
27
27
|
return !this.getPlugin('undoRedo').isUndoAvailable();
|
@@ -11,11 +11,11 @@ export default function undoItem() {
|
|
11
11
|
return this.getTranslatedPhrase(C.CONTEXTMENU_ITEMS_UNDO);
|
12
12
|
},
|
13
13
|
callback() {
|
14
|
-
this.undo();
|
14
|
+
this.getPlugin('undoRedo').undo();
|
15
15
|
},
|
16
16
|
hidden() {
|
17
|
-
const
|
18
|
-
return !
|
17
|
+
const undoRedoPlugin = this.getPlugin('undoRedo');
|
18
|
+
return !undoRedoPlugin || !undoRedoPlugin.isEnabled();
|
19
19
|
},
|
20
20
|
disabled() {
|
21
21
|
return !this.getPlugin('undoRedo').isUndoAvailable();
|
@@ -256,6 +256,9 @@ class CopyPaste extends _base.BasePlugin {
|
|
256
256
|
return _assertClassBrand(_CopyPaste_brand, _this, _onAfterSelection).call(_this, ...args);
|
257
257
|
});
|
258
258
|
this.addHook('afterSelectionEnd', () => _assertClassBrand(_CopyPaste_brand, this, _onAfterSelectionEnd).call(this));
|
259
|
+
|
260
|
+
// Events are attached to the document, not the root table element - as it should,
|
261
|
+
// for Chrome 133 and lower to copy/paste/cut work properly (#dev-2277).
|
259
262
|
this.eventManager.addEventListener(this.hot.rootDocument, 'copy', function () {
|
260
263
|
return _this.onCopy(...arguments);
|
261
264
|
});
|
@@ -562,10 +565,10 @@ class CopyPaste extends _base.BasePlugin {
|
|
562
565
|
* @private
|
563
566
|
*/
|
564
567
|
onCopy(event) {
|
565
|
-
|
568
|
+
const eventTarget = event.composedPath()[0];
|
566
569
|
const focusedElement = this.hot.getFocusManager().getRefocusElement();
|
567
|
-
const isHotInput =
|
568
|
-
if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || (0, _element.isHTMLElement)(
|
570
|
+
const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
|
571
|
+
if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || (0, _element.isHTMLElement)(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !(0, _element.isInternalElement)(eventTarget, this.hot.rootElement))) {
|
569
572
|
return;
|
570
573
|
}
|
571
574
|
event.preventDefault();
|
@@ -595,10 +598,10 @@ class CopyPaste extends _base.BasePlugin {
|
|
595
598
|
* @private
|
596
599
|
*/
|
597
600
|
onCut(event) {
|
598
|
-
|
601
|
+
const eventTarget = event.composedPath()[0];
|
599
602
|
const focusedElement = this.hot.getFocusManager().getRefocusElement();
|
600
|
-
const isHotInput =
|
601
|
-
if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || (0, _element.isHTMLElement)(
|
603
|
+
const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
|
604
|
+
if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || (0, _element.isHTMLElement)(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !(0, _element.isInternalElement)(eventTarget, this.hot.rootElement))) {
|
602
605
|
return;
|
603
606
|
}
|
604
607
|
event.preventDefault();
|
@@ -627,10 +630,10 @@ class CopyPaste extends _base.BasePlugin {
|
|
627
630
|
* @private
|
628
631
|
*/
|
629
632
|
onPaste(event) {
|
630
|
-
|
633
|
+
const eventTarget = event.composedPath()[0];
|
631
634
|
const focusedElement = this.hot.getFocusManager().getRefocusElement();
|
632
|
-
const isHotInput =
|
633
|
-
if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || (0, _element.isHTMLElement)(
|
635
|
+
const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
|
636
|
+
if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || (0, _element.isHTMLElement)(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !(0, _element.isInternalElement)(eventTarget, this.hot.rootElement))) {
|
634
637
|
return;
|
635
638
|
}
|
636
639
|
event.preventDefault();
|
@@ -252,6 +252,9 @@ export class CopyPaste extends BasePlugin {
|
|
252
252
|
return _assertClassBrand(_CopyPaste_brand, _this, _onAfterSelection).call(_this, ...args);
|
253
253
|
});
|
254
254
|
this.addHook('afterSelectionEnd', () => _assertClassBrand(_CopyPaste_brand, this, _onAfterSelectionEnd).call(this));
|
255
|
+
|
256
|
+
// Events are attached to the document, not the root table element - as it should,
|
257
|
+
// for Chrome 133 and lower to copy/paste/cut work properly (#dev-2277).
|
255
258
|
this.eventManager.addEventListener(this.hot.rootDocument, 'copy', function () {
|
256
259
|
return _this.onCopy(...arguments);
|
257
260
|
});
|
@@ -558,10 +561,10 @@ export class CopyPaste extends BasePlugin {
|
|
558
561
|
* @private
|
559
562
|
*/
|
560
563
|
onCopy(event) {
|
561
|
-
|
564
|
+
const eventTarget = event.composedPath()[0];
|
562
565
|
const focusedElement = this.hot.getFocusManager().getRefocusElement();
|
563
|
-
const isHotInput =
|
564
|
-
if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || isHTMLElement(
|
566
|
+
const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
|
567
|
+
if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCopy, this) || this.isEditorOpened() || isHTMLElement(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !isInternalElement(eventTarget, this.hot.rootElement))) {
|
565
568
|
return;
|
566
569
|
}
|
567
570
|
event.preventDefault();
|
@@ -591,10 +594,10 @@ export class CopyPaste extends BasePlugin {
|
|
591
594
|
* @private
|
592
595
|
*/
|
593
596
|
onCut(event) {
|
594
|
-
|
597
|
+
const eventTarget = event.composedPath()[0];
|
595
598
|
const focusedElement = this.hot.getFocusManager().getRefocusElement();
|
596
|
-
const isHotInput =
|
597
|
-
if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || isHTMLElement(
|
599
|
+
const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
|
600
|
+
if (!this.hot.isListening() && !_classPrivateFieldGet(_isTriggeredByCut, this) || this.isEditorOpened() || isHTMLElement(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !isInternalElement(eventTarget, this.hot.rootElement))) {
|
598
601
|
return;
|
599
602
|
}
|
600
603
|
event.preventDefault();
|
@@ -623,10 +626,10 @@ export class CopyPaste extends BasePlugin {
|
|
623
626
|
* @private
|
624
627
|
*/
|
625
628
|
onPaste(event) {
|
626
|
-
|
629
|
+
const eventTarget = event.composedPath()[0];
|
627
630
|
const focusedElement = this.hot.getFocusManager().getRefocusElement();
|
628
|
-
const isHotInput =
|
629
|
-
if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || isHTMLElement(
|
631
|
+
const isHotInput = eventTarget === null || eventTarget === void 0 ? void 0 : eventTarget.hasAttribute('data-hot-input');
|
632
|
+
if (!this.hot.isListening() || this.isEditorOpened() || !this.hot.getSelected() || isHTMLElement(eventTarget) && (isHotInput && eventTarget !== focusedElement || !isHotInput && eventTarget !== this.hot.rootDocument.body && !isInternalElement(eventTarget, this.hot.rootElement))) {
|
630
633
|
return;
|
631
634
|
}
|
632
635
|
event.preventDefault();
|
@@ -116,6 +116,7 @@ class ExportFile extends _base.BasePlugin {
|
|
116
116
|
* @property {boolean} [rowHeaders=false] Include row headers in the exported file.
|
117
117
|
* @property {string} [columnDelimiter=','] Column delimiter.
|
118
118
|
* @property {string} [range=[]] Cell range that will be exported to file.
|
119
|
+
* @property {boolean|RegExp|Function} [sanitizeValues=false] Controls the sanitization of cell value.
|
119
120
|
*/
|
120
121
|
|
121
122
|
/**
|
@@ -145,7 +146,7 @@ class ExportFile extends _base.BasePlugin {
|
|
145
146
|
/**
|
146
147
|
* Exports table data as a downloadable file.
|
147
148
|
*
|
148
|
-
* @param {string} format Export format type
|
149
|
+
* @param {string} format Export format type eg. `'csv'`.
|
149
150
|
* @param {ExportOptions} options Export options.
|
150
151
|
*/
|
151
152
|
downloadFile(format) {
|
@@ -110,6 +110,7 @@ export class ExportFile extends BasePlugin {
|
|
110
110
|
* @property {boolean} [rowHeaders=false] Include row headers in the exported file.
|
111
111
|
* @property {string} [columnDelimiter=','] Column delimiter.
|
112
112
|
* @property {string} [range=[]] Cell range that will be exported to file.
|
113
|
+
* @property {boolean|RegExp|Function} [sanitizeValues=false] Controls the sanitization of cell value.
|
113
114
|
*/
|
114
115
|
|
115
116
|
/**
|
@@ -139,7 +140,7 @@ export class ExportFile extends BasePlugin {
|
|
139
140
|
/**
|
140
141
|
* Exports table data as a downloadable file.
|
141
142
|
*
|
142
|
-
* @param {string} format Export format type
|
143
|
+
* @param {string} format Export format type eg. `'csv'`.
|
143
144
|
* @param {ExportOptions} options Export options.
|
144
145
|
*/
|
145
146
|
downloadFile(format) {
|
@@ -1,20 +1,41 @@
|
|
1
1
|
"use strict";
|
2
2
|
|
3
3
|
exports.__esModule = true;
|
4
|
+
require("core-js/modules/es.error.cause.js");
|
4
5
|
require("core-js/modules/esnext.iterator.constructor.js");
|
5
6
|
require("core-js/modules/esnext.iterator.map.js");
|
6
7
|
var _array = require("../../../helpers/array");
|
7
8
|
var _mixed = require("../../../helpers/mixed");
|
8
9
|
var _base = _interopRequireDefault(require("./_base"));
|
9
10
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
11
|
+
function _classPrivateMethodInitSpec(e, a) { _checkPrivateRedeclaration(e, a), a.add(e); }
|
12
|
+
function _checkPrivateRedeclaration(e, t) { if (t.has(e)) throw new TypeError("Cannot initialize the same private elements twice on an object"); }
|
13
|
+
function _assertClassBrand(e, t, n) { if ("function" == typeof e ? e === t : e.has(t)) return arguments.length < 3 ? t : n; throw new TypeError("Private element is not present on this object"); }
|
10
14
|
const CHAR_CARRIAGE_RETURN = String.fromCharCode(13);
|
11
15
|
const CHAR_DOUBLE_QUOTES = String.fromCharCode(34);
|
12
16
|
const CHAR_LINE_FEED = String.fromCharCode(10);
|
17
|
+
const CHAR_EQUAL = String.fromCharCode(61);
|
18
|
+
const CHAR_PLUS = String.fromCharCode(43);
|
19
|
+
const CHAR_MINUS = String.fromCharCode(45);
|
20
|
+
const CHAR_AT = String.fromCharCode(64);
|
21
|
+
const CHAR_TAB = String.fromCharCode(9);
|
13
22
|
|
14
23
|
/**
|
15
24
|
* @private
|
16
25
|
*/
|
26
|
+
var _Csv_brand = /*#__PURE__*/new WeakSet();
|
17
27
|
class Csv extends _base.default {
|
28
|
+
constructor() {
|
29
|
+
super(...arguments);
|
30
|
+
/**
|
31
|
+
* Sanitize value that may be interpreted as a formula in spreadsheet software.
|
32
|
+
* Following the OWASP recommendations: https://owasp.org/www-community/attacks/CSV_Injection.
|
33
|
+
*
|
34
|
+
* @param {string} value Cell value.
|
35
|
+
* @returns {string}
|
36
|
+
*/
|
37
|
+
_classPrivateMethodInitSpec(this, _Csv_brand);
|
38
|
+
}
|
18
39
|
/**
|
19
40
|
* Default options for exporting CSV format.
|
20
41
|
*
|
@@ -26,7 +47,8 @@ class Csv extends _base.default {
|
|
26
47
|
fileExtension: 'csv',
|
27
48
|
bom: true,
|
28
49
|
columnDelimiter: ',',
|
29
|
-
rowDelimiter: '\r\n'
|
50
|
+
rowDelimiter: '\r\n',
|
51
|
+
sanitizeValues: false
|
30
52
|
};
|
31
53
|
}
|
32
54
|
|
@@ -44,7 +66,10 @@ class Csv extends _base.default {
|
|
44
66
|
const hasRowHeaders = rowHeaders.length > 0;
|
45
67
|
let result = options.bom ? String.fromCharCode(0xFEFF) : '';
|
46
68
|
if (hasColumnHeaders) {
|
47
|
-
columnHeaders = (0, _array.arrayMap)(columnHeaders, value => this._escapeCell(value,
|
69
|
+
columnHeaders = (0, _array.arrayMap)(columnHeaders, value => this._escapeCell(value, {
|
70
|
+
force: true,
|
71
|
+
sanitizeValue: options.sanitizeValues
|
72
|
+
}));
|
48
73
|
if (hasRowHeaders) {
|
49
74
|
result += options.columnDelimiter;
|
50
75
|
}
|
@@ -56,9 +81,15 @@ class Csv extends _base.default {
|
|
56
81
|
result += options.rowDelimiter;
|
57
82
|
}
|
58
83
|
if (hasRowHeaders) {
|
59
|
-
result += this._escapeCell(rowHeaders[index]
|
84
|
+
result += this._escapeCell(rowHeaders[index], {
|
85
|
+
sanitizeValue: options.sanitizeValues
|
86
|
+
});
|
87
|
+
result += options.columnDelimiter;
|
60
88
|
}
|
61
|
-
|
89
|
+
const escapedValue = value.map(cellValue => this._escapeCell(cellValue, {
|
90
|
+
sanitizeValue: options.sanitizeValues
|
91
|
+
})).join(options.columnDelimiter);
|
92
|
+
result += escapedValue;
|
62
93
|
});
|
63
94
|
return result;
|
64
95
|
}
|
@@ -67,17 +98,51 @@ class Csv extends _base.default {
|
|
67
98
|
* Escape cell value.
|
68
99
|
*
|
69
100
|
* @param {*} value Cell value.
|
70
|
-
* @param {
|
101
|
+
* @param {object} options Options.
|
102
|
+
* @param {boolean} [options.force=false] Indicates if cell value will be escaped forcefully.
|
103
|
+
* @param {boolean|RegExp|Function} [options.sanitizeValue=false] Controls the sanitization of cell value.
|
71
104
|
* @returns {string}
|
72
105
|
*/
|
73
106
|
_escapeCell(value) {
|
74
|
-
let
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
107
|
+
let {
|
108
|
+
force = false,
|
109
|
+
sanitizeValue = false
|
110
|
+
} = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
111
|
+
let returnValue = (0, _mixed.stringify)(value);
|
112
|
+
if (returnValue === '') {
|
113
|
+
return returnValue;
|
114
|
+
}
|
115
|
+
if (sanitizeValue) {
|
116
|
+
force = true;
|
117
|
+
}
|
118
|
+
if (sanitizeValue instanceof RegExp) {
|
119
|
+
returnValue = _assertClassBrand(_Csv_brand, this, _sanitizeValueWithRegExp).call(this, returnValue, sanitizeValue);
|
120
|
+
} else if (typeof sanitizeValue === 'function') {
|
121
|
+
returnValue = sanitizeValue(returnValue);
|
122
|
+
} else if (sanitizeValue) {
|
123
|
+
returnValue = _assertClassBrand(_Csv_brand, this, _sanitizeValueWithOWASP).call(this, returnValue);
|
124
|
+
}
|
125
|
+
if (force || returnValue.indexOf(CHAR_CARRIAGE_RETURN) >= 0 || returnValue.indexOf(CHAR_DOUBLE_QUOTES) >= 0 || returnValue.indexOf(CHAR_LINE_FEED) >= 0 || returnValue.indexOf(this.options.columnDelimiter) >= 0) {
|
126
|
+
returnValue = returnValue.replace(new RegExp('"', 'g'), '""');
|
127
|
+
returnValue = `"${returnValue}"`;
|
79
128
|
}
|
80
|
-
return
|
129
|
+
return returnValue;
|
81
130
|
}
|
82
131
|
}
|
132
|
+
function _sanitizeValueWithOWASP(value) {
|
133
|
+
if (value.startsWith(CHAR_EQUAL) || value.startsWith(CHAR_PLUS) || value.startsWith(CHAR_MINUS) || value.startsWith(CHAR_AT) || value.startsWith(CHAR_TAB) || value.startsWith(CHAR_CARRIAGE_RETURN)) {
|
134
|
+
return `'${value}`;
|
135
|
+
}
|
136
|
+
return value;
|
137
|
+
}
|
138
|
+
/**
|
139
|
+
* Sanitize value using regular expression.
|
140
|
+
*
|
141
|
+
* @param {string} value Cell value.
|
142
|
+
* @param {RegExp} regexp Regular expression to test against.
|
143
|
+
* @returns {string}
|
144
|
+
*/
|
145
|
+
function _sanitizeValueWithRegExp(value, regexp) {
|
146
|
+
return regexp.test(value) ? `'${value}` : value;
|
147
|
+
}
|
83
148
|
var _default = exports.default = Csv;
|