@odoo/o-spreadsheet 17.1.0-alpha.1 → 17.1.0-alpha.3

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.1.0-alpha.1
6
- * @date 2023-11-02T09:35:10.532Z
7
- * @hash 3b1fe3b
5
+ * @version 17.1.0-alpha.3
6
+ * @date 2023-11-16T12:04:09.636Z
7
+ * @hash 2ef5b1a
8
8
  */
9
9
 
10
10
  'use strict';
@@ -5968,7 +5968,7 @@ autofillModifiersRegistry
5968
5968
  return { cellData: {} };
5969
5969
  }
5970
5970
  const sheetId = data.sheetId;
5971
- const content = getters.getTranslatedCellFormula(sheetId, x, y, cell.compiledFormula, cell.dependencies);
5971
+ const content = getters.getTranslatedCellFormula(sheetId, x, y, cell.compiledFormula);
5972
5972
  return {
5973
5973
  cellData: {
5974
5974
  border: data.border,
@@ -10720,6 +10720,17 @@ const SELECTION_CONTAINS_FILTER = (env) => {
10720
10720
  const IS_ONLY_ONE_RANGE = (env) => {
10721
10721
  return env.model.getters.getSelectedZones().length === 1;
10722
10722
  };
10723
+ const CAN_INSERT_HEADER = (env, dimension) => {
10724
+ if (!IS_ONLY_ONE_RANGE(env)) {
10725
+ return false;
10726
+ }
10727
+ const activeHeaders = dimension === "COL" ? env.model.getters.getActiveCols() : env.model.getters.getActiveRows();
10728
+ const ortogonalActiveHeaders = dimension === "COL" ? env.model.getters.getActiveRows() : env.model.getters.getActiveCols();
10729
+ const sheetId = env.model.getters.getActiveSheetId();
10730
+ const zone = env.model.getters.getSelectedZone();
10731
+ const allSheetSelected = isEqual(zone, env.model.getters.getSheetZone(sheetId));
10732
+ return isConsecutive(activeHeaders) && (ortogonalActiveHeaders.size === 0 || allSheetSelected);
10733
+ };
10723
10734
 
10724
10735
  const undo = {
10725
10736
  name: _t("Undo"),
@@ -19397,9 +19408,7 @@ const insertRow = {
19397
19408
  const number = getRowsNumber(env);
19398
19409
  return number === 1 ? _t("Insert row") : _t("Insert %s rows", number.toString());
19399
19410
  },
19400
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19401
- IS_ONLY_ONE_RANGE(env) &&
19402
- env.model.getters.getActiveCols().size === 0,
19411
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19403
19412
  icon: "o-spreadsheet-Icon.INSERT_ROW",
19404
19413
  };
19405
19414
  const rowInsertRowBefore = {
@@ -19408,9 +19417,7 @@ const rowInsertRowBefore = {
19408
19417
  return number === 1 ? _t("Insert row above") : _t("Insert %s rows above", number.toString());
19409
19418
  },
19410
19419
  execute: INSERT_ROWS_BEFORE_ACTION,
19411
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19412
- IS_ONLY_ONE_RANGE(env) &&
19413
- env.model.getters.getActiveCols().size === 0,
19420
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19414
19421
  icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
19415
19422
  };
19416
19423
  const topBarInsertRowsBefore = {
@@ -19441,9 +19448,7 @@ const rowInsertRowsAfter = {
19441
19448
  const number = getRowsNumber(env);
19442
19449
  return number === 1 ? _t("Insert row below") : _t("Insert %s rows below", number.toString());
19443
19450
  },
19444
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19445
- IS_ONLY_ONE_RANGE(env) &&
19446
- env.model.getters.getActiveCols().size === 0,
19451
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19447
19452
  icon: "o-spreadsheet-Icon.INSERT_ROW_AFTER",
19448
19453
  };
19449
19454
  const topBarInsertRowsAfter = {
@@ -19461,9 +19466,7 @@ const insertCol = {
19461
19466
  const number = getColumnsNumber(env);
19462
19467
  return number === 1 ? _t("Insert column") : _t("Insert %s columns", number.toString());
19463
19468
  },
19464
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19465
- IS_ONLY_ONE_RANGE(env) &&
19466
- env.model.getters.getActiveRows().size === 0,
19469
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19467
19470
  icon: "o-spreadsheet-Icon.INSERT_COL",
19468
19471
  };
19469
19472
  const colInsertColsBefore = {
@@ -19474,9 +19477,7 @@ const colInsertColsBefore = {
19474
19477
  : _t("Insert %s columns left", number.toString());
19475
19478
  },
19476
19479
  execute: INSERT_COLUMNS_BEFORE_ACTION,
19477
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19478
- IS_ONLY_ONE_RANGE(env) &&
19479
- env.model.getters.getActiveRows().size === 0,
19480
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19480
19481
  icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
19481
19482
  };
19482
19483
  const topBarInsertColsBefore = {
@@ -19509,9 +19510,7 @@ const colInsertColsAfter = {
19509
19510
  : _t("Insert %s columns right", number.toString());
19510
19511
  },
19511
19512
  execute: INSERT_COLUMNS_AFTER_ACTION,
19512
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19513
- IS_ONLY_ONE_RANGE(env) &&
19514
- env.model.getters.getActiveRows().size === 0,
19513
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19515
19514
  icon: "o-spreadsheet-Icon.INSERT_COL_AFTER",
19516
19515
  };
19517
19516
  const topBarInsertColsAfter = {
@@ -23852,7 +23851,7 @@ css /* scss */ `
23852
23851
  }
23853
23852
  .o-input-count {
23854
23853
  width: fit-content;
23855
- padding: 4 0 4 4;
23854
+ padding: 4px 0 4px 4px;
23856
23855
  }
23857
23856
  }
23858
23857
  }
@@ -34968,6 +34967,9 @@ const functionCache = {};
34968
34967
  // -----------------------------------------------------------------------------
34969
34968
  function compile(formula) {
34970
34969
  const tokens = rangeTokenize(formula);
34970
+ return compileTokens(tokens);
34971
+ }
34972
+ function compileTokens(tokens) {
34971
34973
  const { dependencies, constantValues } = formulaArguments(tokens);
34972
34974
  const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
34973
34975
  if (!functionCache[cacheKey]) {
@@ -35334,11 +35336,11 @@ class CellPlugin extends CorePlugin {
35334
35336
  for (const sheet of Object.keys(this.cells)) {
35335
35337
  for (const cell of Object.values(this.cells[sheet] || {})) {
35336
35338
  if (cell.isFormula) {
35337
- for (const range of cell.dependencies) {
35339
+ for (const range of cell.compiledFormula.dependencies) {
35338
35340
  if (!sheetId || range.sheetId === sheetId) {
35339
35341
  const change = applyChange(range);
35340
35342
  if (change.changeType !== "NONE") {
35341
- this.history.update("cells", sheet, cell.id, "dependencies", cell.dependencies.indexOf(range), change.range);
35343
+ this.history.update("cells", sheet, cell.id, "compiledFormula", "dependencies", cell.compiledFormula.dependencies.indexOf(range), change.range);
35342
35344
  }
35343
35345
  }
35344
35346
  }
@@ -35534,10 +35536,10 @@ class CellPlugin extends CorePlugin {
35534
35536
  /*
35535
35537
  * Reconstructs the original formula string based on a normalized form and its dependencies
35536
35538
  */
35537
- getFormulaCellContent(sheetId, cell, dependencies) {
35538
- const ranges = dependencies || cell.dependencies;
35539
+ getFormulaCellContent(sheetId, compiledFormula, dependencies) {
35540
+ const ranges = dependencies || compiledFormula.dependencies;
35539
35541
  let rangeIndex = 0;
35540
- return concat(cell.compiledFormula.tokens.map((token) => {
35542
+ return concat(compiledFormula.tokens.map((token) => {
35541
35543
  if (token.type === "REFERENCE") {
35542
35544
  const range = ranges[rangeIndex++];
35543
35545
  return this.getters.getRangeString(range, sheetId);
@@ -35548,12 +35550,9 @@ class CellPlugin extends CorePlugin {
35548
35550
  /*
35549
35551
  * Constructs a formula string based on an initial formula and a translation vector
35550
35552
  */
35551
- getTranslatedCellFormula(sheetId, offsetX, offsetY, compiledFormula, dependencies) {
35552
- const adaptedDependencies = this.getters.createAdaptedRanges(dependencies, offsetX, offsetY, sheetId);
35553
- return this.getFormulaCellContent(sheetId, {
35554
- compiledFormula,
35555
- dependencies: adaptedDependencies,
35556
- });
35553
+ getTranslatedCellFormula(sheetId, offsetX, offsetY, compiledFormula) {
35554
+ const adaptedDependencies = this.getters.createAdaptedRanges(compiledFormula.dependencies, offsetX, offsetY, sheetId);
35555
+ return this.getFormulaCellContent(sheetId, compiledFormula, adaptedDependencies);
35557
35556
  }
35558
35557
  getCellStyle(position) {
35559
35558
  return this.getters.getCell(position)?.style || {};
@@ -35733,8 +35732,10 @@ class CellPlugin extends CorePlugin {
35733
35732
  style,
35734
35733
  format,
35735
35734
  isFormula: true,
35736
- compiledFormula,
35737
- dependencies: [],
35735
+ compiledFormula: {
35736
+ ...compiledFormula,
35737
+ dependencies: [],
35738
+ },
35738
35739
  };
35739
35740
  }
35740
35741
  /**
@@ -35743,7 +35744,7 @@ class CellPlugin extends CorePlugin {
35743
35744
  */
35744
35745
  createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
35745
35746
  const dependencies = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
35746
- return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getFormulaCellContent.bind(this));
35747
+ return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString.bind(this));
35747
35748
  }
35748
35749
  createErrorFormula(id, content, format, style, error) {
35749
35750
  return {
@@ -35753,13 +35754,12 @@ class CellPlugin extends CorePlugin {
35753
35754
  format,
35754
35755
  isFormula: true,
35755
35756
  compiledFormula: {
35756
- dependencies: [],
35757
35757
  tokens: tokenize(content),
35758
+ dependencies: [],
35758
35759
  execute: function () {
35759
35760
  throw error;
35760
35761
  },
35761
35762
  },
35762
- dependencies: [],
35763
35763
  };
35764
35764
  }
35765
35765
  checkCellOutOfSheet(sheetId, col, row) {
@@ -35772,27 +35772,44 @@ class CellPlugin extends CorePlugin {
35772
35772
  }
35773
35773
  class FormulaCellWithDependencies {
35774
35774
  id;
35775
- compiledFormula;
35776
35775
  format;
35777
35776
  style;
35778
- dependencies;
35779
35777
  sheetId;
35780
- getFormulaCellContent;
35778
+ getRangeString;
35781
35779
  isFormula = true;
35782
- constructor(id, compiledFormula, format, style, dependencies, sheetId, getFormulaCellContent) {
35780
+ compiledFormula;
35781
+ constructor(id, compiledFormula, format, style, dependencies, sheetId, getRangeString) {
35783
35782
  this.id = id;
35784
- this.compiledFormula = compiledFormula;
35785
35783
  this.format = format;
35786
35784
  this.style = style;
35787
- this.dependencies = dependencies;
35788
35785
  this.sheetId = sheetId;
35789
- this.getFormulaCellContent = getFormulaCellContent;
35786
+ this.getRangeString = getRangeString;
35787
+ let rangeIndex = 0;
35788
+ const tokens = compiledFormula.tokens.map((token) => {
35789
+ if (token.type === "REFERENCE") {
35790
+ const index = rangeIndex++;
35791
+ return new RangeReferenceToken(() => this.getRangeString(dependencies[index], this.sheetId));
35792
+ }
35793
+ return token;
35794
+ });
35795
+ this.compiledFormula = {
35796
+ ...compiledFormula,
35797
+ dependencies,
35798
+ tokens,
35799
+ };
35790
35800
  }
35791
35801
  get content() {
35792
- return this.getFormulaCellContent(this.sheetId, {
35793
- dependencies: this.dependencies,
35794
- compiledFormula: this.compiledFormula,
35795
- });
35802
+ return concat(this.compiledFormula.tokens.map((token) => token.value));
35803
+ }
35804
+ }
35805
+ class RangeReferenceToken {
35806
+ getValue;
35807
+ type = "REFERENCE";
35808
+ constructor(getValue) {
35809
+ this.getValue = getValue;
35810
+ }
35811
+ get value() {
35812
+ return this.getValue();
35796
35813
  }
35797
35814
  }
35798
35815
 
@@ -36937,6 +36954,13 @@ class FiltersPlugin extends CorePlugin {
36937
36954
  }
36938
36955
  onDeleteColumnsRows(cmd) {
36939
36956
  for (const table of this.getFilterTables(cmd.sheetId)) {
36957
+ // Remove the filter tables whose data filter headers are in the removed rows.
36958
+ if (cmd.dimension === "ROW" && cmd.elements.includes(table.zone.top)) {
36959
+ const tables = { ...this.tables[cmd.sheetId] };
36960
+ delete tables[table.id];
36961
+ this.history.update("tables", cmd.sheetId, tables);
36962
+ continue;
36963
+ }
36940
36964
  const zone = reduceZoneOnDeletion(table.zone, cmd.dimension === "COL" ? "left" : "top", cmd.elements);
36941
36965
  if (!zone) {
36942
36966
  const tables = { ...this.tables[cmd.sheetId] };
@@ -39985,6 +40009,13 @@ class Evaluator {
39985
40009
  return (this.evaluatedCells.get(this.encodePosition(position)) ||
39986
40010
  createEvaluatedCell("", { locale: this.getters.getLocale() }));
39987
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
+ }
39988
40019
  getArrayFormulaSpreadingOn(position) {
39989
40020
  const positionId = this.encodePosition(position);
39990
40021
  const formulaPosition = this.getArrayFormulaSpreadingOnId(positionId);
@@ -40089,9 +40120,6 @@ class Evaluator {
40089
40120
  }
40090
40121
  }
40091
40122
  setEvaluatedCell(positionId, evaluatedCell) {
40092
- if (this.nextPositionsToUpdate.has(positionId)) {
40093
- this.nextPositionsToUpdate.delete(positionId);
40094
- }
40095
40123
  this.evaluatedCells.set(positionId, evaluatedCell);
40096
40124
  }
40097
40125
  computeCell(positionId) {
@@ -40146,7 +40174,7 @@ class Evaluator {
40146
40174
  const position = this.compilationParams[2].getters.getCellPosition(cellId);
40147
40175
  return toXC(position.col, position.row);
40148
40176
  };
40149
- const formulaReturn = cellData.compiledFormula.execute(cellData.dependencies, ...this.compilationParams);
40177
+ const formulaReturn = cellData.compiledFormula.execute(cellData.compiledFormula.dependencies, ...this.compilationParams);
40150
40178
  if (!isMatrix(formulaReturn)) {
40151
40179
  return createEvaluatedCell(formulaReturn.value, {
40152
40180
  format: cellData.format || formulaReturn.format,
@@ -40246,7 +40274,7 @@ class Evaluator {
40246
40274
  return [];
40247
40275
  }
40248
40276
  const dependencies = [];
40249
- for (const range of cell.dependencies) {
40277
+ for (const range of cell.compiledFormula.dependencies) {
40250
40278
  if (range.invalidSheetName || range.invalidXc) {
40251
40279
  continue;
40252
40280
  }
@@ -40452,6 +40480,7 @@ class EvaluationPlugin extends UIPlugin {
40452
40480
  "getEvaluatedCell",
40453
40481
  "getEvaluatedCells",
40454
40482
  "getEvaluatedCellsInZone",
40483
+ "getSpreadPositionsOf",
40455
40484
  ];
40456
40485
  shouldRebuildDependenciesGraph = true;
40457
40486
  evaluator;
@@ -40561,6 +40590,9 @@ class EvaluationPlugin extends UIPlugin {
40561
40590
  getEvaluatedCellsInZone(sheetId, zone) {
40562
40591
  return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
40563
40592
  }
40593
+ getSpreadPositionsOf(position) {
40594
+ return this.evaluator.getSpreadPositionsOf(position);
40595
+ }
40564
40596
  // ---------------------------------------------------------------------------
40565
40597
  // Export
40566
40598
  // ---------------------------------------------------------------------------
@@ -40598,10 +40630,10 @@ class EvaluationPlugin extends UIPlugin {
40598
40630
  */
40599
40631
  getCorrespondingFormulaCell(position) {
40600
40632
  const cell = this.getters.getCell(position);
40601
- if (cell && cell.content) {
40602
- if (cell.isFormula && !isBadExpression(cell.content)) {
40603
- return cell;
40604
- }
40633
+ if (cell && cell.isFormula) {
40634
+ return isBadExpression(cell.compiledFormula.tokens) ? undefined : cell;
40635
+ }
40636
+ else if (cell && cell.content) {
40605
40637
  return undefined;
40606
40638
  }
40607
40639
  const spreadingFormulaPosition = this.evaluator.getArrayFormulaSpreadingOn(position);
@@ -40618,9 +40650,9 @@ class EvaluationPlugin extends UIPlugin {
40618
40650
  return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
40619
40651
  }
40620
40652
  }
40621
- function isBadExpression(formula) {
40653
+ function isBadExpression(tokens) {
40622
40654
  try {
40623
- compile(formula);
40655
+ compileTokens(tokens);
40624
40656
  return false;
40625
40657
  }
40626
40658
  catch (error) {
@@ -40789,22 +40821,20 @@ class EvaluationChartPlugin extends UIPlugin {
40789
40821
  invalidateCFEvaluationCommands.has(cmd.type) ||
40790
40822
  cmd.type === "EVALUATE_CELLS" ||
40791
40823
  cmd.type === "UPDATE_CELL") {
40792
- if (cmd.type !== "UNDO" && cmd.type !== "REDO") {
40793
- for (const chartId in this.charts) {
40794
- this.history.update("charts", chartId, undefined);
40795
- }
40824
+ for (const chartId in this.charts) {
40825
+ this.charts[chartId] = undefined;
40796
40826
  }
40797
40827
  }
40798
40828
  switch (cmd.type) {
40799
40829
  case "UPDATE_CHART":
40800
40830
  case "CREATE_CHART":
40801
40831
  case "DELETE_FIGURE":
40802
- this.history.update("charts", cmd.id, undefined);
40832
+ this.charts[cmd.id] = undefined;
40803
40833
  break;
40804
40834
  case "DELETE_SHEET":
40805
40835
  for (let chartId in this.charts) {
40806
40836
  if (!this.getters.isChartDefined(chartId)) {
40807
- this.history.update("charts", chartId, undefined);
40837
+ this.charts[chartId] = undefined;
40808
40838
  }
40809
40839
  }
40810
40840
  break;
@@ -40816,8 +40846,7 @@ class EvaluationChartPlugin extends UIPlugin {
40816
40846
  if (!chart) {
40817
40847
  throw new Error(`No chart for the given id: ${figureId}`);
40818
40848
  }
40819
- const runtime = this.createRuntimeChart(chart);
40820
- this.history.update("charts", figureId, runtime);
40849
+ this.charts[figureId] = this.createRuntimeChart(chart);
40821
40850
  }
40822
40851
  return this.charts[figureId];
40823
40852
  }
@@ -40969,7 +40998,10 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
40969
40998
  const values = cf.rule.values.map((value, i) => {
40970
40999
  const compiledFormula = formulas[i];
40971
41000
  if (compiledFormula) {
40972
- return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, compiledFormula, compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)));
41001
+ return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, {
41002
+ ...compiledFormula,
41003
+ dependencies: compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
41004
+ });
40973
41005
  }
40974
41006
  return value;
40975
41007
  });
@@ -41341,7 +41373,10 @@ class EvaluationDataValidationPlugin extends UIPlugin {
41341
41373
  }
41342
41374
  try {
41343
41375
  const formula = compile(value);
41344
- const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, formula, formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)));
41376
+ const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, {
41377
+ ...formula,
41378
+ dependencies: formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
41379
+ });
41345
41380
  const evaluated = this.getters.evaluateFormula(sheetId, translatedFormula);
41346
41381
  return evaluated && !isMatrix(evaluated) ? evaluated.toString() : "";
41347
41382
  }
@@ -43595,7 +43630,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
43595
43630
  }
43596
43631
  let content = origin.cell.content;
43597
43632
  if (origin.cell.isFormula && operation === "COPY") {
43598
- content = this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula, origin.cell.dependencies);
43633
+ content = this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula);
43599
43634
  }
43600
43635
  this.dispatch("UPDATE_CELL", {
43601
43636
  ...target,
@@ -44127,20 +44162,29 @@ class FindAndReplacePlugin extends UIPlugin {
44127
44162
  const sheetId = this.getters.getActiveSheetId();
44128
44163
  const cells = this.getters.getCells(sheetId);
44129
44164
  const matches = [];
44130
- if (this.toSearch) {
44165
+ if (this.toSearch && this.currentSearchRegex) {
44131
44166
  for (const cell of Object.values(cells)) {
44132
44167
  const { col, row } = this.getters.getCellPosition(cell.id);
44168
+ const cellPosition = { sheetId, col, row };
44133
44169
  const isColHidden = this.getters.isColHidden(sheetId, col);
44134
44170
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
44135
44171
  if (isColHidden || isRowHidden) {
44136
44172
  continue;
44137
44173
  }
44138
- if (cell &&
44139
- this.currentSearchRegex &&
44140
- this.currentSearchRegex.test(this.getSearchableString({ sheetId, col, row }))) {
44174
+ if (this.currentSearchRegex.test(this.getSearchableString(cellPosition))) {
44141
44175
  const match = { col, row, selected: false };
44142
44176
  matches.push(match);
44143
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
+ }
44144
44188
  }
44145
44189
  }
44146
44190
  return matches.sort(this.sortByRowThenColumn);
@@ -44201,16 +44245,19 @@ class FindAndReplacePlugin extends UIPlugin {
44201
44245
  return;
44202
44246
  }
44203
44247
  const sheetId = this.getters.getActiveSheetId();
44204
- const cell = this.getters.getCell({ sheetId, ...selectedMatch });
44205
- const { col, row } = selectedMatch;
44248
+ const position = { sheetId, ...selectedMatch };
44249
+ const cell = this.getters.getCell(position);
44250
+ if (!cell?.content) {
44251
+ return;
44252
+ }
44206
44253
  if (cell?.isFormula && !this.searchOptions.searchFormulas) {
44207
44254
  return;
44208
44255
  }
44209
44256
  const replaceRegex = new RegExp(this.currentSearchRegex.source, this.currentSearchRegex.flags + "g");
44210
- const toReplace = this.getSearchableString({ sheetId, col, row });
44257
+ const toReplace = this.getSearchableString(position);
44211
44258
  const content = toReplace.replace(replaceRegex, replaceWith);
44212
44259
  const canonicalContent = canonicalizeNumberContent(content, this.getters.getLocale());
44213
- this.dispatch("UPDATE_CELL", { sheetId, col, row, content: canonicalContent });
44260
+ this.dispatch("UPDATE_CELL", { ...position, content: canonicalContent });
44214
44261
  }
44215
44262
  /**
44216
44263
  * Replace the value of the currently selected match
@@ -45539,7 +45586,6 @@ class SelectionInputsManagerPlugin extends UIPlugin {
45539
45586
  }
45540
45587
 
45541
45588
  class SortPlugin extends UIPlugin {
45542
- static getters = ["getContiguousZone"];
45543
45589
  allowDispatch(cmd) {
45544
45590
  switch (cmd.type) {
45545
45591
  case "SORT_CELLS":
@@ -45587,143 +45633,6 @@ class SortPlugin extends UIPlugin {
45587
45633
  }
45588
45634
  return "Success" /* CommandResult.Success */;
45589
45635
  }
45590
- // getContiguousZone helpers
45591
- /**
45592
- * safe-version of expandZone to make sure we don't get out of the grid
45593
- */
45594
- expand(sheetId, z) {
45595
- const { left, right, top, bottom } = this.getters.expandZone(sheetId, z);
45596
- return {
45597
- left: Math.max(0, left),
45598
- right: Math.min(this.getters.getNumberCols(sheetId) - 1, right),
45599
- top: Math.max(0, top),
45600
- bottom: Math.min(this.getters.getNumberRows(sheetId) - 1, bottom),
45601
- };
45602
- }
45603
- /**
45604
- * verifies the presence of at least one non-empty cell in the given zone
45605
- */
45606
- checkExpandedValues(sheetId, z) {
45607
- const expandedZone = this.expand(sheetId, z);
45608
- let cell;
45609
- if (this.getters.doesIntersectMerge(sheetId, expandedZone)) {
45610
- const { left, right, top, bottom } = expandedZone;
45611
- for (let c = left; c <= right; c++) {
45612
- for (let r = top; r <= bottom; r++) {
45613
- const { col, row } = this.getters.getMainCellPosition({ sheetId, col: c, row: r });
45614
- cell = this.getters.getEvaluatedCell({ sheetId, col, row });
45615
- if (cell.formattedValue) {
45616
- return true;
45617
- }
45618
- }
45619
- }
45620
- }
45621
- else {
45622
- for (let cell of this.getters.getEvaluatedCellsInZone(sheetId, expandedZone)) {
45623
- if (cell.formattedValue) {
45624
- return true;
45625
- }
45626
- }
45627
- }
45628
- return false;
45629
- }
45630
- /**
45631
- * This function will expand the provided zone in directions (top, bottom, left, right) for which there
45632
- * are non-null cells on the external boundary of the zone in the given direction.
45633
- *
45634
- * Example:
45635
- * A B C D E
45636
- * ___ ___ ___ ___ ___
45637
- * 1 | | D | | | |
45638
- * ___ ___ ___ ___ ___
45639
- * 2 | 5 | | 1 | D | |
45640
- * ___ ___ ___ ___ ___
45641
- * 3 | | | A | X | |
45642
- * ___ ___ ___ ___ ___
45643
- * 4 | | | | | |
45644
- * ___ ___ ___ ___ ___
45645
- *
45646
- * Let's consider a provided zone corresponding to (C2:D3) - (left:2, right: 3, top:1, bottom:2)
45647
- * - the top external boundary is (B1:E1)
45648
- * Since we have B1='D' != "", we expand to the top: => (C1:D3)
45649
- * The top boundary having reached the top of the grid, we cannot expand in that direction anymore
45650
- *
45651
- * - the left boundary is (B1:B4)
45652
- * since we have B1 again, we expand to the left => (B1:D3)
45653
- *
45654
- * - the right and bottom boundaries are a dead end for now as (E1:E4) and (A4:E4) are empty.
45655
- *
45656
- * - the left boundary is now (A1:A4)
45657
- * Since we have A2=5 != "", we can therefore expand to the left => (A1:D3)
45658
- *
45659
- * This will be the final zone as left and top have reached the boundaries of the grid and
45660
- * the other boundaries (E1:E4) and (A4:E4) are empty.
45661
- *
45662
- * @param sheetId UID of concerned sheet
45663
- * @param zone Zone
45664
- *
45665
- */
45666
- getContiguousZone(sheetId, zone) {
45667
- let { top, bottom, left, right } = zone;
45668
- let canExpand;
45669
- let stop = false;
45670
- while (!stop) {
45671
- stop = true;
45672
- /** top row external boundary */
45673
- if (top > 0) {
45674
- canExpand = this.checkExpandedValues(sheetId, {
45675
- left: left - 1,
45676
- right: right + 1,
45677
- top: top - 1,
45678
- bottom: top - 1,
45679
- });
45680
- if (canExpand) {
45681
- stop = false;
45682
- top--;
45683
- }
45684
- }
45685
- /** left column external boundary */
45686
- if (left > 0) {
45687
- canExpand = this.checkExpandedValues(sheetId, {
45688
- left: left - 1,
45689
- right: left - 1,
45690
- top: top - 1,
45691
- bottom: bottom + 1,
45692
- });
45693
- if (canExpand) {
45694
- stop = false;
45695
- left--;
45696
- }
45697
- }
45698
- /** right column external boundary */
45699
- if (right < this.getters.getNumberCols(sheetId) - 1) {
45700
- canExpand = this.checkExpandedValues(sheetId, {
45701
- left: right + 1,
45702
- right: right + 1,
45703
- top: top - 1,
45704
- bottom: bottom + 1,
45705
- });
45706
- if (canExpand) {
45707
- stop = false;
45708
- right++;
45709
- }
45710
- }
45711
- /** bottom row external boundary */
45712
- if (bottom < this.getters.getNumberRows(sheetId) - 1) {
45713
- canExpand = this.checkExpandedValues(sheetId, {
45714
- left: left - 1,
45715
- right: right + 1,
45716
- top: bottom + 1,
45717
- bottom: bottom + 1,
45718
- });
45719
- if (canExpand) {
45720
- stop = false;
45721
- bottom++;
45722
- }
45723
- }
45724
- }
45725
- return { left, right, top, bottom };
45726
- }
45727
45636
  /**
45728
45637
  * This function evaluates if the top row of a provided zone can be considered as a `header`
45729
45638
  * by checking the following criteria:
@@ -45788,7 +45697,7 @@ class SortPlugin extends UIPlugin {
45788
45697
  if (cell.isFormula) {
45789
45698
  const position = this.getters.getCellPosition(cell.id);
45790
45699
  // we only have a vertical offset
45791
- content = this.getters.getTranslatedCellFormula(sheetId, 0, newRow - position.row, cell.compiledFormula, cell.dependencies);
45700
+ content = this.getters.getTranslatedCellFormula(sheetId, 0, newRow - position.row, cell.compiledFormula);
45792
45701
  }
45793
45702
  newCellValues.style = cell.style;
45794
45703
  newCellValues.content = content;
@@ -45857,6 +45766,8 @@ class SheetUIPlugin extends UIPlugin {
45857
45766
  "getTextWidth",
45858
45767
  "getCellText",
45859
45768
  "getCellMultiLineText",
45769
+ "getContiguousZone",
45770
+ "isCellEmpty",
45860
45771
  ];
45861
45772
  ctx = document.createElement("canvas").getContext("2d");
45862
45773
  // ---------------------------------------------------------------------------
@@ -45946,9 +45857,52 @@ class SheetUIPlugin extends UIPlugin {
45946
45857
  const hasListIcon = !this.getters.isReadonly() && this.getters.cellHasListDataValidationIcon(position);
45947
45858
  return isFilterHeader || hasListIcon;
45948
45859
  }
45949
- // ---------------------------------------------------------------------------
45950
- // Grid manipulation
45951
- // ---------------------------------------------------------------------------
45860
+ /**
45861
+ * Expands the given zone until bordered by empty cells or reached the sheet boundaries.
45862
+ */
45863
+ getContiguousZone(sheetId, zoneToExpand) {
45864
+ /** Try to expand the zone by one col/row in any direction to include a new non-empty cell */
45865
+ const expandZone = (zone) => {
45866
+ for (const col of range(zone.left, zone.right + 1)) {
45867
+ if (!this.isCellEmpty({ sheetId, col, row: zone.top - 1 })) {
45868
+ return { ...zone, top: zone.top - 1 };
45869
+ }
45870
+ if (!this.isCellEmpty({ sheetId, col, row: zone.bottom + 1 })) {
45871
+ return { ...zone, bottom: zone.bottom + 1 };
45872
+ }
45873
+ }
45874
+ for (const row of range(zone.top, zone.bottom + 1)) {
45875
+ if (!this.isCellEmpty({ sheetId, col: zone.left - 1, row })) {
45876
+ return { ...zone, left: zone.left - 1 };
45877
+ }
45878
+ if (!this.isCellEmpty({ sheetId, col: zone.right + 1, row })) {
45879
+ return { ...zone, right: zone.right + 1 };
45880
+ }
45881
+ }
45882
+ return zone;
45883
+ };
45884
+ let hasExpanded = false;
45885
+ let zone = zoneToExpand;
45886
+ do {
45887
+ hasExpanded = false;
45888
+ const newZone = expandZone(zone);
45889
+ if (!isEqual(zone, newZone)) {
45890
+ hasExpanded = true;
45891
+ zone = newZone;
45892
+ continue;
45893
+ }
45894
+ } while (hasExpanded);
45895
+ return zone;
45896
+ }
45897
+ /**
45898
+ * Check if a cell is empty. If the cell is part of a merge,
45899
+ * check if the merge containing the cell is empty.
45900
+ */
45901
+ isCellEmpty(position) {
45902
+ const mainPosition = this.getters.getMainCellPosition(position);
45903
+ const cell = this.getters.getEvaluatedCell(mainPosition);
45904
+ return cell.type === CellValueType.empty;
45905
+ }
45952
45906
  getColMaxWidth(sheetId, index) {
45953
45907
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
45954
45908
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
@@ -47853,6 +47807,8 @@ class FilterEvaluationPlugin extends UIPlugin {
47853
47807
  case "EVALUATE_CELLS":
47854
47808
  case "ACTIVATE_SHEET":
47855
47809
  case "REMOVE_FILTER_TABLE":
47810
+ case "ADD_COLUMNS_ROWS":
47811
+ case "REMOVE_COLUMNS_ROWS":
47856
47812
  this.isEvaluationDirty = true;
47857
47813
  break;
47858
47814
  case "START":
@@ -53371,7 +53327,7 @@ class SelectionStreamProcessorImpl {
53371
53327
  scrollIntoView: false,
53372
53328
  });
53373
53329
  }
53374
- const tableZone = this.expandZoneToTable(anchor.zone);
53330
+ const tableZone = this.getters.getContiguousZone(sheetId, anchor.zone);
53375
53331
  return !deepEquals(tableZone, anchor.zone)
53376
53332
  ? this.modifyAnchor({ ...anchor, zone: tableZone }, "updateAnchor", {
53377
53333
  scrollIntoView: false,
@@ -53384,7 +53340,8 @@ class SelectionStreamProcessorImpl {
53384
53340
  * cells bordering it
53385
53341
  */
53386
53342
  selectTableAroundSelection() {
53387
- const tableZone = this.expandZoneToTable(this.anchor.zone);
53343
+ const sheetId = this.getters.getActiveSheetId();
53344
+ const tableZone = this.getters.getContiguousZone(sheetId, this.anchor.zone);
53388
53345
  return this.modifyAnchor({ ...this.anchor, zone: tableZone }, "updateAnchor", {
53389
53346
  scrollIntoView: false,
53390
53347
  });
@@ -53561,11 +53518,12 @@ class SelectionStreamProcessorImpl {
53561
53518
  * next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
53562
53519
  */
53563
53520
  getEndOfCluster(startPosition, dim, dir) {
53564
- const sheet = this.getters.getActiveSheet();
53521
+ const sheetId = this.getters.getActiveSheetId();
53565
53522
  let currentPosition = startPosition;
53566
53523
  // If both the current cell and the next cell are not empty, we want to go to the end of the cluster
53567
53524
  const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
53568
- let mode = !this.isCellEmpty(currentPosition, sheet.id) && !this.isCellEmpty(nextCellPosition, sheet.id)
53525
+ let mode = !this.getters.isCellEmpty({ ...currentPosition, sheetId }) &&
53526
+ !this.getters.isCellEmpty({ ...nextCellPosition, sheetId })
53569
53527
  ? "endOfCluster"
53570
53528
  : "nextCluster";
53571
53529
  while (true) {
@@ -53575,7 +53533,7 @@ class SelectionStreamProcessorImpl {
53575
53533
  currentPosition.row === nextCellPosition.row) {
53576
53534
  break;
53577
53535
  }
53578
- const isNextCellEmpty = this.isCellEmpty(nextCellPosition, sheet.id);
53536
+ const isNextCellEmpty = this.getters.isCellEmpty({ ...nextCellPosition, sheetId });
53579
53537
  if (mode === "endOfCluster" && isNextCellEmpty) {
53580
53538
  break;
53581
53539
  }
@@ -53588,15 +53546,6 @@ class SelectionStreamProcessorImpl {
53588
53546
  }
53589
53547
  return dim === "cols" ? currentPosition.col : currentPosition.row;
53590
53548
  }
53591
- /**
53592
- * Check if a cell is empty or undefined in the model. If the cell is part of a merge,
53593
- * check if the merge containing the cell is empty.
53594
- */
53595
- isCellEmpty({ col, row }, sheetId = this.getters.getActiveSheetId()) {
53596
- const position = this.getters.getMainCellPosition({ sheetId, col, row });
53597
- const cell = this.getters.getEvaluatedCell(position);
53598
- return cell.type === CellValueType.empty;
53599
- }
53600
53549
  /** Computes the next cell position in the given direction by crossing through merges and skipping hidden cells.
53601
53550
  *
53602
53551
  * This has the same behaviour as getNextAvailablePosition() for certain arguments, but use this method instead
@@ -53615,45 +53564,6 @@ class SelectionStreamProcessorImpl {
53615
53564
  getPosition() {
53616
53565
  return { ...this.anchor.cell };
53617
53566
  }
53618
- /**
53619
- * Expand the given zone to a table.
53620
- * We define a table by the smallest zone that contain the anchor and that have only empty
53621
- * cells bordering it
53622
- */
53623
- expandZoneToTable(zoneToExpand) {
53624
- /** Try to expand the zone by one col/row in any direction to include a new non-empty cell */
53625
- const expandZone = (zone) => {
53626
- for (const col of range(zone.left, zone.right + 1)) {
53627
- if (!this.isCellEmpty({ col, row: zone.top - 1 })) {
53628
- return { ...zone, top: zone.top - 1 };
53629
- }
53630
- if (!this.isCellEmpty({ col, row: zone.bottom + 1 })) {
53631
- return { ...zone, bottom: zone.bottom + 1 };
53632
- }
53633
- }
53634
- for (const row of range(zone.top, zone.bottom + 1)) {
53635
- if (!this.isCellEmpty({ col: zone.left - 1, row })) {
53636
- return { ...zone, left: zone.left - 1 };
53637
- }
53638
- if (!this.isCellEmpty({ col: zone.right + 1, row })) {
53639
- return { ...zone, right: zone.right + 1 };
53640
- }
53641
- }
53642
- return zone;
53643
- };
53644
- let hasExpanded = false;
53645
- let zone = zoneToExpand;
53646
- do {
53647
- hasExpanded = false;
53648
- const newZone = expandZone(zone);
53649
- if (!isEqual(zone, newZone)) {
53650
- hasExpanded = true;
53651
- zone = newZone;
53652
- continue;
53653
- }
53654
- } while (hasExpanded);
53655
- return zone;
53656
- }
53657
53567
  }
53658
53568
 
53659
53569
  class StateObserver {
@@ -55876,6 +55786,7 @@ exports.__info__ = __info__;
55876
55786
  exports.addFunction = addFunction;
55877
55787
  exports.astToFormula = astToFormula;
55878
55788
  exports.compile = compile;
55789
+ exports.compileTokens = compileTokens;
55879
55790
  exports.components = components;
55880
55791
  exports.constants = constants;
55881
55792
  exports.convertAstNodes = convertAstNodes;
@@ -55891,6 +55802,7 @@ exports.iterateAstNodes = iterateAstNodes;
55891
55802
  exports.links = links;
55892
55803
  exports.load = load;
55893
55804
  exports.parse = parse;
55805
+ exports.parseTokens = parseTokens;
55894
55806
  exports.readonlyAllowedCommands = readonlyAllowedCommands;
55895
55807
  exports.registries = registries;
55896
55808
  exports.setDefaultSheetViewSize = setDefaultSheetViewSize;
@@ -55898,6 +55810,6 @@ exports.setTranslationMethod = setTranslationMethod;
55898
55810
  exports.tokenize = tokenize;
55899
55811
 
55900
55812
 
55901
- __info__.version = "17.1.0-alpha.1";
55902
- __info__.date = "2023-11-02T09:35:10.532Z";
55903
- __info__.hash = "3b1fe3b";
55813
+ __info__.version = "17.1.0-alpha.3";
55814
+ __info__.date = "2023-11-16T12:04:09.636Z";
55815
+ __info__.hash = "2ef5b1a";