@odoo/o-spreadsheet 16.4.13 → 16.4.15

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.
@@ -669,8 +669,7 @@
669
669
  *
670
670
  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
671
671
  */
672
- const whiteSpaceCharacters = [
673
- " ",
672
+ const whiteSpaceSpecialCharacters = [
674
673
  "\t",
675
674
  "\f",
676
675
  "\v",
@@ -685,8 +684,7 @@
685
684
  String.fromCharCode(parseInt("3000", 16)),
686
685
  String.fromCharCode(parseInt("feff", 16)),
687
686
  ];
688
- const whiteSpaceRegexp = new RegExp(whiteSpaceCharacters.join("|"), "g");
689
- const newLineRegex = /\r\n|\r|\n/g;
687
+ const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|") + "|(\r\n|\r|\n)", "g");
690
688
  /**
691
689
  * Replace all the special spaces in a string (non-breaking, tabs, ...) by normal spaces, and all the
692
690
  * different newlines types by \n.
@@ -694,9 +692,9 @@
694
692
  function replaceSpecialSpaces(text) {
695
693
  if (!text)
696
694
  return "";
697
- text = text.replace(whiteSpaceRegexp, " ");
698
- text = text.replace(newLineRegex, NEWLINE);
699
- return text;
695
+ if (!whiteSpaceRegexp.test(text))
696
+ return text;
697
+ return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
700
698
  }
701
699
  /**
702
700
  * Determine if the numbers are consecutive.
@@ -4266,6 +4264,7 @@
4266
4264
  CommandResult[CommandResult["NoActiveSheet"] = 94] = "NoActiveSheet";
4267
4265
  CommandResult[CommandResult["InvalidLocale"] = 95] = "InvalidLocale";
4268
4266
  CommandResult[CommandResult["AlreadyInPaintingFormatMode"] = 96] = "AlreadyInPaintingFormatMode";
4267
+ CommandResult[CommandResult["NoChanges"] = 97] = "NoChanges";
4269
4268
  })(exports.CommandResult || (exports.CommandResult = {}));
4270
4269
 
4271
4270
  const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
@@ -4355,12 +4354,12 @@
4355
4354
  }
4356
4355
  }
4357
4356
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
4358
- function normalizeString(str) {
4357
+ const normalizeString = memoize(function normalizeString(str) {
4359
4358
  return str
4360
4359
  .toLowerCase()
4361
4360
  .normalize("NFD")
4362
4361
  .replace(/[\u0300-\u036f]/g, "");
4363
- }
4362
+ });
4364
4363
  /**
4365
4364
  * Normalize a value.
4366
4365
  * If the cell value is a string, this will set it to lowercase and replacing accent letters with plain letters
@@ -14171,7 +14170,7 @@
14171
14170
  return result;
14172
14171
  }
14173
14172
  function tokenizeDebugger(chars) {
14174
- if (chars.current() === "?") {
14173
+ if (chars.current === "?") {
14175
14174
  chars.shift();
14176
14175
  return { type: "DEBUGGER", value: "?" };
14177
14176
  }
@@ -14182,7 +14181,7 @@
14182
14181
  ")": "RIGHT_PAREN",
14183
14182
  };
14184
14183
  function tokenizeMisc(chars) {
14185
- if (chars.current() in misc) {
14184
+ if (chars.current in misc) {
14186
14185
  const value = chars.shift();
14187
14186
  const type = misc[value];
14188
14187
  return { type, value };
@@ -14190,7 +14189,7 @@
14190
14189
  return null;
14191
14190
  }
14192
14191
  function tokenizeArgsSeparator(chars, locale) {
14193
- if (chars.current() === locale.formulaArgSeparator) {
14192
+ if (chars.current === locale.formulaArgSeparator) {
14194
14193
  const value = chars.shift();
14195
14194
  const type = "ARG_SEPARATOR";
14196
14195
  return { type, value };
@@ -14215,14 +14214,13 @@
14215
14214
  return null;
14216
14215
  }
14217
14216
  function tokenizeString(chars) {
14218
- if (chars.current() === '"') {
14217
+ if (chars.current === '"') {
14219
14218
  const startChar = chars.shift();
14220
14219
  let letters = startChar;
14221
- while (chars.current() &&
14222
- (chars.current() !== startChar || letters[letters.length - 1] === "\\")) {
14220
+ while (chars.current && (chars.current !== startChar || letters[letters.length - 1] === "\\")) {
14223
14221
  letters += chars.shift();
14224
14222
  }
14225
- if (chars.current() === '"') {
14223
+ if (chars.current === '"') {
14226
14224
  letters += chars.shift();
14227
14225
  }
14228
14226
  return {
@@ -14249,14 +14247,14 @@
14249
14247
  let result = "";
14250
14248
  // there are two main cases to manage: either something which starts with
14251
14249
  // a ', like 'Sheet 2'A2, or a word-like element.
14252
- if (chars.current() === "'") {
14250
+ if (chars.current === "'") {
14253
14251
  let lastChar = chars.shift();
14254
14252
  result += lastChar;
14255
- while (chars.current()) {
14253
+ while (chars.current) {
14256
14254
  lastChar = chars.shift();
14257
14255
  result += lastChar;
14258
14256
  if (lastChar === "'") {
14259
- if (chars.current() && chars.current() === "'") {
14257
+ if (chars.current && chars.current === "'") {
14260
14258
  lastChar = chars.shift();
14261
14259
  result += lastChar;
14262
14260
  }
@@ -14272,7 +14270,7 @@
14272
14270
  };
14273
14271
  }
14274
14272
  }
14275
- while (chars.current() && separatorRegexp.test(chars.current())) {
14273
+ while (chars.current && separatorRegexp.test(chars.current)) {
14276
14274
  result += chars.shift();
14277
14275
  }
14278
14276
  if (result.length) {
@@ -14287,14 +14285,14 @@
14287
14285
  }
14288
14286
  function tokenizeSpace(chars) {
14289
14287
  let length = 0;
14290
- while (chars.current() === NEWLINE) {
14288
+ while (chars.current === NEWLINE) {
14291
14289
  length++;
14292
14290
  chars.shift();
14293
14291
  }
14294
14292
  if (length) {
14295
14293
  return { type: "SPACE", value: NEWLINE.repeat(length) };
14296
14294
  }
14297
- while (chars.current() === " ") {
14295
+ while (chars.current === " ") {
14298
14296
  length++;
14299
14297
  chars.shift();
14300
14298
  }
@@ -14313,17 +14311,20 @@
14313
14311
  class TokenizingChars {
14314
14312
  text;
14315
14313
  currentIndex = 0;
14314
+ current;
14316
14315
  constructor(text) {
14317
14316
  this.text = text;
14318
- }
14319
- current() {
14320
- return this.text[this.currentIndex];
14317
+ this.current = text[0];
14321
14318
  }
14322
14319
  shift() {
14323
- return this.text[this.currentIndex++];
14320
+ const current = this.current;
14321
+ const next = this.text[++this.currentIndex];
14322
+ this.current = next;
14323
+ return current;
14324
14324
  }
14325
14325
  advanceBy(length) {
14326
14326
  this.currentIndex += length;
14327
+ this.current = this.text[this.currentIndex];
14327
14328
  }
14328
14329
  isOver() {
14329
14330
  return this.currentIndex >= this.text.length;
@@ -18566,6 +18567,17 @@
18566
18567
  //------------------------------------------------------------------------------
18567
18568
  const IS_ONLY_ONE_RANGE = (env) => {
18568
18569
  return env.model.getters.getSelectedZones().length === 1;
18570
+ };
18571
+ const CAN_INSERT_HEADER = (env, dimension) => {
18572
+ if (!IS_ONLY_ONE_RANGE(env)) {
18573
+ return false;
18574
+ }
18575
+ const activeHeaders = dimension === "COL" ? env.model.getters.getActiveCols() : env.model.getters.getActiveRows();
18576
+ const ortogonalActiveHeaders = dimension === "COL" ? env.model.getters.getActiveRows() : env.model.getters.getActiveCols();
18577
+ const sheetId = env.model.getters.getActiveSheetId();
18578
+ const zone = env.model.getters.getSelectedZone();
18579
+ const allSheetSelected = isEqual(zone, env.model.getters.getSheetZone(sheetId));
18580
+ return isConsecutive(activeHeaders) && (ortogonalActiveHeaders.size === 0 || allSheetSelected);
18569
18581
  };
18570
18582
 
18571
18583
  const undo = {
@@ -18755,9 +18767,7 @@
18755
18767
  const number = getRowsNumber(env);
18756
18768
  return number === 1 ? _lt("Insert row") : _lt("Insert %s rows", number.toString());
18757
18769
  },
18758
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
18759
- IS_ONLY_ONE_RANGE(env) &&
18760
- env.model.getters.getActiveCols().size === 0,
18770
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
18761
18771
  icon: "o-spreadsheet-Icon.INSERT_ROW",
18762
18772
  };
18763
18773
  const rowInsertRowBefore = {
@@ -18766,9 +18776,7 @@
18766
18776
  return number === 1 ? _lt("Insert row above") : _lt("Insert %s rows above", number.toString());
18767
18777
  },
18768
18778
  execute: INSERT_ROWS_BEFORE_ACTION,
18769
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
18770
- IS_ONLY_ONE_RANGE(env) &&
18771
- env.model.getters.getActiveCols().size === 0,
18779
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
18772
18780
  icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
18773
18781
  };
18774
18782
  const topBarInsertRowsBefore = {
@@ -18799,9 +18807,7 @@
18799
18807
  const number = getRowsNumber(env);
18800
18808
  return number === 1 ? _lt("Insert row below") : _lt("Insert %s rows below", number.toString());
18801
18809
  },
18802
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
18803
- IS_ONLY_ONE_RANGE(env) &&
18804
- env.model.getters.getActiveCols().size === 0,
18810
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
18805
18811
  icon: "o-spreadsheet-Icon.INSERT_ROW_AFTER",
18806
18812
  };
18807
18813
  const topBarInsertRowsAfter = {
@@ -18819,9 +18825,7 @@
18819
18825
  const number = getColumnsNumber(env);
18820
18826
  return number === 1 ? _lt("Insert column") : _lt("Insert %s columns", number.toString());
18821
18827
  },
18822
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
18823
- IS_ONLY_ONE_RANGE(env) &&
18824
- env.model.getters.getActiveRows().size === 0,
18828
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
18825
18829
  icon: "o-spreadsheet-Icon.INSERT_COL",
18826
18830
  };
18827
18831
  const colInsertColsBefore = {
@@ -18832,9 +18836,7 @@
18832
18836
  : _lt("Insert %s columns left", number.toString());
18833
18837
  },
18834
18838
  execute: INSERT_COLUMNS_BEFORE_ACTION,
18835
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
18836
- IS_ONLY_ONE_RANGE(env) &&
18837
- env.model.getters.getActiveRows().size === 0,
18839
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
18838
18840
  icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
18839
18841
  };
18840
18842
  const topBarInsertColsBefore = {
@@ -18867,9 +18869,7 @@
18867
18869
  : _lt("Insert %s columns right", number.toString());
18868
18870
  },
18869
18871
  execute: INSERT_COLUMNS_AFTER_ACTION,
18870
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
18871
- IS_ONLY_ONE_RANGE(env) &&
18872
- env.model.getters.getActiveRows().size === 0,
18872
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
18873
18873
  icon: "o-spreadsheet-Icon.INSERT_COL_AFTER",
18874
18874
  };
18875
18875
  const topBarInsertColsAfter = {
@@ -22827,7 +22827,7 @@
22827
22827
  }
22828
22828
  .o-input-count {
22829
22829
  width: fit-content;
22830
- padding: 4 0 4 4;
22830
+ padding: 4px 0 4px 4px;
22831
22831
  }
22832
22832
  }
22833
22833
  }
@@ -31168,6 +31168,14 @@
31168
31168
  // ---------------------------------------------------------------------------
31169
31169
  // Command Handling
31170
31170
  // ---------------------------------------------------------------------------
31171
+ allowDispatch(cmd) {
31172
+ switch (cmd.type) {
31173
+ case "SET_BORDER":
31174
+ return this.checkBordersUnchanged(cmd);
31175
+ default:
31176
+ return 0 /* CommandResult.Success */;
31177
+ }
31178
+ }
31171
31179
  handle(cmd) {
31172
31180
  switch (cmd.type) {
31173
31181
  case "ADD_MERGE":
@@ -31587,6 +31595,14 @@
31587
31595
  this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
31588
31596
  }
31589
31597
  }
31598
+ checkBordersUnchanged(cmd) {
31599
+ const currentBorder = this.getCellBorder(cmd);
31600
+ const areAllNewBordersUndefined = !cmd.border?.bottom && !cmd.border?.left && !cmd.border?.right && !cmd.border?.top;
31601
+ if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
31602
+ return 97 /* CommandResult.NoChanges */;
31603
+ }
31604
+ return 0 /* CommandResult.Success */;
31605
+ }
31590
31606
  // ---------------------------------------------------------------------------
31591
31607
  // Import/Export
31592
31608
  // ---------------------------------------------------------------------------
@@ -31694,8 +31710,9 @@
31694
31710
  allowDispatch(cmd) {
31695
31711
  switch (cmd.type) {
31696
31712
  case "UPDATE_CELL":
31713
+ return this.checkCellOutOfSheet(cmd);
31697
31714
  case "CLEAR_CELL":
31698
- return this.checkCellOutOfSheet(cmd.sheetId, cmd.col, cmd.row);
31715
+ return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
31699
31716
  default:
31700
31717
  return 0 /* CommandResult.Success */;
31701
31718
  }
@@ -31854,14 +31871,9 @@
31854
31871
  */
31855
31872
  getCellById(cellId) {
31856
31873
  // this must be as fast as possible
31857
- for (const sheetId in this.cells) {
31858
- const sheet = this.cells[sheetId];
31859
- const cell = sheet[cellId];
31860
- if (cell) {
31861
- return cell;
31862
- }
31863
- }
31864
- return undefined;
31874
+ const position = this.getters.getCellPosition(cellId);
31875
+ const sheet = this.cells[position.sheetId];
31876
+ return sheet[cellId];
31865
31877
  }
31866
31878
  /*
31867
31879
  * Reconstructs the original formula string based on a normalized form and its dependencies
@@ -32087,13 +32099,23 @@
32087
32099
  dependencies: [],
32088
32100
  };
32089
32101
  }
32090
- checkCellOutOfSheet(sheetId, col, row) {
32102
+ checkCellOutOfSheet(cmd) {
32103
+ const { sheetId, col, row } = cmd;
32091
32104
  const sheet = this.getters.tryGetSheet(sheetId);
32092
32105
  if (!sheet)
32093
32106
  return 28 /* CommandResult.InvalidSheetId */;
32094
32107
  const sheetZone = this.getters.getSheetZone(sheetId);
32095
32108
  return isInside(col, row, sheetZone) ? 0 /* CommandResult.Success */ : 19 /* CommandResult.TargetOutOfSheet */;
32096
32109
  }
32110
+ checkUselessClearCell(cmd) {
32111
+ const cell = this.getters.getCell(cmd);
32112
+ if (!cell)
32113
+ return 97 /* CommandResult.NoChanges */;
32114
+ if (!cell.content && !cell.style && !cell.format) {
32115
+ return 97 /* CommandResult.NoChanges */;
32116
+ }
32117
+ return 0 /* CommandResult.Success */;
32118
+ }
32097
32119
  }
32098
32120
  class FormulaCellWithDependencies {
32099
32121
  id;
@@ -33074,6 +33096,13 @@
33074
33096
  }
33075
33097
  onDeleteColumnsRows(cmd) {
33076
33098
  for (const table of this.getFilterTables(cmd.sheetId)) {
33099
+ // Remove the filter tables whose data filter headers are in the removed rows.
33100
+ if (cmd.dimension === "ROW" && cmd.elements.includes(table.zone.top)) {
33101
+ const tables = { ...this.tables[cmd.sheetId] };
33102
+ delete tables[table.id];
33103
+ this.history.update("tables", cmd.sheetId, tables);
33104
+ continue;
33105
+ }
33077
33106
  const zone = reduceZoneOnDeletion(table.zone, cmd.dimension === "COL" ? "left" : "top", cmd.elements);
33078
33107
  if (!zone) {
33079
33108
  const tables = { ...this.tables[cmd.sheetId] };
@@ -35155,10 +35184,13 @@
35155
35184
  // begin with the end.
35156
35185
  rows.sort((a, b) => b - a);
35157
35186
  for (let group of groupConsecutive(rows)) {
35187
+ // indexes are sorted in the descending order
35188
+ const from = group[group.length - 1];
35189
+ const to = group[0];
35158
35190
  // Move the cells.
35159
- this.moveCellOnRowsDeletion(sheet, group[group.length - 1], group[0]);
35160
- // Effectively delete the element and recompute the left-right/top-bottom.
35161
- group.map((row) => this.updateRowsStructureOnDeletion(row, sheet));
35191
+ this.moveCellOnRowsDeletion(sheet, from, to);
35192
+ // Effectively delete the rows
35193
+ this.updateRowsStructureOnDeletion(sheet, from, to);
35162
35194
  }
35163
35195
  const count = rows.filter((row) => row < sheet.panes.ySplit).length;
35164
35196
  if (count) {
@@ -35180,8 +35212,6 @@
35180
35212
  this.addEmptyRows(sheet, quantity);
35181
35213
  // Move the cells.
35182
35214
  this.moveCellsOnAddition(sheet, index, quantity, "rows");
35183
- // Recompute the left-right/top-bottom.
35184
- this.updateRowsStructureOnAddition(sheet, row, quantity);
35185
35215
  if (index < sheet.panes.ySplit) {
35186
35216
  this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
35187
35217
  }
@@ -35282,35 +35312,20 @@
35282
35312
  }
35283
35313
  }
35284
35314
  }
35285
- updateRowsStructureOnDeletion(index, sheet) {
35315
+ updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
35286
35316
  const rows = [];
35287
- const cellsQueue = sheet.rows.map((row) => row.cells);
35317
+ const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
35288
35318
  for (let i in sheet.rows) {
35289
- if (Number(i) === index) {
35319
+ const row = Number(i);
35320
+ if (row >= deleteFromRow && row <= deleteToRow) {
35290
35321
  continue;
35291
35322
  }
35292
35323
  rows.push({
35293
- cells: cellsQueue.shift(),
35324
+ cells: cellsQueue.pop(),
35294
35325
  });
35295
35326
  }
35296
35327
  this.history.update("sheets", sheet.id, "rows", rows);
35297
35328
  }
35298
- /**
35299
- * Update the rows of the sheet after an addition:
35300
- * - Rename the rows
35301
- *
35302
- * @param sheet Sheet on which the deletion occurs
35303
- * @param addedRow Index of the added row
35304
- * @param rowsToAdd Number of the rows to add
35305
- */
35306
- updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
35307
- const rows = [];
35308
- const cellsQueue = sheet.rows.map((row) => row.cells);
35309
- sheet.rows.forEach(() => rows.push({
35310
- cells: cellsQueue.shift(),
35311
- }));
35312
- this.history.update("sheets", sheet.id, "rows", rows);
35313
- }
35314
35329
  /**
35315
35330
  * Add empty rows at the end of the rows
35316
35331
  *
@@ -35426,6 +35441,7 @@
35426
35441
  getters;
35427
35442
  computeCell;
35428
35443
  evalContext;
35444
+ rangeCache = {};
35429
35445
  constructor(context, getters, computeCell) {
35430
35446
  this.getters = getters;
35431
35447
  this.computeCell = computeCell;
@@ -35511,25 +35527,32 @@
35511
35527
  if (!_zone) {
35512
35528
  return { value: [[]], format: [[]] };
35513
35529
  }
35530
+ const { top, left, bottom, right } = zone;
35531
+ const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
35532
+ if (cacheKey in this.rangeCache) {
35533
+ return this.rangeCache[cacheKey];
35534
+ }
35514
35535
  const height = _zone.bottom - _zone.top + 1;
35515
35536
  const width = _zone.right - _zone.left + 1;
35516
- const value = Array.from({ length: width }, () => Array.from({ length: height }));
35517
- const format = Array.from({ length: width }, () => Array.from({ length: height }));
35537
+ const value = new Array(width);
35538
+ const format = new Array(width);
35518
35539
  // Performance issue: nested loop is faster than a map here
35519
35540
  for (let col = _zone.left; col <= _zone.right; col++) {
35541
+ const colIndex = col - _zone.left;
35542
+ value[colIndex] = new Array(height);
35543
+ format[colIndex] = new Array(height);
35520
35544
  for (let row = _zone.top; row <= _zone.bottom; row++) {
35521
- const evaluatedCell = this.getEvaluatedCellIfNotEmpty({ sheetId: sheetId, col, row });
35522
- if (evaluatedCell) {
35523
- const colIndex = col - _zone.left;
35524
- const rowIndex = row - _zone.top;
35525
- value[colIndex][rowIndex] = evaluatedCell.value;
35526
- if (evaluatedCell.format !== undefined) {
35527
- format[colIndex][rowIndex] = evaluatedCell.format;
35528
- }
35545
+ const evaluatedCell = this.getEvaluatedCellIfNotEmpty({ sheetId, col, row });
35546
+ const rowIndex = row - _zone.top;
35547
+ value[colIndex][rowIndex] = evaluatedCell?.value;
35548
+ if (evaluatedCell?.format !== undefined) {
35549
+ format[colIndex][rowIndex] = evaluatedCell.format;
35529
35550
  }
35530
35551
  }
35531
35552
  }
35532
- return { value, format };
35553
+ const result = { value, format };
35554
+ this.rangeCache[cacheKey] = result;
35555
+ return result;
35533
35556
  }
35534
35557
  }
35535
35558
 
@@ -35727,6 +35750,7 @@
35727
35750
  this.formulaDependencies().addDependencies(positionId, dependencies);
35728
35751
  }
35729
35752
  updateCompilationParameters() {
35753
+ // rebuild the compilation parameters (with a clean cache)
35730
35754
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
35731
35755
  }
35732
35756
  evaluateCells(positions) {
@@ -35770,6 +35794,15 @@
35770
35794
  this.evaluatedCells = new Map();
35771
35795
  this.evaluate(this.getAllCells());
35772
35796
  }
35797
+ evaluateFormula(sheetId, formulaString) {
35798
+ const compiledFormula = compile(formulaString);
35799
+ const ranges = [];
35800
+ for (let xc of compiledFormula.dependencies) {
35801
+ ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
35802
+ }
35803
+ this.updateCompilationParameters();
35804
+ return compiledFormula.execute(ranges, ...this.compilationParams).value;
35805
+ }
35773
35806
  getAllCells() {
35774
35807
  const positionIds = new JetSet();
35775
35808
  for (const sheetId of this.getters.getSheetIds()) {
@@ -35796,6 +35829,7 @@
35796
35829
  this.nextPositionsToUpdate = cells;
35797
35830
  let currentIteration = 0;
35798
35831
  while (this.nextPositionsToUpdate.size && currentIteration++ < MAX_ITERATION) {
35832
+ this.updateCompilationParameters();
35799
35833
  const positionIds = Array.from(this.nextPositionsToUpdate);
35800
35834
  this.nextPositionsToUpdate.clear();
35801
35835
  for (let i = 0; i < positionIds.length; ++i) {
@@ -36180,7 +36214,6 @@
36180
36214
  // of other cells depending on it, at the next iteration.
36181
36215
  //#endregion
36182
36216
  class EvaluationPlugin extends UIPlugin {
36183
- config;
36184
36217
  static getters = [
36185
36218
  "evaluateFormula",
36186
36219
  "getRangeFormattedValues",
@@ -36192,12 +36225,9 @@
36192
36225
  ];
36193
36226
  shouldRebuildDependenciesGraph = true;
36194
36227
  evaluator;
36195
- compilationParams;
36196
36228
  positionsToUpdate = [];
36197
36229
  constructor(config) {
36198
36230
  super(config);
36199
- this.config = config;
36200
- this.compilationParams = this.getCompilationParameters();
36201
36231
  this.evaluator = new Evaluator(config.custom, this.getters);
36202
36232
  }
36203
36233
  // ---------------------------------------------------------------------------
@@ -36222,10 +36252,6 @@
36222
36252
  case "EVALUATE_CELLS":
36223
36253
  this.evaluator.evaluateAllCells();
36224
36254
  break;
36225
- case "UPDATE_LOCALE":
36226
- this.compilationParams = this.getCompilationParameters();
36227
- this.evaluator.updateCompilationParameters();
36228
- break;
36229
36255
  }
36230
36256
  }
36231
36257
  finalize() {
@@ -36243,12 +36269,7 @@
36243
36269
  // Getters
36244
36270
  // ---------------------------------------------------------------------------
36245
36271
  evaluateFormula(sheetId, formulaString) {
36246
- const compiledFormula = compile(formulaString);
36247
- const ranges = [];
36248
- for (let xc of compiledFormula.dependencies) {
36249
- ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
36250
- }
36251
- return compiledFormula.execute(ranges, ...this.compilationParams).value;
36272
+ return this.evaluator.evaluateFormula(sheetId, formulaString);
36252
36273
  }
36253
36274
  /**
36254
36275
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -36347,9 +36368,6 @@
36347
36368
  }
36348
36369
  return undefined;
36349
36370
  }
36350
- getCompilationParameters() {
36351
- return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
36352
- }
36353
36371
  }
36354
36372
  function isBadExpression(formula) {
36355
36373
  try {
@@ -36522,22 +36540,20 @@
36522
36540
  invalidateCFEvaluationCommands.has(cmd.type) ||
36523
36541
  cmd.type === "EVALUATE_CELLS" ||
36524
36542
  cmd.type === "UPDATE_CELL") {
36525
- if (cmd.type !== "UNDO" && cmd.type !== "REDO") {
36526
- for (const chartId in this.charts) {
36527
- this.history.update("charts", chartId, undefined);
36528
- }
36543
+ for (const chartId in this.charts) {
36544
+ this.charts[chartId] = undefined;
36529
36545
  }
36530
36546
  }
36531
36547
  switch (cmd.type) {
36532
36548
  case "UPDATE_CHART":
36533
36549
  case "CREATE_CHART":
36534
36550
  case "DELETE_FIGURE":
36535
- this.history.update("charts", cmd.id, undefined);
36551
+ this.charts[cmd.id] = undefined;
36536
36552
  break;
36537
36553
  case "DELETE_SHEET":
36538
36554
  for (let chartId in this.charts) {
36539
36555
  if (!this.getters.isChartDefined(chartId)) {
36540
- this.history.update("charts", chartId, undefined);
36556
+ this.charts[chartId] = undefined;
36541
36557
  }
36542
36558
  }
36543
36559
  break;
@@ -36549,7 +36565,7 @@
36549
36565
  if (!chart) {
36550
36566
  throw new Error(`No chart for the given id: ${figureId}`);
36551
36567
  }
36552
- this.history.update("charts", figureId, this.createRuntimeChart(chart));
36568
+ this.charts[figureId] = this.createRuntimeChart(chart);
36553
36569
  }
36554
36570
  return this.charts[figureId];
36555
36571
  }
@@ -42068,8 +42084,8 @@
42068
42084
  this.lastPasteState = this.state;
42069
42085
  if (this.paintFormatStatus === "oneOff") {
42070
42086
  this.paintFormatStatus = "inactive";
42071
- this.status = "invisible";
42072
42087
  }
42088
+ this.status = "invisible";
42073
42089
  break;
42074
42090
  case "CLEAN_CLIPBOARD_HIGHLIGHT":
42075
42091
  this.status = "invisible";
@@ -43013,6 +43029,8 @@
43013
43029
  case "EVALUATE_CELLS":
43014
43030
  case "ACTIVATE_SHEET":
43015
43031
  case "REMOVE_FILTER_TABLE":
43032
+ case "ADD_COLUMNS_ROWS":
43033
+ case "REMOVE_COLUMNS_ROWS":
43016
43034
  this.isEvaluationDirty = true;
43017
43035
  break;
43018
43036
  case "START":
@@ -47884,9 +47902,9 @@
47884
47902
  * Apply the changes of the given HistoryChange to the state
47885
47903
  */
47886
47904
  function applyChange(change, target) {
47887
- let val = change.root;
47888
- let key = change.path[change.path.length - 1];
47889
- for (let pathIndex = 0; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
47905
+ let val = change.path[0];
47906
+ const key = change.path[change.path.length - 1];
47907
+ for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
47890
47908
  const p = change.path[pathIndex];
47891
47909
  if (val[p] === undefined) {
47892
47910
  const nextPath = change.path[pathIndex + 1];
@@ -48567,13 +48585,14 @@
48567
48585
  }
48568
48586
  addChange(...args) {
48569
48587
  const val = args.pop();
48570
- const [root, ...path] = args;
48588
+ const root = args[0];
48571
48589
  let value = root;
48572
- let key = path[path.length - 1];
48573
- for (let pathIndex = 0; pathIndex <= path.length - 2; pathIndex++) {
48574
- const p = path[pathIndex];
48590
+ let key = args[args.length - 1];
48591
+ const pathLength = args.length - 2;
48592
+ for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
48593
+ const p = args[pathIndex];
48575
48594
  if (value[p] === undefined) {
48576
- const nextPath = path[pathIndex + 1];
48595
+ const nextPath = args[pathIndex + 1];
48577
48596
  value[p] = createEmptyStructure(nextPath);
48578
48597
  }
48579
48598
  value = value[p];
@@ -48582,8 +48601,7 @@
48582
48601
  return;
48583
48602
  }
48584
48603
  this.changes.push({
48585
- root,
48586
- path,
48604
+ path: args,
48587
48605
  before: value[key],
48588
48606
  after: val,
48589
48607
  });
@@ -50433,19 +50451,22 @@
50433
50451
  * Check if the given command is allowed by all the plugins and the history.
50434
50452
  */
50435
50453
  checkDispatchAllowed(command) {
50436
- if (isCoreCommand(command)) {
50437
- return this.checkDispatchAllowedCoreCommand(command);
50454
+ const results = isCoreCommand(command)
50455
+ ? this.checkDispatchAllowedCoreCommand(command)
50456
+ : this.checkDispatchAllowedLocalCommand(command);
50457
+ if (results.some((r) => r !== 0 /* CommandResult.Success */)) {
50458
+ return new DispatchResult(results.flat());
50438
50459
  }
50439
- return this.checkDispatchAllowedLocalCommand(command);
50460
+ return DispatchResult.Success;
50440
50461
  }
50441
50462
  checkDispatchAllowedCoreCommand(command) {
50442
50463
  const results = this.corePlugins.map((handler) => handler.allowDispatch(command));
50443
50464
  results.push(this.range.allowDispatch(command));
50444
- return new DispatchResult(results.flat());
50465
+ return results;
50445
50466
  }
50446
50467
  checkDispatchAllowedLocalCommand(command) {
50447
50468
  const results = this.uiHandlers.map((handler) => handler.allowDispatch(command));
50448
- return new DispatchResult(results.flat());
50469
+ return results;
50449
50470
  }
50450
50471
  finalize() {
50451
50472
  this.status = 3 /* Status.Finalizing */;
@@ -50771,9 +50792,9 @@
50771
50792
  Object.defineProperty(exports, '__esModule', { value: true });
50772
50793
 
50773
50794
 
50774
- __info__.version = '16.4.13';
50775
- __info__.date = '2023-11-03T12:21:08.124Z';
50776
- __info__.hash = '001985e';
50795
+ __info__.version = '16.4.15';
50796
+ __info__.date = '2023-11-24T13:12:26.608Z';
50797
+ __info__.hash = '141943d';
50777
50798
 
50778
50799
 
50779
50800
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);