@odoo/o-spreadsheet 17.0.53 → 17.0.55

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 17.0.53
6
- * @date 2025-03-12T15:26:58.496Z
7
- * @hash 47dfd62
5
+ * @version 17.0.55
6
+ * @date 2025-03-26T12:44:29.690Z
7
+ * @hash c3a4769
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -948,7 +948,10 @@
948
948
  }
949
949
  else if (stringVals.length === 4) {
950
950
  const alpha = parseFloat(stringVals.pop() || "1");
951
- alphaHex = Math.round((alpha || 1) * 255);
951
+ if (isNaN(alpha)) {
952
+ throw new Error("invalid alpha value");
953
+ }
954
+ alphaHex = Math.round(alpha * 255);
952
955
  }
953
956
  const vals = stringVals.map((val) => parseInt(val, 10));
954
957
  if (alphaHex !== 255) {
@@ -4493,11 +4496,13 @@
4493
4496
  if (!cell || (!cell.isFormula && !cell.content)) {
4494
4497
  return DEFAULT_CELL_HEIGHT;
4495
4498
  }
4496
- const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
4497
- const numberOfLines = cell.isFormula
4498
- ? 1
4499
- : splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
4500
- const fontSize = computeTextFontSizeInPixels(cell.style);
4499
+ const content = cell.isFormula ? "" : cell.content;
4500
+ return getCellContentHeight(ctx, content, cell.style, colSize);
4501
+ }
4502
+ function getCellContentHeight(ctx, content, style, colSize) {
4503
+ const maxWidth = style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
4504
+ const numberOfLines = splitTextToWidth(ctx, content, style, maxWidth).length;
4505
+ const fontSize = computeTextFontSizeInPixels(style);
4501
4506
  return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
4502
4507
  }
4503
4508
  const textWidthCache = {};
@@ -7768,7 +7773,7 @@
7768
7773
  */
7769
7774
  function canonicalizeNumberContent(content, locale) {
7770
7775
  return content.startsWith("=")
7771
- ? canonicalizeFormula$1(content, locale)
7776
+ ? canonicalizeFormula(content, locale)
7772
7777
  : canonicalizeNumberLiteral(content, locale);
7773
7778
  }
7774
7779
  /**
@@ -7783,7 +7788,7 @@
7783
7788
  */
7784
7789
  function canonicalizeContent(content, locale) {
7785
7790
  return content.startsWith("=")
7786
- ? canonicalizeFormula$1(content, locale)
7791
+ ? canonicalizeFormula(content, locale)
7787
7792
  : canonicalizeLiteral(content, locale);
7788
7793
  }
7789
7794
  /**
@@ -7799,15 +7804,21 @@
7799
7804
  ? localizeFormula(content, locale)
7800
7805
  : localizeLiteral(content, locale);
7801
7806
  }
7807
+ /** Change a number string to its canonical form (en_US locale) */
7808
+ function canonicalizeNumberValue(content, locale) {
7809
+ return content.startsWith("=")
7810
+ ? canonicalizeFormula(content, locale)
7811
+ : canonicalizeNumberLiteral(content, locale);
7812
+ }
7802
7813
  /** Change a formula to its canonical form (en_US locale) */
7803
- function canonicalizeFormula$1(formula, locale) {
7804
- return _localizeFormula$1(formula, locale, DEFAULT_LOCALE);
7814
+ function canonicalizeFormula(formula, locale) {
7815
+ return _localizeFormula(formula, locale, DEFAULT_LOCALE);
7805
7816
  }
7806
7817
  /** Change a formula from the canonical form to the given locale */
7807
7818
  function localizeFormula(formula, locale) {
7808
- return _localizeFormula$1(formula, DEFAULT_LOCALE, locale);
7819
+ return _localizeFormula(formula, DEFAULT_LOCALE, locale);
7809
7820
  }
7810
- function _localizeFormula$1(formula, fromLocale, toLocale) {
7821
+ function _localizeFormula(formula, fromLocale, toLocale) {
7811
7822
  if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
7812
7823
  fromLocale.decimalSeparator === toLocale.decimalSeparator) {
7813
7824
  return formula;
@@ -8561,7 +8572,8 @@
8561
8572
  }
8562
8573
  }
8563
8574
  else if (dataSets.length === 1) {
8564
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
8575
+ const dataLength = getData(getters, dataSets[0]).length;
8576
+ for (let i = 0; i < dataLength; i++) {
8565
8577
  labels.formattedValues.push("");
8566
8578
  labels.values.push("");
8567
8579
  }
@@ -24291,6 +24303,7 @@
24291
24303
  columns: {},
24292
24304
  });
24293
24305
  setup() {
24306
+ this.updateColumns();
24294
24307
  owl.onWillUpdateProps(() => this.updateColumns());
24295
24308
  }
24296
24309
  toggleHasHeader() {
@@ -30361,9 +30374,9 @@
30361
30374
  /** In XLSX color format (no #) */
30362
30375
  const AUTO_COLOR = "000000";
30363
30376
  const XLSX_ICONSET_MAP = {
30364
- arrow: "3Arrows",
30377
+ arrows: "3Arrows",
30365
30378
  smiley: "3Symbols",
30366
- dot: "3TrafficLights1",
30379
+ dots: "3TrafficLights1",
30367
30380
  };
30368
30381
  const NAMESPACE = {
30369
30382
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -30779,6 +30792,7 @@
30779
30792
  };
30780
30793
  /** Map between legend position in XLSX file and human readable position */
30781
30794
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
30795
+ none: "none",
30782
30796
  b: "bottom",
30783
30797
  t: "top",
30784
30798
  l: "left",
@@ -33011,7 +33025,7 @@
33011
33025
  ? "right"
33012
33026
  : "left",
33013
33027
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
33014
- default: "b",
33028
+ default: "none",
33015
33029
  }).asString()],
33016
33030
  stacked: barChartGrouping === "stacked",
33017
33031
  fontColor: "000000",
@@ -45469,12 +45483,7 @@
45469
45483
  continue;
45470
45484
  }
45471
45485
  const position = { col: col + c, row: row + r, sheetId: sheetId };
45472
- // TODO: refactor this part. the "Paste merge" action is also executed with
45473
- // MOVE_RANGES in pasteFromCut. Adding a condition on the operation type here
45474
- // is not appropriate
45475
- if (this.operation !== "CUT") {
45476
- this.pasteMergeIfExist(origin.position, position);
45477
- }
45486
+ this.pasteMergeIfExist(origin.position, position, this.operation);
45478
45487
  this.pasteCell(origin, position, this.operation, clipboardOptions);
45479
45488
  if (shouldPasteCF) {
45480
45489
  this.pasteCf(origin.position, position);
@@ -45531,7 +45540,7 @@
45531
45540
  * If the origin position given is the top left of a merge, merge the target
45532
45541
  * position.
45533
45542
  */
45534
- pasteMergeIfExist(origin, target) {
45543
+ pasteMergeIfExist(origin, target, operation) {
45535
45544
  let { sheetId, col, row } = origin;
45536
45545
  const { col: mainCellColOrigin, row: mainCellRowOrigin } = this.getters.getMainCellPosition(origin);
45537
45546
  if (mainCellColOrigin === col && mainCellRowOrigin === row) {
@@ -45539,6 +45548,9 @@
45539
45548
  if (!merge) {
45540
45549
  return;
45541
45550
  }
45551
+ if (operation === "CUT") {
45552
+ this.dispatch("REMOVE_MERGE", { sheetId, target: [merge] });
45553
+ }
45542
45554
  ({ sheetId, col, row } = target);
45543
45555
  this.dispatch("ADD_MERGE", {
45544
45556
  sheetId,
@@ -47830,12 +47842,7 @@
47830
47842
  }
47831
47843
  break;
47832
47844
  case "AUTORESIZE_ROWS":
47833
- this.dispatch("RESIZE_COLUMNS_ROWS", {
47834
- elements: cmd.rows,
47835
- dimension: "ROW",
47836
- size: null,
47837
- sheetId: cmd.sheetId,
47838
- });
47845
+ this.autoResizeRows(cmd.sheetId, cmd.rows);
47839
47846
  break;
47840
47847
  }
47841
47848
  }
@@ -47933,6 +47940,48 @@
47933
47940
  }
47934
47941
  return "Success" /* CommandResult.Success */;
47935
47942
  }
47943
+ autoResizeRows(sheetId, rows) {
47944
+ const rowSizes = [];
47945
+ for (const row of rows) {
47946
+ let evaluatedRowSize = 0;
47947
+ for (const cellId of this.getters.getRowCells(sheetId, row)) {
47948
+ const cell = this.getters.getCellById(cellId);
47949
+ if (!cell) {
47950
+ continue;
47951
+ }
47952
+ const position = this.getters.getCellPosition(cell.id);
47953
+ const colSize = this.getters.getColSize(sheetId, position.col);
47954
+ if (cell.isFormula) {
47955
+ const content = this.getters.getEvaluatedCell(position).formattedValue;
47956
+ const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
47957
+ if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
47958
+ evaluatedRowSize = evaluatedSize;
47959
+ }
47960
+ }
47961
+ else {
47962
+ const content = cell.content;
47963
+ const dynamicRowSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
47964
+ // Only keep the size of evaluated cells if it's bigger than the dynamic row size
47965
+ if (dynamicRowSize >= evaluatedRowSize && dynamicRowSize > DEFAULT_CELL_HEIGHT) {
47966
+ evaluatedRowSize = 0;
47967
+ }
47968
+ }
47969
+ }
47970
+ rowSizes.push(evaluatedRowSize || null);
47971
+ }
47972
+ const groupedSizes = new Map(rowSizes.map((size) => [size, []]));
47973
+ for (let i = 0; i < rowSizes.length; i++) {
47974
+ groupedSizes.get(rowSizes[i])?.push(rows[i]);
47975
+ }
47976
+ for (const [size, rows] of groupedSizes) {
47977
+ this.dispatch("RESIZE_COLUMNS_ROWS", {
47978
+ elements: rows,
47979
+ dimension: "ROW",
47980
+ size,
47981
+ sheetId,
47982
+ });
47983
+ }
47984
+ }
47936
47985
  }
47937
47986
 
47938
47987
  const genericRepeatsTransforms = [
@@ -48582,37 +48631,6 @@
48582
48631
  }
48583
48632
  }
48584
48633
 
48585
- /** Change a number string to its canonical form (en_US locale) */
48586
- function canonicalizeNumberValue(content, locale) {
48587
- return content.startsWith("=")
48588
- ? canonicalizeFormula(content, locale)
48589
- : canonicalizeNumberLiteral(content, locale);
48590
- }
48591
- /** Change a formula to its canonical form (en_US locale) */
48592
- function canonicalizeFormula(formula, locale) {
48593
- return _localizeFormula(formula, locale, DEFAULT_LOCALE);
48594
- }
48595
- function _localizeFormula(formula, fromLocale, toLocale) {
48596
- if (fromLocale.formulaArgSeparator === toLocale.formulaArgSeparator &&
48597
- fromLocale.decimalSeparator === toLocale.decimalSeparator) {
48598
- return formula;
48599
- }
48600
- const tokens = tokenize(formula, fromLocale);
48601
- let localizedFormula = "";
48602
- for (const token of tokens) {
48603
- if (token.type === "NUMBER") {
48604
- localizedFormula += token.value.replace(fromLocale.decimalSeparator, toLocale.decimalSeparator);
48605
- }
48606
- else if (token.type === "ARG_SEPARATOR") {
48607
- localizedFormula += toLocale.formulaArgSeparator;
48608
- }
48609
- else {
48610
- localizedFormula += token.value;
48611
- }
48612
- }
48613
- return localizedFormula;
48614
- }
48615
-
48616
48634
  /** State of the clipboard when copying/cutting from the OS clipboard*/
48617
48635
  class ClipboardOsState extends ClipboardCellsAbstractState {
48618
48636
  values;
@@ -49189,8 +49207,8 @@
49189
49207
  this.colorIndexByRange = {};
49190
49208
  break;
49191
49209
  case "CANCEL_EDITION":
49192
- this.cancelEditionAndActivateSheet();
49193
49210
  this.resetContent();
49211
+ this.cancelEditionAndActivateSheet();
49194
49212
  this.colorIndexByRange = {};
49195
49213
  break;
49196
49214
  case "SET_CURRENT_CONTENT":
@@ -49201,8 +49219,8 @@
49201
49219
  this.replaceSelection(cmd.text);
49202
49220
  break;
49203
49221
  case "SELECT_FIGURE":
49204
- this.cancelEditionAndActivateSheet();
49205
49222
  this.resetContent();
49223
+ this.cancelEditionAndActivateSheet();
49206
49224
  break;
49207
49225
  case "ADD_COLUMNS_ROWS":
49208
49226
  this.onAddElements(cmd);
@@ -49245,8 +49263,8 @@
49245
49263
  const sheetIdExists = !!this.getters.tryGetSheet(this.sheetId);
49246
49264
  if (!sheetIdExists && this.mode !== "inactive") {
49247
49265
  this.sheetId = this.getters.getActiveSheetId();
49248
- this.cancelEditionAndActivateSheet();
49249
49266
  this.resetContent();
49267
+ this.cancelEditionAndActivateSheet();
49250
49268
  this.ui.raiseBlockingErrorUI(CELL_DELETED_MESSAGE);
49251
49269
  }
49252
49270
  break;
@@ -53468,7 +53486,9 @@
53468
53486
  margin-top: -1px;
53469
53487
  border: 1px solid;
53470
53488
 
53471
- .o-composer:empty:not(:focus):not(.active)::before {
53489
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
53490
+ .o-composer:empty:not(:focus):not(.active)::before,
53491
+ &.o-topbar-composer-readonly .o-composer:empty::before {
53472
53492
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
53473
53493
  position: relative;
53474
53494
  top: 20%;
@@ -56469,10 +56489,14 @@
56469
56489
  continue;
56470
56490
  }
56471
56491
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
56492
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
56493
+ if (isIconSetReversed(rule.icons)) {
56494
+ iconSetAttrs.push(["reverse", "1"]);
56495
+ }
56472
56496
  conditionalFormats.push(escapeXml /*xml*/ `
56473
56497
  <conditionalFormatting sqref="${range}">
56474
56498
  <cfRule ${formatAttributes(ruleAttributes)}>
56475
- <iconSet iconSet="${getIconSet(rule.icons)}">
56499
+ <iconSet ${formatAttributes(iconSetAttrs)}>
56476
56500
  ${joinXmlNodes(cfValueObjectNodes)}
56477
56501
  </iconSet>
56478
56502
  </cfRule>
@@ -56490,9 +56514,21 @@
56490
56514
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
56491
56515
  ];
56492
56516
  }
56517
+ function isIconSetReversed(iconSet) {
56518
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
56519
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
56520
+ }
56493
56521
  function getIconSet(iconSet) {
56494
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
56495
- "dots"];
56522
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
56523
+ }
56524
+ /**
56525
+ * Partial detection based on "upper" point only.
56526
+ * We support any arbitrary icon in the set, while excel doesn't allow
56527
+ * mixing icons from different types.
56528
+ */
56529
+ function detectIconsType(iconSet) {
56530
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
56531
+ return type;
56496
56532
  }
56497
56533
  function thresholdAttributes(threshold, position) {
56498
56534
  const type = getExcelThresholdType(threshold.type, position);
@@ -58068,9 +58104,9 @@
58068
58104
  exports.tokenize = tokenize;
58069
58105
 
58070
58106
 
58071
- __info__.version = "17.0.53";
58072
- __info__.date = "2025-03-12T15:26:58.496Z";
58073
- __info__.hash = "47dfd62";
58107
+ __info__.version = "17.0.55";
58108
+ __info__.date = "2025-03-26T12:44:29.690Z";
58109
+ __info__.hash = "c3a4769";
58074
58110
 
58075
58111
 
58076
58112
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);