handsontable 0.0.0-next-7936038-20230411 → 0.0.0-next-931651e-20230412

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of handsontable might be problematic. Click here for more details.

@@ -19,6 +19,8 @@ import "core-js/modules/es.set.js";
19
19
  import "core-js/modules/es.string.iterator.js";
20
20
  import "core-js/modules/web.dom-collections.iterator.js";
21
21
  import "core-js/modules/es.array.map.js";
22
+ import "core-js/modules/es.string.starts-with.js";
23
+ import "core-js/modules/es.array.slice.js";
22
24
  import "core-js/modules/es.array.includes.js";
23
25
  import "core-js/modules/es.string.includes.js";
24
26
  import "core-js/modules/es.array.reverse.js";
@@ -35,7 +37,6 @@ import "core-js/modules/es.reflect.construct.js";
35
37
  import "core-js/modules/es.reflect.get.js";
36
38
  import "core-js/modules/es.object.get-own-property-descriptor.js";
37
39
  import "core-js/modules/es.symbol.iterator.js";
38
- import "core-js/modules/es.array.slice.js";
39
40
  import "core-js/modules/es.function.name.js";
40
41
  import "core-js/modules/es.array.from.js";
41
42
  import "core-js/modules/es.regexp.exec.js";
@@ -70,7 +71,7 @@ import { error, warn } from "../../helpers/console.mjs";
70
71
  import { isNumeric } from "../../helpers/number.mjs";
71
72
  import { isDefined, isUndefined } from "../../helpers/mixed.mjs";
72
73
  import { setupEngine, setupSheet, unregisterEngine, getRegisteredHotInstances } from "./engine/register.mjs";
73
- import { isEscapedFormulaExpression, unescapeFormulaExpression } from "./utils.mjs";
74
+ import { isEscapedFormulaExpression, unescapeFormulaExpression, isDate, isDateValid, getDateInHfFormat, getDateFromExcelDate, getDateInHotFormat, isFormula } from "./utils.mjs";
74
75
  import { getEngineSettingsWithOverrides } from "./engine/settings.mjs";
75
76
  import { isArrayOfArrays } from "../../helpers/data.mjs";
76
77
  import { toUpperCaseFirst } from "../../helpers/string.mjs";
@@ -291,6 +292,13 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
291
292
  return _this8.onAfterRemoveCol.apply(_this8, arguments);
292
293
  });
293
294
 
295
+ // TODO: Actions related to overwriting dates from HOT format to HF default format are done as callback to this
296
+ // hook, because some hooks, such as `afterLoadData` doesn't have information about composed cell properties.
297
+ // Another hooks are triggered to late for setting HF's engine data needed for some actions.
298
+ this.addHook('afterCellMetaReset', function () {
299
+ return _this8.onAfterCellMetaReset.apply(_this8, arguments);
300
+ });
301
+
294
302
  // Handling undo actions on data just using HyperFormula's UndoRedo mechanism
295
303
  this.addHook('beforeUndo', function (action) {
296
304
  // TODO: Move action isn't handled by HyperFormula.
@@ -659,6 +667,16 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
659
667
  warn("Not possible to set cell data at ".concat(JSON.stringify(address)));
660
668
  return;
661
669
  }
670
+ var cellMeta = this.hot.getCellMeta(row, column);
671
+ if (isDate(newValue, cellMeta.type)) {
672
+ if (isDateValid(newValue, cellMeta.dateFormat)) {
673
+ // Rewriting date in HOT format to HF format.
674
+ newValue = getDateInHfFormat(newValue, cellMeta.dateFormat);
675
+ } else if (isFormula(newValue) === false) {
676
+ // Escaping value from date parsing using "'" sign (HF feature).
677
+ newValue = "'".concat(newValue);
678
+ }
679
+ }
662
680
  return this.engine.setCellContents(address, newValue);
663
681
  }
664
682
 
@@ -682,7 +700,12 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
682
700
  col: this.hot.toPhysicalColumn(visualColumn),
683
701
  sheet: this.sheetId
684
702
  };
685
- var cellValue = this.engine.getCellValue(address);
703
+ var cellMeta = this.hot.getCellMeta(visualRow, visualColumn);
704
+ var cellValue = this.engine.getCellValue(address); // Date as an integer (Excel-like date).
705
+
706
+ if (cellMeta.type === 'date' && isNumeric(cellValue)) {
707
+ cellValue = getDateFromExcelDate(cellValue, cellMeta.dateFormat);
708
+ }
686
709
 
687
710
  // If `cellValue` is an object it is expected to be an error
688
711
  return _typeof(cellValue) === 'object' && cellValue !== null ? cellValue.value : cellValue;
@@ -723,7 +746,33 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
723
746
  if (this.engine.isItPossibleToSetCellContents(engineTargetRange) === false) {
724
747
  return false;
725
748
  }
726
- return this.engine.getFillRangeData(engineSourceRange, engineTargetRange);
749
+ var fillRangeData = this.engine.getFillRangeData(engineSourceRange, engineTargetRange);
750
+ var _engineSourceRange$st = engineSourceRange.start,
751
+ sourceStartRow = _engineSourceRange$st.row,
752
+ sourceStartColumn = _engineSourceRange$st.col;
753
+ var _engineSourceRange$en = engineSourceRange.end,
754
+ sourceEndRow = _engineSourceRange$en.row,
755
+ sourceEndColumn = _engineSourceRange$en.col;
756
+ var populationRowLength = sourceEndRow - sourceStartRow + 1;
757
+ var populationColumnLength = sourceEndColumn - sourceStartColumn + 1;
758
+ for (var populatedRowIndex = 0; populatedRowIndex < fillRangeData.length; populatedRowIndex += 1) {
759
+ for (var populatedColumnIndex = 0; populatedColumnIndex < fillRangeData[populatedRowIndex].length; populatedColumnIndex += 1) {
760
+ var populatedValue = fillRangeData[populatedRowIndex][populatedColumnIndex];
761
+ var sourceRow = populatedRowIndex % populationRowLength;
762
+ var sourceColumn = populatedColumnIndex % populationColumnLength;
763
+ var sourceCellMeta = this.hot.getCellMeta(sourceRow, sourceColumn);
764
+ if (isDate(populatedValue, sourceCellMeta.type)) {
765
+ if (populatedValue.startsWith('\'')) {
766
+ // Populating values on HOT side without apostrophe.
767
+ fillRangeData[populatedRowIndex][populatedColumnIndex] = populatedValue.slice(1);
768
+ } else if (this.isFormulaCellType(sourceRow, sourceColumn, this.sheetId) === false) {
769
+ // Populating date in proper format, coming from the source cell.
770
+ fillRangeData[populatedRowIndex][populatedColumnIndex] = getDateInHotFormat(populatedValue, sourceCellMeta.dateFormat);
771
+ }
772
+ }
773
+ }
774
+ }
775
+ return fillRangeData;
727
776
  }
728
777
 
729
778
  /**
@@ -747,6 +796,40 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
747
796
  _classPrivateFieldSet(this, _hotWasInitializedWithEmptyData, isUndefined(this.hot.getSettings().data));
748
797
  }
749
798
 
799
+ /**
800
+ * Callback to `afterCellMetaReset` hook which is triggered after setting cell meta.
801
+ *
802
+ * @private
803
+ */
804
+ }, {
805
+ key: "onAfterCellMetaReset",
806
+ value: function onAfterCellMetaReset() {
807
+ var _this14 = this;
808
+ var sourceDataArray = this.hot.getSourceDataArray();
809
+ var valueChanged = false;
810
+ sourceDataArray.forEach(function (rowData, rowIndex) {
811
+ rowData.forEach(function (cellValue, columnIndex) {
812
+ var cellMeta = _this14.hot.getCellMeta(rowIndex, columnIndex);
813
+ var dateFormat = cellMeta.dateFormat;
814
+ if (isDate(cellValue, cellMeta.type)) {
815
+ valueChanged = true;
816
+ if (isDateValid(cellValue, dateFormat)) {
817
+ // Rewriting date in HOT format to HF format.
818
+ sourceDataArray[rowIndex][columnIndex] = getDateInHfFormat(cellValue, dateFormat);
819
+ } else if (_this14.isFormulaCellType(rowIndex, columnIndex) === false) {
820
+ // Escaping value from date parsing using "'" sign (HF feature).
821
+ sourceDataArray[rowIndex][columnIndex] = "'".concat(cellValue);
822
+ }
823
+ }
824
+ });
825
+ });
826
+ if (valueChanged === true) {
827
+ _classPrivateFieldSet(this, _internalOperationPending, true);
828
+ this.engine.setSheetContent(this.sheetId, sourceDataArray);
829
+ _classPrivateFieldSet(this, _internalOperationPending, false);
830
+ }
831
+ }
832
+
750
833
  /**
751
834
  * `afterLoadData` hook callback.
752
835
  *
@@ -767,7 +850,7 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
767
850
  var sourceDataArray = this.hot.getSourceDataArray();
768
851
  if (this.engine.isItPossibleToReplaceSheetContent(this.sheetId, sourceDataArray)) {
769
852
  _classPrivateFieldSet(this, _internalOperationPending, true);
770
- var dependentCells = this.engine.setSheetContent(this.sheetId, this.hot.getSourceDataArray());
853
+ var dependentCells = this.engine.setSheetContent(this.sheetId, sourceDataArray);
771
854
  this.renderDependentSheets(dependentCells);
772
855
  _classPrivateFieldSet(this, _internalOperationPending, false);
773
856
  }
@@ -812,7 +895,11 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
812
895
  col: this.toPhysicalColumnPosition(column),
813
896
  sheet: this.sheetId
814
897
  };
815
- var cellValue = this.engine.getCellValue(address);
898
+ var cellValue = this.engine.getCellValue(address); // Date as an integer (Excel like date).
899
+ var cellMeta = this.hot.getCellMeta(row, column);
900
+ if (cellMeta.type === 'date' && isNumeric(cellValue)) {
901
+ cellValue = getDateFromExcelDate(cellValue, cellMeta.dateFormat);
902
+ }
816
903
 
817
904
  // If `cellValue` is an object it is expected to be an error
818
905
  var value = _typeof(cellValue) === 'object' && cellValue !== null ? cellValue.value : cellValue;
@@ -875,7 +962,7 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
875
962
  }, {
876
963
  key: "onAfterSetDataAtCell",
877
964
  value: function onAfterSetDataAtCell(changes, source) {
878
- var _this14 = this;
965
+ var _this15 = this;
879
966
  if (isBlockedSource(source)) {
880
967
  return;
881
968
  }
@@ -887,16 +974,16 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
887
974
  row = _ref10[0],
888
975
  prop = _ref10[1],
889
976
  newValue = _ref10[3];
890
- var column = _this14.hot.propToCol(prop);
891
- var physicalRow = _this14.hot.toPhysicalRow(row);
892
- var physicalColumn = _this14.hot.toPhysicalColumn(column);
977
+ var column = _this15.hot.propToCol(prop);
978
+ var physicalRow = _this15.hot.toPhysicalRow(row);
979
+ var physicalColumn = _this15.hot.toPhysicalColumn(column);
893
980
  var address = {
894
981
  row: physicalRow,
895
982
  col: physicalColumn,
896
- sheet: _this14.sheetId
983
+ sheet: _this15.sheetId
897
984
  };
898
985
  if (physicalRow !== null && physicalColumn !== null) {
899
- _this14.syncChangeWithEngine(row, column, newValue);
986
+ _this15.syncChangeWithEngine(row, column, newValue);
900
987
  } else {
901
988
  outOfBoundsChanges.push([row, column, newValue]);
902
989
  }
@@ -909,16 +996,16 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
909
996
  // Workaround for rows/columns being created two times (by HOT and the engine).
910
997
  // (unfortunately, this requires an extra re-render)
911
998
  this.hot.addHookOnce('afterChange', function () {
912
- var outOfBoundsDependentCells = _this14.engine.batch(function () {
999
+ var outOfBoundsDependentCells = _this15.engine.batch(function () {
913
1000
  outOfBoundsChanges.forEach(function (_ref11) {
914
1001
  var _ref12 = _slicedToArray(_ref11, 3),
915
1002
  row = _ref12[0],
916
1003
  column = _ref12[1],
917
1004
  newValue = _ref12[2];
918
- _this14.syncChangeWithEngine(row, column, newValue);
1005
+ _this15.syncChangeWithEngine(row, column, newValue);
919
1006
  });
920
1007
  });
921
- _this14.renderDependentSheets(outOfBoundsDependentCells, true);
1008
+ _this15.renderDependentSheets(outOfBoundsDependentCells, true);
922
1009
  });
923
1010
  }
924
1011
  this.renderDependentSheets(dependentCells);
@@ -936,7 +1023,7 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
936
1023
  }, {
937
1024
  key: "onAfterSetSourceDataAtCell",
938
1025
  value: function onAfterSetSourceDataAtCell(changes, source) {
939
- var _this15 = this;
1026
+ var _this16 = this;
940
1027
  if (isBlockedSource(source)) {
941
1028
  return;
942
1029
  }
@@ -947,23 +1034,23 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
947
1034
  row = _ref14[0],
948
1035
  prop = _ref14[1],
949
1036
  newValue = _ref14[3];
950
- var column = _this15.hot.propToCol(prop);
1037
+ var column = _this16.hot.propToCol(prop);
951
1038
  if (!isNumeric(column)) {
952
1039
  return;
953
1040
  }
954
1041
  var address = {
955
1042
  row: row,
956
- col: _this15.toPhysicalColumnPosition(column),
957
- sheet: _this15.sheetId
1043
+ col: _this16.toPhysicalColumnPosition(column),
1044
+ sheet: _this16.sheetId
958
1045
  };
959
- if (!_this15.engine.isItPossibleToSetCellContents(address)) {
1046
+ if (!_this16.engine.isItPossibleToSetCellContents(address)) {
960
1047
  warn("Not possible to set source cell data at ".concat(JSON.stringify(address)));
961
1048
  return;
962
1049
  }
963
1050
  changedCells.push({
964
1051
  address: address
965
1052
  });
966
- dependentCells.push.apply(dependentCells, _toConsumableArray(_this15.engine.setCellContents(address, newValue)));
1053
+ dependentCells.push.apply(dependentCells, _toConsumableArray(_this16.engine.setCellContents(address, newValue)));
967
1054
  });
968
1055
  this.renderDependentSheets(dependentCells);
969
1056
  this.validateDependentCells(dependentCells, changedCells);
@@ -1013,9 +1100,9 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
1013
1100
  }, {
1014
1101
  key: "onBeforeRemoveRow",
1015
1102
  value: function onBeforeRemoveRow(row, amount, physicalRows) {
1016
- var _this16 = this;
1103
+ var _this17 = this;
1017
1104
  var possible = physicalRows.every(function (physicalRow) {
1018
- return _this16.engine.isItPossibleToRemoveRows(_this16.sheetId, [physicalRow, 1]);
1105
+ return _this17.engine.isItPossibleToRemoveRows(_this17.sheetId, [physicalRow, 1]);
1019
1106
  });
1020
1107
  return possible === false ? false : void 0;
1021
1108
  }
@@ -1032,9 +1119,9 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
1032
1119
  }, {
1033
1120
  key: "onBeforeRemoveCol",
1034
1121
  value: function onBeforeRemoveCol(col, amount, physicalColumns) {
1035
- var _this17 = this;
1122
+ var _this18 = this;
1036
1123
  var possible = physicalColumns.every(function (physicalColumn) {
1037
- return _this17.engine.isItPossibleToRemoveColumns(_this17.sheetId, [physicalColumn, 1]);
1124
+ return _this18.engine.isItPossibleToRemoveColumns(_this18.sheetId, [physicalColumn, 1]);
1038
1125
  });
1039
1126
  return possible === false ? false : void 0;
1040
1127
  }
@@ -1090,14 +1177,14 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
1090
1177
  }, {
1091
1178
  key: "onAfterRemoveRow",
1092
1179
  value: function onAfterRemoveRow(row, amount, physicalRows, source) {
1093
- var _this18 = this;
1180
+ var _this19 = this;
1094
1181
  if (isBlockedSource(source)) {
1095
1182
  return;
1096
1183
  }
1097
1184
  var descendingPhysicalRows = physicalRows.sort().reverse();
1098
1185
  var changes = this.engine.batch(function () {
1099
1186
  descendingPhysicalRows.forEach(function (physicalRow) {
1100
- _this18.engine.removeRows(_this18.sheetId, [physicalRow, 1]);
1187
+ _this19.engine.removeRows(_this19.sheetId, [physicalRow, 1]);
1101
1188
  });
1102
1189
  });
1103
1190
  this.renderDependentSheets(changes);
@@ -1116,14 +1203,14 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
1116
1203
  }, {
1117
1204
  key: "onAfterRemoveCol",
1118
1205
  value: function onAfterRemoveCol(col, amount, physicalColumns, source) {
1119
- var _this19 = this;
1206
+ var _this20 = this;
1120
1207
  if (isBlockedSource(source)) {
1121
1208
  return;
1122
1209
  }
1123
1210
  var descendingPhysicalColumns = physicalColumns.sort().reverse();
1124
1211
  var changes = this.engine.batch(function () {
1125
1212
  descendingPhysicalColumns.forEach(function (physicalColumn) {
1126
- _this19.engine.removeColumns(_this19.sheetId, [physicalColumn, 1]);
1213
+ _this20.engine.removeColumns(_this20.sheetId, [physicalColumn, 1]);
1127
1214
  });
1128
1215
  });
1129
1216
  this.renderDependentSheets(changes);
@@ -1142,16 +1229,16 @@ export var Formulas = /*#__PURE__*/function (_BasePlugin) {
1142
1229
  key: "onAfterDetachChild",
1143
1230
  value: function onAfterDetachChild(parent, element, finalElementRowIndex) {
1144
1231
  var _element$__children,
1145
- _this20 = this;
1232
+ _this21 = this;
1146
1233
  _classPrivateFieldSet(this, _internalOperationPending, true);
1147
1234
  var rowsData = this.hot.getSourceDataArray(finalElementRowIndex, 0, finalElementRowIndex + (((_element$__children = element.__children) === null || _element$__children === void 0 ? void 0 : _element$__children.length) || 0), this.hot.countSourceCols());
1148
1235
  _classPrivateFieldSet(this, _internalOperationPending, false);
1149
1236
  rowsData.forEach(function (row, relativeRowIndex) {
1150
1237
  row.forEach(function (value, colIndex) {
1151
- _this20.engine.setCellContents({
1238
+ _this21.engine.setCellContents({
1152
1239
  col: colIndex,
1153
1240
  row: finalElementRowIndex + relativeRowIndex,
1154
- sheet: _this20.sheetId
1241
+ sheet: _this21.sheetId
1155
1242
  }, [[value]]);
1156
1243
  });
1157
1244
  });
@@ -1,8 +1,19 @@
1
1
  "use strict";
2
2
 
3
3
  exports.__esModule = true;
4
+ exports.getDateFromExcelDate = getDateFromExcelDate;
5
+ exports.getDateInHfFormat = getDateInHfFormat;
6
+ exports.getDateInHotFormat = getDateInHotFormat;
7
+ exports.isDate = isDate;
8
+ exports.isDateValid = isDateValid;
4
9
  exports.isEscapedFormulaExpression = isEscapedFormulaExpression;
10
+ exports.isFormula = isFormula;
5
11
  exports.unescapeFormulaExpression = unescapeFormulaExpression;
12
+ require("core-js/modules/es.string.starts-with.js");
13
+ var _moment = _interopRequireDefault(require("moment"));
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+ var DEFAULT_DATE_FORMAT_HYPERFORMULA = 'DD/MM/YYYY';
16
+
6
17
  /**
7
18
  * Checks if provided formula expression is escaped.
8
19
  *
@@ -21,4 +32,74 @@ function isEscapedFormulaExpression(expression) {
21
32
  */
22
33
  function unescapeFormulaExpression(expression) {
23
34
  return isEscapedFormulaExpression(expression) ? expression.substr(1) : expression;
35
+ }
36
+
37
+ /**
38
+ * Checks whether string looks like formula or not. Corresponds to {@link https://hyperformula.handsontable.com/api/globals.html#isformula|HyperFormula's implementation}.
39
+ *
40
+ * @param {string} value Checked value.
41
+ * @returns {boolean}
42
+ */
43
+ function isFormula(value) {
44
+ return typeof value === 'string' && value.startsWith('=');
45
+ }
46
+
47
+ /**
48
+ * Checks if provided value is a date according to cell meta.
49
+ *
50
+ * @param {*} value Checked value.
51
+ * @param {string} cellType Type of a cell.
52
+ * @returns {boolean}
53
+ */
54
+ function isDate(value, cellType) {
55
+ return typeof value === 'string' && cellType === 'date';
56
+ }
57
+
58
+ /**
59
+ * Checks if provided date is a valid date according to cell date format.
60
+ *
61
+ * @param {*} date Checked date.
62
+ * @param {object} dateFormat Handled format for a date.
63
+ * @returns {boolean}
64
+ */
65
+ function isDateValid(date, dateFormat) {
66
+ return (0, _moment.default)(date, dateFormat, true).isValid();
67
+ }
68
+
69
+ /**
70
+ * Returns date formatted in HF's default format.
71
+ *
72
+ * @param {string} date Date formatted according to Handsontable cell date format.
73
+ * @param {string} dateFormat The format used for the date passed.
74
+ * @returns {string}
75
+ */
76
+ function getDateInHfFormat(date, dateFormat) {
77
+ return (0, _moment.default)(date, dateFormat, true).format(DEFAULT_DATE_FORMAT_HYPERFORMULA);
78
+ }
79
+
80
+ /**
81
+ * Returns date formatted in HF's default format.
82
+ *
83
+ * @param {string} date Date formatted according to Handsontable cell date format.
84
+ * @param {string} dateFormat The format used for the date passed.
85
+ * @returns {string}
86
+ */
87
+ function getDateInHotFormat(date, dateFormat) {
88
+ return (0, _moment.default)(date, DEFAULT_DATE_FORMAT_HYPERFORMULA, true).format(dateFormat);
89
+ }
90
+
91
+ /**
92
+ * Converts Excel-like dates into strings and formats them based on the handled date format.
93
+ *
94
+ * @param {number} numericDate An integer representing numbers of days from January 1, 1900.
95
+ * @param {string} dateFormat The format used for parsing an output.
96
+ * @returns {string}
97
+ */
98
+ function getDateFromExcelDate(numericDate, dateFormat) {
99
+ // To replicate the behavior from the HyperFormula. UTC starts from 31/12/1899, while HF from 30/12/1899.
100
+ var dateOffset = -1;
101
+
102
+ // Based on solution from: https://stackoverflow.com/a/67130235.
103
+ var dateForFormatting = new Date(Date.UTC(0, 0, numericDate + dateOffset));
104
+ return (0, _moment.default)(dateForFormatting).format(dateFormat);
24
105
  }
@@ -1,3 +1,7 @@
1
+ import "core-js/modules/es.string.starts-with.js";
2
+ import moment from 'moment';
3
+ var DEFAULT_DATE_FORMAT_HYPERFORMULA = 'DD/MM/YYYY';
4
+
1
5
  /**
2
6
  * Checks if provided formula expression is escaped.
3
7
  *
@@ -16,4 +20,74 @@ export function isEscapedFormulaExpression(expression) {
16
20
  */
17
21
  export function unescapeFormulaExpression(expression) {
18
22
  return isEscapedFormulaExpression(expression) ? expression.substr(1) : expression;
23
+ }
24
+
25
+ /**
26
+ * Checks whether string looks like formula or not. Corresponds to {@link https://hyperformula.handsontable.com/api/globals.html#isformula|HyperFormula's implementation}.
27
+ *
28
+ * @param {string} value Checked value.
29
+ * @returns {boolean}
30
+ */
31
+ export function isFormula(value) {
32
+ return typeof value === 'string' && value.startsWith('=');
33
+ }
34
+
35
+ /**
36
+ * Checks if provided value is a date according to cell meta.
37
+ *
38
+ * @param {*} value Checked value.
39
+ * @param {string} cellType Type of a cell.
40
+ * @returns {boolean}
41
+ */
42
+ export function isDate(value, cellType) {
43
+ return typeof value === 'string' && cellType === 'date';
44
+ }
45
+
46
+ /**
47
+ * Checks if provided date is a valid date according to cell date format.
48
+ *
49
+ * @param {*} date Checked date.
50
+ * @param {object} dateFormat Handled format for a date.
51
+ * @returns {boolean}
52
+ */
53
+ export function isDateValid(date, dateFormat) {
54
+ return moment(date, dateFormat, true).isValid();
55
+ }
56
+
57
+ /**
58
+ * Returns date formatted in HF's default format.
59
+ *
60
+ * @param {string} date Date formatted according to Handsontable cell date format.
61
+ * @param {string} dateFormat The format used for the date passed.
62
+ * @returns {string}
63
+ */
64
+ export function getDateInHfFormat(date, dateFormat) {
65
+ return moment(date, dateFormat, true).format(DEFAULT_DATE_FORMAT_HYPERFORMULA);
66
+ }
67
+
68
+ /**
69
+ * Returns date formatted in HF's default format.
70
+ *
71
+ * @param {string} date Date formatted according to Handsontable cell date format.
72
+ * @param {string} dateFormat The format used for the date passed.
73
+ * @returns {string}
74
+ */
75
+ export function getDateInHotFormat(date, dateFormat) {
76
+ return moment(date, DEFAULT_DATE_FORMAT_HYPERFORMULA, true).format(dateFormat);
77
+ }
78
+
79
+ /**
80
+ * Converts Excel-like dates into strings and formats them based on the handled date format.
81
+ *
82
+ * @param {number} numericDate An integer representing numbers of days from January 1, 1900.
83
+ * @param {string} dateFormat The format used for parsing an output.
84
+ * @returns {string}
85
+ */
86
+ export function getDateFromExcelDate(numericDate, dateFormat) {
87
+ // To replicate the behavior from the HyperFormula. UTC starts from 31/12/1899, while HF from 30/12/1899.
88
+ var dateOffset = -1;
89
+
90
+ // Based on solution from: https://stackoverflow.com/a/67130235.
91
+ var dateForFormatting = new Date(Date.UTC(0, 0, numericDate + dateOffset));
92
+ return moment(dateForFormatting).format(dateFormat);
19
93
  }