@odoo/o-spreadsheet 17.0.2 → 17.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 17.0.2
6
- * @date 2023-11-03T12:22:44.945Z
7
- * @hash 3184728
5
+ * @version 17.0.4
6
+ * @date 2023-11-24T13:13:42.575Z
7
+ * @hash 7346d0a
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -692,8 +692,7 @@
692
692
  *
693
693
  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
694
694
  */
695
- const whiteSpaceCharacters = [
696
- " ",
695
+ const whiteSpaceSpecialCharacters = [
697
696
  "\t",
698
697
  "\f",
699
698
  "\v",
@@ -708,8 +707,7 @@
708
707
  String.fromCharCode(parseInt("3000", 16)),
709
708
  String.fromCharCode(parseInt("feff", 16)),
710
709
  ];
711
- const whiteSpaceRegexp = new RegExp(whiteSpaceCharacters.join("|"), "g");
712
- const newLineRegex = /\r\n|\r|\n/g;
710
+ const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|") + "|(\r\n|\r|\n)", "g");
713
711
  /**
714
712
  * Replace all the special spaces in a string (non-breaking, tabs, ...) by normal spaces, and all the
715
713
  * different newlines types by \n.
@@ -717,9 +715,9 @@
717
715
  function replaceSpecialSpaces(text) {
718
716
  if (!text)
719
717
  return "";
720
- text = text.replace(whiteSpaceRegexp, " ");
721
- text = text.replace(newLineRegex, NEWLINE);
722
- return text;
718
+ if (!whiteSpaceRegexp.test(text))
719
+ return text;
720
+ return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
723
721
  }
724
722
  /**
725
723
  * Determine if the numbers are consecutive.
@@ -2061,6 +2059,7 @@
2061
2059
  CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
2062
2060
  CommandResult["BlockingValidationRule"] = "BlockingValidationRule";
2063
2061
  CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
2062
+ CommandResult["NoChanges"] = "NoChanges";
2064
2063
  })(exports.CommandResult || (exports.CommandResult = {}));
2065
2064
 
2066
2065
  const DEFAULT_LOCALES = [
@@ -2190,12 +2189,12 @@
2190
2189
  }
2191
2190
  }
2192
2191
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
2193
- function normalizeString(str) {
2192
+ const normalizeString = memoize(function normalizeString(str) {
2194
2193
  return str
2195
2194
  .toLowerCase()
2196
2195
  .normalize("NFD")
2197
2196
  .replace(/[\u0300-\u036f]/g, "");
2198
- }
2197
+ });
2199
2198
  const expectBooleanValueError = (value) => _t("The function [[FUNCTION_NAME]] expects a boolean value, but '%s' is a text, and cannot be coerced to a number.", value);
2200
2199
  function toBoolean(value) {
2201
2200
  switch (typeof value) {
@@ -4541,14 +4540,14 @@
4541
4540
  switch (context.textBaseline) {
4542
4541
  case "top":
4543
4542
  underlineY += boxHeight - 2 * strokeWidth;
4544
- strikeY += boxHeight - textHeight;
4543
+ strikeY += boxHeight / 2 - strokeWidth;
4545
4544
  break;
4546
4545
  case "middle":
4547
4546
  underlineY += boxHeight / 2 - strokeWidth;
4548
4547
  break;
4549
4548
  case "alphabetic":
4550
4549
  underlineY += 2 * strokeWidth;
4551
- strikeY -= textHeight / 2 - strokeWidth / 2;
4550
+ strikeY -= 3 * strokeWidth;
4552
4551
  break;
4553
4552
  case "bottom":
4554
4553
  underlineY = y;
@@ -5967,7 +5966,7 @@
5967
5966
  return { cellData: {} };
5968
5967
  }
5969
5968
  const sheetId = data.sheetId;
5970
- const content = getters.getTranslatedCellFormula(sheetId, x, y, cell.compiledFormula, cell.dependencies);
5969
+ const content = getters.getTranslatedCellFormula(sheetId, x, y, cell.compiledFormula);
5971
5970
  return {
5972
5971
  cellData: {
5973
5972
  border: data.border,
@@ -7330,7 +7329,7 @@
7330
7329
  return result;
7331
7330
  }
7332
7331
  function tokenizeDebugger(chars) {
7333
- if (chars.current() === "?") {
7332
+ if (chars.current === "?") {
7334
7333
  chars.shift();
7335
7334
  return { type: "DEBUGGER", value: "?" };
7336
7335
  }
@@ -7341,7 +7340,7 @@
7341
7340
  ")": "RIGHT_PAREN",
7342
7341
  };
7343
7342
  function tokenizeMisc(chars) {
7344
- if (chars.current() in misc$1) {
7343
+ if (chars.current in misc$1) {
7345
7344
  const value = chars.shift();
7346
7345
  const type = misc$1[value];
7347
7346
  return { type, value };
@@ -7349,7 +7348,7 @@
7349
7348
  return null;
7350
7349
  }
7351
7350
  function tokenizeArgsSeparator(chars, locale) {
7352
- if (chars.current() === locale.formulaArgSeparator) {
7351
+ if (chars.current === locale.formulaArgSeparator) {
7353
7352
  const value = chars.shift();
7354
7353
  const type = "ARG_SEPARATOR";
7355
7354
  return { type, value };
@@ -7374,14 +7373,13 @@
7374
7373
  return null;
7375
7374
  }
7376
7375
  function tokenizeString(chars) {
7377
- if (chars.current() === '"') {
7376
+ if (chars.current === '"') {
7378
7377
  const startChar = chars.shift();
7379
7378
  let letters = startChar;
7380
- while (chars.current() &&
7381
- (chars.current() !== startChar || letters[letters.length - 1] === "\\")) {
7379
+ while (chars.current && (chars.current !== startChar || letters[letters.length - 1] === "\\")) {
7382
7380
  letters += chars.shift();
7383
7381
  }
7384
- if (chars.current() === '"') {
7382
+ if (chars.current === '"') {
7385
7383
  letters += chars.shift();
7386
7384
  }
7387
7385
  return {
@@ -7408,14 +7406,14 @@
7408
7406
  let result = "";
7409
7407
  // there are two main cases to manage: either something which starts with
7410
7408
  // a ', like 'Sheet 2'A2, or a word-like element.
7411
- if (chars.current() === "'") {
7409
+ if (chars.current === "'") {
7412
7410
  let lastChar = chars.shift();
7413
7411
  result += lastChar;
7414
- while (chars.current()) {
7412
+ while (chars.current) {
7415
7413
  lastChar = chars.shift();
7416
7414
  result += lastChar;
7417
7415
  if (lastChar === "'") {
7418
- if (chars.current() && chars.current() === "'") {
7416
+ if (chars.current && chars.current === "'") {
7419
7417
  lastChar = chars.shift();
7420
7418
  result += lastChar;
7421
7419
  }
@@ -7431,7 +7429,7 @@
7431
7429
  };
7432
7430
  }
7433
7431
  }
7434
- while (chars.current() && separatorRegexp.test(chars.current())) {
7432
+ while (chars.current && separatorRegexp.test(chars.current)) {
7435
7433
  result += chars.shift();
7436
7434
  }
7437
7435
  if (result.length) {
@@ -7446,14 +7444,14 @@
7446
7444
  }
7447
7445
  function tokenizeSpace(chars) {
7448
7446
  let length = 0;
7449
- while (chars.current() === NEWLINE) {
7447
+ while (chars.current === NEWLINE) {
7450
7448
  length++;
7451
7449
  chars.shift();
7452
7450
  }
7453
7451
  if (length) {
7454
7452
  return { type: "SPACE", value: NEWLINE.repeat(length) };
7455
7453
  }
7456
- while (chars.current() === " ") {
7454
+ while (chars.current === " ") {
7457
7455
  length++;
7458
7456
  chars.shift();
7459
7457
  }
@@ -7472,17 +7470,20 @@
7472
7470
  class TokenizingChars {
7473
7471
  text;
7474
7472
  currentIndex = 0;
7473
+ current;
7475
7474
  constructor(text) {
7476
7475
  this.text = text;
7477
- }
7478
- current() {
7479
- return this.text[this.currentIndex];
7476
+ this.current = text[0];
7480
7477
  }
7481
7478
  shift() {
7482
- return this.text[this.currentIndex++];
7479
+ const current = this.current;
7480
+ const next = this.text[++this.currentIndex];
7481
+ this.current = next;
7482
+ return current;
7483
7483
  }
7484
7484
  advanceBy(length) {
7485
7485
  this.currentIndex += length;
7486
+ this.current = this.text[this.currentIndex];
7486
7487
  }
7487
7488
  isOver() {
7488
7489
  return this.currentIndex >= this.text.length;
@@ -10694,6 +10695,17 @@
10694
10695
  const IS_ONLY_ONE_RANGE = (env) => {
10695
10696
  return env.model.getters.getSelectedZones().length === 1;
10696
10697
  };
10698
+ const CAN_INSERT_HEADER = (env, dimension) => {
10699
+ if (!IS_ONLY_ONE_RANGE(env)) {
10700
+ return false;
10701
+ }
10702
+ const activeHeaders = dimension === "COL" ? env.model.getters.getActiveCols() : env.model.getters.getActiveRows();
10703
+ const ortogonalActiveHeaders = dimension === "COL" ? env.model.getters.getActiveRows() : env.model.getters.getActiveCols();
10704
+ const sheetId = env.model.getters.getActiveSheetId();
10705
+ const zone = env.model.getters.getSelectedZone();
10706
+ const allSheetSelected = isEqual(zone, env.model.getters.getSheetZone(sheetId));
10707
+ return isConsecutive(activeHeaders) && (ortogonalActiveHeaders.size === 0 || allSheetSelected);
10708
+ };
10697
10709
 
10698
10710
  const undo = {
10699
10711
  name: _t("Undo"),
@@ -19371,9 +19383,7 @@
19371
19383
  const number = getRowsNumber(env);
19372
19384
  return number === 1 ? _t("Insert row") : _t("Insert %s rows", number.toString());
19373
19385
  },
19374
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19375
- IS_ONLY_ONE_RANGE(env) &&
19376
- env.model.getters.getActiveCols().size === 0,
19386
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19377
19387
  icon: "o-spreadsheet-Icon.INSERT_ROW",
19378
19388
  };
19379
19389
  const rowInsertRowBefore = {
@@ -19382,9 +19392,7 @@
19382
19392
  return number === 1 ? _t("Insert row above") : _t("Insert %s rows above", number.toString());
19383
19393
  },
19384
19394
  execute: INSERT_ROWS_BEFORE_ACTION,
19385
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19386
- IS_ONLY_ONE_RANGE(env) &&
19387
- env.model.getters.getActiveCols().size === 0,
19395
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19388
19396
  icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
19389
19397
  };
19390
19398
  const topBarInsertRowsBefore = {
@@ -19415,9 +19423,7 @@
19415
19423
  const number = getRowsNumber(env);
19416
19424
  return number === 1 ? _t("Insert row below") : _t("Insert %s rows below", number.toString());
19417
19425
  },
19418
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19419
- IS_ONLY_ONE_RANGE(env) &&
19420
- env.model.getters.getActiveCols().size === 0,
19426
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19421
19427
  icon: "o-spreadsheet-Icon.INSERT_ROW_AFTER",
19422
19428
  };
19423
19429
  const topBarInsertRowsAfter = {
@@ -19435,9 +19441,7 @@
19435
19441
  const number = getColumnsNumber(env);
19436
19442
  return number === 1 ? _t("Insert column") : _t("Insert %s columns", number.toString());
19437
19443
  },
19438
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19439
- IS_ONLY_ONE_RANGE(env) &&
19440
- env.model.getters.getActiveRows().size === 0,
19444
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19441
19445
  icon: "o-spreadsheet-Icon.INSERT_COL",
19442
19446
  };
19443
19447
  const colInsertColsBefore = {
@@ -19448,9 +19452,7 @@
19448
19452
  : _t("Insert %s columns left", number.toString());
19449
19453
  },
19450
19454
  execute: INSERT_COLUMNS_BEFORE_ACTION,
19451
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19452
- IS_ONLY_ONE_RANGE(env) &&
19453
- env.model.getters.getActiveRows().size === 0,
19455
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19454
19456
  icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
19455
19457
  };
19456
19458
  const topBarInsertColsBefore = {
@@ -19483,9 +19485,7 @@
19483
19485
  : _t("Insert %s columns right", number.toString());
19484
19486
  },
19485
19487
  execute: INSERT_COLUMNS_AFTER_ACTION,
19486
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19487
- IS_ONLY_ONE_RANGE(env) &&
19488
- env.model.getters.getActiveRows().size === 0,
19488
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19489
19489
  icon: "o-spreadsheet-Icon.INSERT_COL_AFTER",
19490
19490
  };
19491
19491
  const topBarInsertColsAfter = {
@@ -23826,7 +23826,7 @@
23826
23826
  }
23827
23827
  .o-input-count {
23828
23828
  width: fit-content;
23829
- padding: 4 0 4 4;
23829
+ padding: 4px 0 4px 4px;
23830
23830
  }
23831
23831
  }
23832
23832
  }
@@ -29759,6 +29759,7 @@
29759
29759
  const content = clipboardData.getData(ClipboardMIMEType.PlainText);
29760
29760
  const target = this.env.model.getters.getSelectedZones();
29761
29761
  const clipboardString = this.env.model.getters.getClipboardTextContent();
29762
+ const isCutOperation = this.env.model.getters.isCutOperation();
29762
29763
  if (clipboardString === content) {
29763
29764
  // the paste actually comes from o-spreadsheet itself
29764
29765
  interactivePaste(this.env, target);
@@ -29766,7 +29767,7 @@
29766
29767
  else {
29767
29768
  interactivePasteFromOS(this.env, target, content);
29768
29769
  }
29769
- if (this.env.model.getters.isCutOperation()) {
29770
+ if (isCutOperation) {
29770
29771
  await this.env.clipboard.write({ [ClipboardMIMEType.PlainText]: "" });
29771
29772
  }
29772
29773
  }
@@ -34060,6 +34061,14 @@
34060
34061
  // ---------------------------------------------------------------------------
34061
34062
  // Command Handling
34062
34063
  // ---------------------------------------------------------------------------
34064
+ allowDispatch(cmd) {
34065
+ switch (cmd.type) {
34066
+ case "SET_BORDER":
34067
+ return this.checkBordersUnchanged(cmd);
34068
+ default:
34069
+ return "Success" /* CommandResult.Success */;
34070
+ }
34071
+ }
34063
34072
  handle(cmd) {
34064
34073
  switch (cmd.type) {
34065
34074
  case "ADD_MERGE":
@@ -34479,6 +34488,14 @@
34479
34488
  this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
34480
34489
  }
34481
34490
  }
34491
+ checkBordersUnchanged(cmd) {
34492
+ const currentBorder = this.getCellBorder(cmd);
34493
+ const areAllNewBordersUndefined = !cmd.border?.bottom && !cmd.border?.left && !cmd.border?.right && !cmd.border?.top;
34494
+ if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
34495
+ return "NoChanges" /* CommandResult.NoChanges */;
34496
+ }
34497
+ return "Success" /* CommandResult.Success */;
34498
+ }
34482
34499
  // ---------------------------------------------------------------------------
34483
34500
  // Import/Export
34484
34501
  // ---------------------------------------------------------------------------
@@ -34947,6 +34964,9 @@
34947
34964
  // -----------------------------------------------------------------------------
34948
34965
  function compile(formula) {
34949
34966
  const tokens = rangeTokenize(formula);
34967
+ return compileTokens(tokens);
34968
+ }
34969
+ function compileTokens(tokens) {
34950
34970
  const { dependencies, constantValues } = formulaArguments(tokens);
34951
34971
  const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
34952
34972
  if (!functionCache[cacheKey]) {
@@ -35313,11 +35333,11 @@
35313
35333
  for (const sheet of Object.keys(this.cells)) {
35314
35334
  for (const cell of Object.values(this.cells[sheet] || {})) {
35315
35335
  if (cell.isFormula) {
35316
- for (const range of cell.dependencies) {
35336
+ for (const range of cell.compiledFormula.dependencies) {
35317
35337
  if (!sheetId || range.sheetId === sheetId) {
35318
35338
  const change = applyChange(range);
35319
35339
  if (change.changeType !== "NONE") {
35320
- this.history.update("cells", sheet, cell.id, "dependencies", cell.dependencies.indexOf(range), change.range);
35340
+ this.history.update("cells", sheet, cell.id, "compiledFormula", "dependencies", cell.compiledFormula.dependencies.indexOf(range), change.range);
35321
35341
  }
35322
35342
  }
35323
35343
  }
@@ -35331,8 +35351,9 @@
35331
35351
  allowDispatch(cmd) {
35332
35352
  switch (cmd.type) {
35333
35353
  case "UPDATE_CELL":
35354
+ return this.checkCellOutOfSheet(cmd);
35334
35355
  case "CLEAR_CELL":
35335
- return this.checkCellOutOfSheet(cmd.sheetId, cmd.col, cmd.row);
35356
+ return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
35336
35357
  default:
35337
35358
  return "Success" /* CommandResult.Success */;
35338
35359
  }
@@ -35501,22 +35522,17 @@
35501
35522
  */
35502
35523
  getCellById(cellId) {
35503
35524
  // this must be as fast as possible
35504
- for (const sheetId in this.cells) {
35505
- const sheet = this.cells[sheetId];
35506
- const cell = sheet[cellId];
35507
- if (cell) {
35508
- return cell;
35509
- }
35510
- }
35511
- return undefined;
35525
+ const position = this.getters.getCellPosition(cellId);
35526
+ const sheet = this.cells[position.sheetId];
35527
+ return sheet[cellId];
35512
35528
  }
35513
35529
  /*
35514
35530
  * Reconstructs the original formula string based on a normalized form and its dependencies
35515
35531
  */
35516
- getFormulaCellContent(sheetId, cell, dependencies) {
35517
- const ranges = dependencies || cell.dependencies;
35532
+ getFormulaCellContent(sheetId, compiledFormula, dependencies) {
35533
+ const ranges = dependencies || compiledFormula.dependencies;
35518
35534
  let rangeIndex = 0;
35519
- return concat(cell.compiledFormula.tokens.map((token) => {
35535
+ return concat(compiledFormula.tokens.map((token) => {
35520
35536
  if (token.type === "REFERENCE") {
35521
35537
  const range = ranges[rangeIndex++];
35522
35538
  return this.getters.getRangeString(range, sheetId);
@@ -35527,12 +35543,9 @@
35527
35543
  /*
35528
35544
  * Constructs a formula string based on an initial formula and a translation vector
35529
35545
  */
35530
- getTranslatedCellFormula(sheetId, offsetX, offsetY, compiledFormula, dependencies) {
35531
- const adaptedDependencies = this.getters.createAdaptedRanges(dependencies, offsetX, offsetY, sheetId);
35532
- return this.getFormulaCellContent(sheetId, {
35533
- compiledFormula,
35534
- dependencies: adaptedDependencies,
35535
- });
35546
+ getTranslatedCellFormula(sheetId, offsetX, offsetY, compiledFormula) {
35547
+ const adaptedDependencies = this.getters.createAdaptedRanges(compiledFormula.dependencies, offsetX, offsetY, sheetId);
35548
+ return this.getFormulaCellContent(sheetId, compiledFormula, adaptedDependencies);
35536
35549
  }
35537
35550
  getCellStyle(position) {
35538
35551
  return this.getters.getCell(position)?.style || {};
@@ -35712,8 +35725,10 @@
35712
35725
  style,
35713
35726
  format,
35714
35727
  isFormula: true,
35715
- compiledFormula,
35716
- dependencies: [],
35728
+ compiledFormula: {
35729
+ ...compiledFormula,
35730
+ dependencies: [],
35731
+ },
35717
35732
  };
35718
35733
  }
35719
35734
  /**
@@ -35722,7 +35737,7 @@
35722
35737
  */
35723
35738
  createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
35724
35739
  const dependencies = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
35725
- return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getFormulaCellContent.bind(this));
35740
+ return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString.bind(this));
35726
35741
  }
35727
35742
  createErrorFormula(id, content, format, style, error) {
35728
35743
  return {
@@ -35732,46 +35747,72 @@
35732
35747
  format,
35733
35748
  isFormula: true,
35734
35749
  compiledFormula: {
35735
- dependencies: [],
35736
35750
  tokens: tokenize(content),
35751
+ dependencies: [],
35737
35752
  execute: function () {
35738
35753
  throw error;
35739
35754
  },
35740
35755
  },
35741
- dependencies: [],
35742
35756
  };
35743
35757
  }
35744
- checkCellOutOfSheet(sheetId, col, row) {
35758
+ checkCellOutOfSheet(cmd) {
35759
+ const { sheetId, col, row } = cmd;
35745
35760
  const sheet = this.getters.tryGetSheet(sheetId);
35746
35761
  if (!sheet)
35747
35762
  return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
35748
35763
  const sheetZone = this.getters.getSheetZone(sheetId);
35749
35764
  return isInside(col, row, sheetZone) ? "Success" /* CommandResult.Success */ : "TargetOutOfSheet" /* CommandResult.TargetOutOfSheet */;
35750
35765
  }
35766
+ checkUselessClearCell(cmd) {
35767
+ const cell = this.getters.getCell(cmd);
35768
+ if (!cell)
35769
+ return "NoChanges" /* CommandResult.NoChanges */;
35770
+ if (!cell.content && !cell.style && !cell.format) {
35771
+ return "NoChanges" /* CommandResult.NoChanges */;
35772
+ }
35773
+ return "Success" /* CommandResult.Success */;
35774
+ }
35751
35775
  }
35752
35776
  class FormulaCellWithDependencies {
35753
35777
  id;
35754
- compiledFormula;
35755
35778
  format;
35756
35779
  style;
35757
- dependencies;
35758
35780
  sheetId;
35759
- getFormulaCellContent;
35781
+ getRangeString;
35760
35782
  isFormula = true;
35761
- constructor(id, compiledFormula, format, style, dependencies, sheetId, getFormulaCellContent) {
35783
+ compiledFormula;
35784
+ constructor(id, compiledFormula, format, style, dependencies, sheetId, getRangeString) {
35762
35785
  this.id = id;
35763
- this.compiledFormula = compiledFormula;
35764
35786
  this.format = format;
35765
35787
  this.style = style;
35766
- this.dependencies = dependencies;
35767
35788
  this.sheetId = sheetId;
35768
- this.getFormulaCellContent = getFormulaCellContent;
35789
+ this.getRangeString = getRangeString;
35790
+ let rangeIndex = 0;
35791
+ const tokens = compiledFormula.tokens.map((token) => {
35792
+ if (token.type === "REFERENCE") {
35793
+ const index = rangeIndex++;
35794
+ return new RangeReferenceToken(() => this.getRangeString(dependencies[index], this.sheetId));
35795
+ }
35796
+ return token;
35797
+ });
35798
+ this.compiledFormula = {
35799
+ ...compiledFormula,
35800
+ dependencies,
35801
+ tokens,
35802
+ };
35769
35803
  }
35770
35804
  get content() {
35771
- return this.getFormulaCellContent(this.sheetId, {
35772
- dependencies: this.dependencies,
35773
- compiledFormula: this.compiledFormula,
35774
- });
35805
+ return concat(this.compiledFormula.tokens.map((token) => token.value));
35806
+ }
35807
+ }
35808
+ class RangeReferenceToken {
35809
+ getValue;
35810
+ type = "REFERENCE";
35811
+ constructor(getValue) {
35812
+ this.getValue = getValue;
35813
+ }
35814
+ get value() {
35815
+ return this.getValue();
35775
35816
  }
35776
35817
  }
35777
35818
 
@@ -36420,6 +36461,9 @@
36420
36461
  return this.rules[sheetId].find((rule) => rule.id === id);
36421
36462
  }
36422
36463
  getValidationRuleForCell({ sheetId, col, row }) {
36464
+ if (!this.rules[sheetId]) {
36465
+ return undefined;
36466
+ }
36423
36467
  for (const rule of this.rules[sheetId]) {
36424
36468
  for (const range of rule.ranges) {
36425
36469
  if (isInside(col, row, range.zone)) {
@@ -36916,6 +36960,13 @@
36916
36960
  }
36917
36961
  onDeleteColumnsRows(cmd) {
36918
36962
  for (const table of this.getFilterTables(cmd.sheetId)) {
36963
+ // Remove the filter tables whose data filter headers are in the removed rows.
36964
+ if (cmd.dimension === "ROW" && cmd.elements.includes(table.zone.top)) {
36965
+ const tables = { ...this.tables[cmd.sheetId] };
36966
+ delete tables[table.id];
36967
+ this.history.update("tables", cmd.sheetId, tables);
36968
+ continue;
36969
+ }
36919
36970
  const zone = reduceZoneOnDeletion(table.zone, cmd.dimension === "COL" ? "left" : "top", cmd.elements);
36920
36971
  if (!zone) {
36921
36972
  const tables = { ...this.tables[cmd.sheetId] };
@@ -39010,10 +39061,13 @@
39010
39061
  // begin with the end.
39011
39062
  rows.sort((a, b) => b - a);
39012
39063
  for (let group of groupConsecutive(rows)) {
39064
+ // indexes are sorted in the descending order
39065
+ const from = group[group.length - 1];
39066
+ const to = group[0];
39013
39067
  // Move the cells.
39014
- this.moveCellOnRowsDeletion(sheet, group[group.length - 1], group[0]);
39015
- // Effectively delete the element and recompute the left-right/top-bottom.
39016
- group.map((row) => this.updateRowsStructureOnDeletion(row, sheet));
39068
+ this.moveCellOnRowsDeletion(sheet, from, to);
39069
+ // Effectively delete the rows
39070
+ this.updateRowsStructureOnDeletion(sheet, from, to);
39017
39071
  }
39018
39072
  const count = rows.filter((row) => row < sheet.panes.ySplit).length;
39019
39073
  if (count) {
@@ -39035,8 +39089,6 @@
39035
39089
  this.addEmptyRows(sheet, quantity);
39036
39090
  // Move the cells.
39037
39091
  this.moveCellsOnAddition(sheet, index, quantity, "rows");
39038
- // Recompute the left-right/top-bottom.
39039
- this.updateRowsStructureOnAddition(sheet, row, quantity);
39040
39092
  if (index < sheet.panes.ySplit) {
39041
39093
  this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
39042
39094
  }
@@ -39137,35 +39189,20 @@
39137
39189
  }
39138
39190
  }
39139
39191
  }
39140
- updateRowsStructureOnDeletion(index, sheet) {
39192
+ updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
39141
39193
  const rows = [];
39142
- const cellsQueue = sheet.rows.map((row) => row.cells);
39194
+ const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
39143
39195
  for (let i in sheet.rows) {
39144
- if (Number(i) === index) {
39196
+ const row = Number(i);
39197
+ if (row >= deleteFromRow && row <= deleteToRow) {
39145
39198
  continue;
39146
39199
  }
39147
39200
  rows.push({
39148
- cells: cellsQueue.shift(),
39201
+ cells: cellsQueue.pop(),
39149
39202
  });
39150
39203
  }
39151
39204
  this.history.update("sheets", sheet.id, "rows", rows);
39152
39205
  }
39153
- /**
39154
- * Update the rows of the sheet after an addition:
39155
- * - Rename the rows
39156
- *
39157
- * @param sheet Sheet on which the deletion occurs
39158
- * @param addedRow Index of the added row
39159
- * @param rowsToAdd Number of the rows to add
39160
- */
39161
- updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
39162
- const rows = [];
39163
- const cellsQueue = sheet.rows.map((row) => row.cells);
39164
- sheet.rows.forEach(() => rows.push({
39165
- cells: cellsQueue.shift(),
39166
- }));
39167
- this.history.update("sheets", sheet.id, "rows", rows);
39168
- }
39169
39206
  /**
39170
39207
  * Add empty rows at the end of the rows
39171
39208
  *
@@ -39692,6 +39729,7 @@
39692
39729
  getters;
39693
39730
  computeCell;
39694
39731
  evalContext;
39732
+ rangeCache = {};
39695
39733
  constructor(context, getters, computeCell) {
39696
39734
  this.getters = getters;
39697
39735
  this.computeCell = computeCell;
@@ -39777,17 +39815,24 @@
39777
39815
  if (!_zone) {
39778
39816
  return [[]];
39779
39817
  }
39818
+ const { top, left, bottom, right } = zone;
39819
+ const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
39820
+ if (cacheKey in this.rangeCache) {
39821
+ return this.rangeCache[cacheKey];
39822
+ }
39780
39823
  const height = _zone.bottom - _zone.top + 1;
39781
39824
  const width = _zone.right - _zone.left + 1;
39782
- const matrix = Array.from({ length: width }, () => Array.from({ length: height }));
39825
+ const matrix = new Array(width);
39783
39826
  // Performance issue: nested loop is faster than a map here
39784
39827
  for (let col = _zone.left; col <= _zone.right; col++) {
39828
+ const colIndex = col - _zone.left;
39829
+ matrix[colIndex] = new Array(height);
39785
39830
  for (let row = _zone.top; row <= _zone.bottom; row++) {
39786
- const colIndex = col - _zone.left;
39787
39831
  const rowIndex = row - _zone.top;
39788
39832
  matrix[colIndex][rowIndex] = this.readCell({ sheetId, col, row });
39789
39833
  }
39790
39834
  }
39835
+ this.rangeCache[cacheKey] = matrix;
39791
39836
  return matrix;
39792
39837
  }
39793
39838
  }
@@ -39964,6 +40009,13 @@
39964
40009
  return (this.evaluatedCells.get(this.encodePosition(position)) ||
39965
40010
  createEvaluatedCell("", { locale: this.getters.getLocale() }));
39966
40011
  }
40012
+ getSpreadPositionsOf(position) {
40013
+ const positionId = this.encodePosition(position);
40014
+ if (!this.spreadingRelations.isArrayFormula(positionId)) {
40015
+ return [];
40016
+ }
40017
+ return Array.from(this.spreadingRelations.getArrayResultPositionIds(positionId)).map(this.decodePosition.bind(this));
40018
+ }
39967
40019
  getArrayFormulaSpreadingOn(position) {
39968
40020
  const positionId = this.encodePosition(position);
39969
40021
  const formulaPosition = this.getArrayFormulaSpreadingOnId(positionId);
@@ -39986,6 +40038,7 @@
39986
40038
  this.formulaDependencies().addDependencies(positionId, dependencies);
39987
40039
  }
39988
40040
  updateCompilationParameters() {
40041
+ // rebuild the compilation parameters (with a clean cache)
39989
40042
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
39990
40043
  }
39991
40044
  evaluateCells(positions) {
@@ -40029,6 +40082,16 @@
40029
40082
  this.evaluatedCells = new Map();
40030
40083
  this.evaluate(this.getAllCells());
40031
40084
  }
40085
+ evaluateFormula(sheetId, formulaString) {
40086
+ const compiledFormula = compile(formulaString);
40087
+ const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
40088
+ this.updateCompilationParameters();
40089
+ const array = compiledFormula.execute(ranges, ...this.compilationParams);
40090
+ if (isMatrix(array)) {
40091
+ return matrixMap(array, (cell) => cell.value);
40092
+ }
40093
+ return array.value;
40094
+ }
40032
40095
  getAllCells() {
40033
40096
  const positionIds = new JetSet();
40034
40097
  for (const sheetId of this.getters.getSheetIds()) {
@@ -40055,6 +40118,7 @@
40055
40118
  this.nextPositionsToUpdate = cells;
40056
40119
  let currentIteration = 0;
40057
40120
  while (this.nextPositionsToUpdate.size && currentIteration++ < MAX_ITERATION) {
40121
+ this.updateCompilationParameters();
40058
40122
  const positionIds = Array.from(this.nextPositionsToUpdate);
40059
40123
  this.nextPositionsToUpdate.clear();
40060
40124
  for (let i = 0; i < positionIds.length; ++i) {
@@ -40122,7 +40186,7 @@
40122
40186
  const position = this.compilationParams[2].getters.getCellPosition(cellId);
40123
40187
  return toXC(position.col, position.row);
40124
40188
  };
40125
- const formulaReturn = cellData.compiledFormula.execute(cellData.dependencies, ...this.compilationParams);
40189
+ const formulaReturn = cellData.compiledFormula.execute(cellData.compiledFormula.dependencies, ...this.compilationParams);
40126
40190
  if (!isMatrix(formulaReturn)) {
40127
40191
  return createEvaluatedCell(formulaReturn.value, {
40128
40192
  format: cellData.format || formulaReturn.format,
@@ -40222,7 +40286,7 @@
40222
40286
  return [];
40223
40287
  }
40224
40288
  const dependencies = [];
40225
- for (const range of cell.dependencies) {
40289
+ for (const range of cell.compiledFormula.dependencies) {
40226
40290
  if (range.invalidSheetName || range.invalidXc) {
40227
40291
  continue;
40228
40292
  }
@@ -40418,7 +40482,6 @@
40418
40482
  // of other cells depending on it, at the next iteration.
40419
40483
  //#endregion
40420
40484
  class EvaluationPlugin extends UIPlugin {
40421
- config;
40422
40485
  static getters = [
40423
40486
  "evaluateFormula",
40424
40487
  "getCorrespondingFormulaCell",
@@ -40428,15 +40491,14 @@
40428
40491
  "getEvaluatedCell",
40429
40492
  "getEvaluatedCells",
40430
40493
  "getEvaluatedCellsInZone",
40494
+ "getSpreadPositionsOf",
40495
+ "getArrayFormulaSpreadingOn",
40431
40496
  ];
40432
40497
  shouldRebuildDependenciesGraph = true;
40433
40498
  evaluator;
40434
- compilationParams;
40435
40499
  positionsToUpdate = [];
40436
40500
  constructor(config) {
40437
40501
  super(config);
40438
- this.config = config;
40439
- this.compilationParams = this.getCompilationParameters();
40440
40502
  this.evaluator = new Evaluator(config.custom, this.getters);
40441
40503
  }
40442
40504
  // ---------------------------------------------------------------------------
@@ -40461,10 +40523,6 @@
40461
40523
  case "EVALUATE_CELLS":
40462
40524
  this.evaluator.evaluateAllCells();
40463
40525
  break;
40464
- case "UPDATE_LOCALE":
40465
- this.compilationParams = this.getCompilationParameters();
40466
- this.evaluator.updateCompilationParameters();
40467
- break;
40468
40526
  }
40469
40527
  }
40470
40528
  finalize() {
@@ -40482,16 +40540,7 @@
40482
40540
  // Getters
40483
40541
  // ---------------------------------------------------------------------------
40484
40542
  evaluateFormula(sheetId, formulaString) {
40485
- const compiledFormula = compile(formulaString);
40486
- const ranges = [];
40487
- for (let xc of compiledFormula.dependencies) {
40488
- ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
40489
- }
40490
- const array = compiledFormula.execute(ranges, ...this.compilationParams);
40491
- if (isMatrix(array)) {
40492
- return array.map((col) => col.map((row) => row.value));
40493
- }
40494
- return array.value;
40543
+ return this.evaluator.evaluateFormula(sheetId, formulaString);
40495
40544
  }
40496
40545
  /**
40497
40546
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -40537,6 +40586,12 @@
40537
40586
  getEvaluatedCellsInZone(sheetId, zone) {
40538
40587
  return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
40539
40588
  }
40589
+ getSpreadPositionsOf(position) {
40590
+ return this.evaluator.getSpreadPositionsOf(position);
40591
+ }
40592
+ getArrayFormulaSpreadingOn(position) {
40593
+ return this.evaluator.getArrayFormulaSpreadingOn(position);
40594
+ }
40540
40595
  // ---------------------------------------------------------------------------
40541
40596
  // Export
40542
40597
  // ---------------------------------------------------------------------------
@@ -40574,13 +40629,13 @@
40574
40629
  */
40575
40630
  getCorrespondingFormulaCell(position) {
40576
40631
  const cell = this.getters.getCell(position);
40577
- if (cell && cell.content) {
40578
- if (cell.isFormula && !isBadExpression(cell.content)) {
40579
- return cell;
40580
- }
40632
+ if (cell && cell.isFormula) {
40633
+ return isBadExpression(cell.compiledFormula.tokens) ? undefined : cell;
40634
+ }
40635
+ else if (cell && cell.content) {
40581
40636
  return undefined;
40582
40637
  }
40583
- const spreadingFormulaPosition = this.evaluator.getArrayFormulaSpreadingOn(position);
40638
+ const spreadingFormulaPosition = this.getArrayFormulaSpreadingOn(position);
40584
40639
  if (spreadingFormulaPosition === undefined) {
40585
40640
  return undefined;
40586
40641
  }
@@ -40590,13 +40645,10 @@
40590
40645
  }
40591
40646
  return undefined;
40592
40647
  }
40593
- getCompilationParameters() {
40594
- return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
40595
- }
40596
40648
  }
40597
- function isBadExpression(formula) {
40649
+ function isBadExpression(tokens) {
40598
40650
  try {
40599
- compile(formula);
40651
+ compileTokens(tokens);
40600
40652
  return false;
40601
40653
  }
40602
40654
  catch (error) {
@@ -40765,22 +40817,20 @@
40765
40817
  invalidateCFEvaluationCommands.has(cmd.type) ||
40766
40818
  cmd.type === "EVALUATE_CELLS" ||
40767
40819
  cmd.type === "UPDATE_CELL") {
40768
- if (cmd.type !== "UNDO" && cmd.type !== "REDO") {
40769
- for (const chartId in this.charts) {
40770
- this.history.update("charts", chartId, undefined);
40771
- }
40820
+ for (const chartId in this.charts) {
40821
+ this.charts[chartId] = undefined;
40772
40822
  }
40773
40823
  }
40774
40824
  switch (cmd.type) {
40775
40825
  case "UPDATE_CHART":
40776
40826
  case "CREATE_CHART":
40777
40827
  case "DELETE_FIGURE":
40778
- this.history.update("charts", cmd.id, undefined);
40828
+ this.charts[cmd.id] = undefined;
40779
40829
  break;
40780
40830
  case "DELETE_SHEET":
40781
40831
  for (let chartId in this.charts) {
40782
40832
  if (!this.getters.isChartDefined(chartId)) {
40783
- this.history.update("charts", chartId, undefined);
40833
+ this.charts[chartId] = undefined;
40784
40834
  }
40785
40835
  }
40786
40836
  break;
@@ -40792,8 +40842,7 @@
40792
40842
  if (!chart) {
40793
40843
  throw new Error(`No chart for the given id: ${figureId}`);
40794
40844
  }
40795
- const runtime = this.createRuntimeChart(chart);
40796
- this.history.update("charts", figureId, runtime);
40845
+ this.charts[figureId] = this.createRuntimeChart(chart);
40797
40846
  }
40798
40847
  return this.charts[figureId];
40799
40848
  }
@@ -40945,7 +40994,10 @@
40945
40994
  const values = cf.rule.values.map((value, i) => {
40946
40995
  const compiledFormula = formulas[i];
40947
40996
  if (compiledFormula) {
40948
- return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, compiledFormula, compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)));
40997
+ return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, {
40998
+ ...compiledFormula,
40999
+ dependencies: compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
41000
+ });
40949
41001
  }
40950
41002
  return value;
40951
41003
  });
@@ -41317,7 +41369,10 @@
41317
41369
  }
41318
41370
  try {
41319
41371
  const formula = compile(value);
41320
- const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, formula, formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)));
41372
+ const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, {
41373
+ ...formula,
41374
+ dependencies: formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
41375
+ });
41321
41376
  const evaluated = this.getters.evaluateFormula(sheetId, translatedFormula);
41322
41377
  return evaluated && !isMatrix(evaluated) ? evaluated.toString() : "";
41323
41378
  }
@@ -43288,11 +43343,26 @@
43288
43343
  let cellsInRow = [];
43289
43344
  for (let col of columnsIndex) {
43290
43345
  const position = { col, row, sheetId };
43346
+ const spreader = getters.getArrayFormulaSpreadingOn(position);
43347
+ let cell = getters.getCell(position);
43348
+ const evaluatedCell = getters.getEvaluatedCell(position);
43349
+ if (spreader) {
43350
+ const isSpreaderCopied = rowsIndex.includes(spreader.row) && columnsIndex.includes(spreader.col);
43351
+ const content = isSpreaderCopied
43352
+ ? ""
43353
+ : formatValue(evaluatedCell.value, { locale: getters.getLocale() });
43354
+ cell = {
43355
+ id: cell?.id || "",
43356
+ style: cell?.style,
43357
+ format: evaluatedCell.format,
43358
+ content,
43359
+ isFormula: false,
43360
+ };
43361
+ }
43291
43362
  cellsInRow.push({
43292
- cell: getters.getCell(position),
43293
- style: getters.getCellComputedStyle(position),
43294
- evaluatedCell: getters.getEvaluatedCell(position),
43363
+ cell,
43295
43364
  border: getters.getCellBorder(position) || undefined,
43365
+ evaluatedCell,
43296
43366
  position,
43297
43367
  });
43298
43368
  }
@@ -43414,13 +43484,6 @@
43414
43484
  });
43415
43485
  }
43416
43486
  this.pasteCopiedTables(target);
43417
- this.cells.forEach((row) => {
43418
- row.forEach((c) => {
43419
- if (c.cell) {
43420
- c.cell = undefined;
43421
- }
43422
- });
43423
- });
43424
43487
  }
43425
43488
  /**
43426
43489
  * The clipped zone is copied as many times as it fits in the target.
@@ -43492,7 +43555,7 @@
43492
43555
  clearClippedZones() {
43493
43556
  for (const row of this.cells) {
43494
43557
  for (const cell of row) {
43495
- if (cell.cell) {
43558
+ if (cell?.cell) {
43496
43559
  this.dispatch("CLEAR_CELL", cell.position);
43497
43560
  }
43498
43561
  }
@@ -43518,6 +43581,9 @@
43518
43581
  const rowCells = this.cells[r];
43519
43582
  for (let c = 0; c < width; c++) {
43520
43583
  const origin = rowCells[c];
43584
+ if (!origin) {
43585
+ continue;
43586
+ }
43521
43587
  const position = { col: col + c, row: row + r, sheetId: sheetId };
43522
43588
  // TODO: refactor this part. the "Paste merge" action is also executed with
43523
43589
  // MOVE_RANGES in pasteFromCut. Adding a condition on the operation type here
@@ -43541,53 +43607,42 @@
43541
43607
  pasteCell(origin, target, operation, clipboardOption) {
43542
43608
  const { sheetId, col, row } = target;
43543
43609
  const targetCell = this.getters.getEvaluatedCell(target);
43544
- if (clipboardOption?.pasteOption !== "onlyValue") {
43545
- const targetBorders = this.getters.getCellBorder(target);
43546
- const originBorders = origin.border;
43547
- const border = {
43548
- top: targetBorders?.top || originBorders?.top,
43549
- bottom: targetBorders?.bottom || originBorders?.bottom,
43550
- left: targetBorders?.left || originBorders?.left,
43551
- right: targetBorders?.right || originBorders?.right,
43552
- };
43553
- this.dispatch("SET_BORDER", { sheetId, col, row, border });
43610
+ if (clipboardOption?.pasteOption === "onlyValue") {
43611
+ const locale = this.getters.getLocale();
43612
+ const content = formatValue(origin.evaluatedCell.value, { locale });
43613
+ this.dispatch("UPDATE_CELL", { ...target, content });
43614
+ return;
43554
43615
  }
43555
- if (origin.cell) {
43556
- if (clipboardOption?.pasteOption === "onlyFormat") {
43557
- this.dispatch("UPDATE_CELL", {
43558
- ...target,
43559
- style: origin.cell.style,
43560
- format: origin.evaluatedCell.format,
43561
- });
43562
- return;
43563
- }
43564
- if (clipboardOption?.pasteOption === "onlyValue") {
43565
- const locale = this.getters.getLocale();
43566
- const content = formatValue(origin.evaluatedCell.value, { locale });
43567
- this.dispatch("UPDATE_CELL", { ...target, content });
43568
- return;
43569
- }
43570
- let content = origin.cell.content;
43571
- if (origin.cell.isFormula && operation === "COPY") {
43572
- content = this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula, origin.cell.dependencies);
43573
- }
43616
+ const targetBorders = this.getters.getCellBorder(target);
43617
+ const originBorders = origin.border;
43618
+ const border = {
43619
+ top: targetBorders?.top || originBorders?.top,
43620
+ bottom: targetBorders?.bottom || originBorders?.bottom,
43621
+ left: targetBorders?.left || originBorders?.left,
43622
+ right: targetBorders?.right || originBorders?.right,
43623
+ };
43624
+ this.dispatch("SET_BORDER", { sheetId, col, row, border });
43625
+ if (clipboardOption?.pasteOption === "onlyFormat") {
43626
+ this.dispatch("UPDATE_CELL", {
43627
+ ...target,
43628
+ style: origin.cell?.style ?? null,
43629
+ format: origin.cell?.format ?? origin.evaluatedCell.format ?? targetCell.format,
43630
+ });
43631
+ return;
43632
+ }
43633
+ const content = origin.cell && origin.cell.isFormula && operation === "COPY"
43634
+ ? this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula)
43635
+ : origin.cell?.content;
43636
+ if (content !== "" || origin.cell?.format || origin.cell?.style) {
43574
43637
  this.dispatch("UPDATE_CELL", {
43575
43638
  ...target,
43576
43639
  content,
43577
- style: origin.cell.style || null,
43578
- format: origin.cell.format,
43640
+ style: origin.cell?.style || null,
43641
+ format: origin.cell?.format,
43579
43642
  });
43580
43643
  }
43581
43644
  else if (targetCell) {
43582
- if (clipboardOption?.pasteOption === "onlyValue") {
43583
- this.dispatch("UPDATE_CELL", { ...target, content: "" });
43584
- }
43585
- else if (clipboardOption?.pasteOption === "onlyFormat") {
43586
- this.dispatch("UPDATE_CELL", { ...target, style: null, format: "" });
43587
- }
43588
- else {
43589
- this.dispatch("CLEAR_CELL", target);
43590
- }
43645
+ this.dispatch("CLEAR_CELL", target);
43591
43646
  }
43592
43647
  }
43593
43648
  /**
@@ -43649,22 +43704,28 @@
43649
43704
  return (this.cells
43650
43705
  .map((cells) => {
43651
43706
  return cells
43652
- .map((c) => this.getters.shouldShowFormulas() && c.cell?.isFormula
43707
+ .map((c) => this.getters.shouldShowFormulas() && c?.cell?.isFormula
43653
43708
  ? c.cell?.content || ""
43654
- : c.evaluatedCell?.formattedValue || "")
43709
+ : c?.evaluatedCell?.formattedValue || "")
43655
43710
  .join("\t");
43656
43711
  })
43657
43712
  .join("\n") || "\t");
43658
43713
  }
43659
43714
  getHTMLContent() {
43660
43715
  if (this.cells.length === 1 && this.cells[0].length === 1) {
43716
+ if (!this.cells[0][0]) {
43717
+ return "";
43718
+ }
43661
43719
  return this.getters.getCellText(this.cells[0][0].position);
43662
43720
  }
43663
43721
  let htmlTable = '<table border="1" style="border-collapse:collapse">';
43664
43722
  for (const row of this.cells) {
43665
43723
  htmlTable += "<tr>";
43666
43724
  for (const cell of row) {
43667
- const cssStyle = cssPropertiesToCss(cellStyleToCss(cell.style));
43725
+ if (!cell) {
43726
+ continue;
43727
+ }
43728
+ const cssStyle = cssPropertiesToCss(cellStyleToCss(this.getters.getCellComputedStyle(cell.position)));
43668
43729
  const cellText = this.getters.getCellText(cell.position);
43669
43730
  htmlTable += `<td style="${cssStyle}">` + xmlEscape(cellText) + "</td>";
43670
43731
  }
@@ -44101,20 +44162,29 @@
44101
44162
  const sheetId = this.getters.getActiveSheetId();
44102
44163
  const cells = this.getters.getCells(sheetId);
44103
44164
  const matches = [];
44104
- if (this.toSearch) {
44165
+ if (this.toSearch && this.currentSearchRegex) {
44105
44166
  for (const cell of Object.values(cells)) {
44106
44167
  const { col, row } = this.getters.getCellPosition(cell.id);
44168
+ const cellPosition = { sheetId, col, row };
44107
44169
  const isColHidden = this.getters.isColHidden(sheetId, col);
44108
44170
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
44109
44171
  if (isColHidden || isRowHidden) {
44110
44172
  continue;
44111
44173
  }
44112
- if (cell &&
44113
- this.currentSearchRegex &&
44114
- this.currentSearchRegex.test(this.getSearchableString({ sheetId, col, row }))) {
44174
+ if (this.currentSearchRegex.test(this.getSearchableString(cellPosition))) {
44115
44175
  const match = { col, row, selected: false };
44116
44176
  matches.push(match);
44117
44177
  }
44178
+ for (const spreadPosition of this.getters.getSpreadPositionsOf(cellPosition)) {
44179
+ if (this.currentSearchRegex.test(this.getSearchableString(spreadPosition))) {
44180
+ const match = {
44181
+ col: spreadPosition.col,
44182
+ row: spreadPosition.row,
44183
+ selected: false,
44184
+ };
44185
+ matches.push(match);
44186
+ }
44187
+ }
44118
44188
  }
44119
44189
  }
44120
44190
  return matches.sort(this.sortByRowThenColumn);
@@ -44173,16 +44243,19 @@
44173
44243
  return;
44174
44244
  }
44175
44245
  const sheetId = this.getters.getActiveSheetId();
44176
- const cell = this.getters.getCell({ sheetId, ...selectedMatch });
44177
- const { col, row } = selectedMatch;
44246
+ const position = { sheetId, ...selectedMatch };
44247
+ const cell = this.getters.getCell(position);
44248
+ if (!cell?.content) {
44249
+ return;
44250
+ }
44178
44251
  if (cell?.isFormula && !this.searchOptions.searchFormulas) {
44179
44252
  return;
44180
44253
  }
44181
44254
  const replaceRegex = new RegExp(this.currentSearchRegex.source, this.currentSearchRegex.flags + "g");
44182
- const toReplace = this.getSearchableString({ sheetId, col, row });
44255
+ const toReplace = this.getSearchableString(position);
44183
44256
  const content = toReplace.replace(replaceRegex, replaceWith);
44184
44257
  const canonicalContent = canonicalizeNumberContent(content, this.getters.getLocale());
44185
- this.dispatch("UPDATE_CELL", { sheetId, col, row, content: canonicalContent });
44258
+ this.dispatch("UPDATE_CELL", { ...position, content: canonicalContent });
44186
44259
  }
44187
44260
  /**
44188
44261
  * Replace the value of the currently selected match
@@ -45757,7 +45830,7 @@
45757
45830
  if (cell.isFormula) {
45758
45831
  const position = this.getters.getCellPosition(cell.id);
45759
45832
  // we only have a vertical offset
45760
- content = this.getters.getTranslatedCellFormula(sheetId, 0, newRow - position.row, cell.compiledFormula, cell.dependencies);
45833
+ content = this.getters.getTranslatedCellFormula(sheetId, 0, newRow - position.row, cell.compiledFormula);
45761
45834
  }
45762
45835
  newCellValues.style = cell.style;
45763
45836
  newCellValues.content = content;
@@ -46782,11 +46855,14 @@
46782
46855
  }
46783
46856
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
46784
46857
  this.state.paste(cmd.target, { pasteOption, shouldPasteCF: true, selectTarget: true });
46858
+ if (this.state.operation === "CUT") {
46859
+ this.state = undefined;
46860
+ }
46785
46861
  this.lastPasteState = this.state;
46786
46862
  if (this.paintFormatStatus === "oneOff") {
46787
46863
  this.paintFormatStatus = "inactive";
46788
- this.status = "invisible";
46789
46864
  }
46865
+ this.status = "invisible";
46790
46866
  break;
46791
46867
  case "COPY_PASTE_CELLS_ABOVE":
46792
46868
  {
@@ -47820,6 +47896,8 @@
47820
47896
  case "EVALUATE_CELLS":
47821
47897
  case "ACTIVATE_SHEET":
47822
47898
  case "REMOVE_FILTER_TABLE":
47899
+ case "ADD_COLUMNS_ROWS":
47900
+ case "REMOVE_COLUMNS_ROWS":
47823
47901
  this.isEvaluationDirty = true;
47824
47902
  break;
47825
47903
  case "START":
@@ -55508,19 +55586,22 @@
55508
55586
  * Check if the given command is allowed by all the plugins and the history.
55509
55587
  */
55510
55588
  checkDispatchAllowed(command) {
55511
- if (isCoreCommand(command)) {
55512
- return this.checkDispatchAllowedCoreCommand(command);
55589
+ const results = isCoreCommand(command)
55590
+ ? this.checkDispatchAllowedCoreCommand(command)
55591
+ : this.checkDispatchAllowedLocalCommand(command);
55592
+ if (results.some((r) => r !== "Success" /* CommandResult.Success */)) {
55593
+ return new DispatchResult(results.flat());
55513
55594
  }
55514
- return this.checkDispatchAllowedLocalCommand(command);
55595
+ return DispatchResult.Success;
55515
55596
  }
55516
55597
  checkDispatchAllowedCoreCommand(command) {
55517
55598
  const results = this.corePlugins.map((handler) => handler.allowDispatch(command));
55518
55599
  results.push(this.range.allowDispatch(command));
55519
- return new DispatchResult(results.flat());
55600
+ return results;
55520
55601
  }
55521
55602
  checkDispatchAllowedLocalCommand(command) {
55522
55603
  const results = this.uiHandlers.map((handler) => handler.allowDispatch(command));
55523
- return new DispatchResult(results.flat());
55604
+ return results;
55524
55605
  }
55525
55606
  finalize() {
55526
55607
  this.status = 3 /* Status.Finalizing */;
@@ -55843,6 +55924,7 @@
55843
55924
  exports.addFunction = addFunction;
55844
55925
  exports.astToFormula = astToFormula;
55845
55926
  exports.compile = compile;
55927
+ exports.compileTokens = compileTokens;
55846
55928
  exports.components = components;
55847
55929
  exports.constants = constants;
55848
55930
  exports.convertAstNodes = convertAstNodes;
@@ -55858,6 +55940,7 @@
55858
55940
  exports.links = links;
55859
55941
  exports.load = load;
55860
55942
  exports.parse = parse;
55943
+ exports.parseTokens = parseTokens;
55861
55944
  exports.readonlyAllowedCommands = readonlyAllowedCommands;
55862
55945
  exports.registries = registries;
55863
55946
  exports.setDefaultSheetViewSize = setDefaultSheetViewSize;
@@ -55865,9 +55948,9 @@
55865
55948
  exports.tokenize = tokenize;
55866
55949
 
55867
55950
 
55868
- __info__.version = "17.0.2";
55869
- __info__.date = "2023-11-03T12:22:44.945Z";
55870
- __info__.hash = "3184728";
55951
+ __info__.version = "17.0.4";
55952
+ __info__.date = "2023-11-24T13:13:42.575Z";
55953
+ __info__.hash = "7346d0a";
55871
55954
 
55872
55955
 
55873
55956
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);