@odoo/o-spreadsheet 17.4.33 → 17.4.35

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.4.33
6
- * @date 2025-05-02T12:30:31.263Z
7
- * @hash 3ba00e6
5
+ * @version 17.4.35
6
+ * @date 2025-05-13T17:49:44.553Z
7
+ * @hash 534c5f4
8
8
  */
9
9
 
10
10
  'use strict';
@@ -1916,7 +1916,7 @@ function isDateAfter(date, dateAfter) {
1916
1916
  */
1917
1917
  const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
1918
1918
  decimalSeparator = escapeRegExp(decimalSeparator);
1919
- return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1919
+ return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1920
1920
  });
1921
1921
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1922
1922
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
@@ -5192,6 +5192,32 @@ function moveHeaderIndexesOnHeaderDeletion(deletedHeaders, headers) {
5192
5192
  })
5193
5193
  .filter(isDefined);
5194
5194
  }
5195
+ function getNextSheetName(existingNames, baseName = "Sheet") {
5196
+ let i = 1;
5197
+ let name = `${baseName}${i}`;
5198
+ while (existingNames.includes(name)) {
5199
+ name = `${baseName}${i}`;
5200
+ i++;
5201
+ }
5202
+ return name;
5203
+ }
5204
+ function getDuplicateSheetName(nameToDuplicate, existingNames) {
5205
+ let i = 1;
5206
+ const baseName = _t("Copy of %s", nameToDuplicate);
5207
+ let name = baseName.toString();
5208
+ while (existingNames.includes(name)) {
5209
+ name = `${baseName} (${i})`;
5210
+ i++;
5211
+ }
5212
+ return name;
5213
+ }
5214
+ function isSheetNameEqual(name1, name2) {
5215
+ if (name1 === undefined || name2 === undefined) {
5216
+ return false;
5217
+ }
5218
+ return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
5219
+ getUnquotedSheetName(name2.trim().toUpperCase()));
5220
+ }
5195
5221
 
5196
5222
  function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
5197
5223
  return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
@@ -6395,6 +6421,24 @@ const monthNumberAdapter = {
6395
6421
  return `${normalizedValue}`;
6396
6422
  },
6397
6423
  };
6424
+ /**
6425
+ * normalizes month number + year
6426
+ */
6427
+ const monthAdapter = {
6428
+ normalizeFunctionValue(value) {
6429
+ const date = toNumber(value, DEFAULT_LOCALE);
6430
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
6431
+ },
6432
+ toValueAndFormat(normalizedValue) {
6433
+ return {
6434
+ value: toNumber(normalizedValue, DEFAULT_LOCALE),
6435
+ format: "mmmm yyyy",
6436
+ };
6437
+ },
6438
+ toFunctionValue(normalizedValue) {
6439
+ return `"${normalizedValue}"`;
6440
+ },
6441
+ };
6398
6442
  /**
6399
6443
  * normalizes quarter number
6400
6444
  */
@@ -6462,6 +6506,7 @@ pivotTimeAdapterRegistry
6462
6506
  .add("day_of_month", nullHandlerDecorator(dayOfMonthAdapter))
6463
6507
  .add("iso_week_number", nullHandlerDecorator(isoWeekNumberAdapter))
6464
6508
  .add("month_number", nullHandlerDecorator(monthNumberAdapter))
6509
+ .add("month", nullHandlerDecorator(monthAdapter))
6465
6510
  .add("quarter_number", nullHandlerDecorator(quarterNumberAdapter));
6466
6511
 
6467
6512
  const AGGREGATOR_NAMES = {
@@ -6474,10 +6519,9 @@ const AGGREGATOR_NAMES = {
6474
6519
  avg: _t("Average"),
6475
6520
  sum: _t("Sum"),
6476
6521
  };
6477
- const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
6478
6522
  const AGGREGATORS_BY_FIELD_TYPE = {
6479
- integer: NUMBER_CHAR_AGGREGATORS,
6480
- char: NUMBER_CHAR_AGGREGATORS,
6523
+ integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
6524
+ char: ["count_distinct", "count"],
6481
6525
  boolean: ["count_distinct", "count", "bool_and", "bool_or"],
6482
6526
  };
6483
6527
  const AGGREGATORS = {};
@@ -6642,10 +6686,7 @@ function toNormalizedPivotValue(dimension, groupValue) {
6642
6686
  return normalizer(groupValueString, dimension.granularity);
6643
6687
  }
6644
6688
  function normalizeDateTime(value, granularity) {
6645
- if (!granularity) {
6646
- throw new Error("Missing granularity");
6647
- }
6648
- return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
6689
+ return pivotTimeAdapter(granularity ?? "month").normalizeFunctionValue(value);
6649
6690
  }
6650
6691
  function toFunctionPivotValue(value, dimension) {
6651
6692
  if (value === null) {
@@ -6657,10 +6698,7 @@ function toFunctionPivotValue(value, dimension) {
6657
6698
  return pivotToFunctionValueRegistry.get(dimension.type)(value, dimension.granularity);
6658
6699
  }
6659
6700
  function toFunctionValueDateTime(value, granularity) {
6660
- if (!granularity) {
6661
- throw new Error("Missing granularity");
6662
- }
6663
- return pivotTimeAdapter(granularity).toFunctionValue(value);
6701
+ return pivotTimeAdapter(granularity ?? "month").toFunctionValue(value);
6664
6702
  }
6665
6703
  const pivotNormalizationValueRegistry = new Registry();
6666
6704
  pivotNormalizationValueRegistry
@@ -6697,8 +6735,11 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6697
6735
  const evaluatedCell = this.getters.getEvaluatedCell(position);
6698
6736
  const pivotId = this.getters.getPivotIdFromPosition(position);
6699
6737
  const spreader = this.getters.getArrayFormulaSpreadingOn(position);
6700
- if (pivotId) {
6701
- if (spreader && (!deepEquals(spreader, position) || !isCopyingOneCell)) {
6738
+ if (pivotId && spreader) {
6739
+ const pivotZone = this.getters.getSpreadZone(spreader);
6740
+ if ((!deepEquals(spreader, position) || !isCopyingOneCell) &&
6741
+ pivotZone &&
6742
+ !data.zones.some((z) => isZoneInside(pivotZone, z))) {
6702
6743
  const pivotCell = this.getters.getPivotCellFromPosition(position);
6703
6744
  const formulaPivotId = this.getters.getPivotFormulaId(pivotId);
6704
6745
  const pivotFormula = createPivotFormula(formulaPivotId, pivotCell);
@@ -9420,7 +9461,10 @@ function proxifyStoreMutation(store, callback) {
9420
9461
  const functionProxy = new Proxy(value, {
9421
9462
  // trap the function call
9422
9463
  apply(target, thisArg, argArray) {
9423
- Reflect.apply(target, thisStore, argArray);
9464
+ const res = Reflect.apply(target, thisStore, argArray);
9465
+ if (res === "noStateChange") {
9466
+ return;
9467
+ }
9424
9468
  callback();
9425
9469
  },
9426
9470
  });
@@ -9442,7 +9486,7 @@ function getDependencyContainer(env) {
9442
9486
  const ModelStore = createAbstractStore("Model");
9443
9487
 
9444
9488
  class RendererStore {
9445
- mutators = ["register", "unRegister"];
9489
+ mutators = ["register", "unRegister", "drawLayer"];
9446
9490
  renderers = {};
9447
9491
  register(renderer) {
9448
9492
  if (!renderer.renderingLayers.length) {
@@ -9462,14 +9506,14 @@ class RendererStore {
9462
9506
  }
9463
9507
  drawLayer(context, layer) {
9464
9508
  const renderers = this.renderers[layer];
9465
- if (!renderers) {
9466
- return;
9467
- }
9468
- for (const renderer of renderers) {
9469
- context.ctx.save();
9470
- renderer.drawLayer(context, layer);
9471
- context.ctx.restore();
9509
+ if (renderers) {
9510
+ for (const renderer of renderers) {
9511
+ context.ctx.save();
9512
+ renderer.drawLayer(context, layer);
9513
+ context.ctx.restore();
9514
+ }
9472
9515
  }
9516
+ return "noStateChange";
9473
9517
  }
9474
9518
  }
9475
9519
 
@@ -10082,7 +10126,7 @@ class ComposerStore extends SpreadsheetStore {
10082
10126
  .find((token) => {
10083
10127
  const { xc, sheetName: sheet } = splitReference(token.value);
10084
10128
  const sheetName = sheet || this.getters.getSheetName(this.sheetId);
10085
- if (this.getters.getSheetName(activeSheetId) !== sheetName) {
10129
+ if (!isSheetNameEqual(this.getters.getSheetName(activeSheetId), sheetName)) {
10086
10130
  return false;
10087
10131
  }
10088
10132
  const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
@@ -10387,27 +10431,30 @@ class ComposerFocusStore extends SpreadsheetStore {
10387
10431
  }
10388
10432
  focusTopBarComposer(selection) {
10389
10433
  if (this.getters.isReadonly()) {
10390
- return;
10434
+ return "noStateChange";
10391
10435
  }
10392
10436
  this.topBarFocus = "contentFocus";
10393
10437
  this.gridFocusMode = "inactive";
10394
- this.setComposerContent({ selection } || {});
10438
+ this.setComposerContent({ selection });
10439
+ return;
10395
10440
  }
10396
10441
  focusGridComposerContent() {
10397
10442
  if (this.getters.isReadonly()) {
10398
- return;
10443
+ return "noStateChange";
10399
10444
  }
10400
10445
  this.topBarFocus = "inactive";
10401
10446
  this.gridFocusMode = "contentFocus";
10402
10447
  this.setComposerContent({});
10448
+ return;
10403
10449
  }
10404
10450
  focusGridComposerCell(content, selection) {
10405
10451
  if (this.getters.isReadonly()) {
10406
- return;
10452
+ return "noStateChange";
10407
10453
  }
10408
10454
  this.topBarFocus = "inactive";
10409
10455
  this.gridFocusMode = "cellFocus";
10410
- this.setComposerContent({ content, selection } || {});
10456
+ this.setComposerContent({ content, selection });
10457
+ return;
10411
10458
  }
10412
10459
  /**
10413
10460
  * Start the edition or update the content if it's already started.
@@ -19384,7 +19431,7 @@ const IF = {
19384
19431
  return { value: "" };
19385
19432
  }
19386
19433
  if (result.value === null) {
19387
- result.value = "";
19434
+ return { ...result, value: "" };
19388
19435
  }
19389
19436
  return result;
19390
19437
  },
@@ -19405,7 +19452,7 @@ const IFERROR = {
19405
19452
  return { value: "" };
19406
19453
  }
19407
19454
  if (result.value === null) {
19408
- result.value = "";
19455
+ return { ...result, value: "" };
19409
19456
  }
19410
19457
  return result;
19411
19458
  },
@@ -19426,7 +19473,7 @@ const IFNA = {
19426
19473
  return { value: "" };
19427
19474
  }
19428
19475
  if (result.value === null) {
19429
- result.value = "";
19476
+ return { ...result, value: "" };
19430
19477
  }
19431
19478
  return result;
19432
19479
  },
@@ -19452,7 +19499,7 @@ const IFS = {
19452
19499
  return { value: "" };
19453
19500
  }
19454
19501
  if (result.value === null) {
19455
- result.value = "";
19502
+ return { ...result, value: "" };
19456
19503
  }
19457
19504
  return result;
19458
19505
  }
@@ -20292,6 +20339,9 @@ function isEmpty(data) {
20292
20339
  return data === undefined || data.value === null;
20293
20340
  }
20294
20341
  const getNeutral = { number: 0, string: "", boolean: false };
20342
+ function areAlmostEqual(value1, value2, epsilon = 2e-16) {
20343
+ return Math.abs(value1 - value2) < epsilon;
20344
+ }
20295
20345
  const EQ = {
20296
20346
  description: _t("Equal."),
20297
20347
  args: [
@@ -20313,6 +20363,9 @@ const EQ = {
20313
20363
  if (isEvaluationError(_value2)) {
20314
20364
  throw value2;
20315
20365
  }
20366
+ if (typeof _value1 === "number" && typeof _value2 === "number") {
20367
+ return areAlmostEqual(_value1, _value2);
20368
+ }
20316
20369
  return _value1 === _value2;
20317
20370
  },
20318
20371
  };
@@ -20352,6 +20405,9 @@ const GT = {
20352
20405
  ],
20353
20406
  compute: function (value1, value2) {
20354
20407
  return applyRelationalOperator(value1, value2, (v1, v2) => {
20408
+ if (typeof v1 === "number" && typeof v2 === "number") {
20409
+ return !areAlmostEqual(v1, v2) && v1 > v2;
20410
+ }
20355
20411
  return v1 > v2;
20356
20412
  });
20357
20413
  },
@@ -20367,6 +20423,9 @@ const GTE = {
20367
20423
  ],
20368
20424
  compute: function (value1, value2) {
20369
20425
  return applyRelationalOperator(value1, value2, (v1, v2) => {
20426
+ if (typeof v1 === "number" && typeof v2 === "number") {
20427
+ return areAlmostEqual(v1, v2) || v1 > v2;
20428
+ }
20370
20429
  return v1 >= v2;
20371
20430
  });
20372
20431
  },
@@ -21467,10 +21526,18 @@ autoCompleteProviders.add("functions", {
21467
21526
  });
21468
21527
 
21469
21528
  class DOMFocusableElementStore {
21470
- mutators = ["setFocusableElement"];
21529
+ mutators = ["setFocusableElement", "focus"];
21471
21530
  focusableElement = undefined;
21472
21531
  setFocusableElement(element) {
21473
21532
  this.focusableElement = element;
21533
+ return "noStateChange";
21534
+ }
21535
+ focus() {
21536
+ if (this.focusableElement === document.activeElement) {
21537
+ return "noStateChange";
21538
+ }
21539
+ this.focusableElement?.focus();
21540
+ return;
21474
21541
  }
21475
21542
  }
21476
21543
 
@@ -21727,12 +21794,20 @@ class HoveredCellStore extends SpreadsheetStore {
21727
21794
  }
21728
21795
  }
21729
21796
  hover(position) {
21797
+ if (position.col === this.col && position.row === this.row) {
21798
+ return "noStateChange";
21799
+ }
21730
21800
  this.col = position.col;
21731
21801
  this.row = position.row;
21802
+ return;
21732
21803
  }
21733
21804
  clear() {
21805
+ if (this.col === undefined && this.row === undefined) {
21806
+ return "noStateChange";
21807
+ }
21734
21808
  this.col = undefined;
21735
21809
  this.row = undefined;
21810
+ return;
21736
21811
  }
21737
21812
  }
21738
21813
 
@@ -21754,7 +21829,11 @@ class CellPopoverStore extends SpreadsheetStore {
21754
21829
  this.persistentPopover = { col, row, sheetId, type };
21755
21830
  }
21756
21831
  close() {
21832
+ if (!this.persistentPopover) {
21833
+ return "noStateChange";
21834
+ }
21757
21835
  this.persistentPopover = undefined;
21836
+ return;
21758
21837
  }
21759
21838
  get persistentCellPopover() {
21760
21839
  return ((this.persistentPopover && { isOpen: true, ...this.persistentPopover }) || { isOpen: false });
@@ -22623,10 +22702,13 @@ const duplicateSheet = {
22623
22702
  name: _t("Duplicate"),
22624
22703
  execute: (env) => {
22625
22704
  const sheetIdFrom = env.model.getters.getActiveSheetId();
22705
+ const sheetNameFrom = env.model.getters.getSheetName(sheetIdFrom);
22626
22706
  const sheetIdTo = env.model.uuidGenerator.smallUuid();
22707
+ const sheetNameTo = env.model.getters.getDuplicateSheetName(sheetNameFrom);
22627
22708
  env.model.dispatch("DUPLICATE_SHEET", {
22628
22709
  sheetId: sheetIdFrom,
22629
22710
  sheetIdTo,
22711
+ sheetNameTo,
22630
22712
  });
22631
22713
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
22632
22714
  },
@@ -24071,6 +24153,13 @@ class Composer extends owl.Component {
24071
24153
  this.props.onInputContextMenu?.(ev);
24072
24154
  }
24073
24155
  }
24156
+ onWheel(event) {
24157
+ // detect if scrollbar is available
24158
+ if (this.composerRef.el &&
24159
+ this.composerRef.el.scrollHeight > this.composerRef.el.clientHeight) {
24160
+ event.stopPropagation();
24161
+ }
24162
+ }
24074
24163
  // ---------------------------------------------------------------------------
24075
24164
  // Private
24076
24165
  // ---------------------------------------------------------------------------
@@ -29359,7 +29448,7 @@ const FIX_FORMULAS = {
29359
29448
  if (!pivot.isValid()) {
29360
29449
  return;
29361
29450
  }
29362
- env.model.dispatch("INSERT_PIVOT", {
29451
+ env.model.dispatch("SPLIT_PIVOT_FORMULA", {
29363
29452
  sheetId,
29364
29453
  col,
29365
29454
  row,
@@ -36993,8 +37082,8 @@ function compareDimensionValues(dimension, a, b) {
36993
37082
 
36994
37083
  const NULL_SYMBOL = Symbol("NULL");
36995
37084
  function createDate(dimension, value, locale) {
36996
- const granularity = dimension.granularity;
36997
- if (!granularity || !(granularity in MAP_VALUE_DIMENSION_DATE)) {
37085
+ const granularity = dimension.granularity || "month";
37086
+ if (!(granularity in MAP_VALUE_DIMENSION_DATE)) {
36998
37087
  throw new Error(`Unknown date granularity: ${granularity}`);
36999
37088
  }
37000
37089
  const keyInMap = typeof value === "number" || typeof value === "string" ? value : NULL_SYMBOL;
@@ -37013,6 +37102,9 @@ function createDate(dimension, value, locale) {
37013
37102
  case "month_number":
37014
37103
  number = date.getMonth() + 1;
37015
37104
  break;
37105
+ case "month":
37106
+ number = Math.floor(toNumber(value, locale));
37107
+ break;
37016
37108
  case "iso_week_number":
37017
37109
  number = date.getIsoWeek();
37018
37110
  break;
@@ -37071,6 +37163,10 @@ const MAP_VALUE_DIMENSION_DATE = {
37071
37163
  set: new Set(),
37072
37164
  values: {},
37073
37165
  },
37166
+ month: {
37167
+ set: new Set(),
37168
+ values: {},
37169
+ },
37074
37170
  iso_week_number: {
37075
37171
  set: new Set(),
37076
37172
  values: {},
@@ -37247,7 +37343,7 @@ class SpreadsheetPivot {
37247
37343
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
37248
37344
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
37249
37345
  if (dimension.type === "date") {
37250
- const adapter = pivotTimeAdapter(dimension.granularity);
37346
+ const adapter = pivotTimeAdapter((dimension.granularity || "month"));
37251
37347
  return adapter.toValueAndFormat(lastNode.value, this.getters.getLocale());
37252
37348
  }
37253
37349
  if (!finalCell) {
@@ -37332,7 +37428,7 @@ class SpreadsheetPivot {
37332
37428
  if (nonEmptyCells.length === 0) {
37333
37429
  return "integer";
37334
37430
  }
37335
- if (nonEmptyCells.every((cell) => cell.format && isDateTimeFormat(cell.format))) {
37431
+ if (nonEmptyCells.every((cell) => cell.type === CellValueType.number && cell.format && isDateTimeFormat(cell.format))) {
37336
37432
  return "date";
37337
37433
  }
37338
37434
  if (nonEmptyCells.every((cell) => cell.type === CellValueType.boolean)) {
@@ -37413,7 +37509,12 @@ class SpreadsheetPivot {
37413
37509
  entry[field.name] = { value: null, type: CellValueType.empty };
37414
37510
  }
37415
37511
  else {
37416
- entry[field.name] = cell;
37512
+ if (field.type === "char") {
37513
+ entry[field.name] = { ...cell, value: cell.formattedValue || null };
37514
+ }
37515
+ else {
37516
+ entry[field.name] = cell;
37517
+ }
37417
37518
  }
37418
37519
  }
37419
37520
  entry["__count"] = { value: 1, type: CellValueType.number };
@@ -37447,6 +37548,7 @@ pivotRegistry.add("SPREADSHEET", {
37447
37548
  "year",
37448
37549
  "quarter_number",
37449
37550
  "month_number",
37551
+ "month",
37450
37552
  "iso_week_number",
37451
37553
  "day_of_month",
37452
37554
  "day",
@@ -37656,7 +37758,7 @@ class PivotSidePanelStore extends SpreadsheetStore {
37656
37758
  granularitiesPerFields[field.name] = new Set(granularities);
37657
37759
  }
37658
37760
  for (const field of dateFields) {
37659
- granularitiesPerFields[field.name].delete(field.granularity);
37761
+ granularitiesPerFields[field.name].delete(field.granularity || "month");
37660
37762
  }
37661
37763
  return granularitiesPerFields;
37662
37764
  }
@@ -39543,12 +39645,15 @@ class GridComposer extends owl.Component {
39543
39645
  });
39544
39646
  }
39545
39647
  get composerProps() {
39648
+ // Remove the wrapper border width
39649
+ const maxHeight = this.props.gridDims.height - this.rect.y - 2 * COMPOSER_BORDER_WIDTH;
39546
39650
  return {
39547
39651
  focus: this.composerFocusStore.gridComposerFocus,
39548
39652
  isDefaultFocus: true,
39549
39653
  onComposerContentFocused: () => this.composerFocusStore.focusGridComposerContent(),
39550
39654
  onComposerCellFocused: (content) => this.composerFocusStore.focusGridComposerCell(content),
39551
39655
  onInputContextMenu: this.props.onInputContextMenu,
39656
+ inputStyle: `max-height: ${maxHeight}px;`,
39552
39657
  };
39553
39658
  }
39554
39659
  get containerStyle() {
@@ -39604,7 +39709,7 @@ class GridComposer extends owl.Component {
39604
39709
  this.isEditing = isEditing;
39605
39710
  if (!isEditing) {
39606
39711
  this.rect = this.defaultRect;
39607
- this.DOMFocusableElementStore.focusableElement?.focus();
39712
+ this.DOMFocusableElementStore.focus();
39608
39713
  return;
39609
39714
  }
39610
39715
  const position = this.env.model.getters.getActivePosition();
@@ -42040,10 +42145,6 @@ function useGridDrawing(refName, model, canvasSize) {
42040
42145
  ctx.scale(dpr, dpr);
42041
42146
  for (const layer of OrderedLayers()) {
42042
42147
  model.drawLayer(renderingContext, layer);
42043
- // @ts-ignore 'drawLayer' is not declated as a mutator because:
42044
- // it does not mutate anything. Most importantly it's used
42045
- // during rendering. Invoking a mutator during rendering would
42046
- // trigger another rendering, ultimately resulting in an infinite loop.
42047
42148
  rendererStore.drawLayer(renderingContext, layer);
42048
42149
  }
42049
42150
  }
@@ -42666,7 +42767,7 @@ class Grid extends owl.Component {
42666
42767
  this.cellPopovers = useStore(CellPopoverStore);
42667
42768
  owl.useEffect(() => {
42668
42769
  if (!this.sidePanel.isOpen) {
42669
- this.DOMFocusableElementStore.focusableElement?.focus();
42770
+ this.DOMFocusableElementStore.focus();
42670
42771
  }
42671
42772
  }, () => [this.sidePanel.isOpen]);
42672
42773
  }
@@ -42870,7 +42971,7 @@ class Grid extends owl.Component {
42870
42971
  focusDefaultElement() {
42871
42972
  if (!this.env.model.getters.getSelectedFigureId() &&
42872
42973
  this.composerStore.editionMode === "inactive") {
42873
- this.DOMFocusableElementStore.focusableElement?.focus();
42974
+ this.DOMFocusableElementStore.focus();
42874
42975
  }
42875
42976
  }
42876
42977
  get gridEl() {
@@ -44607,7 +44708,7 @@ function getRangeSize(reference, defaultSheetIndex, data) {
44607
44708
  ({ xc, sheetName } = splitReference(reference));
44608
44709
  let rangeSheetIndex;
44609
44710
  if (sheetName) {
44610
- const index = data.sheets.findIndex((sheet) => sheet.name === sheetName);
44711
+ const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
44611
44712
  if (index < 0) {
44612
44713
  throw new Error("Unable to find a sheet with the name " + sheetName);
44613
44714
  }
@@ -44828,7 +44929,7 @@ function convertFormula(formula, data) {
44828
44929
  formula = formula.replace(externalReferenceRegex, (match, externalRefId, sheetName, cellRef) => {
44829
44930
  externalRefId = Number(externalRefId) - 1;
44830
44931
  cellRef = cellRef.replace(/\$/g, "");
44831
- const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => name === sheetName);
44932
+ const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => isSheetNameEqual(name, sheetName));
44832
44933
  if (sheetIndex === -1) {
44833
44934
  return match;
44834
44935
  }
@@ -45157,7 +45258,7 @@ function convertPivotTableConfig(pivotTable) {
45157
45258
  */
45158
45259
  function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
45159
45260
  for (let tableSheet of convertedSheets) {
45160
- const tables = xlsxSheets.find((s) => s.sheetName === tableSheet.name).tables;
45261
+ const tables = xlsxSheets.find((s) => isSheetNameEqual(s.sheetName, tableSheet.name)).tables;
45161
45262
  for (let table of tables) {
45162
45263
  const tabRef = table.name + "[";
45163
45264
  for (let sheet of convertedSheets) {
@@ -47305,6 +47406,7 @@ function repairInitialMessages(data, initialMessages) {
47305
47406
  initialMessages = dropCommands(initialMessages, "SORT_CELLS");
47306
47407
  initialMessages = dropCommands(initialMessages, "SET_DECIMAL");
47307
47408
  initialMessages = fixChartDefinitions(data, initialMessages);
47409
+ initialMessages = fixTranslatedDuplicateSheetName(data, initialMessages);
47308
47410
  return initialMessages;
47309
47411
  }
47310
47412
  /**
@@ -47424,6 +47526,40 @@ function fixOverlappingFilters(data) {
47424
47526
  }
47425
47527
  return data;
47426
47528
  }
47529
+ function fixTranslatedDuplicateSheetName(data, initialMessages) {
47530
+ const sheetNames = {};
47531
+ for (const sheet of data.sheets || []) {
47532
+ sheetNames[sheet.id] = sheet.name;
47533
+ }
47534
+ const messages = [];
47535
+ for (const message of initialMessages) {
47536
+ if (message.type === "REMOTE_REVISION") {
47537
+ const commands = [];
47538
+ for (const cmd of message.commands) {
47539
+ switch (cmd.type) {
47540
+ case "DUPLICATE_SHEET":
47541
+ cmd.sheetNameTo =
47542
+ cmd.sheetNameTo ??
47543
+ getDuplicateSheetName(sheetNames[cmd.sheetId], Object.values(sheetNames));
47544
+ break;
47545
+ case "CREATE_SHEET":
47546
+ case "RENAME_SHEET":
47547
+ sheetNames[cmd.sheetId] = cmd.name || getNextSheetName(Object.values(sheetNames));
47548
+ break;
47549
+ }
47550
+ commands.push(cmd);
47551
+ }
47552
+ messages.push({
47553
+ ...message,
47554
+ commands,
47555
+ });
47556
+ }
47557
+ else {
47558
+ messages.push(message);
47559
+ }
47560
+ }
47561
+ return initialMessages;
47562
+ }
47427
47563
  // -----------------------------------------------------------------------------
47428
47564
  // Helpers
47429
47565
  // -----------------------------------------------------------------------------
@@ -48959,9 +49095,7 @@ class ChartPlugin extends CorePlugin {
48959
49095
  : "Success" /* CommandResult.Success */;
48960
49096
  }
48961
49097
  checkChartExists(cmd) {
48962
- return this.getters.getFigureSheetId(cmd.id)
48963
- ? "Success" /* CommandResult.Success */
48964
- : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
49098
+ return this.isChartDefined(cmd.id) ? "Success" /* CommandResult.Success */ : "ChartDoesNotExist" /* CommandResult.ChartDoesNotExist */;
48965
49099
  }
48966
49100
  }
48967
49101
 
@@ -50801,7 +50935,7 @@ class RangeAdapter {
50801
50935
  if (range.sheetId === cmd.sheetId) {
50802
50936
  return { changeType: "CHANGE", range };
50803
50937
  }
50804
- if (cmd.name && range.invalidSheetName === cmd.name) {
50938
+ if (isSheetNameEqual(range.invalidSheetName, cmd.name)) {
50805
50939
  const invalidSheetName = undefined;
50806
50940
  const sheetId = cmd.sheetId;
50807
50941
  const newRange = range.clone({ sheetId, invalidSheetName });
@@ -51138,6 +51272,7 @@ class SheetPlugin extends CorePlugin {
51138
51272
  "getCommandZones",
51139
51273
  "getUnboundedZone",
51140
51274
  "checkElementsIncludeAllNonFrozenHeaders",
51275
+ "getDuplicateSheetName",
51141
51276
  ];
51142
51277
  sheetIdsMapName = {};
51143
51278
  orderedSheetIds = [];
@@ -51162,7 +51297,11 @@ class SheetPlugin extends CorePlugin {
51162
51297
  return this.checkValidations(cmd, this.checkSheetName, this.checkSheetPosition);
51163
51298
  }
51164
51299
  case "DUPLICATE_SHEET": {
51165
- return this.sheets[cmd.sheetIdTo] ? "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */ : "Success" /* CommandResult.Success */;
51300
+ if (this.sheets[cmd.sheetIdTo])
51301
+ return "DuplicatedSheetId" /* CommandResult.DuplicatedSheetId */;
51302
+ if (this.orderedSheetIds.map(this.getSheetName.bind(this)).includes(cmd.sheetNameTo))
51303
+ return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
51304
+ return "Success" /* CommandResult.Success */;
51166
51305
  }
51167
51306
  case "MOVE_SHEET":
51168
51307
  try {
@@ -51232,7 +51371,7 @@ class SheetPlugin extends CorePlugin {
51232
51371
  this.showSheet(cmd.sheetId);
51233
51372
  break;
51234
51373
  case "DUPLICATE_SHEET":
51235
- this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo);
51374
+ this.duplicateSheet(cmd.sheetId, cmd.sheetIdTo, cmd.sheetNameTo);
51236
51375
  break;
51237
51376
  case "DELETE_SHEET":
51238
51377
  this.deleteSheet(this.sheets[cmd.sheetId]);
@@ -51367,7 +51506,7 @@ class SheetPlugin extends CorePlugin {
51367
51506
  if (name) {
51368
51507
  const unquotedName = getUnquotedSheetName(name);
51369
51508
  for (const key in this.sheetIdsMapName) {
51370
- if (key.toUpperCase() === unquotedName.toUpperCase()) {
51509
+ if (isSheetNameEqual(key, unquotedName)) {
51371
51510
  return this.sheetIdsMapName[key];
51372
51511
  }
51373
51512
  }
@@ -51432,14 +51571,8 @@ class SheetPlugin extends CorePlugin {
51432
51571
  return dimension === "COL" ? this.getNumberCols(sheetId) : this.getNumberRows(sheetId);
51433
51572
  }
51434
51573
  getNextSheetName(baseName = "Sheet") {
51435
- let i = 1;
51436
51574
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
51437
- let name = `${baseName}${i}`;
51438
- while (names.includes(name)) {
51439
- name = `${baseName}${i}`;
51440
- i++;
51441
- }
51442
- return name;
51575
+ return getNextSheetName(names, baseName);
51443
51576
  }
51444
51577
  getSheetSize(sheetId) {
51445
51578
  return {
@@ -51621,7 +51754,7 @@ class SheetPlugin extends CorePlugin {
51621
51754
  }
51622
51755
  const { orderedSheetIds, sheets } = this;
51623
51756
  const name = cmd.name && cmd.name.trim().toLowerCase();
51624
- if (orderedSheetIds.find((id) => sheets[id]?.name.toLowerCase() === name && id !== cmd.sheetId)) {
51757
+ if (orderedSheetIds.find((id) => isSheetNameEqual(sheets[id]?.name, name) && id !== cmd.sheetId)) {
51625
51758
  return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
51626
51759
  }
51627
51760
  if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
@@ -51685,9 +51818,8 @@ class SheetPlugin extends CorePlugin {
51685
51818
  showSheet(sheetId) {
51686
51819
  this.history.update("sheets", sheetId, "isVisible", true);
51687
51820
  }
51688
- duplicateSheet(fromId, toId) {
51821
+ duplicateSheet(fromId, toId, toName) {
51689
51822
  const sheet = this.getSheet(fromId);
51690
- const toName = this.getDuplicateSheetName(sheet.name);
51691
51823
  const newSheet = deepCopy(sheet);
51692
51824
  newSheet.id = toId;
51693
51825
  newSheet.name = toName;
@@ -51719,15 +51851,8 @@ class SheetPlugin extends CorePlugin {
51719
51851
  this.history.update("sheetIdsMapName", sheetIdsMapName);
51720
51852
  }
51721
51853
  getDuplicateSheetName(sheetName) {
51722
- let i = 1;
51723
51854
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
51724
- const baseName = _t("Copy of %s", sheetName);
51725
- let name = baseName.toString();
51726
- while (names.includes(name)) {
51727
- name = `${baseName} (${i})`;
51728
- i++;
51729
- }
51730
- return name;
51855
+ return getDuplicateSheetName(sheetName, names);
51731
51856
  }
51732
51857
  deleteSheet(sheet) {
51733
51858
  const name = sheet.name;
@@ -54526,8 +54651,8 @@ class SpreadingRelation {
54526
54651
  const EMPTY_ARRAY = [];
54527
54652
 
54528
54653
  const MAX_ITERATION = 30;
54529
- const ERROR_CYCLE_CELL = createEvaluatedCell(new CircularDependencyError());
54530
- const EMPTY_CELL = createEvaluatedCell({ value: null });
54654
+ const ERROR_CYCLE_CELL = Object.freeze(createEvaluatedCell(new CircularDependencyError()));
54655
+ const EMPTY_CELL = Object.freeze(createEvaluatedCell({ value: null }));
54531
54656
  class Evaluator {
54532
54657
  context;
54533
54658
  getters;
@@ -58589,6 +58714,8 @@ class InsertPivotPlugin extends UIPlugin {
58589
58714
  case "INSERT_PIVOT_WITH_TABLE":
58590
58715
  this.insertPivotWithTable(cmd.sheetId, cmd.col, cmd.row, cmd.pivotId, cmd.table, cmd.pivotMode);
58591
58716
  break;
58717
+ case "SPLIT_PIVOT_FORMULA":
58718
+ this.splitPivotFormula(cmd.sheetId, cmd.col, cmd.row, cmd.pivotId, cmd.table);
58592
58719
  }
58593
58720
  }
58594
58721
  insertNewPivot(pivotId, sheetId) {
@@ -58736,6 +58863,36 @@ class InsertPivotPlugin extends UIPlugin {
58736
58863
  });
58737
58864
  }
58738
58865
  }
58866
+ splitPivotFormula(sheetId, col, row, pivotId, pivotTableData) {
58867
+ this.dispatch("INSERT_PIVOT", {
58868
+ sheetId,
58869
+ col,
58870
+ row,
58871
+ pivotId,
58872
+ table: pivotTableData,
58873
+ });
58874
+ const table = this.getters.getCoreTable({ sheetId, col, row });
58875
+ if (table?.type === "dynamic") {
58876
+ const zone = positionToZone({ col, row });
58877
+ const { cols, rows, measures, fieldsType } = pivotTableData;
58878
+ const pivotTable = new SpreadsheetPivotTable(cols, rows, measures, fieldsType || {});
58879
+ const colNumber = pivotTable.getNumberOfDataColumns() + 1;
58880
+ const rowNumber = pivotTable.columns.length + pivotTable.rows.length;
58881
+ const tableZone = {
58882
+ left: col,
58883
+ top: row,
58884
+ right: col + colNumber - 1,
58885
+ bottom: row + rowNumber - 1,
58886
+ };
58887
+ const rangeData = this.getters.getRangeDataFromZone(sheetId, tableZone);
58888
+ this.dispatch("UPDATE_TABLE", {
58889
+ sheetId,
58890
+ zone,
58891
+ newTableRange: rangeData,
58892
+ tableType: "static",
58893
+ });
58894
+ }
58895
+ }
58739
58896
  }
58740
58897
 
58741
58898
  class SortPlugin extends UIPlugin {
@@ -62929,11 +63086,11 @@ class BottomBarSheet extends owl.Component {
62929
63086
  if (ev.key === "Enter") {
62930
63087
  ev.preventDefault();
62931
63088
  this.stopEdition();
62932
- this.DOMFocusableElementStore.focusableElement?.focus();
63089
+ this.DOMFocusableElementStore.focus();
62933
63090
  }
62934
63091
  if (ev.key === "Escape") {
62935
63092
  this.cancelEdition();
62936
- this.DOMFocusableElementStore.focusableElement?.focus();
63093
+ this.DOMFocusableElementStore.focus();
62937
63094
  }
62938
63095
  }
62939
63096
  onMouseEventSheetName(ev) {
@@ -69406,6 +69563,6 @@ exports.tokenColors = tokenColors;
69406
69563
  exports.tokenize = tokenize;
69407
69564
 
69408
69565
 
69409
- __info__.version = "17.4.33";
69410
- __info__.date = "2025-05-02T12:30:31.263Z";
69411
- __info__.hash = "3ba00e6";
69566
+ __info__.version = "17.4.35";
69567
+ __info__.date = "2025-05-13T17:49:44.553Z";
69568
+ __info__.hash = "534c5f4";