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