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