@odoo/o-spreadsheet 16.1.5 → 16.1.7

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.
@@ -112,88 +112,88 @@
112
112
  const FILTERS_COLOR = "#188038";
113
113
  const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
114
114
  const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
115
- // Color picker
115
+ // Color picker defaults as upper case HEX to match `toHex`helper
116
116
  const COLOR_PICKER_DEFAULTS = [
117
117
  "#000000",
118
118
  "#434343",
119
119
  "#666666",
120
120
  "#999999",
121
- "#b7b7b7",
122
- "#cccccc",
123
- "#d9d9d9",
124
- "#efefef",
125
- "#f3f3f3",
126
- "#ffffff",
121
+ "#B7B7B7",
122
+ "#CCCCCC",
123
+ "#D9D9D9",
124
+ "#EFEFEF",
125
+ "#F3F3F3",
126
+ "#FFFFFF",
127
127
  "#980000",
128
- "#ff0000",
129
- "#ff9900",
130
- "#ffff00",
131
- "#00ff00",
132
- "#00ffff",
133
- "#4a86e8",
134
- "#0000ff",
135
- "#9900ff",
136
- "#ff00ff",
137
- "#e6b8af",
138
- "#f4cccc",
139
- "#fce5cd",
140
- "#fff2cc",
141
- "#d9ead3",
142
- "#d0e0e3",
143
- "#c9daf8",
144
- "#cfe2f3",
145
- "#d9d2e9",
146
- "#ead1dc",
147
- "#dd7e6b",
148
- "#ea9999",
149
- "#f9cb9c",
150
- "#ffe599",
151
- "#b6d7a8",
152
- "#a2c4c9",
153
- "#a4c2f4",
154
- "#9fc5e8",
155
- "#b4a7d6",
156
- "#d5a6bd",
157
- "#cc4125",
158
- "#e06666",
159
- "#f6b26b",
160
- "#ffd966",
161
- "#93c47d",
162
- "#76a5af",
163
- "#6d9eeb",
164
- "#6fa8dc",
165
- "#8e7cc3",
166
- "#c27ba0",
167
- "#a61c00",
168
- "#cc0000",
169
- "#e69138",
170
- "#f1c232",
171
- "#6aa84f",
172
- "#45818e",
173
- "#3c78d8",
174
- "#3d85c6",
175
- "#674ea7",
176
- "#a64d79",
177
- "#85200c",
128
+ "#FF0000",
129
+ "#FF9900",
130
+ "#FFFF00",
131
+ "#00FF00",
132
+ "#00FFFF",
133
+ "#4A86E8",
134
+ "#0000FF",
135
+ "#9900FF",
136
+ "#FF00FF",
137
+ "#E6B8AF",
138
+ "#F4CCCC",
139
+ "#FCE5CD",
140
+ "#FFF2CC",
141
+ "#D9EAD3",
142
+ "#D0E0E3",
143
+ "#C9DAF8",
144
+ "#CFE2F3",
145
+ "#D9D2E9",
146
+ "#EAD1DC",
147
+ "#DD7E6B",
148
+ "#EA9999",
149
+ "#F9CB9C",
150
+ "#FFE599",
151
+ "#B6D7A8",
152
+ "#A2C4C9",
153
+ "#A4C2F4",
154
+ "#9FC5E8",
155
+ "#B4A7D6",
156
+ "#D5A6BD",
157
+ "#CC4125",
158
+ "#E06666",
159
+ "#F6B26B",
160
+ "#FFD966",
161
+ "#93C47D",
162
+ "#76A5AF",
163
+ "#6D9EEB",
164
+ "#6FA8DC",
165
+ "#8E7CC3",
166
+ "#C27BA0",
167
+ "#A61C00",
168
+ "#CC0000",
169
+ "#E69138",
170
+ "#F1C232",
171
+ "#6AA84F",
172
+ "#45818E",
173
+ "#3C78D8",
174
+ "#3D85C6",
175
+ "#674EA7",
176
+ "#A64D79",
177
+ "#85200C",
178
178
  "#990000",
179
- "#b45f06",
180
- "#bf9000",
181
- "#38761d",
182
- "#134f5c",
183
- "#1155cc",
184
- "#0b5394",
185
- "#351c75",
186
- "#741b47",
187
- "#5b0f00",
179
+ "#B45F06",
180
+ "#BF9000",
181
+ "#38761D",
182
+ "#134F5C",
183
+ "#1155CC",
184
+ "#0B5394",
185
+ "#351C75",
186
+ "#741B47",
187
+ "#5B0F00",
188
188
  "#660000",
189
- "#783f04",
190
- "#7f6000",
191
- "#274e13",
192
- "#0c343d",
193
- "#1c4587",
189
+ "#783F04",
190
+ "#7F6000",
191
+ "#274E13",
192
+ "#0C343D",
193
+ "#1C4587",
194
194
  "#073763",
195
- "#20124d",
196
- "#4c1130",
195
+ "#20124D",
196
+ "#4C1130",
197
197
  ];
198
198
  // Dimensions
199
199
  const MIN_ROW_HEIGHT = 10;
@@ -232,7 +232,7 @@
232
232
  const DEFAULT_BORDER_DESC = ["thin", "#000"];
233
233
  const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
234
234
  // DateTimeRegex
235
- const DATETIME_FORMAT = /[ymd:]/;
235
+ const DATETIME_FORMAT = /[ymdhs:]/;
236
236
  // Ranges
237
237
  const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
238
238
  // Max Number of history steps kept in memory
@@ -269,11 +269,13 @@
269
269
  ComponentsImportance[ComponentsImportance["Highlight"] = 5] = "Highlight";
270
270
  ComponentsImportance[ComponentsImportance["Figure"] = 10] = "Figure";
271
271
  ComponentsImportance[ComponentsImportance["ScrollBar"] = 15] = "ScrollBar";
272
- ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
273
- ComponentsImportance[ComponentsImportance["Composer"] = 20] = "Composer";
272
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
273
+ ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
274
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
274
275
  ComponentsImportance[ComponentsImportance["ColorPicker"] = 25] = "ColorPicker";
275
276
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
276
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
277
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
278
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
277
279
  ComponentsImportance[ComponentsImportance["ChartAnchor"] = 1000] = "ChartAnchor";
278
280
  })(ComponentsImportance || (ComponentsImportance = {}));
279
281
  const DEFAULT_SHEETVIEW_SIZE = 1000;
@@ -1036,6 +1038,8 @@
1036
1038
  return matrix[0].map((_, i) => matrix.map((row) => row[i]));
1037
1039
  }
1038
1040
 
1041
+ const RBA_REGEX = /rgba?\(|\s+|\)/gi;
1042
+ const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
1039
1043
  const colors$1 = [
1040
1044
  "#eb6d00",
1041
1045
  "#0074d9",
@@ -1061,7 +1065,10 @@
1061
1065
  }
1062
1066
  /**
1063
1067
  * Converts any CSS color value to a standardized hex6 value.
1064
- * Accepts: hex3, hex6, hex8 and rgb (rgba is not supported)
1068
+ * Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
1069
+ *
1070
+ * [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
1071
+ * with r,g,b ∈ [0, 255] and a ∈ [0, 1]
1065
1072
  *
1066
1073
  * toHex("#ABC")
1067
1074
  * >> "#AABBCC"
@@ -1072,27 +1079,31 @@
1072
1079
  * toHex("rgb(30, 80, 16)")
1073
1080
  * >> "#1E5010"
1074
1081
  *
1082
+ * * toHex("rgb(30, 80, 16, 0.5)")
1083
+ * >> "#1E501080"
1084
+ *
1075
1085
  */
1076
1086
  function toHex(color) {
1077
- if (color.includes("rgba")) {
1078
- throw new Error(`rgba() conversion currently not supported: ${color}`);
1087
+ let hexColor = color;
1088
+ if (color.startsWith("rgb")) {
1089
+ hexColor = rgbaStringToHex(color);
1079
1090
  }
1080
- if (color.includes("rgb")) {
1081
- return rgbToHex6(color);
1082
- }
1083
- color = color.replace("#", "").toUpperCase();
1084
- if (color.length === 3 || color.length === 4) {
1085
- color = color.split("").reduce((acc, h) => acc + h + h, "");
1091
+ else {
1092
+ hexColor = color.replace("#", "").toUpperCase();
1093
+ if (hexColor.length === 3 || hexColor.length === 4) {
1094
+ hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
1095
+ }
1096
+ hexColor = `#${hexColor}`;
1086
1097
  }
1087
- if (color.replace(/[a-f0-9]/gi, "") !== "") {
1088
- throw new Error("invalid color");
1098
+ if (!hexColor.match(HEX_MATCH)) {
1099
+ throw new Error(`invalid color input: ${color}`);
1089
1100
  }
1090
- return "#" + color;
1101
+ return hexColor;
1091
1102
  }
1092
1103
  function isColorValid(color) {
1093
1104
  try {
1094
- const { r, g, b, a } = colorToRGBA(color);
1095
- return (isColorValueValid(r) && isColorValueValid(g) && isColorValueValid(b) && isColorValueValid(a));
1105
+ toHex(color);
1106
+ return true;
1096
1107
  }
1097
1108
  catch (error) {
1098
1109
  return false;
@@ -1125,15 +1136,29 @@
1125
1136
  /**
1126
1137
  * Convert a CSS rgb color string to a standardized hex6 color value.
1127
1138
  *
1128
- * rgbToHex6("rgb(30, 80, 16)")
1139
+ * rgbaStringToHex("rgb(30, 80, 16)")
1129
1140
  * >> "#1E5010"
1141
+ *
1142
+ * rgbaStringToHex("rgba(30, 80, 16, 0.5)")
1143
+ * >> "#1E501080"
1144
+ *
1145
+ * DOES NOT SUPPORT NON INTEGER RGB VALUES
1130
1146
  */
1131
- function rgbToHex6(color) {
1132
- return ("#" +
1133
- concat(color
1134
- .slice(4, -1)
1135
- .split(",")
1136
- .map((valueString) => parseInt(valueString, 10).toString(16).padStart(2, "0"))).toUpperCase());
1147
+ function rgbaStringToHex(color) {
1148
+ const stringVals = color.replace(RBA_REGEX, "").split(",");
1149
+ let alphaHex = 255;
1150
+ if (stringVals.length !== 3 && stringVals.length !== 4) {
1151
+ throw new Error("invalid color");
1152
+ }
1153
+ else if (stringVals.length === 4) {
1154
+ const alpha = parseFloat(stringVals.pop() || "1");
1155
+ alphaHex = Math.round((alpha || 1) * 255);
1156
+ }
1157
+ const vals = stringVals.map((val) => parseInt(val, 10));
1158
+ if (alphaHex !== 255) {
1159
+ vals.push(alphaHex);
1160
+ }
1161
+ return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
1137
1162
  }
1138
1163
  /**
1139
1164
  * RGBA to HEX representation (#RRGGBBAA).
@@ -1155,7 +1180,7 @@
1155
1180
  a = "0" + a;
1156
1181
  if (a === "ff")
1157
1182
  a = "";
1158
- return "#" + r + g + b + a;
1183
+ return ("#" + r + g + b + a).toUpperCase();
1159
1184
  }
1160
1185
  /**
1161
1186
  * Color string to RGBA representation
@@ -1276,6 +1301,9 @@
1276
1301
  s = +(s * 100).toFixed(1);
1277
1302
  l = +(l * 100).toFixed(1);
1278
1303
  return { a: rgba.a, h, s, l };
1304
+ }
1305
+ function isSameColor(color1, color2) {
1306
+ return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
1279
1307
  }
1280
1308
 
1281
1309
  /** Reference of a cell (eg. A1, $B$5) */
@@ -1427,7 +1455,7 @@
1427
1455
  * formula, commas are used to separate arguments
1428
1456
  * - it does not support % symbol, in formulas % is an operator
1429
1457
  */
1430
- const formulaNumberRegexp = /^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+/;
1458
+ const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
1431
1459
  const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
1432
1460
  const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
1433
1461
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -3022,6 +3050,7 @@
3022
3050
  const LINE_HEIGHT = 1.2;
3023
3051
  css /* scss */ `
3024
3052
  div.o-scorecard {
3053
+ font-family: ${DEFAULT_FONT};
3025
3054
  user-select: none;
3026
3055
  background-color: white;
3027
3056
  display: flex;
@@ -5646,6 +5675,11 @@
5646
5675
  this.currentPosition = newPosition;
5647
5676
  });
5648
5677
  }
5678
+ get popoverStyle() {
5679
+ return cssPropertiesToCss({
5680
+ "z-index": `${this.props.zIndex}`,
5681
+ });
5682
+ }
5649
5683
  }
5650
5684
  Popover.template = "o-spreadsheet-Popover";
5651
5685
  Popover.defaultProps = {
@@ -5654,6 +5688,7 @@
5654
5688
  onMouseWheel: () => { },
5655
5689
  onPopoverMoved: () => { },
5656
5690
  onPopoverHidden: () => { },
5691
+ zIndex: ComponentsImportance.Popover,
5657
5692
  };
5658
5693
  Popover.props = {
5659
5694
  anchorRect: Object,
@@ -5665,6 +5700,7 @@
5665
5700
  onMouseWheel: { type: Function, optional: true },
5666
5701
  onPopoverHidden: { type: Function, optional: true },
5667
5702
  onPopoverMoved: { type: Function, optional: true },
5703
+ zIndex: { type: Number, optional: true },
5668
5704
  slots: Object,
5669
5705
  };
5670
5706
  class PopoverPositionContext {
@@ -16522,6 +16558,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
16522
16558
  this.setContent(this.initialContent || "");
16523
16559
  }
16524
16560
  setContent(text, selection, raise) {
16561
+ text = text.replace(/[\r\n]/g, "");
16525
16562
  const isNewCurrentContent = this.currentContent !== text;
16526
16563
  this.currentContent = text;
16527
16564
  if (selection) {
@@ -16806,6 +16843,8 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
16806
16843
  start = 0;
16807
16844
  if (end > this.el.textContent.length)
16808
16845
  end = this.el.textContent.length;
16846
+ if (start > this.el.textContent.length)
16847
+ start = this.el.textContent.length;
16809
16848
  }
16810
16849
  let startNode = this.findChildAtCharacterIndex(start);
16811
16850
  let endNode = this.findChildAtCharacterIndex(end);
@@ -17032,10 +17071,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
17032
17071
  padding: 0;
17033
17072
  margin: 0;
17034
17073
  border: 0;
17035
- z-index: ${ComponentsImportance.Composer};
17036
17074
  flex-grow: 1;
17037
17075
  max-height: inherit;
17038
17076
  .o-composer {
17077
+ font-family: ${DEFAULT_FONT};
17039
17078
  caret-color: black;
17040
17079
  padding-left: 3px;
17041
17080
  padding-right: 3px;
@@ -17070,6 +17109,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
17070
17109
  .o-topbar-toolbar .o-composer-container:focus-within {
17071
17110
  border: 1px solid ${SELECTION_BORDER_COLOR};
17072
17111
  }
17112
+
17113
+ .o-topbar-toolbar .o-composer-container {
17114
+ z-index: ${ComponentsImportance.TopBarComposer};
17115
+ }
17073
17116
  `;
17074
17117
  class Composer extends owl.Component {
17075
17118
  constructor() {
@@ -17518,7 +17561,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
17518
17561
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
17519
17562
  css /* scss */ `
17520
17563
  div.o-grid-composer {
17521
- z-index: ${ComponentsImportance.Composer};
17564
+ z-index: ${ComponentsImportance.GridComposer};
17522
17565
  box-sizing: border-box;
17523
17566
  position: absolute;
17524
17567
  border: ${COMPOSER_BORDER_WIDTH}px solid ${SELECTION_BORDER_COLOR};
@@ -20054,6 +20097,9 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
20054
20097
  const { display, background, left, top } = this.state.style;
20055
20098
  return `display:${display};${display === "block" ? `background-color:${background};left:${left};top:${top};` : ""}`;
20056
20099
  }
20100
+ isSameColor(color1, color2) {
20101
+ return isSameColor(color1, color2);
20102
+ }
20057
20103
  }
20058
20104
  ColorPicker.template = "o-spreadsheet-ColorPicker";
20059
20105
  ColorPicker.defaultProps = {
@@ -20198,6 +20244,12 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
20198
20244
  const cancelledReasons = [...(((_a = this.state.sectionRuleDispatchResult) === null || _a === void 0 ? void 0 : _a.reasons) || [])];
20199
20245
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
20200
20246
  }
20247
+ onClick(ev) {
20248
+ this.state.openedMenu = undefined;
20249
+ }
20250
+ setup() {
20251
+ owl.useExternalListener(window, "click", this.onClick);
20252
+ }
20201
20253
  updateBackgroundColor(color) {
20202
20254
  this.state.openedMenu = undefined;
20203
20255
  this.props.updateChart({
@@ -20381,6 +20433,12 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
20381
20433
  openedColorPicker: undefined,
20382
20434
  });
20383
20435
  }
20436
+ onClick(ev) {
20437
+ this.state.openedColorPicker = undefined;
20438
+ }
20439
+ setup() {
20440
+ owl.useExternalListener(window, "click", this.onClick);
20441
+ }
20384
20442
  updateTitle(ev) {
20385
20443
  this.props.updateChart({
20386
20444
  title: ev.target.value,
@@ -22284,6 +22342,9 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22284
22342
  owl.onMounted(() => {
22285
22343
  resizeObserver.observe(this.gridOverlayEl);
22286
22344
  });
22345
+ owl.onWillUnmount(() => {
22346
+ resizeObserver.disconnect();
22347
+ });
22287
22348
  useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
22288
22349
  const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
22289
22350
  return scrollY > 0;
@@ -22340,6 +22401,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22340
22401
  };
22341
22402
 
22342
22403
  class GridPopover extends owl.Component {
22404
+ constructor() {
22405
+ super(...arguments);
22406
+ this.zIndex = ComponentsImportance.GridPopover;
22407
+ }
22343
22408
  get cellPopover() {
22344
22409
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
22345
22410
  if (!popover.isOpen) {
@@ -23704,6 +23769,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
23704
23769
  }
23705
23770
  }
23706
23771
  onInput(ev) {
23772
+ // the user meant to paste in the sheet, not open the composer with the pasted content
23773
+ if (!ev.isComposing && ev.inputType === "insertFromPaste") {
23774
+ return;
23775
+ }
23707
23776
  if (ev.data) {
23708
23777
  // if the user types a character on the grid, it means he wants to start composing the selected cell with that
23709
23778
  // character
@@ -24553,6 +24622,70 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
24553
24622
  });
24554
24623
  }
24555
24624
 
24625
+ const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
24626
+ /**
24627
+ * Convert excel format to o_spreadsheet format
24628
+ *
24629
+ * Excel format are defined in openXML §18.8.31
24630
+ */
24631
+ function convertXlsxFormat(numFmtId, formats, warningManager) {
24632
+ var _a, _b, _c;
24633
+ if (numFmtId === 0) {
24634
+ return undefined;
24635
+ }
24636
+ // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
24637
+ let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
24638
+ if (format) {
24639
+ try {
24640
+ let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
24641
+ convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
24642
+ convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
24643
+ // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
24644
+ const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
24645
+ const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
24646
+ if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
24647
+ throw new Error("Multiple escaped blocks in format");
24648
+ }
24649
+ convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
24650
+ convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
24651
+ convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
24652
+ convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
24653
+ convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
24654
+ if (isXlsxDateFormat(convertedFormat)) {
24655
+ convertedFormat = convertDateFormat$1(convertedFormat);
24656
+ }
24657
+ if (isFormatSupported(convertedFormat)) {
24658
+ return convertedFormat;
24659
+ }
24660
+ }
24661
+ catch (e) { }
24662
+ }
24663
+ warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
24664
+ return undefined;
24665
+ }
24666
+ function isFormatSupported(format) {
24667
+ try {
24668
+ formatValue(0, format);
24669
+ return true;
24670
+ }
24671
+ catch (e) {
24672
+ return false;
24673
+ }
24674
+ }
24675
+ function isXlsxDateFormat(format) {
24676
+ return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
24677
+ }
24678
+ function convertDateFormat$1(format) {
24679
+ // Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
24680
+ // but can still occur and are supported by Excel/Google sheets
24681
+ format = format.toLowerCase();
24682
+ format = format.replace(/mmmmm/g, "mmm");
24683
+ format = format.replace(/am\/pm|a\/m/g, "a");
24684
+ format = format.replace(/hhhh/g, "hh");
24685
+ format = format.replace(/\bh\b/g, "hh");
24686
+ return format;
24687
+ }
24688
+
24556
24689
  function convertBorders(data, warningManager) {
24557
24690
  const borderArray = data.borders.map((border) => {
24558
24691
  addBorderWarnings(border, warningManager);
@@ -24617,41 +24750,6 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
24617
24750
  }
24618
24751
  return arrayToObject(formats, 1);
24619
24752
  }
24620
- /**
24621
- * Convert excel format to o_spreadsheet format
24622
- *
24623
- * Excel format are defined in openXML §18.8.31
24624
- */
24625
- function convertXlsxFormat(numFmtId, formats, warningManager) {
24626
- var _a, _b, _c;
24627
- if (numFmtId === 0) {
24628
- return undefined;
24629
- }
24630
- // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
24631
- let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
24632
- if (format) {
24633
- try {
24634
- let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
24635
- convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
24636
- convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
24637
- // Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
24638
- const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
24639
- const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
24640
- if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
24641
- throw new Error("Multiple escaped blocks in format");
24642
- }
24643
- convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
24644
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
24645
- convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
24646
- convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
24647
- formatValue(0, convertedFormat);
24648
- return convertedFormat;
24649
- }
24650
- catch (e) { }
24651
- }
24652
- warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
24653
- return undefined;
24654
- }
24655
24753
  /**
24656
24754
  * We currently only support only a set of font sizes, we cannot define new font sizes.
24657
24755
  * This function adapts an arbitrary font size to the closest supported font size.
@@ -30516,6 +30614,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
30516
30614
  }
30517
30615
  else if (range.zone[start] >= min && range.zone[end] <= max) {
30518
30616
  changeType = "REMOVE";
30617
+ newRange = range.clone({ ...this.getInvalidRange() });
30519
30618
  }
30520
30619
  else if (range.zone[start] <= max && range.zone[end] >= max) {
30521
30620
  const toRemove = max - range.zone[start] + 1;
@@ -30581,8 +30680,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
30581
30680
  return { changeType: "NONE" };
30582
30681
  }
30583
30682
  const invalidSheetName = this.getters.getSheetName(cmd.sheetId);
30584
- const sheetId = "";
30585
- range = range.clone({ sheetId, invalidSheetName });
30683
+ range = range.clone({
30684
+ ...this.getInvalidRange(),
30685
+ invalidSheetName,
30686
+ });
30586
30687
  return { changeType: "REMOVE", range };
30587
30688
  }, cmd.sheetId);
30588
30689
  break;
@@ -30842,6 +30943,15 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
30842
30943
  }
30843
30944
  return str;
30844
30945
  }
30946
+ getInvalidRange() {
30947
+ return {
30948
+ parts: [],
30949
+ prefixSheet: false,
30950
+ zone: { left: -1, top: -1, right: -1, bottom: -1 },
30951
+ sheetId: "",
30952
+ invalidXc: INCORRECT_RANGE_STRING,
30953
+ };
30954
+ }
30845
30955
  }
30846
30956
  RangeAdapter.getters = [
30847
30957
  "getRangeString",
@@ -31806,9 +31916,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
31806
31916
  // remove duplicates first to check validity on a reduced
31807
31917
  // set of colors, then normalize to HEX and remove duplicates
31808
31918
  // again
31809
- [...new Set([...usedColors, ...this.customColors])]
31810
- .filter(isColorValid)
31811
- .map((c) => toHex(c).toLowerCase())),
31919
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
31812
31920
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
31813
31921
  }
31814
31922
  getColorsFromCells(cells) {
@@ -31869,7 +31977,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
31869
31977
  return [...chartsColors];
31870
31978
  }
31871
31979
  tryToAddColor(color) {
31872
- const formattedColor = toHex(color).toLowerCase();
31980
+ const formattedColor = toHex(color);
31873
31981
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
31874
31982
  this.customColors.add(formattedColor);
31875
31983
  }
@@ -32874,8 +32982,8 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32874
32982
  this.getters = getters;
32875
32983
  this.sheetId = sheetId;
32876
32984
  this.boundaries = boundaries;
32877
- this.width = sizeInGrid.width;
32878
- this.height = sizeInGrid.height;
32985
+ this.viewportWidth = sizeInGrid.width;
32986
+ this.viewportHeight = sizeInGrid.height;
32879
32987
  this.offsetScrollbarX = offsets.x;
32880
32988
  this.offsetScrollbarY = offsets.y;
32881
32989
  this.canScrollVertically = options.canScrollVertically;
@@ -32886,6 +32994,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32886
32994
  this.adjustViewportOffsetY();
32887
32995
  }
32888
32996
  // PUBLIC
32997
+ /** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
32998
+ * When the viewport grid size is smaller than its client width (resp. height), it will return
32999
+ * the client width (resp. height).
33000
+ */
32889
33001
  getMaxSize() {
32890
33002
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
32891
33003
  first: this.boundaries.left,
@@ -32897,20 +33009,24 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32897
33009
  });
32898
33010
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
32899
33011
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
32900
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
33012
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
32901
33013
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
32902
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
33014
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
32903
33015
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
32904
- const width = lastColEnd -
32905
- this.offsetCorrectionX +
32906
- (this.canScrollHorizontally
32907
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
32908
- : 0);
32909
- const height = lastRowEnd -
32910
- this.offsetCorrectionY +
32911
- (this.canScrollVertically
32912
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
32913
- : 0);
33016
+ let width = lastColEnd - this.offsetCorrectionX;
33017
+ if (this.canScrollHorizontally) {
33018
+ width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
33019
+ Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
33020
+ );
33021
+ width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
33022
+ }
33023
+ let height = lastRowEnd - this.offsetCorrectionY;
33024
+ if (this.canScrollVertically) {
33025
+ height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
33026
+ Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
33027
+ );
33028
+ height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
33029
+ }
32914
33030
  return { width, height };
32915
33031
  }
32916
33032
  /**
@@ -32919,7 +33035,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32919
33035
  * It returns -1 if no column is found.
32920
33036
  */
32921
33037
  getColIndex(x, absolute = false) {
32922
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
33038
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
32923
33039
  return -1;
32924
33040
  }
32925
33041
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -32930,7 +33046,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32930
33046
  * It returns -1 if no row is found.
32931
33047
  */
32932
33048
  getRowIndex(y, absolute = false) {
32933
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
33049
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
32934
33050
  return -1;
32935
33051
  }
32936
33052
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -32957,7 +33073,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32957
33073
  adjustPositionX(col) {
32958
33074
  const sheetId = this.sheetId;
32959
33075
  const { start, end } = this.getters.getColDimensions(sheetId, col);
32960
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
33076
+ while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
32961
33077
  this.offsetX + this.offsetCorrectionX < start) {
32962
33078
  this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
32963
33079
  this.offsetScrollbarX = this.offsetX;
@@ -32979,7 +33095,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32979
33095
  adjustPositionY(row) {
32980
33096
  const sheetId = this.sheetId;
32981
33097
  while (this.getters.getRowDimensions(sheetId, row).end >
32982
- this.offsetY + this.height + this.offsetCorrectionY &&
33098
+ this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
32983
33099
  this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
32984
33100
  this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
32985
33101
  this.offsetScrollbarY = this.offsetY;
@@ -33017,8 +33133,8 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
33017
33133
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
33018
33134
  this.offsetCorrectionX;
33019
33135
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
33020
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
33021
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
33136
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
33137
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
33022
33138
  return {
33023
33139
  x,
33024
33140
  y,
@@ -33081,12 +33197,12 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
33081
33197
  adjustViewportOffsetX() {
33082
33198
  if (this.canScrollHorizontally) {
33083
33199
  const { width: viewportWidth } = this.getMaxSize();
33084
- if (this.width + this.offsetScrollbarX > viewportWidth) {
33085
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
33200
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
33201
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
33086
33202
  }
33087
33203
  }
33088
33204
  this.left = this.getColIndex(this.offsetScrollbarX, true);
33089
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
33205
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
33090
33206
  if (this.right === -1) {
33091
33207
  this.right = this.boundaries.right;
33092
33208
  }
@@ -33098,12 +33214,12 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
33098
33214
  adjustViewportOffsetY() {
33099
33215
  if (this.canScrollVertically) {
33100
33216
  const { height: paneHeight } = this.getMaxSize();
33101
- if (this.height + this.offsetScrollbarY > paneHeight) {
33102
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
33217
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
33218
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
33103
33219
  }
33104
33220
  }
33105
33221
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
33106
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
33222
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
33107
33223
  if (this.bottom === -1) {
33108
33224
  this.bottom = this.boundaries.bottom;
33109
33225
  }
@@ -33114,7 +33230,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
33114
33230
  adjustViewportZoneX() {
33115
33231
  const sheetId = this.sheetId;
33116
33232
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
33117
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
33233
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
33118
33234
  if (this.right === -1) {
33119
33235
  this.right = this.getters.getNumberCols(sheetId) - 1;
33120
33236
  }
@@ -33127,7 +33243,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
33127
33243
  adjustViewportZoneY() {
33128
33244
  const sheetId = this.sheetId;
33129
33245
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
33130
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
33246
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
33131
33247
  if (this.bottom === -1) {
33132
33248
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
33133
33249
  }
@@ -33389,8 +33505,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
33389
33505
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
33390
33506
  }
33391
33507
  /**
33392
- * Return the main viewport maximum size. That is the zone dimension
33393
- * with some bottom and right padding.
33508
+ * Return the main viewport maximum size relative to the client size.
33394
33509
  */
33395
33510
  getMainViewportRect() {
33396
33511
  const sheetId = this.getters.getActiveSheetId();
@@ -33406,8 +33521,8 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
33406
33521
  const { width, height } = this.getMainViewportRect();
33407
33522
  const viewport = this.getMainInternalViewport(sheetId);
33408
33523
  return {
33409
- maxOffsetX: Math.max(0, width - viewport.width + 1),
33410
- maxOffsetY: Math.max(0, height - viewport.height + 1),
33524
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
33525
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
33411
33526
  };
33412
33527
  }
33413
33528
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -39891,6 +40006,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
39891
40006
  this.state.menuState.parentMenu = menu;
39892
40007
  this.isSelectingMenu = true;
39893
40008
  this.openedEl = ev.target;
40009
+ this.env.model.dispatch("STOP_EDITION");
39894
40010
  }
39895
40011
  closeMenus() {
39896
40012
  this.state.activeTool = "";
@@ -40110,9 +40226,6 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
40110
40226
  color: #333;
40111
40227
  }
40112
40228
 
40113
- * {
40114
- font-family: "Roboto", "RobotoDraft", Helvetica, Arial, sans-serif;
40115
- }
40116
40229
  &,
40117
40230
  *,
40118
40231
  *:before,
@@ -43910,9 +44023,9 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
43910
44023
  Object.defineProperty(exports, '__esModule', { value: true });
43911
44024
 
43912
44025
 
43913
- __info__.version = '16.1.5';
43914
- __info__.date = '2023-03-16T12:12:08.747Z';
43915
- __info__.hash = '12f7a8e';
44026
+ __info__.version = '16.1.7';
44027
+ __info__.date = '2023-04-13T08:29:52.140Z';
44028
+ __info__.hash = '3141a6d';
43916
44029
 
43917
44030
 
43918
44031
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);