@odoo/o-spreadsheet 17.0.60 → 17.0.62

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.60
6
- * @date 2025-05-02T12:28:49.842Z
7
- * @hash 29510cc
5
+ * @version 17.0.62
6
+ * @date 2025-05-13T17:48:40.925Z
7
+ * @hash 23805e7
8
8
  */
9
9
 
10
10
  'use strict';
@@ -1815,7 +1815,7 @@ function isDateAfter(date, dateAfter) {
1815
1815
  */
1816
1816
  const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
1817
1817
  decimalSeparator = escapeRegExp(decimalSeparator);
1818
- return new RegExp(`(^-?\\d+(${decimalSeparator}?\\d*(e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1818
+ return new RegExp(`(^-?\\d+(${decimalSeparator}?\\d*(e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1819
1819
  });
1820
1820
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1821
1821
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
@@ -4486,6 +4486,32 @@ function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
4486
4486
  })
4487
4487
  .filter(isDefined$1);
4488
4488
  }
4489
+ function getNextSheetName(existingNames, baseName = "Sheet") {
4490
+ let i = 1;
4491
+ let name = `${baseName}${i}`;
4492
+ while (existingNames.includes(name)) {
4493
+ name = `${baseName}${i}`;
4494
+ i++;
4495
+ }
4496
+ return name;
4497
+ }
4498
+ function getDuplicateSheetName(nameToDuplicate, existingNames) {
4499
+ let i = 1;
4500
+ const baseName = _t("Copy of %s", nameToDuplicate);
4501
+ let name = baseName.toString();
4502
+ while (existingNames.includes(name)) {
4503
+ name = `${baseName} (${i})`;
4504
+ i++;
4505
+ }
4506
+ return name;
4507
+ }
4508
+ function isSheetNameEqual(name1, name2) {
4509
+ if (name1 === undefined || name2 === undefined) {
4510
+ return false;
4511
+ }
4512
+ return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
4513
+ getUnquotedSheetName(name2.trim().toUpperCase()));
4514
+ }
4489
4515
 
4490
4516
  function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
4491
4517
  return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
@@ -8028,10 +8054,13 @@ const duplicateSheet = {
8028
8054
  name: _t("Duplicate"),
8029
8055
  execute: (env) => {
8030
8056
  const sheetIdFrom = env.model.getters.getActiveSheetId();
8057
+ const sheetNameFrom = env.model.getters.getSheetName(sheetIdFrom);
8031
8058
  const sheetIdTo = env.model.uuidGenerator.smallUuid();
8059
+ const sheetNameTo = env.model.getters.getDuplicateSheetName(sheetNameFrom);
8032
8060
  env.model.dispatch("DUPLICATE_SHEET", {
8033
8061
  sheetId: sheetIdFrom,
8034
8062
  sheetIdTo,
8063
+ sheetNameTo,
8035
8064
  });
8036
8065
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
8037
8066
  },
@@ -18963,6 +18992,9 @@ function isEmpty(value) {
18963
18992
  return value === null || value === undefined;
18964
18993
  }
18965
18994
  const getNeutral = { number: 0, string: "", boolean: false };
18995
+ function areAlmostEqual(value1, value2, epsilon = 2e-16) {
18996
+ return Math.abs(value1 - value2) < epsilon;
18997
+ }
18966
18998
  const EQ = {
18967
18999
  description: _t("Equal."),
18968
19000
  args: [
@@ -18979,6 +19011,9 @@ const EQ = {
18979
19011
  if (typeof value2 === "string") {
18980
19012
  value2 = value2.toUpperCase();
18981
19013
  }
19014
+ if (typeof value1 === "number" && typeof value2 === "number") {
19015
+ return areAlmostEqual(value1, value2);
19016
+ }
18982
19017
  return value1 === value2;
18983
19018
  },
18984
19019
  };
@@ -19013,6 +19048,9 @@ const GT = {
19013
19048
  returns: ["BOOLEAN"],
19014
19049
  compute: function (value1, value2) {
19015
19050
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19051
+ if (typeof v1 === "number" && typeof v2 === "number") {
19052
+ return !areAlmostEqual(v1, v2) && v1 > v2;
19053
+ }
19016
19054
  return v1 > v2;
19017
19055
  });
19018
19056
  },
@@ -19029,6 +19067,9 @@ const GTE = {
19029
19067
  returns: ["BOOLEAN"],
19030
19068
  compute: function (value1, value2) {
19031
19069
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19070
+ if (typeof v1 === "number" && typeof v2 === "number") {
19071
+ return areAlmostEqual(v1, v2) || v1 > v2;
19072
+ }
19032
19073
  return v1 >= v2;
19033
19074
  });
19034
19075
  },
@@ -27069,7 +27110,6 @@ class Composer extends owl.Component {
27069
27110
  searchTermUpperCase === "FALSE") {
27070
27111
  return;
27071
27112
  }
27072
- this.autoCompleteState.showProvider = true;
27073
27113
  this.autoCompleteState.type = "function";
27074
27114
  let values = Object.entries(functionRegistry.content)
27075
27115
  .filter(([_, { hidden }]) => !hidden)
@@ -27085,6 +27125,9 @@ class Composer extends owl.Component {
27085
27125
  if (searchTerm) {
27086
27126
  values = fuzzyLookup(searchTerm, values, (t) => t.text).slice(0, AUTOCOMPLETE_ENTRIES);
27087
27127
  }
27128
+ if (values.length) {
27129
+ this.autoCompleteState.showProvider = true;
27130
+ }
27088
27131
  this.autoCompleteState.values = values.slice(0, AUTOCOMPLETE_ENTRIES);
27089
27132
  this.autoCompleteState.getHtmlContent = (value) => getHtmlContentFromPattern(searchTerm, value, COMPOSER_ASSISTANT_COLOR, "o-semi-bold");
27090
27133
  this.autoCompleteState.selectedIndex = 0;
@@ -27149,6 +27192,13 @@ class Composer extends owl.Component {
27149
27192
  this.props.onInputContextMenu?.(ev);
27150
27193
  }
27151
27194
  }
27195
+ onWheel(event) {
27196
+ // detect if scrollbar is available
27197
+ if (this.composerRef.el &&
27198
+ this.composerRef.el.scrollHeight > this.composerRef.el.clientHeight) {
27199
+ event.stopPropagation();
27200
+ }
27201
+ }
27152
27202
  // ---------------------------------------------------------------------------
27153
27203
  // Private
27154
27204
  // ---------------------------------------------------------------------------
@@ -27457,12 +27507,15 @@ class GridComposer extends owl.Component {
27457
27507
  });
27458
27508
  }
27459
27509
  get composerProps() {
27510
+ // Remove the wrapper border width
27511
+ const maxHeight = this.props.gridDims.height - this.rect.y - 2 * COMPOSER_BORDER_WIDTH;
27460
27512
  return {
27461
27513
  focus: this.props.focus,
27462
27514
  isDefaultFocus: true,
27463
27515
  onComposerContentFocused: this.props.onComposerContentFocused,
27464
27516
  onComposerCellFocused: this.props.onComposerCellFocused,
27465
27517
  onInputContextMenu: this.props.onInputContextMenu,
27518
+ inputStyle: `max-height: ${maxHeight}px;`,
27466
27519
  };
27467
27520
  }
27468
27521
  get containerStyle() {
@@ -31737,7 +31790,7 @@ function getRangeSize(reference, defaultSheetIndex, data) {
31737
31790
  ({ xc, sheetName } = splitReference(reference));
31738
31791
  let rangeSheetIndex;
31739
31792
  if (sheetName) {
31740
- const index = data.sheets.findIndex((sheet) => sheet.name === sheetName);
31793
+ const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
31741
31794
  if (index < 0) {
31742
31795
  throw new Error("Unable to find a sheet with the name " + sheetName);
31743
31796
  }
@@ -31943,7 +31996,7 @@ function convertFormula(formula, data) {
31943
31996
  formula = formula.replace(externalReferenceRegex, (match, externalRefId, sheetName, cellRef) => {
31944
31997
  externalRefId = Number(externalRefId) - 1;
31945
31998
  cellRef = cellRef.replace(/\$/g, "");
31946
- const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => name === sheetName);
31999
+ const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => isSheetNameEqual(name, sheetName));
31947
32000
  if (sheetIndex === -1) {
31948
32001
  return match;
31949
32002
  }
@@ -32278,7 +32331,7 @@ function applyStyleToZone(appliedStyle, zone, cells, styles) {
32278
32331
  */
32279
32332
  function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
32280
32333
  for (let tableSheet of convertedSheets) {
32281
- const tables = xlsxSheets.find((s) => s.sheetName === tableSheet.name).tables;
32334
+ const tables = xlsxSheets.find((s) => isSheetNameEqual(s.sheetName, tableSheet.name)).tables;
32282
32335
  for (let table of tables) {
32283
32336
  const tabRef = table.name + "[";
32284
32337
  for (let sheet of convertedSheets) {
@@ -34355,6 +34408,7 @@ function repairInitialMessages(data, initialMessages) {
34355
34408
  initialMessages = dropCommands(initialMessages, "SORT_CELLS");
34356
34409
  initialMessages = dropCommands(initialMessages, "SET_DECIMAL");
34357
34410
  initialMessages = fixChartDefinitions(data, initialMessages);
34411
+ initialMessages = fixTranslatedDuplicateSheetName(data, initialMessages);
34358
34412
  return initialMessages;
34359
34413
  }
34360
34414
  /**
@@ -34474,6 +34528,40 @@ function fixOverlappingFilters(data) {
34474
34528
  }
34475
34529
  return data;
34476
34530
  }
34531
+ function fixTranslatedDuplicateSheetName(data, initialMessages) {
34532
+ const sheetNames = {};
34533
+ for (const sheet of data.sheets || []) {
34534
+ sheetNames[sheet.id] = sheet.name;
34535
+ }
34536
+ const messages = [];
34537
+ for (const message of initialMessages) {
34538
+ if (message.type === "REMOTE_REVISION") {
34539
+ const commands = [];
34540
+ for (const cmd of message.commands) {
34541
+ switch (cmd.type) {
34542
+ case "DUPLICATE_SHEET":
34543
+ cmd.sheetNameTo =
34544
+ cmd.sheetNameTo ??
34545
+ getDuplicateSheetName(sheetNames[cmd.sheetId], Object.values(sheetNames));
34546
+ break;
34547
+ case "CREATE_SHEET":
34548
+ case "RENAME_SHEET":
34549
+ sheetNames[cmd.sheetId] = cmd.name || getNextSheetName(Object.values(sheetNames));
34550
+ break;
34551
+ }
34552
+ commands.push(cmd);
34553
+ }
34554
+ messages.push({
34555
+ ...message,
34556
+ commands,
34557
+ });
34558
+ }
34559
+ else {
34560
+ messages.push(message);
34561
+ }
34562
+ }
34563
+ return initialMessages;
34564
+ }
34477
34565
  // -----------------------------------------------------------------------------
34478
34566
  // Helpers
34479
34567
  // -----------------------------------------------------------------------------
@@ -36704,9 +36792,7 @@ class ChartPlugin extends CorePlugin {
36704
36792
  : "Success" /* CommandResult.Success */;
36705
36793
  }
36706
36794
  checkChartExists(cmd) {
36707
- return this.getters.getFigureSheetId(cmd.id)
36708
- ? "Success" /* CommandResult.Success */
36709
- : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
36795
+ return this.isChartDefined(cmd.id) ? "Success" /* CommandResult.Success */ : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
36710
36796
  }
36711
36797
  }
36712
36798
 
@@ -39213,7 +39299,7 @@ class RangeAdapter {
39213
39299
  if (range.sheetId === cmd.sheetId) {
39214
39300
  return { changeType: "CHANGE", range };
39215
39301
  }
39216
- if (cmd.name && range.invalidSheetName === cmd.name) {
39302
+ if (isSheetNameEqual(range.invalidSheetName, cmd.name)) {
39217
39303
  const invalidSheetName = undefined;
39218
39304
  const sheetId = cmd.sheetId;
39219
39305
  const newRange = range.clone({ sheetId, invalidSheetName });
@@ -39505,6 +39591,7 @@ class SheetPlugin extends CorePlugin {
39505
39591
  "getCommandZones",
39506
39592
  "getUnboundedZone",
39507
39593
  "checkElementsIncludeAllNonFrozenHeaders",
39594
+ "getDuplicateSheetName",
39508
39595
  ];
39509
39596
  sheetIdsMapName = {};
39510
39597
  orderedSheetIds = [];
@@ -39529,7 +39616,11 @@ class SheetPlugin extends CorePlugin {
39529
39616
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
39530
39617
  }
39531
39618
  case "DUPLICATE_SHEET": {
39532
- return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
39619
+ if (this.sheets[cmd.sheetIdTo])
39620
+ return "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */;
39621
+ if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo))
39622
+ return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
39623
+ return "Success" /* CommandResult.Success */;
39533
39624
  }
39534
39625
  case "MOVE_SHEET":
39535
39626
  try {
@@ -39602,7 +39693,7 @@ class SheetPlugin extends CorePlugin {
39602
39693
  this.showSheet(cmd.sheetId);
39603
39694
  break;
39604
39695
  case "DUPLICATE_SHEET":
39605
- this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo);
39696
+ this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo, cmd.sheetNameTo);
39606
39697
  break;
39607
39698
  case "DELETE_SHEET":
39608
39699
  this.deleteSheet(this.sheets[cmd.sheetId]);
@@ -39737,7 +39828,7 @@ class SheetPlugin extends CorePlugin {
39737
39828
  if (name) {
39738
39829
  const unquotedName = getUnquotedSheetName(name);
39739
39830
  for (const key in this.sheetIdsMapName) {
39740
- if (key.toUpperCase() === unquotedName.toUpperCase()) {
39831
+ if (isSheetNameEqual(key, unquotedName)) {
39741
39832
  return this.sheetIdsMapName[key];
39742
39833
  }
39743
39834
  }
@@ -39812,14 +39903,8 @@ class SheetPlugin extends CorePlugin {
39812
39903
  return dimension === "COL" ? this.getNumberCols(sheetId) : this.getNumberRows(sheetId);
39813
39904
  }
39814
39905
  getNextSheetName(baseName = "Sheet") {
39815
- let i = 1;
39816
39906
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
39817
- let name = `${baseName}${i}`;
39818
- while (names.includes(name)) {
39819
- name = `${baseName}${i}`;
39820
- i++;
39821
- }
39822
- return name;
39907
+ return getNextSheetName(names, baseName);
39823
39908
  }
39824
39909
  getSheetSize(sheetId) {
39825
39910
  return {
@@ -40015,7 +40100,7 @@ class SheetPlugin extends CorePlugin {
40015
40100
  }
40016
40101
  const { orderedSheetIds, sheets } = this;
40017
40102
  const name = cmd.name && cmd.name.trim().toLowerCase();
40018
- if (orderedSheetIds.find((id) => sheets[id]?.name.toLowerCase() === name && id !== cmd.sheetId)) {
40103
+ if (orderedSheetIds.find((id) => isSheetNameEqual(sheets[id]?.name, name) && id !== cmd.sheetId)) {
40019
40104
  return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
40020
40105
  }
40021
40106
  if (FORBIDDEN_IN_EXCEL_REGEX.test(name)) {
@@ -40079,9 +40164,8 @@ class SheetPlugin extends CorePlugin {
40079
40164
  showSheet(sheetId) {
40080
40165
  this.history.update("sheets", sheetId, "isVisible", true);
40081
40166
  }
40082
- duplicateSheet(fromId, toId) {
40167
+ duplicateSheet(fromId, toId, toName) {
40083
40168
  const sheet = this.getSheet(fromId);
40084
- const toName = this.getDuplicateSheetName(sheet.name);
40085
40169
  const newSheet = deepCopy(sheet);
40086
40170
  newSheet.id = toId;
40087
40171
  newSheet.name = toName;
@@ -40113,15 +40197,8 @@ class SheetPlugin extends CorePlugin {
40113
40197
  this.history.update("sheetIdsMapName", sheetIdsMapName);
40114
40198
  }
40115
40199
  getDuplicateSheetName(sheetName) {
40116
- let i = 1;
40117
40200
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
40118
- const baseName = _t("Copy of %s", sheetName);
40119
- let name = baseName.toString();
40120
- while (names.includes(name)) {
40121
- name = `${baseName} (${i})`;
40122
- i++;
40123
- }
40124
- return name;
40201
+ return getDuplicateSheetName(sheetName, names);
40125
40202
  }
40126
40203
  deleteSheet(sheet) {
40127
40204
  const name = sheet.name;
@@ -49747,7 +49824,7 @@ class EditionPlugin extends UIPlugin {
49747
49824
  .find((token) => {
49748
49825
  const { xc, sheetName: sheet } = splitReference(token.value);
49749
49826
  const sheetName = sheet || this.getters.getSheetName(this.sheetId);
49750
- if (this.getters.getSheetName(activeSheetId) !== sheetName) {
49827
+ if (!isSheetNameEqual(this.getters.getSheetName(activeSheetId), sheetName)) {
49751
49828
  return false;
49752
49829
  }
49753
49830
  const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
@@ -58252,6 +58329,6 @@ exports.setTranslationMethod = setTranslationMethod;
58252
58329
  exports.tokenize = tokenize;
58253
58330
 
58254
58331
 
58255
- __info__.version = "17.0.60";
58256
- __info__.date = "2025-05-02T12:28:49.842Z";
58257
- __info__.hash = "29510cc";
58332
+ __info__.version = "17.0.62";
58333
+ __info__.date = "2025-05-13T17:48:40.925Z";
58334
+ __info__.hash = "23805e7";
@@ -1892,6 +1892,7 @@ interface DeleteSheetCommand extends SheetDependentCommand {
1892
1892
  interface DuplicateSheetCommand extends SheetDependentCommand {
1893
1893
  type: "DUPLICATE_SHEET";
1894
1894
  sheetIdTo: UID;
1895
+ sheetNameTo: string;
1895
1896
  }
1896
1897
  interface MoveSheetCommand extends SheetDependentCommand {
1897
1898
  type: "MOVE_SHEET";
@@ -4030,7 +4031,7 @@ interface SheetState {
4030
4031
  readonly cellPosition: Record<UID, CellPosition | undefined>;
4031
4032
  }
4032
4033
  declare class SheetPlugin extends CorePlugin<SheetState> implements SheetState {
4033
- static getters: readonly ["getSheetName", "tryGetSheetName", "getSheet", "tryGetSheet", "getSheetIdByName", "getSheetIds", "getVisibleSheetIds", "isSheetVisible", "getEvaluationSheets", "doesHeaderExist", "doesHeadersExist", "getCell", "getCellPosition", "getColsZone", "getRowCells", "getRowsZone", "getNumberCols", "getNumberRows", "getNumberHeaders", "getGridLinesVisibility", "getNextSheetName", "getSheetSize", "getSheetZone", "getPaneDivisions", "checkZonesExistInSheet", "getCommandZones", "getUnboundedZone", "checkElementsIncludeAllNonFrozenHeaders"];
4034
+ static getters: readonly ["getSheetName", "tryGetSheetName", "getSheet", "tryGetSheet", "getSheetIdByName", "getSheetIds", "getVisibleSheetIds", "isSheetVisible", "getEvaluationSheets", "doesHeaderExist", "doesHeadersExist", "getCell", "getCellPosition", "getColsZone", "getRowCells", "getRowsZone", "getNumberCols", "getNumberRows", "getNumberHeaders", "getGridLinesVisibility", "getNextSheetName", "getSheetSize", "getSheetZone", "getPaneDivisions", "checkZonesExistInSheet", "getCommandZones", "getUnboundedZone", "checkElementsIncludeAllNonFrozenHeaders", "getDuplicateSheetName"];
4034
4035
  readonly sheetIdsMapName: Record<string, UID | undefined>;
4035
4036
  readonly orderedSheetIds: UID[];
4036
4037
  readonly sheets: Record<UID, Sheet | undefined>;
@@ -4110,7 +4111,7 @@ declare class SheetPlugin extends CorePlugin<SheetState> implements SheetState {
4110
4111
  private hideSheet;
4111
4112
  private showSheet;
4112
4113
  private duplicateSheet;
4113
- private getDuplicateSheetName;
4114
+ getDuplicateSheetName(sheetName: string): string;
4114
4115
  private deleteSheet;
4115
4116
  /**
4116
4117
  * Delete column. This requires a lot of handling:
@@ -7342,6 +7343,7 @@ declare class Composer extends Component<ComposerProps, SpreadsheetChildEnv> {
7342
7343
  onClick(): void;
7343
7344
  onDblClick(): void;
7344
7345
  onContextMenu(ev: MouseEvent): void;
7346
+ onWheel(event: WheelEvent): void;
7345
7347
  private processContent;
7346
7348
  /**
7347
7349
  * Get the HTML content corresponding to the current composer token, divided by lines.