@odoo/o-spreadsheet 17.1.0-alpha.2 → 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.2
6
- * @date 2023-11-03T12:24:57.341Z
7
- * @hash 0595868
5
+ * @version 17.1.0-alpha.3
6
+ * @date 2023-11-16T12:04:09.636Z
7
+ * @hash 2ef5b1a
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -5966,7 +5966,7 @@ autofillModifiersRegistry
5966
5966
  return { cellData: {} };
5967
5967
  }
5968
5968
  const sheetId = data.sheetId;
5969
- const content = getters.getTranslatedCellFormula(sheetId, x, y, cell.compiledFormula, cell.dependencies);
5969
+ const content = getters.getTranslatedCellFormula(sheetId, x, y, cell.compiledFormula);
5970
5970
  return {
5971
5971
  cellData: {
5972
5972
  border: data.border,
@@ -10718,6 +10718,17 @@ const SELECTION_CONTAINS_FILTER = (env) => {
10718
10718
  const IS_ONLY_ONE_RANGE = (env) => {
10719
10719
  return env.model.getters.getSelectedZones().length === 1;
10720
10720
  };
10721
+ const CAN_INSERT_HEADER = (env, dimension) => {
10722
+ if (!IS_ONLY_ONE_RANGE(env)) {
10723
+ return false;
10724
+ }
10725
+ const activeHeaders = dimension === "COL" ? env.model.getters.getActiveCols() : env.model.getters.getActiveRows();
10726
+ const ortogonalActiveHeaders = dimension === "COL" ? env.model.getters.getActiveRows() : env.model.getters.getActiveCols();
10727
+ const sheetId = env.model.getters.getActiveSheetId();
10728
+ const zone = env.model.getters.getSelectedZone();
10729
+ const allSheetSelected = isEqual(zone, env.model.getters.getSheetZone(sheetId));
10730
+ return isConsecutive(activeHeaders) && (ortogonalActiveHeaders.size === 0 || allSheetSelected);
10731
+ };
10721
10732
 
10722
10733
  const undo = {
10723
10734
  name: _t("Undo"),
@@ -19395,9 +19406,7 @@ const insertRow = {
19395
19406
  const number = getRowsNumber(env);
19396
19407
  return number === 1 ? _t("Insert row") : _t("Insert %s rows", number.toString());
19397
19408
  },
19398
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19399
- IS_ONLY_ONE_RANGE(env) &&
19400
- env.model.getters.getActiveCols().size === 0,
19409
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19401
19410
  icon: "o-spreadsheet-Icon.INSERT_ROW",
19402
19411
  };
19403
19412
  const rowInsertRowBefore = {
@@ -19406,9 +19415,7 @@ const rowInsertRowBefore = {
19406
19415
  return number === 1 ? _t("Insert row above") : _t("Insert %s rows above", number.toString());
19407
19416
  },
19408
19417
  execute: INSERT_ROWS_BEFORE_ACTION,
19409
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19410
- IS_ONLY_ONE_RANGE(env) &&
19411
- env.model.getters.getActiveCols().size === 0,
19418
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19412
19419
  icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
19413
19420
  };
19414
19421
  const topBarInsertRowsBefore = {
@@ -19439,9 +19446,7 @@ const rowInsertRowsAfter = {
19439
19446
  const number = getRowsNumber(env);
19440
19447
  return number === 1 ? _t("Insert row below") : _t("Insert %s rows below", number.toString());
19441
19448
  },
19442
- isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
19443
- IS_ONLY_ONE_RANGE(env) &&
19444
- env.model.getters.getActiveCols().size === 0,
19449
+ isVisible: (env) => CAN_INSERT_HEADER(env, "ROW"),
19445
19450
  icon: "o-spreadsheet-Icon.INSERT_ROW_AFTER",
19446
19451
  };
19447
19452
  const topBarInsertRowsAfter = {
@@ -19459,9 +19464,7 @@ const insertCol = {
19459
19464
  const number = getColumnsNumber(env);
19460
19465
  return number === 1 ? _t("Insert column") : _t("Insert %s columns", number.toString());
19461
19466
  },
19462
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19463
- IS_ONLY_ONE_RANGE(env) &&
19464
- env.model.getters.getActiveRows().size === 0,
19467
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19465
19468
  icon: "o-spreadsheet-Icon.INSERT_COL",
19466
19469
  };
19467
19470
  const colInsertColsBefore = {
@@ -19472,9 +19475,7 @@ const colInsertColsBefore = {
19472
19475
  : _t("Insert %s columns left", number.toString());
19473
19476
  },
19474
19477
  execute: INSERT_COLUMNS_BEFORE_ACTION,
19475
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19476
- IS_ONLY_ONE_RANGE(env) &&
19477
- env.model.getters.getActiveRows().size === 0,
19478
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19478
19479
  icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
19479
19480
  };
19480
19481
  const topBarInsertColsBefore = {
@@ -19507,9 +19508,7 @@ const colInsertColsAfter = {
19507
19508
  : _t("Insert %s columns right", number.toString());
19508
19509
  },
19509
19510
  execute: INSERT_COLUMNS_AFTER_ACTION,
19510
- isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
19511
- IS_ONLY_ONE_RANGE(env) &&
19512
- env.model.getters.getActiveRows().size === 0,
19511
+ isVisible: (env) => CAN_INSERT_HEADER(env, "COL"),
19513
19512
  icon: "o-spreadsheet-Icon.INSERT_COL_AFTER",
19514
19513
  };
19515
19514
  const topBarInsertColsAfter = {
@@ -23850,7 +23849,7 @@ css /* scss */ `
23850
23849
  }
23851
23850
  .o-input-count {
23852
23851
  width: fit-content;
23853
- padding: 4 0 4 4;
23852
+ padding: 4px 0 4px 4px;
23854
23853
  }
23855
23854
  }
23856
23855
  }
@@ -34966,6 +34965,9 @@ const functionCache = {};
34966
34965
  // -----------------------------------------------------------------------------
34967
34966
  function compile(formula) {
34968
34967
  const tokens = rangeTokenize(formula);
34968
+ return compileTokens(tokens);
34969
+ }
34970
+ function compileTokens(tokens) {
34969
34971
  const { dependencies, constantValues } = formulaArguments(tokens);
34970
34972
  const cacheKey = compilationCacheKey(tokens, dependencies, constantValues);
34971
34973
  if (!functionCache[cacheKey]) {
@@ -35332,11 +35334,11 @@ class CellPlugin extends CorePlugin {
35332
35334
  for (const sheet of Object.keys(this.cells)) {
35333
35335
  for (const cell of Object.values(this.cells[sheet] || {})) {
35334
35336
  if (cell.isFormula) {
35335
- for (const range of cell.dependencies) {
35337
+ for (const range of cell.compiledFormula.dependencies) {
35336
35338
  if (!sheetId || range.sheetId === sheetId) {
35337
35339
  const change = applyChange(range);
35338
35340
  if (change.changeType !== "NONE") {
35339
- 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);
35340
35342
  }
35341
35343
  }
35342
35344
  }
@@ -35532,10 +35534,10 @@ class CellPlugin extends CorePlugin {
35532
35534
  /*
35533
35535
  * Reconstructs the original formula string based on a normalized form and its dependencies
35534
35536
  */
35535
- getFormulaCellContent(sheetId, cell, dependencies) {
35536
- const ranges = dependencies || cell.dependencies;
35537
+ getFormulaCellContent(sheetId, compiledFormula, dependencies) {
35538
+ const ranges = dependencies || compiledFormula.dependencies;
35537
35539
  let rangeIndex = 0;
35538
- return concat(cell.compiledFormula.tokens.map((token) => {
35540
+ return concat(compiledFormula.tokens.map((token) => {
35539
35541
  if (token.type === "REFERENCE") {
35540
35542
  const range = ranges[rangeIndex++];
35541
35543
  return this.getters.getRangeString(range, sheetId);
@@ -35546,12 +35548,9 @@ class CellPlugin extends CorePlugin {
35546
35548
  /*
35547
35549
  * Constructs a formula string based on an initial formula and a translation vector
35548
35550
  */
35549
- getTranslatedCellFormula(sheetId, offsetX, offsetY, compiledFormula, dependencies) {
35550
- const adaptedDependencies = this.getters.createAdaptedRanges(dependencies, offsetX, offsetY, sheetId);
35551
- return this.getFormulaCellContent(sheetId, {
35552
- compiledFormula,
35553
- dependencies: adaptedDependencies,
35554
- });
35551
+ getTranslatedCellFormula(sheetId, offsetX, offsetY, compiledFormula) {
35552
+ const adaptedDependencies = this.getters.createAdaptedRanges(compiledFormula.dependencies, offsetX, offsetY, sheetId);
35553
+ return this.getFormulaCellContent(sheetId, compiledFormula, adaptedDependencies);
35555
35554
  }
35556
35555
  getCellStyle(position) {
35557
35556
  return this.getters.getCell(position)?.style || {};
@@ -35731,8 +35730,10 @@ class CellPlugin extends CorePlugin {
35731
35730
  style,
35732
35731
  format,
35733
35732
  isFormula: true,
35734
- compiledFormula,
35735
- dependencies: [],
35733
+ compiledFormula: {
35734
+ ...compiledFormula,
35735
+ dependencies: [],
35736
+ },
35736
35737
  };
35737
35738
  }
35738
35739
  /**
@@ -35741,7 +35742,7 @@ class CellPlugin extends CorePlugin {
35741
35742
  */
35742
35743
  createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
35743
35744
  const dependencies = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
35744
- return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getFormulaCellContent.bind(this));
35745
+ return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString.bind(this));
35745
35746
  }
35746
35747
  createErrorFormula(id, content, format, style, error) {
35747
35748
  return {
@@ -35751,13 +35752,12 @@ class CellPlugin extends CorePlugin {
35751
35752
  format,
35752
35753
  isFormula: true,
35753
35754
  compiledFormula: {
35754
- dependencies: [],
35755
35755
  tokens: tokenize(content),
35756
+ dependencies: [],
35756
35757
  execute: function () {
35757
35758
  throw error;
35758
35759
  },
35759
35760
  },
35760
- dependencies: [],
35761
35761
  };
35762
35762
  }
35763
35763
  checkCellOutOfSheet(sheetId, col, row) {
@@ -35770,27 +35770,44 @@ class CellPlugin extends CorePlugin {
35770
35770
  }
35771
35771
  class FormulaCellWithDependencies {
35772
35772
  id;
35773
- compiledFormula;
35774
35773
  format;
35775
35774
  style;
35776
- dependencies;
35777
35775
  sheetId;
35778
- getFormulaCellContent;
35776
+ getRangeString;
35779
35777
  isFormula = true;
35780
- constructor(id, compiledFormula, format, style, dependencies, sheetId, getFormulaCellContent) {
35778
+ compiledFormula;
35779
+ constructor(id, compiledFormula, format, style, dependencies, sheetId, getRangeString) {
35781
35780
  this.id = id;
35782
- this.compiledFormula = compiledFormula;
35783
35781
  this.format = format;
35784
35782
  this.style = style;
35785
- this.dependencies = dependencies;
35786
35783
  this.sheetId = sheetId;
35787
- this.getFormulaCellContent = getFormulaCellContent;
35784
+ this.getRangeString = getRangeString;
35785
+ let rangeIndex = 0;
35786
+ const tokens = compiledFormula.tokens.map((token) => {
35787
+ if (token.type === "REFERENCE") {
35788
+ const index = rangeIndex++;
35789
+ return new RangeReferenceToken(() => this.getRangeString(dependencies[index], this.sheetId));
35790
+ }
35791
+ return token;
35792
+ });
35793
+ this.compiledFormula = {
35794
+ ...compiledFormula,
35795
+ dependencies,
35796
+ tokens,
35797
+ };
35788
35798
  }
35789
35799
  get content() {
35790
- return this.getFormulaCellContent(this.sheetId, {
35791
- dependencies: this.dependencies,
35792
- compiledFormula: this.compiledFormula,
35793
- });
35800
+ return concat(this.compiledFormula.tokens.map((token) => token.value));
35801
+ }
35802
+ }
35803
+ class RangeReferenceToken {
35804
+ getValue;
35805
+ type = "REFERENCE";
35806
+ constructor(getValue) {
35807
+ this.getValue = getValue;
35808
+ }
35809
+ get value() {
35810
+ return this.getValue();
35794
35811
  }
35795
35812
  }
35796
35813
 
@@ -36935,6 +36952,13 @@ class FiltersPlugin extends CorePlugin {
36935
36952
  }
36936
36953
  onDeleteColumnsRows(cmd) {
36937
36954
  for (const table of this.getFilterTables(cmd.sheetId)) {
36955
+ // Remove the filter tables whose data filter headers are in the removed rows.
36956
+ if (cmd.dimension === "ROW" && cmd.elements.includes(table.zone.top)) {
36957
+ const tables = { ...this.tables[cmd.sheetId] };
36958
+ delete tables[table.id];
36959
+ this.history.update("tables", cmd.sheetId, tables);
36960
+ continue;
36961
+ }
36938
36962
  const zone = reduceZoneOnDeletion(table.zone, cmd.dimension === "COL" ? "left" : "top", cmd.elements);
36939
36963
  if (!zone) {
36940
36964
  const tables = { ...this.tables[cmd.sheetId] };
@@ -39983,6 +40007,13 @@ class Evaluator {
39983
40007
  return (this.evaluatedCells.get(this.encodePosition(position)) ||
39984
40008
  createEvaluatedCell("", { locale: this.getters.getLocale() }));
39985
40009
  }
40010
+ getSpreadPositionsOf(position) {
40011
+ const positionId = this.encodePosition(position);
40012
+ if (!this.spreadingRelations.isArrayFormula(positionId)) {
40013
+ return [];
40014
+ }
40015
+ return Array.from(this.spreadingRelations.getArrayResultPositionIds(positionId)).map(this.decodePosition.bind(this));
40016
+ }
39986
40017
  getArrayFormulaSpreadingOn(position) {
39987
40018
  const positionId = this.encodePosition(position);
39988
40019
  const formulaPosition = this.getArrayFormulaSpreadingOnId(positionId);
@@ -40141,7 +40172,7 @@ class Evaluator {
40141
40172
  const position = this.compilationParams[2].getters.getCellPosition(cellId);
40142
40173
  return toXC(position.col, position.row);
40143
40174
  };
40144
- const formulaReturn = cellData.compiledFormula.execute(cellData.dependencies, ...this.compilationParams);
40175
+ const formulaReturn = cellData.compiledFormula.execute(cellData.compiledFormula.dependencies, ...this.compilationParams);
40145
40176
  if (!isMatrix(formulaReturn)) {
40146
40177
  return createEvaluatedCell(formulaReturn.value, {
40147
40178
  format: cellData.format || formulaReturn.format,
@@ -40241,7 +40272,7 @@ class Evaluator {
40241
40272
  return [];
40242
40273
  }
40243
40274
  const dependencies = [];
40244
- for (const range of cell.dependencies) {
40275
+ for (const range of cell.compiledFormula.dependencies) {
40245
40276
  if (range.invalidSheetName || range.invalidXc) {
40246
40277
  continue;
40247
40278
  }
@@ -40447,6 +40478,7 @@ class EvaluationPlugin extends UIPlugin {
40447
40478
  "getEvaluatedCell",
40448
40479
  "getEvaluatedCells",
40449
40480
  "getEvaluatedCellsInZone",
40481
+ "getSpreadPositionsOf",
40450
40482
  ];
40451
40483
  shouldRebuildDependenciesGraph = true;
40452
40484
  evaluator;
@@ -40556,6 +40588,9 @@ class EvaluationPlugin extends UIPlugin {
40556
40588
  getEvaluatedCellsInZone(sheetId, zone) {
40557
40589
  return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
40558
40590
  }
40591
+ getSpreadPositionsOf(position) {
40592
+ return this.evaluator.getSpreadPositionsOf(position);
40593
+ }
40559
40594
  // ---------------------------------------------------------------------------
40560
40595
  // Export
40561
40596
  // ---------------------------------------------------------------------------
@@ -40593,10 +40628,10 @@ class EvaluationPlugin extends UIPlugin {
40593
40628
  */
40594
40629
  getCorrespondingFormulaCell(position) {
40595
40630
  const cell = this.getters.getCell(position);
40596
- if (cell && cell.content) {
40597
- if (cell.isFormula && !isBadExpression(cell.content)) {
40598
- return cell;
40599
- }
40631
+ if (cell && cell.isFormula) {
40632
+ return isBadExpression(cell.compiledFormula.tokens) ? undefined : cell;
40633
+ }
40634
+ else if (cell && cell.content) {
40600
40635
  return undefined;
40601
40636
  }
40602
40637
  const spreadingFormulaPosition = this.evaluator.getArrayFormulaSpreadingOn(position);
@@ -40613,9 +40648,9 @@ class EvaluationPlugin extends UIPlugin {
40613
40648
  return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
40614
40649
  }
40615
40650
  }
40616
- function isBadExpression(formula) {
40651
+ function isBadExpression(tokens) {
40617
40652
  try {
40618
- compile(formula);
40653
+ compileTokens(tokens);
40619
40654
  return false;
40620
40655
  }
40621
40656
  catch (error) {
@@ -40784,22 +40819,20 @@ class EvaluationChartPlugin extends UIPlugin {
40784
40819
  invalidateCFEvaluationCommands.has(cmd.type) ||
40785
40820
  cmd.type === "EVALUATE_CELLS" ||
40786
40821
  cmd.type === "UPDATE_CELL") {
40787
- if (cmd.type !== "UNDO" && cmd.type !== "REDO") {
40788
- for (const chartId in this.charts) {
40789
- this.history.update("charts", chartId, undefined);
40790
- }
40822
+ for (const chartId in this.charts) {
40823
+ this.charts[chartId] = undefined;
40791
40824
  }
40792
40825
  }
40793
40826
  switch (cmd.type) {
40794
40827
  case "UPDATE_CHART":
40795
40828
  case "CREATE_CHART":
40796
40829
  case "DELETE_FIGURE":
40797
- this.history.update("charts", cmd.id, undefined);
40830
+ this.charts[cmd.id] = undefined;
40798
40831
  break;
40799
40832
  case "DELETE_SHEET":
40800
40833
  for (let chartId in this.charts) {
40801
40834
  if (!this.getters.isChartDefined(chartId)) {
40802
- this.history.update("charts", chartId, undefined);
40835
+ this.charts[chartId] = undefined;
40803
40836
  }
40804
40837
  }
40805
40838
  break;
@@ -40811,8 +40844,7 @@ class EvaluationChartPlugin extends UIPlugin {
40811
40844
  if (!chart) {
40812
40845
  throw new Error(`No chart for the given id: ${figureId}`);
40813
40846
  }
40814
- const runtime = this.createRuntimeChart(chart);
40815
- this.history.update("charts", figureId, runtime);
40847
+ this.charts[figureId] = this.createRuntimeChart(chart);
40816
40848
  }
40817
40849
  return this.charts[figureId];
40818
40850
  }
@@ -40964,7 +40996,10 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
40964
40996
  const values = cf.rule.values.map((value, i) => {
40965
40997
  const compiledFormula = formulas[i];
40966
40998
  if (compiledFormula) {
40967
- return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, compiledFormula, compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)));
40999
+ return this.getters.getTranslatedCellFormula(sheetId, col - zone.left, row - zone.top, {
41000
+ ...compiledFormula,
41001
+ dependencies: compiledFormula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
41002
+ });
40968
41003
  }
40969
41004
  return value;
40970
41005
  });
@@ -41336,7 +41371,10 @@ class EvaluationDataValidationPlugin extends UIPlugin {
41336
41371
  }
41337
41372
  try {
41338
41373
  const formula = compile(value);
41339
- const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, formula, formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)));
41374
+ const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, {
41375
+ ...formula,
41376
+ dependencies: formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)),
41377
+ });
41340
41378
  const evaluated = this.getters.evaluateFormula(sheetId, translatedFormula);
41341
41379
  return evaluated && !isMatrix(evaluated) ? evaluated.toString() : "";
41342
41380
  }
@@ -43590,7 +43628,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
43590
43628
  }
43591
43629
  let content = origin.cell.content;
43592
43630
  if (origin.cell.isFormula && operation === "COPY") {
43593
- content = this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula, origin.cell.dependencies);
43631
+ content = this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula);
43594
43632
  }
43595
43633
  this.dispatch("UPDATE_CELL", {
43596
43634
  ...target,
@@ -44122,20 +44160,29 @@ class FindAndReplacePlugin extends UIPlugin {
44122
44160
  const sheetId = this.getters.getActiveSheetId();
44123
44161
  const cells = this.getters.getCells(sheetId);
44124
44162
  const matches = [];
44125
- if (this.toSearch) {
44163
+ if (this.toSearch && this.currentSearchRegex) {
44126
44164
  for (const cell of Object.values(cells)) {
44127
44165
  const { col, row } = this.getters.getCellPosition(cell.id);
44166
+ const cellPosition = { sheetId, col, row };
44128
44167
  const isColHidden = this.getters.isColHidden(sheetId, col);
44129
44168
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
44130
44169
  if (isColHidden || isRowHidden) {
44131
44170
  continue;
44132
44171
  }
44133
- if (cell &&
44134
- this.currentSearchRegex &&
44135
- this.currentSearchRegex.test(this.getSearchableString({ sheetId, col, row }))) {
44172
+ if (this.currentSearchRegex.test(this.getSearchableString(cellPosition))) {
44136
44173
  const match = { col, row, selected: false };
44137
44174
  matches.push(match);
44138
44175
  }
44176
+ for (const spreadPosition of this.getters.getSpreadPositionsOf(cellPosition)) {
44177
+ if (this.currentSearchRegex.test(this.getSearchableString(spreadPosition))) {
44178
+ const match = {
44179
+ col: spreadPosition.col,
44180
+ row: spreadPosition.row,
44181
+ selected: false,
44182
+ };
44183
+ matches.push(match);
44184
+ }
44185
+ }
44139
44186
  }
44140
44187
  }
44141
44188
  return matches.sort(this.sortByRowThenColumn);
@@ -44196,16 +44243,19 @@ class FindAndReplacePlugin extends UIPlugin {
44196
44243
  return;
44197
44244
  }
44198
44245
  const sheetId = this.getters.getActiveSheetId();
44199
- const cell = this.getters.getCell({ sheetId, ...selectedMatch });
44200
- const { col, row } = selectedMatch;
44246
+ const position = { sheetId, ...selectedMatch };
44247
+ const cell = this.getters.getCell(position);
44248
+ if (!cell?.content) {
44249
+ return;
44250
+ }
44201
44251
  if (cell?.isFormula && !this.searchOptions.searchFormulas) {
44202
44252
  return;
44203
44253
  }
44204
44254
  const replaceRegex = new RegExp(this.currentSearchRegex.source, this.currentSearchRegex.flags + "g");
44205
- const toReplace = this.getSearchableString({ sheetId, col, row });
44255
+ const toReplace = this.getSearchableString(position);
44206
44256
  const content = toReplace.replace(replaceRegex, replaceWith);
44207
44257
  const canonicalContent = canonicalizeNumberContent(content, this.getters.getLocale());
44208
- this.dispatch("UPDATE_CELL", { sheetId, col, row, content: canonicalContent });
44258
+ this.dispatch("UPDATE_CELL", { ...position, content: canonicalContent });
44209
44259
  }
44210
44260
  /**
44211
44261
  * Replace the value of the currently selected match
@@ -45534,7 +45584,6 @@ class SelectionInputsManagerPlugin extends UIPlugin {
45534
45584
  }
45535
45585
 
45536
45586
  class SortPlugin extends UIPlugin {
45537
- static getters = ["getContiguousZone"];
45538
45587
  allowDispatch(cmd) {
45539
45588
  switch (cmd.type) {
45540
45589
  case "SORT_CELLS":
@@ -45582,143 +45631,6 @@ class SortPlugin extends UIPlugin {
45582
45631
  }
45583
45632
  return "Success" /* CommandResult.Success */;
45584
45633
  }
45585
- // getContiguousZone helpers
45586
- /**
45587
- * safe-version of expandZone to make sure we don't get out of the grid
45588
- */
45589
- expand(sheetId, z) {
45590
- const { left, right, top, bottom } = this.getters.expandZone(sheetId, z);
45591
- return {
45592
- left: Math.max(0, left),
45593
- right: Math.min(this.getters.getNumberCols(sheetId) - 1, right),
45594
- top: Math.max(0, top),
45595
- bottom: Math.min(this.getters.getNumberRows(sheetId) - 1, bottom),
45596
- };
45597
- }
45598
- /**
45599
- * verifies the presence of at least one non-empty cell in the given zone
45600
- */
45601
- checkExpandedValues(sheetId, z) {
45602
- const expandedZone = this.expand(sheetId, z);
45603
- let cell;
45604
- if (this.getters.doesIntersectMerge(sheetId, expandedZone)) {
45605
- const { left, right, top, bottom } = expandedZone;
45606
- for (let c = left; c <= right; c++) {
45607
- for (let r = top; r <= bottom; r++) {
45608
- const { col, row } = this.getters.getMainCellPosition({ sheetId, col: c, row: r });
45609
- cell = this.getters.getEvaluatedCell({ sheetId, col, row });
45610
- if (cell.formattedValue) {
45611
- return true;
45612
- }
45613
- }
45614
- }
45615
- }
45616
- else {
45617
- for (let cell of this.getters.getEvaluatedCellsInZone(sheetId, expandedZone)) {
45618
- if (cell.formattedValue) {
45619
- return true;
45620
- }
45621
- }
45622
- }
45623
- return false;
45624
- }
45625
- /**
45626
- * This function will expand the provided zone in directions (top, bottom, left, right) for which there
45627
- * are non-null cells on the external boundary of the zone in the given direction.
45628
- *
45629
- * Example:
45630
- * A B C D E
45631
- * ___ ___ ___ ___ ___
45632
- * 1 | | D | | | |
45633
- * ___ ___ ___ ___ ___
45634
- * 2 | 5 | | 1 | D | |
45635
- * ___ ___ ___ ___ ___
45636
- * 3 | | | A | X | |
45637
- * ___ ___ ___ ___ ___
45638
- * 4 | | | | | |
45639
- * ___ ___ ___ ___ ___
45640
- *
45641
- * Let's consider a provided zone corresponding to (C2:D3) - (left:2, right: 3, top:1, bottom:2)
45642
- * - the top external boundary is (B1:E1)
45643
- * Since we have B1='D' != "", we expand to the top: => (C1:D3)
45644
- * The top boundary having reached the top of the grid, we cannot expand in that direction anymore
45645
- *
45646
- * - the left boundary is (B1:B4)
45647
- * since we have B1 again, we expand to the left => (B1:D3)
45648
- *
45649
- * - the right and bottom boundaries are a dead end for now as (E1:E4) and (A4:E4) are empty.
45650
- *
45651
- * - the left boundary is now (A1:A4)
45652
- * Since we have A2=5 != "", we can therefore expand to the left => (A1:D3)
45653
- *
45654
- * This will be the final zone as left and top have reached the boundaries of the grid and
45655
- * the other boundaries (E1:E4) and (A4:E4) are empty.
45656
- *
45657
- * @param sheetId UID of concerned sheet
45658
- * @param zone Zone
45659
- *
45660
- */
45661
- getContiguousZone(sheetId, zone) {
45662
- let { top, bottom, left, right } = zone;
45663
- let canExpand;
45664
- let stop = false;
45665
- while (!stop) {
45666
- stop = true;
45667
- /** top row external boundary */
45668
- if (top > 0) {
45669
- canExpand = this.checkExpandedValues(sheetId, {
45670
- left: left - 1,
45671
- right: right + 1,
45672
- top: top - 1,
45673
- bottom: top - 1,
45674
- });
45675
- if (canExpand) {
45676
- stop = false;
45677
- top--;
45678
- }
45679
- }
45680
- /** left column external boundary */
45681
- if (left > 0) {
45682
- canExpand = this.checkExpandedValues(sheetId, {
45683
- left: left - 1,
45684
- right: left - 1,
45685
- top: top - 1,
45686
- bottom: bottom + 1,
45687
- });
45688
- if (canExpand) {
45689
- stop = false;
45690
- left--;
45691
- }
45692
- }
45693
- /** right column external boundary */
45694
- if (right < this.getters.getNumberCols(sheetId) - 1) {
45695
- canExpand = this.checkExpandedValues(sheetId, {
45696
- left: right + 1,
45697
- right: right + 1,
45698
- top: top - 1,
45699
- bottom: bottom + 1,
45700
- });
45701
- if (canExpand) {
45702
- stop = false;
45703
- right++;
45704
- }
45705
- }
45706
- /** bottom row external boundary */
45707
- if (bottom < this.getters.getNumberRows(sheetId) - 1) {
45708
- canExpand = this.checkExpandedValues(sheetId, {
45709
- left: left - 1,
45710
- right: right + 1,
45711
- top: bottom + 1,
45712
- bottom: bottom + 1,
45713
- });
45714
- if (canExpand) {
45715
- stop = false;
45716
- bottom++;
45717
- }
45718
- }
45719
- }
45720
- return { left, right, top, bottom };
45721
- }
45722
45634
  /**
45723
45635
  * This function evaluates if the top row of a provided zone can be considered as a `header`
45724
45636
  * by checking the following criteria:
@@ -45783,7 +45695,7 @@ class SortPlugin extends UIPlugin {
45783
45695
  if (cell.isFormula) {
45784
45696
  const position = this.getters.getCellPosition(cell.id);
45785
45697
  // we only have a vertical offset
45786
- content = this.getters.getTranslatedCellFormula(sheetId, 0, newRow - position.row, cell.compiledFormula, cell.dependencies);
45698
+ content = this.getters.getTranslatedCellFormula(sheetId, 0, newRow - position.row, cell.compiledFormula);
45787
45699
  }
45788
45700
  newCellValues.style = cell.style;
45789
45701
  newCellValues.content = content;
@@ -45852,6 +45764,8 @@ class SheetUIPlugin extends UIPlugin {
45852
45764
  "getTextWidth",
45853
45765
  "getCellText",
45854
45766
  "getCellMultiLineText",
45767
+ "getContiguousZone",
45768
+ "isCellEmpty",
45855
45769
  ];
45856
45770
  ctx = document.createElement("canvas").getContext("2d");
45857
45771
  // ---------------------------------------------------------------------------
@@ -45941,9 +45855,52 @@ class SheetUIPlugin extends UIPlugin {
45941
45855
  const hasListIcon = !this.getters.isReadonly() && this.getters.cellHasListDataValidationIcon(position);
45942
45856
  return isFilterHeader || hasListIcon;
45943
45857
  }
45944
- // ---------------------------------------------------------------------------
45945
- // Grid manipulation
45946
- // ---------------------------------------------------------------------------
45858
+ /**
45859
+ * Expands the given zone until bordered by empty cells or reached the sheet boundaries.
45860
+ */
45861
+ getContiguousZone(sheetId, zoneToExpand) {
45862
+ /** Try to expand the zone by one col/row in any direction to include a new non-empty cell */
45863
+ const expandZone = (zone) => {
45864
+ for (const col of range(zone.left, zone.right + 1)) {
45865
+ if (!this.isCellEmpty({ sheetId, col, row: zone.top - 1 })) {
45866
+ return { ...zone, top: zone.top - 1 };
45867
+ }
45868
+ if (!this.isCellEmpty({ sheetId, col, row: zone.bottom + 1 })) {
45869
+ return { ...zone, bottom: zone.bottom + 1 };
45870
+ }
45871
+ }
45872
+ for (const row of range(zone.top, zone.bottom + 1)) {
45873
+ if (!this.isCellEmpty({ sheetId, col: zone.left - 1, row })) {
45874
+ return { ...zone, left: zone.left - 1 };
45875
+ }
45876
+ if (!this.isCellEmpty({ sheetId, col: zone.right + 1, row })) {
45877
+ return { ...zone, right: zone.right + 1 };
45878
+ }
45879
+ }
45880
+ return zone;
45881
+ };
45882
+ let hasExpanded = false;
45883
+ let zone = zoneToExpand;
45884
+ do {
45885
+ hasExpanded = false;
45886
+ const newZone = expandZone(zone);
45887
+ if (!isEqual(zone, newZone)) {
45888
+ hasExpanded = true;
45889
+ zone = newZone;
45890
+ continue;
45891
+ }
45892
+ } while (hasExpanded);
45893
+ return zone;
45894
+ }
45895
+ /**
45896
+ * Check if a cell is empty. If the cell is part of a merge,
45897
+ * check if the merge containing the cell is empty.
45898
+ */
45899
+ isCellEmpty(position) {
45900
+ const mainPosition = this.getters.getMainCellPosition(position);
45901
+ const cell = this.getters.getEvaluatedCell(mainPosition);
45902
+ return cell.type === CellValueType.empty;
45903
+ }
45947
45904
  getColMaxWidth(sheetId, index) {
45948
45905
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
45949
45906
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
@@ -47848,6 +47805,8 @@ class FilterEvaluationPlugin extends UIPlugin {
47848
47805
  case "EVALUATE_CELLS":
47849
47806
  case "ACTIVATE_SHEET":
47850
47807
  case "REMOVE_FILTER_TABLE":
47808
+ case "ADD_COLUMNS_ROWS":
47809
+ case "REMOVE_COLUMNS_ROWS":
47851
47810
  this.isEvaluationDirty = true;
47852
47811
  break;
47853
47812
  case "START":
@@ -53366,7 +53325,7 @@ class SelectionStreamProcessorImpl {
53366
53325
  scrollIntoView: false,
53367
53326
  });
53368
53327
  }
53369
- const tableZone = this.expandZoneToTable(anchor.zone);
53328
+ const tableZone = this.getters.getContiguousZone(sheetId, anchor.zone);
53370
53329
  return !deepEquals(tableZone, anchor.zone)
53371
53330
  ? this.modifyAnchor({ ...anchor, zone: tableZone }, "updateAnchor", {
53372
53331
  scrollIntoView: false,
@@ -53379,7 +53338,8 @@ class SelectionStreamProcessorImpl {
53379
53338
  * cells bordering it
53380
53339
  */
53381
53340
  selectTableAroundSelection() {
53382
- const tableZone = this.expandZoneToTable(this.anchor.zone);
53341
+ const sheetId = this.getters.getActiveSheetId();
53342
+ const tableZone = this.getters.getContiguousZone(sheetId, this.anchor.zone);
53383
53343
  return this.modifyAnchor({ ...this.anchor, zone: tableZone }, "updateAnchor", {
53384
53344
  scrollIntoView: false,
53385
53345
  });
@@ -53556,11 +53516,12 @@ class SelectionStreamProcessorImpl {
53556
53516
  * next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
53557
53517
  */
53558
53518
  getEndOfCluster(startPosition, dim, dir) {
53559
- const sheet = this.getters.getActiveSheet();
53519
+ const sheetId = this.getters.getActiveSheetId();
53560
53520
  let currentPosition = startPosition;
53561
53521
  // If both the current cell and the next cell are not empty, we want to go to the end of the cluster
53562
53522
  const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
53563
- let mode = !this.isCellEmpty(currentPosition, sheet.id) && !this.isCellEmpty(nextCellPosition, sheet.id)
53523
+ let mode = !this.getters.isCellEmpty({ ...currentPosition, sheetId }) &&
53524
+ !this.getters.isCellEmpty({ ...nextCellPosition, sheetId })
53564
53525
  ? "endOfCluster"
53565
53526
  : "nextCluster";
53566
53527
  while (true) {
@@ -53570,7 +53531,7 @@ class SelectionStreamProcessorImpl {
53570
53531
  currentPosition.row === nextCellPosition.row) {
53571
53532
  break;
53572
53533
  }
53573
- const isNextCellEmpty = this.isCellEmpty(nextCellPosition, sheet.id);
53534
+ const isNextCellEmpty = this.getters.isCellEmpty({ ...nextCellPosition, sheetId });
53574
53535
  if (mode === "endOfCluster" && isNextCellEmpty) {
53575
53536
  break;
53576
53537
  }
@@ -53583,15 +53544,6 @@ class SelectionStreamProcessorImpl {
53583
53544
  }
53584
53545
  return dim === "cols" ? currentPosition.col : currentPosition.row;
53585
53546
  }
53586
- /**
53587
- * Check if a cell is empty or undefined in the model. If the cell is part of a merge,
53588
- * check if the merge containing the cell is empty.
53589
- */
53590
- isCellEmpty({ col, row }, sheetId = this.getters.getActiveSheetId()) {
53591
- const position = this.getters.getMainCellPosition({ sheetId, col, row });
53592
- const cell = this.getters.getEvaluatedCell(position);
53593
- return cell.type === CellValueType.empty;
53594
- }
53595
53547
  /** Computes the next cell position in the given direction by crossing through merges and skipping hidden cells.
53596
53548
  *
53597
53549
  * This has the same behaviour as getNextAvailablePosition() for certain arguments, but use this method instead
@@ -53610,45 +53562,6 @@ class SelectionStreamProcessorImpl {
53610
53562
  getPosition() {
53611
53563
  return { ...this.anchor.cell };
53612
53564
  }
53613
- /**
53614
- * Expand the given zone to a table.
53615
- * We define a table by the smallest zone that contain the anchor and that have only empty
53616
- * cells bordering it
53617
- */
53618
- expandZoneToTable(zoneToExpand) {
53619
- /** Try to expand the zone by one col/row in any direction to include a new non-empty cell */
53620
- const expandZone = (zone) => {
53621
- for (const col of range(zone.left, zone.right + 1)) {
53622
- if (!this.isCellEmpty({ col, row: zone.top - 1 })) {
53623
- return { ...zone, top: zone.top - 1 };
53624
- }
53625
- if (!this.isCellEmpty({ col, row: zone.bottom + 1 })) {
53626
- return { ...zone, bottom: zone.bottom + 1 };
53627
- }
53628
- }
53629
- for (const row of range(zone.top, zone.bottom + 1)) {
53630
- if (!this.isCellEmpty({ col: zone.left - 1, row })) {
53631
- return { ...zone, left: zone.left - 1 };
53632
- }
53633
- if (!this.isCellEmpty({ col: zone.right + 1, row })) {
53634
- return { ...zone, right: zone.right + 1 };
53635
- }
53636
- }
53637
- return zone;
53638
- };
53639
- let hasExpanded = false;
53640
- let zone = zoneToExpand;
53641
- do {
53642
- hasExpanded = false;
53643
- const newZone = expandZone(zone);
53644
- if (!isEqual(zone, newZone)) {
53645
- hasExpanded = true;
53646
- zone = newZone;
53647
- continue;
53648
- }
53649
- } while (hasExpanded);
53650
- return zone;
53651
- }
53652
53565
  }
53653
53566
 
53654
53567
  class StateObserver {
@@ -55857,9 +55770,9 @@ const constants = {
55857
55770
  DEFAULT_LOCALE,
55858
55771
  };
55859
55772
 
55860
- export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
55773
+ export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
55861
55774
 
55862
55775
 
55863
- __info__.version = "17.1.0-alpha.2";
55864
- __info__.date = "2023-11-03T12:24:57.341Z";
55865
- __info__.hash = "0595868";
55776
+ __info__.version = "17.1.0-alpha.3";
55777
+ __info__.date = "2023-11-16T12:04:09.636Z";
55778
+ __info__.hash = "2ef5b1a";