@odoo/o-spreadsheet 16.2.22 → 16.2.23

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.
@@ -607,13 +607,6 @@ function getYearFrac(startDate, endDate, _dayCountConvention) {
607
607
  }
608
608
 
609
609
  //------------------------------------------------------------------------------
610
- /**
611
- * Stringify an object, like JSON.stringify, except that the first level of keys
612
- * is ordered.
613
- */
614
- function stringify(obj) {
615
- return JSON.stringify(obj, Object.keys(obj).sort());
616
- }
617
610
  /**
618
611
  * Remove quotes from a quoted string
619
612
  * ```js
@@ -913,7 +906,7 @@ function isObjectEmptyRecursive(argument) {
913
906
  */
914
907
  function getItemId(item, itemsDic) {
915
908
  for (let [key, value] of Object.entries(itemsDic)) {
916
- if (stringify(value) === stringify(item)) {
909
+ if (deepEquals(value, item)) {
917
910
  return parseInt(key, 10);
918
911
  }
919
912
  }
@@ -979,6 +972,22 @@ function lazy(fn) {
979
972
  lazyValue.map = (callback) => lazy(() => callback(lazyValue()));
980
973
  return lazyValue;
981
974
  }
975
+ /**
976
+ * Creates a version of the function that's memoized on the value of its first
977
+ * argument, if any.
978
+ */
979
+ function memoize(func) {
980
+ const cache = new Map();
981
+ const funcName = func.name ? func.name + " (memoized)" : "memoized";
982
+ return {
983
+ [funcName](...args) {
984
+ if (!cache.has(args[0])) {
985
+ cache.set(args[0], func(...args));
986
+ }
987
+ return cache.get(args[0]);
988
+ },
989
+ }[funcName];
990
+ }
982
991
  /**
983
992
  * Find the next defined value after the given index in an array of strings. If there is no defined value
984
993
  * after the index, return the closest defined value before the index. Return an empty string if no
@@ -3576,12 +3585,12 @@ function toString(value) {
3576
3585
  }
3577
3586
  }
3578
3587
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
3579
- function normalizeString(str) {
3588
+ const normalizeString = memoize(function normalizeString(str) {
3580
3589
  return str
3581
3590
  .toLowerCase()
3582
3591
  .normalize("NFD")
3583
3592
  .replace(/[\u0300-\u036f]/g, "");
3584
- }
3593
+ });
3585
3594
  /**
3586
3595
  * Normalize a value.
3587
3596
  * If the cell value is a string, this will set it to lowercase and replacing accent letters with plain letters
@@ -4305,6 +4314,7 @@ exports.CommandResult = void 0;
4305
4314
  CommandResult[CommandResult["ChartDoesNotExist"] = 85] = "ChartDoesNotExist";
4306
4315
  CommandResult[CommandResult["InvalidHeaderIndex"] = 86] = "InvalidHeaderIndex";
4307
4316
  CommandResult[CommandResult["InvalidQuantity"] = 87] = "InvalidQuantity";
4317
+ CommandResult[CommandResult["NoChanges"] = 88] = "NoChanges";
4308
4318
  })(exports.CommandResult || (exports.CommandResult = {}));
4309
4319
 
4310
4320
  function isMatrix(x) {
@@ -27520,6 +27530,14 @@ class BordersPlugin extends CorePlugin {
27520
27530
  // ---------------------------------------------------------------------------
27521
27531
  // Command Handling
27522
27532
  // ---------------------------------------------------------------------------
27533
+ allowDispatch(cmd) {
27534
+ switch (cmd.type) {
27535
+ case "SET_BORDER":
27536
+ return this.checkBordersUnchanged(cmd);
27537
+ default:
27538
+ return 0 /* CommandResult.Success */;
27539
+ }
27540
+ }
27523
27541
  handle(cmd) {
27524
27542
  switch (cmd.type) {
27525
27543
  case "ADD_MERGE":
@@ -27915,6 +27933,15 @@ class BordersPlugin extends CorePlugin {
27915
27933
  this.setBorders(sheetId, [{ ...zone, left: right }], "right");
27916
27934
  }
27917
27935
  }
27936
+ checkBordersUnchanged(cmd) {
27937
+ var _a, _b, _c, _d;
27938
+ const currentBorder = this.getCellBorder(cmd);
27939
+ const areAllNewBordersUndefined = !((_a = cmd.border) === null || _a === void 0 ? void 0 : _a.bottom) && !((_b = cmd.border) === null || _b === void 0 ? void 0 : _b.left) && !((_c = cmd.border) === null || _c === void 0 ? void 0 : _c.right) && !((_d = cmd.border) === null || _d === void 0 ? void 0 : _d.top);
27940
+ if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
27941
+ return 88 /* CommandResult.NoChanges */;
27942
+ }
27943
+ return 0 /* CommandResult.Success */;
27944
+ }
27918
27945
  // ---------------------------------------------------------------------------
27919
27946
  // Import/Export
27920
27947
  // ---------------------------------------------------------------------------
@@ -27950,7 +27977,7 @@ class BordersPlugin extends CorePlugin {
27950
27977
  */
27951
27978
  function getBorderId(border) {
27952
27979
  for (let [key, value] of Object.entries(borders)) {
27953
- if (stringify(value) === stringify(border)) {
27980
+ if (deepEquals(value, border)) {
27954
27981
  return parseInt(key, 10);
27955
27982
  }
27956
27983
  }
@@ -28017,8 +28044,9 @@ class CellPlugin extends CorePlugin {
28017
28044
  allowDispatch(cmd) {
28018
28045
  switch (cmd.type) {
28019
28046
  case "UPDATE_CELL":
28047
+ return this.checkCellOutOfSheet(cmd);
28020
28048
  case "CLEAR_CELL":
28021
- return this.checkCellOutOfSheet(cmd.sheetId, cmd.col, cmd.row);
28049
+ return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
28022
28050
  default:
28023
28051
  return 0 /* CommandResult.Success */;
28024
28052
  }
@@ -28177,14 +28205,9 @@ class CellPlugin extends CorePlugin {
28177
28205
  */
28178
28206
  getCellById(cellId) {
28179
28207
  // this must be as fast as possible
28180
- for (const sheetId in this.cells) {
28181
- const sheet = this.cells[sheetId];
28182
- const cell = sheet[cellId];
28183
- if (cell) {
28184
- return cell;
28185
- }
28186
- }
28187
- return undefined;
28208
+ const position = this.getters.getCellPosition(cellId);
28209
+ const sheet = this.cells[position.sheetId];
28210
+ return sheet[cellId];
28188
28211
  }
28189
28212
  /*
28190
28213
  * Reconstructs the original formula string based on a normalized form and its dependencies
@@ -28422,13 +28445,23 @@ class CellPlugin extends CorePlugin {
28422
28445
  dependencies: [],
28423
28446
  };
28424
28447
  }
28425
- checkCellOutOfSheet(sheetId, col, row) {
28448
+ checkCellOutOfSheet(cmd) {
28449
+ const { sheetId, col, row } = cmd;
28426
28450
  const sheet = this.getters.tryGetSheet(sheetId);
28427
28451
  if (!sheet)
28428
28452
  return 27 /* CommandResult.InvalidSheetId */;
28429
28453
  const sheetZone = this.getters.getSheetZone(sheetId);
28430
28454
  return isInside(col, row, sheetZone) ? 0 /* CommandResult.Success */ : 18 /* CommandResult.TargetOutOfSheet */;
28431
28455
  }
28456
+ checkUselessClearCell(cmd) {
28457
+ const cell = this.getters.getCell(cmd);
28458
+ if (!cell)
28459
+ return 88 /* CommandResult.NoChanges */;
28460
+ if (!cell.content && !cell.style && !cell.format) {
28461
+ return 88 /* CommandResult.NoChanges */;
28462
+ }
28463
+ return 0 /* CommandResult.Success */;
28464
+ }
28432
28465
  }
28433
28466
  CellPlugin.getters = [
28434
28467
  "zoneToXC",
@@ -31494,10 +31527,13 @@ class SheetPlugin extends CorePlugin {
31494
31527
  // begin with the end.
31495
31528
  rows.sort((a, b) => b - a);
31496
31529
  for (let group of groupConsecutive(rows)) {
31530
+ // indexes are sorted in the descending order
31531
+ const from = group[group.length - 1];
31532
+ const to = group[0];
31497
31533
  // Move the cells.
31498
- this.moveCellOnRowsDeletion(sheet, group[group.length - 1], group[0]);
31499
- // Effectively delete the element and recompute the left-right/top-bottom.
31500
- group.map((row) => this.updateRowsStructureOnDeletion(row, sheet));
31534
+ this.moveCellOnRowsDeletion(sheet, from, to);
31535
+ // Effectively delete the rows
31536
+ this.updateRowsStructureOnDeletion(sheet, from, to);
31501
31537
  }
31502
31538
  const count = rows.filter((row) => row < sheet.panes.ySplit).length;
31503
31539
  if (count) {
@@ -31519,8 +31555,6 @@ class SheetPlugin extends CorePlugin {
31519
31555
  this.addEmptyRows(sheet, quantity);
31520
31556
  // Move the cells.
31521
31557
  this.moveCellsOnAddition(sheet, index, quantity, "rows");
31522
- // Recompute the left-right/top-bottom.
31523
- this.updateRowsStructureOnAddition(sheet, row, quantity);
31524
31558
  if (index < sheet.panes.ySplit) {
31525
31559
  this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
31526
31560
  }
@@ -31621,35 +31655,20 @@ class SheetPlugin extends CorePlugin {
31621
31655
  }
31622
31656
  }
31623
31657
  }
31624
- updateRowsStructureOnDeletion(index, sheet) {
31658
+ updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
31625
31659
  const rows = [];
31626
- const cellsQueue = sheet.rows.map((row) => row.cells);
31660
+ const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
31627
31661
  for (let i in sheet.rows) {
31628
- if (Number(i) === index) {
31662
+ const row = Number(i);
31663
+ if (row >= deleteFromRow && row <= deleteToRow) {
31629
31664
  continue;
31630
31665
  }
31631
31666
  rows.push({
31632
- cells: cellsQueue.shift(),
31667
+ cells: cellsQueue.pop(),
31633
31668
  });
31634
31669
  }
31635
31670
  this.history.update("sheets", sheet.id, "rows", rows);
31636
31671
  }
31637
- /**
31638
- * Update the rows of the sheet after an addition:
31639
- * - Rename the rows
31640
- *
31641
- * @param sheet Sheet on which the deletion occurs
31642
- * @param addedRow Index of the added row
31643
- * @param rowsToAdd Number of the rows to add
31644
- */
31645
- updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
31646
- const rows = [];
31647
- const cellsQueue = sheet.rows.map((row) => row.cells);
31648
- sheet.rows.forEach(() => rows.push({
31649
- cells: cellsQueue.shift(),
31650
- }));
31651
- this.history.update("sheets", sheet.id, "rows", rows);
31652
- }
31653
31672
  /**
31654
31673
  * Add empty rows at the end of the rows
31655
31674
  *
@@ -32133,6 +32152,7 @@ class EvaluationPlugin extends UIPlugin {
32133
32152
  }
32134
32153
  return evaluatedCell;
32135
32154
  };
32155
+ const rangeCache = {};
32136
32156
  /**
32137
32157
  * Return the values of the cell(s) used in reference, but always in the format of a range even
32138
32158
  * if a single cell is referenced. It is a list of col values. This is useful for the formulas that describe parameters as
@@ -32149,21 +32169,26 @@ class EvaluationPlugin extends UIPlugin {
32149
32169
  // Performance issue: Avoid fetching data on positions that are out of the spreadsheet
32150
32170
  // e.g. A1:ZZZ9999 in a sheet with 10 cols and 10 rows should ignore everything past J10 and return a 10x10 array
32151
32171
  const sheetZone = getters.getSheetZone(sheetId);
32152
- const result = [];
32153
32172
  const zone = intersection(range.zone, sheetZone);
32154
32173
  if (!zone) {
32155
- result.push([]);
32156
- return result;
32174
+ return [[]];
32175
+ }
32176
+ const { top, left, bottom, right } = zone;
32177
+ const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
32178
+ if (cacheKey in rangeCache) {
32179
+ return rangeCache[cacheKey];
32157
32180
  }
32181
+ const result = new Array(right - left + 1);
32158
32182
  // Performance issue: nested loop is faster than a map here
32159
- for (let col = zone.left; col <= zone.right; col++) {
32160
- const rowValues = [];
32161
- for (let row = zone.top; row <= zone.bottom; row++) {
32183
+ for (let col = left; col <= right; col++) {
32184
+ const rowValues = new Array(bottom - top + 1);
32185
+ for (let row = top; row <= bottom; row++) {
32162
32186
  const cell = evalContext.getters.getCell({ sheetId: range.sheetId, col, row });
32163
- rowValues.push(cell ? getEvaluatedCell(cell) : undefined);
32187
+ rowValues[row - top] = cell ? getEvaluatedCell(cell) : undefined;
32164
32188
  }
32165
- result.push(rowValues);
32189
+ result[col - left] = rowValues;
32166
32190
  }
32191
+ rangeCache[cacheKey] = result;
32167
32192
  return result;
32168
32193
  }
32169
32194
  /**
@@ -42690,9 +42715,9 @@ function revertChanges(revisions) {
42690
42715
  * Apply the changes of the given HistoryChange to the state
42691
42716
  */
42692
42717
  function applyChange(change, target) {
42693
- let val = change.root;
42694
- let key = change.path[change.path.length - 1];
42695
- for (let pathIndex = 0; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
42718
+ let val = change.path[0];
42719
+ const key = change.path[change.path.length - 1];
42720
+ for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
42696
42721
  const p = change.path[pathIndex];
42697
42722
  if (val[p] === undefined) {
42698
42723
  const nextPath = change.path[pathIndex + 1];
@@ -43449,13 +43474,14 @@ class StateObserver {
43449
43474
  }
43450
43475
  addChange(...args) {
43451
43476
  const val = args.pop();
43452
- const [root, ...path] = args;
43477
+ const root = args[0];
43453
43478
  let value = root;
43454
- let key = path[path.length - 1];
43455
- for (let pathIndex = 0; pathIndex <= path.length - 2; pathIndex++) {
43456
- const p = path[pathIndex];
43479
+ let key = args[args.length - 1];
43480
+ const pathLength = args.length - 2;
43481
+ for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
43482
+ const p = args[pathIndex];
43457
43483
  if (value[p] === undefined) {
43458
- const nextPath = path[pathIndex + 1];
43484
+ const nextPath = args[pathIndex + 1];
43459
43485
  value[p] = createEmptyStructure(nextPath);
43460
43486
  }
43461
43487
  value = value[p];
@@ -43464,8 +43490,7 @@ class StateObserver {
43464
43490
  return;
43465
43491
  }
43466
43492
  this.changes.push({
43467
- root,
43468
- path,
43493
+ path: args,
43469
43494
  before: value[key],
43470
43495
  after: val,
43471
43496
  });
@@ -45317,7 +45342,10 @@ class Model extends EventBus {
45317
45342
  */
45318
45343
  checkDispatchAllowed(command) {
45319
45344
  const results = this.handlers.map((handler) => handler.allowDispatch(command));
45320
- return new DispatchResult(results.flat());
45345
+ if (results.some((r) => r !== 0 /* CommandResult.Success */)) {
45346
+ return new DispatchResult(results.flat());
45347
+ }
45348
+ return DispatchResult.Success;
45321
45349
  }
45322
45350
  finalize() {
45323
45351
  this.status = 3 /* Status.Finalizing */;
@@ -45544,6 +45572,6 @@ exports.setTranslationMethod = setTranslationMethod;
45544
45572
  exports.tokenize = tokenize;
45545
45573
 
45546
45574
 
45547
- __info__.version = '16.2.22';
45548
- __info__.date = '2023-11-16T11:57:01.482Z';
45549
- __info__.hash = 'b78d5dd';
45575
+ __info__.version = '16.2.23';
45576
+ __info__.date = '2023-11-24T13:11:02.651Z';
45577
+ __info__.hash = '3c723d3';
@@ -1080,7 +1080,7 @@ declare class StateObserver {
1080
1080
  commands: CoreCommand[];
1081
1081
  };
1082
1082
  addCommand(command: CoreCommand): void;
1083
- addChange(...args: any[]): void;
1083
+ addChange(...args: [...HistoryChange["path"], any]): void;
1084
1084
  }
1085
1085
 
1086
1086
  interface Validator {
@@ -2140,7 +2140,8 @@ declare const enum CommandResult {
2140
2140
  DuplicatedChartId = 84,
2141
2141
  ChartDoesNotExist = 85,
2142
2142
  InvalidHeaderIndex = 86,
2143
- InvalidQuantity = 87
2143
+ InvalidQuantity = 87,
2144
+ NoChanges = 88
2144
2145
  }
2145
2146
  interface CommandHandler<T> {
2146
2147
  allowDispatch(command: T): CommandResult | CommandResult[];
@@ -2933,7 +2934,8 @@ interface BordersPluginState {
2933
2934
  declare class BordersPlugin extends CorePlugin<BordersPluginState> implements BordersPluginState {
2934
2935
  static getters: readonly ["getCellBorder"];
2935
2936
  readonly borders: BordersPluginState["borders"];
2936
- handle(cmd: Command): void;
2937
+ allowDispatch(cmd: CoreCommand): CommandResult.Success | CommandResult.NoChanges;
2938
+ handle(cmd: CoreCommand): void;
2937
2939
  /**
2938
2940
  * Move borders according to the inserted columns.
2939
2941
  * Ensure borders continuity.
@@ -3030,6 +3032,7 @@ declare class BordersPlugin extends CorePlugin<BordersPluginState> implements Bo
3030
3032
  * Compute the borders to add to the given zone merged.
3031
3033
  */
3032
3034
  private addBordersToMerge;
3035
+ private checkBordersUnchanged;
3033
3036
  import(data: WorkbookData): void;
3034
3037
  export(data: WorkbookData): void;
3035
3038
  exportForExcel(data: ExcelWorkbookData): void;
@@ -3054,7 +3057,7 @@ declare class CellPlugin extends CorePlugin<CoreState> implements CoreState {
3054
3057
  };
3055
3058
  };
3056
3059
  adaptRanges(applyChange: ApplyRangeChange, sheetId?: UID): void;
3057
- allowDispatch(cmd: CoreCommand): CommandResult;
3060
+ allowDispatch(cmd: CoreCommand): CommandResult | CommandResult[];
3058
3061
  handle(cmd: CoreCommand): void;
3059
3062
  /**
3060
3063
  * Set a format to all the cells in a zone
@@ -3127,6 +3130,7 @@ declare class CellPlugin extends CorePlugin<CoreState> implements CoreState {
3127
3130
  private createFormulaCellWithDependencies;
3128
3131
  private createErrorFormula;
3129
3132
  private checkCellOutOfSheet;
3133
+ private checkUselessClearCell;
3130
3134
  }
3131
3135
 
3132
3136
  /**
@@ -3635,15 +3639,6 @@ declare class SheetPlugin extends CorePlugin<SheetState$1> implements SheetState
3635
3639
  */
3636
3640
  private moveCellOnRowsDeletion;
3637
3641
  private updateRowsStructureOnDeletion;
3638
- /**
3639
- * Update the rows of the sheet after an addition:
3640
- * - Rename the rows
3641
- *
3642
- * @param sheet Sheet on which the deletion occurs
3643
- * @param addedRow Index of the added row
3644
- * @param rowsToAdd Number of the rows to add
3645
- */
3646
- private updateRowsStructureOnAddition;
3647
3642
  /**
3648
3643
  * Add empty rows at the end of the rows
3649
3644
  *
@@ -4699,8 +4694,7 @@ type Getters = {
4699
4694
  } & LocalHistoryGetters & CoreGetters & SessionGetters & AutofillGetters & AutomaticSumGetters & ClipboardGetters & EditionGetters & EvaluationGetters & EvaluationChartGetters & EvaluationConditionalFormatGetters & FindAndReplaceGetters & HighlightGetters & CustomColorsGetters & RendererGetters & SelectionGetters & SelectionInputGetters & SelectionMultiUserGetters & SortGetters & UIOptionsGetters & SheetUIGetters & ViewportGetters & CellPopoverPluginGetters & FilterEvaluationGetters & HeaderVisibilityIUIGetters;
4700
4695
 
4701
4696
  interface HistoryChange {
4702
- root: any;
4703
- path: (string | number)[];
4697
+ path: [any, ...(number | string)[]];
4704
4698
  before: any;
4705
4699
  after: any;
4706
4700
  }