@odoo/o-spreadsheet 18.3.3 → 18.3.4

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 18.3.3
6
- * @date 2025-05-13T17:54:43.312Z
7
- * @hash b79924a
5
+ * @version 18.3.4
6
+ * @date 2025-05-20T05:57:03.751Z
7
+ * @hash 28f4521
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -1623,18 +1623,53 @@ function lettersToNumber(letters) {
1623
1623
  let result = 0;
1624
1624
  const l = letters.length;
1625
1625
  for (let i = 0; i < l; i++) {
1626
- const charCode = letters.charCodeAt(i);
1627
- const colIndex = charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
1626
+ const colIndex = charToNumber(letters[i]);
1628
1627
  result = result * 26 + colIndex;
1629
1628
  }
1630
1629
  return result - 1;
1631
1630
  }
1631
+ function charToNumber(char) {
1632
+ const charCode = char.charCodeAt(0);
1633
+ return charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
1634
+ }
1632
1635
  function isCharALetter(char) {
1633
1636
  return (char >= "A" && char <= "Z") || (char >= "a" && char <= "z");
1634
1637
  }
1635
1638
  function isCharADigit(char) {
1636
1639
  return char >= "0" && char <= "9";
1637
1640
  }
1641
+ // we limit the max column to 3 letters and max row to 7 digits for performance reasons
1642
+ const MAX_COL = lettersToNumber("ZZZ");
1643
+ const MAX_ROW = 9999998;
1644
+ function consumeSpaces(chars) {
1645
+ while (chars.current === " ") {
1646
+ chars.advanceBy(1);
1647
+ }
1648
+ }
1649
+ function consumeLetters(chars) {
1650
+ if (chars.current === "$")
1651
+ chars.advanceBy(1);
1652
+ if (!chars.current || !isCharALetter(chars.current)) {
1653
+ return -1;
1654
+ }
1655
+ let colCoordinate = 0;
1656
+ while (chars.current && isCharALetter(chars.current)) {
1657
+ colCoordinate = colCoordinate * 26 + charToNumber(chars.shift());
1658
+ }
1659
+ return colCoordinate;
1660
+ }
1661
+ function consumeDigits(chars) {
1662
+ if (chars.current === "$")
1663
+ chars.advanceBy(1);
1664
+ if (!chars.current || !isCharADigit(chars.current)) {
1665
+ return -1;
1666
+ }
1667
+ let num = 0;
1668
+ while (chars.current && isCharADigit(chars.current)) {
1669
+ num = num * 10 + Number(chars.shift());
1670
+ }
1671
+ return num;
1672
+ }
1638
1673
  /**
1639
1674
  * Convert a "XC" coordinate to cartesian coordinates.
1640
1675
  *
@@ -1645,33 +1680,17 @@ function isCharADigit(char) {
1645
1680
  * Note: it also accepts lowercase coordinates, but not fixed references
1646
1681
  */
1647
1682
  function toCartesian(xc) {
1648
- xc = xc.trim();
1649
- let letterPart = "";
1650
- let numberPart = "";
1651
- let i = 0;
1652
- // Process letter part
1653
- if (xc[i] === "$")
1654
- i++;
1655
- while (i < xc.length && isCharALetter(xc[i])) {
1656
- letterPart += xc[i++];
1657
- }
1658
- if (letterPart.length === 0 || letterPart.length > 3) {
1659
- // limit to max 3 letters for performance reasons
1683
+ const chars = new TokenizingChars(xc);
1684
+ consumeSpaces(chars);
1685
+ const letterPart = consumeLetters(chars);
1686
+ if (letterPart === -1 || !chars.current) {
1660
1687
  throw new Error(`Invalid cell description: ${xc}`);
1661
1688
  }
1662
- // Process number part
1663
- if (xc[i] === "$")
1664
- i++;
1665
- while (i < xc.length && isCharADigit(xc[i])) {
1666
- numberPart += xc[i++];
1667
- }
1668
- if (i !== xc.length || numberPart.length === 0 || numberPart.length > 7) {
1669
- // limit to max 7 numbers for performance reasons
1670
- throw new Error(`Invalid cell description: ${xc}`);
1671
- }
1672
- const col = lettersToNumber(letterPart);
1673
- const row = Number(numberPart) - 1;
1674
- if (isNaN(row)) {
1689
+ const num = consumeDigits(chars);
1690
+ consumeSpaces(chars);
1691
+ const col = letterPart - 1;
1692
+ const row = num - 1;
1693
+ if (!chars.isOver() || col > MAX_COL || row > MAX_ROW) {
1675
1694
  throw new Error(`Invalid cell description: ${xc}`);
1676
1695
  }
1677
1696
  return { col, row };
@@ -2026,67 +2045,6 @@ function binarySuccessorSearch(arr, val, start = 0, matchEqual = true) {
2026
2045
  return result;
2027
2046
  }
2028
2047
 
2029
- /** Reference of a cell (eg. A1, $B$5) */
2030
- const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
2031
- // Same as above, but matches the exact string (nothing before or after)
2032
- const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
2033
- /** Reference of a column header (eg. A, AB, $A) */
2034
- const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
2035
- /** Reference of a row header (eg. 1, $1) */
2036
- const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
2037
- /** Reference of a column (eg. A, $CA, Sheet1!B) */
2038
- const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
2039
- /** Reference of a row (eg. 1, 59, Sheet1!9) */
2040
- const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
2041
- /** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
2042
- const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
2043
- /** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
2044
- const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
2045
- /** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
2046
- const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
2047
- "(" +
2048
- [cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
2049
- ")" +
2050
- /$/.source, "i");
2051
- /**
2052
- * Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
2053
- */
2054
- function isColReference(xc) {
2055
- return colReference.test(xc);
2056
- }
2057
- /**
2058
- * Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
2059
- */
2060
- function isRowReference(xc) {
2061
- return rowReference.test(xc);
2062
- }
2063
- function isColHeader(str) {
2064
- return colHeader.test(str);
2065
- }
2066
- function isRowHeader(str) {
2067
- return rowHeader.test(str);
2068
- }
2069
- /**
2070
- * Return true if the given xc is the reference of a single cell,
2071
- * without any specified sheet (e.g. A1)
2072
- */
2073
- function isSingleCellReference(xc) {
2074
- return singleCellReference.test(xc);
2075
- }
2076
- function splitReference(ref) {
2077
- if (!ref.includes("!")) {
2078
- return { xc: ref };
2079
- }
2080
- const parts = ref.split("!");
2081
- const xc = parts.pop();
2082
- const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
2083
- return { sheetName, xc };
2084
- }
2085
- /** Return a reference SheetName!xc from the given arguments */
2086
- function getFullReference(sheetName, xc) {
2087
- return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
2088
- }
2089
-
2090
2048
  /**
2091
2049
  * Convert from a cartesian reference to a Zone
2092
2050
  * The range boundaries will be kept in the same order as the
@@ -2104,63 +2062,55 @@ function getFullReference(sheetName, xc) {
2104
2062
  *
2105
2063
  */
2106
2064
  function toZoneWithoutBoundaryChanges(xc) {
2107
- if (xc.includes("!")) {
2108
- xc = xc.split("!").at(-1);
2109
- }
2110
- if (xc.includes("$")) {
2111
- xc = xc.replaceAll("$", "");
2112
- }
2113
- let firstRangePart = "";
2114
- let secondRangePart;
2115
- if (xc.includes(":")) {
2116
- [firstRangePart, secondRangePart] = xc.split(":");
2117
- firstRangePart = firstRangePart.trim();
2118
- secondRangePart = secondRangePart.trim();
2119
- }
2120
- else {
2121
- firstRangePart = xc.trim();
2122
- }
2065
+ const chars = new TokenizingChars(xc);
2066
+ consumeSpaces(chars);
2067
+ const sheetSeparatorIndex = xc.indexOf("!");
2068
+ if (sheetSeparatorIndex !== -1) {
2069
+ chars.advanceBy(sheetSeparatorIndex + 1);
2070
+ }
2071
+ const leftLetters = consumeLetters(chars);
2072
+ const leftNumbers = consumeDigits(chars);
2123
2073
  let top, bottom, left, right;
2124
2074
  let fullCol = false;
2125
2075
  let fullRow = false;
2126
2076
  let hasHeader = false;
2127
- if (isColReference(firstRangePart)) {
2128
- left = right = lettersToNumber(firstRangePart);
2077
+ if (leftNumbers === -1) {
2078
+ left = right = leftLetters - 1;
2129
2079
  top = bottom = 0;
2130
2080
  fullCol = true;
2131
2081
  }
2132
- else if (isRowReference(firstRangePart)) {
2133
- top = bottom = parseInt(firstRangePart, 10) - 1;
2082
+ else if (leftLetters === -1) {
2083
+ top = bottom = leftNumbers - 1;
2134
2084
  left = right = 0;
2135
2085
  fullRow = true;
2136
2086
  }
2137
2087
  else {
2138
- const c = toCartesian(firstRangePart);
2139
- left = right = c.col;
2140
- top = bottom = c.row;
2088
+ left = right = leftLetters - 1;
2089
+ top = bottom = leftNumbers - 1;
2141
2090
  hasHeader = true;
2142
2091
  }
2143
- if (secondRangePart) {
2144
- if (isColReference(secondRangePart)) {
2145
- right = lettersToNumber(secondRangePart);
2092
+ consumeSpaces(chars);
2093
+ if (chars.current === ":") {
2094
+ chars.advanceBy(1);
2095
+ consumeSpaces(chars);
2096
+ const rightLetters = consumeLetters(chars);
2097
+ const rightNumbers = consumeDigits(chars);
2098
+ if (rightNumbers === -1) {
2099
+ right = rightLetters - 1;
2146
2100
  fullCol = true;
2147
2101
  }
2148
- else if (isRowReference(secondRangePart)) {
2149
- bottom = parseInt(secondRangePart, 10) - 1;
2102
+ else if (rightLetters === -1) {
2103
+ bottom = rightNumbers - 1;
2150
2104
  fullRow = true;
2151
2105
  }
2152
2106
  else {
2153
- const c = toCartesian(secondRangePart);
2154
- right = c.col;
2155
- bottom = c.row;
2107
+ right = rightLetters - 1;
2108
+ bottom = rightNumbers - 1;
2156
2109
  top = fullCol ? bottom : top;
2157
2110
  left = fullRow ? right : left;
2158
2111
  hasHeader = true;
2159
2112
  }
2160
2113
  }
2161
- if (fullCol && fullRow) {
2162
- throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
2163
- }
2164
2114
  const zone = {
2165
2115
  top,
2166
2116
  left,
@@ -2189,7 +2139,16 @@ function toZoneWithoutBoundaryChanges(xc) {
2189
2139
  */
2190
2140
  function toUnboundedZone(xc) {
2191
2141
  const zone = toZoneWithoutBoundaryChanges(xc);
2192
- return reorderZone(zone);
2142
+ const orderedZone = reorderZone(zone);
2143
+ const bottom = orderedZone.bottom;
2144
+ const right = orderedZone.right;
2145
+ if ((bottom !== undefined && bottom > MAX_ROW) || (right !== undefined && right > MAX_COL)) {
2146
+ throw new Error(`Range string out of bounds: ${xc}`); // limit the size of the zone for performance
2147
+ }
2148
+ if (bottom === undefined && right === undefined) {
2149
+ throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
2150
+ }
2151
+ return orderedZone;
2193
2152
  }
2194
2153
  /**
2195
2154
  * Convert from a cartesian reference to a Zone.
@@ -6000,6 +5959,67 @@ function scrollDelay(value) {
6000
5959
  return MIN_DELAY + (MAX_DELAY - MIN_DELAY) * Math.exp(-ACCELERATION * (value - 1));
6001
5960
  }
6002
5961
 
5962
+ /** Reference of a cell (eg. A1, $B$5) */
5963
+ const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
5964
+ // Same as above, but matches the exact string (nothing before or after)
5965
+ const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
5966
+ /** Reference of a column header (eg. A, AB, $A) */
5967
+ const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
5968
+ /** Reference of a row header (eg. 1, $1) */
5969
+ const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
5970
+ /** Reference of a column (eg. A, $CA, Sheet1!B) */
5971
+ const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
5972
+ /** Reference of a row (eg. 1, 59, Sheet1!9) */
5973
+ const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
5974
+ /** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
5975
+ const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
5976
+ /** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
5977
+ const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
5978
+ /** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
5979
+ const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
5980
+ "(" +
5981
+ [cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
5982
+ ")" +
5983
+ /$/.source, "i");
5984
+ /**
5985
+ * Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
5986
+ */
5987
+ function isColReference(xc) {
5988
+ return colReference.test(xc);
5989
+ }
5990
+ /**
5991
+ * Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
5992
+ */
5993
+ function isRowReference(xc) {
5994
+ return rowReference.test(xc);
5995
+ }
5996
+ function isColHeader(str) {
5997
+ return colHeader.test(str);
5998
+ }
5999
+ function isRowHeader(str) {
6000
+ return rowHeader.test(str);
6001
+ }
6002
+ /**
6003
+ * Return true if the given xc is the reference of a single cell,
6004
+ * without any specified sheet (e.g. A1)
6005
+ */
6006
+ function isSingleCellReference(xc) {
6007
+ return singleCellReference.test(xc);
6008
+ }
6009
+ function splitReference(ref) {
6010
+ if (!ref.includes("!")) {
6011
+ return { xc: ref };
6012
+ }
6013
+ const parts = ref.split("!");
6014
+ const xc = parts.pop();
6015
+ const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
6016
+ return { sheetName, xc };
6017
+ }
6018
+ /** Return a reference SheetName!xc from the given arguments */
6019
+ function getFullReference(sheetName, xc) {
6020
+ return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
6021
+ }
6022
+
6003
6023
  function createDefaultRows(rowNumber) {
6004
6024
  const rows = [];
6005
6025
  for (let i = 0; i < rowNumber; i++) {
@@ -43608,12 +43628,13 @@ class StandaloneComposerStore extends AbstractComposerStore {
43608
43628
  return res;
43609
43629
  }
43610
43630
  getComposerContent() {
43631
+ let content = this._currentContent;
43611
43632
  if (this.editionMode === "inactive") {
43612
43633
  // References in the content might not be linked to the current active sheet
43613
43634
  // We here force the sheet name prefix for all references that are not in
43614
43635
  // the current active sheet
43615
43636
  const defaultRangeSheetId = this.args().defaultRangeSheetId;
43616
- return rangeTokenize(this.args().content)
43637
+ content = rangeTokenize(this.args().content)
43617
43638
  .map((token) => {
43618
43639
  if (token.type === "REFERENCE") {
43619
43640
  const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
@@ -43623,7 +43644,7 @@ class StandaloneComposerStore extends AbstractComposerStore {
43623
43644
  })
43624
43645
  .join("");
43625
43646
  }
43626
- return this._currentContent;
43647
+ return localizeContent(content, this.getters.getLocale());
43627
43648
  }
43628
43649
  stopEdition() {
43629
43650
  this._stopEdition();
@@ -48088,6 +48109,9 @@ class PivotMeasureEditor extends Component {
48088
48109
  }
48089
48110
  return undefined;
48090
48111
  }
48112
+ get isCalculatedMeasureInvalid() {
48113
+ return this.env.model.getters.getMeasureCompiledFormula(this.props.measure).isBadExpression;
48114
+ }
48091
48115
  }
48092
48116
 
48093
48117
  css /* scss */ `
@@ -52525,14 +52549,14 @@ function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }
52525
52549
  const deltaX = Math.min(dirX * (mouseInitialX - mouseX + scrollX - initialScrollX), width - minFigSize);
52526
52550
  const deltaY = Math.min(dirY * (mouseInitialY - mouseY + scrollY - initialScrollY), height - minFigSize);
52527
52551
  const fraction = Math.min(deltaX / width, deltaY / height);
52528
- width = width * (1 - fraction);
52529
- height = height * (1 - fraction);
52530
52552
  if (dirX < 0) {
52531
52553
  x = x + width * fraction;
52532
52554
  }
52533
52555
  if (dirY < 0) {
52534
52556
  y = y + height * fraction;
52535
52557
  }
52558
+ width = width * (1 - fraction);
52559
+ height = height * (1 - fraction);
52536
52560
  }
52537
52561
  else {
52538
52562
  const deltaX = Math.max(dirX * (mouseX - mouseInitialX + scrollX - initialScrollX), minFigSize - width);
@@ -63774,10 +63798,9 @@ class Evaluator {
63774
63798
  return this.evaluatedCells.keysForSheet(sheetId);
63775
63799
  }
63776
63800
  getArrayFormulaSpreadingOn(position) {
63777
- const hasArrayFormulaResult = this.getEvaluatedCell(position).type !== CellValueType.empty &&
63778
- !this.getters.getCell(position)?.isFormula;
63779
- if (!hasArrayFormulaResult) {
63780
- return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
63801
+ const isEmpty = this.getEvaluatedCell(position).type === CellValueType.empty;
63802
+ if (isEmpty) {
63803
+ return undefined;
63781
63804
  }
63782
63805
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
63783
63806
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
@@ -80391,6 +80414,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
80391
80414
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
80392
80415
 
80393
80416
 
80394
- __info__.version = "18.3.3";
80395
- __info__.date = "2025-05-13T17:54:43.312Z";
80396
- __info__.hash = "b79924a";
80417
+ __info__.version = "18.3.4";
80418
+ __info__.date = "2025-05-20T05:57:03.751Z";
80419
+ __info__.hash = "28f4521";