@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
  (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);
@@ -40142,7 +40173,7 @@
40142
40173
  const position = this.compilationParams[2].getters.getCellPosition(cellId);
40143
40174
  return toXC(position.col, position.row);
40144
40175
  };
40145
- const formulaReturn = cellData.compiledFormula.execute(cellData.dependencies, ...this.compilationParams);
40176
+ const formulaReturn = cellData.compiledFormula.execute(cellData.compiledFormula.dependencies, ...this.compilationParams);
40146
40177
  if (!isMatrix(formulaReturn)) {
40147
40178
  return createEvaluatedCell(formulaReturn.value, {
40148
40179
  format: cellData.format || formulaReturn.format,
@@ -40242,7 +40273,7 @@
40242
40273
  return [];
40243
40274
  }
40244
40275
  const dependencies = [];
40245
- for (const range of cell.dependencies) {
40276
+ for (const range of cell.compiledFormula.dependencies) {
40246
40277
  if (range.invalidSheetName || range.invalidXc) {
40247
40278
  continue;
40248
40279
  }
@@ -40448,6 +40479,7 @@
40448
40479
  "getEvaluatedCell",
40449
40480
  "getEvaluatedCells",
40450
40481
  "getEvaluatedCellsInZone",
40482
+ "getSpreadPositionsOf",
40451
40483
  ];
40452
40484
  shouldRebuildDependenciesGraph = true;
40453
40485
  evaluator;
@@ -40557,6 +40589,9 @@
40557
40589
  getEvaluatedCellsInZone(sheetId, zone) {
40558
40590
  return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
40559
40591
  }
40592
+ getSpreadPositionsOf(position) {
40593
+ return this.evaluator.getSpreadPositionsOf(position);
40594
+ }
40560
40595
  // ---------------------------------------------------------------------------
40561
40596
  // Export
40562
40597
  // ---------------------------------------------------------------------------
@@ -40594,10 +40629,10 @@
40594
40629
  */
40595
40630
  getCorrespondingFormulaCell(position) {
40596
40631
  const cell = this.getters.getCell(position);
40597
- if (cell && cell.content) {
40598
- if (cell.isFormula && !isBadExpression(cell.content)) {
40599
- return cell;
40600
- }
40632
+ if (cell && cell.isFormula) {
40633
+ return isBadExpression(cell.compiledFormula.tokens) ? undefined : cell;
40634
+ }
40635
+ else if (cell && cell.content) {
40601
40636
  return undefined;
40602
40637
  }
40603
40638
  const spreadingFormulaPosition = this.evaluator.getArrayFormulaSpreadingOn(position);
@@ -40614,9 +40649,9 @@
40614
40649
  return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
40615
40650
  }
40616
40651
  }
40617
- function isBadExpression(formula) {
40652
+ function isBadExpression(tokens) {
40618
40653
  try {
40619
- compile(formula);
40654
+ compileTokens(tokens);
40620
40655
  return false;
40621
40656
  }
40622
40657
  catch (error) {
@@ -40785,22 +40820,20 @@
40785
40820
  invalidateCFEvaluationCommands.has(cmd.type) ||
40786
40821
  cmd.type === "EVALUATE_CELLS" ||
40787
40822
  cmd.type === "UPDATE_CELL") {
40788
- if (cmd.type !== "UNDO" && cmd.type !== "REDO") {
40789
- for (const chartId in this.charts) {
40790
- this.history.update("charts", chartId, undefined);
40791
- }
40823
+ for (const chartId in this.charts) {
40824
+ this.charts[chartId] = undefined;
40792
40825
  }
40793
40826
  }
40794
40827
  switch (cmd.type) {
40795
40828
  case "UPDATE_CHART":
40796
40829
  case "CREATE_CHART":
40797
40830
  case "DELETE_FIGURE":
40798
- this.history.update("charts", cmd.id, undefined);
40831
+ this.charts[cmd.id] = undefined;
40799
40832
  break;
40800
40833
  case "DELETE_SHEET":
40801
40834
  for (let chartId in this.charts) {
40802
40835
  if (!this.getters.isChartDefined(chartId)) {
40803
- this.history.update("charts", chartId, undefined);
40836
+ this.charts[chartId] = undefined;
40804
40837
  }
40805
40838
  }
40806
40839
  break;
@@ -40812,8 +40845,7 @@
40812
40845
  if (!chart) {
40813
40846
  throw new Error(`No chart for the given id: ${figureId}`);
40814
40847
  }
40815
- const runtime = this.createRuntimeChart(chart);
40816
- this.history.update("charts", figureId, runtime);
40848
+ this.charts[figureId] = this.createRuntimeChart(chart);
40817
40849
  }
40818
40850
  return this.charts[figureId];
40819
40851
  }
@@ -40965,7 +40997,10 @@
40965
40997
  const values = cf.rule.values.map((value, i) => {
40966
40998
  const compiledFormula = formulas[i];
40967
40999
  if (compiledFormula) {
40968
- 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
+ });
40969
41004
  }
40970
41005
  return value;
40971
41006
  });
@@ -41337,7 +41372,10 @@
41337
41372
  }
41338
41373
  try {
41339
41374
  const formula = compile(value);
41340
- 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
+ });
41341
41379
  const evaluated = this.getters.evaluateFormula(sheetId, translatedFormula);
41342
41380
  return evaluated && !isMatrix(evaluated) ? evaluated.toString() : "";
41343
41381
  }
@@ -43591,7 +43629,7 @@
43591
43629
  }
43592
43630
  let content = origin.cell.content;
43593
43631
  if (origin.cell.isFormula && operation === "COPY") {
43594
- 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);
43595
43633
  }
43596
43634
  this.dispatch("UPDATE_CELL", {
43597
43635
  ...target,
@@ -44123,20 +44161,29 @@
44123
44161
  const sheetId = this.getters.getActiveSheetId();
44124
44162
  const cells = this.getters.getCells(sheetId);
44125
44163
  const matches = [];
44126
- if (this.toSearch) {
44164
+ if (this.toSearch && this.currentSearchRegex) {
44127
44165
  for (const cell of Object.values(cells)) {
44128
44166
  const { col, row } = this.getters.getCellPosition(cell.id);
44167
+ const cellPosition = { sheetId, col, row };
44129
44168
  const isColHidden = this.getters.isColHidden(sheetId, col);
44130
44169
  const isRowHidden = this.getters.isRowHidden(sheetId, row);
44131
44170
  if (isColHidden || isRowHidden) {
44132
44171
  continue;
44133
44172
  }
44134
- if (cell &&
44135
- this.currentSearchRegex &&
44136
- this.currentSearchRegex.test(this.getSearchableString({ sheetId, col, row }))) {
44173
+ if (this.currentSearchRegex.test(this.getSearchableString(cellPosition))) {
44137
44174
  const match = { col, row, selected: false };
44138
44175
  matches.push(match);
44139
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
+ }
44140
44187
  }
44141
44188
  }
44142
44189
  return matches.sort(this.sortByRowThenColumn);
@@ -44197,16 +44244,19 @@
44197
44244
  return;
44198
44245
  }
44199
44246
  const sheetId = this.getters.getActiveSheetId();
44200
- const cell = this.getters.getCell({ sheetId, ...selectedMatch });
44201
- const { col, row } = selectedMatch;
44247
+ const position = { sheetId, ...selectedMatch };
44248
+ const cell = this.getters.getCell(position);
44249
+ if (!cell?.content) {
44250
+ return;
44251
+ }
44202
44252
  if (cell?.isFormula && !this.searchOptions.searchFormulas) {
44203
44253
  return;
44204
44254
  }
44205
44255
  const replaceRegex = new RegExp(this.currentSearchRegex.source, this.currentSearchRegex.flags + "g");
44206
- const toReplace = this.getSearchableString({ sheetId, col, row });
44256
+ const toReplace = this.getSearchableString(position);
44207
44257
  const content = toReplace.replace(replaceRegex, replaceWith);
44208
44258
  const canonicalContent = canonicalizeNumberContent(content, this.getters.getLocale());
44209
- this.dispatch("UPDATE_CELL", { sheetId, col, row, content: canonicalContent });
44259
+ this.dispatch("UPDATE_CELL", { ...position, content: canonicalContent });
44210
44260
  }
44211
44261
  /**
44212
44262
  * Replace the value of the currently selected match
@@ -45535,7 +45585,6 @@
45535
45585
  }
45536
45586
 
45537
45587
  class SortPlugin extends UIPlugin {
45538
- static getters = ["getContiguousZone"];
45539
45588
  allowDispatch(cmd) {
45540
45589
  switch (cmd.type) {
45541
45590
  case "SORT_CELLS":
@@ -45583,143 +45632,6 @@
45583
45632
  }
45584
45633
  return "Success" /* CommandResult.Success */;
45585
45634
  }
45586
- // getContiguousZone helpers
45587
- /**
45588
- * safe-version of expandZone to make sure we don't get out of the grid
45589
- */
45590
- expand(sheetId, z) {
45591
- const { left, right, top, bottom } = this.getters.expandZone(sheetId, z);
45592
- return {
45593
- left: Math.max(0, left),
45594
- right: Math.min(this.getters.getNumberCols(sheetId) - 1, right),
45595
- top: Math.max(0, top),
45596
- bottom: Math.min(this.getters.getNumberRows(sheetId) - 1, bottom),
45597
- };
45598
- }
45599
- /**
45600
- * verifies the presence of at least one non-empty cell in the given zone
45601
- */
45602
- checkExpandedValues(sheetId, z) {
45603
- const expandedZone = this.expand(sheetId, z);
45604
- let cell;
45605
- if (this.getters.doesIntersectMerge(sheetId, expandedZone)) {
45606
- const { left, right, top, bottom } = expandedZone;
45607
- for (let c = left; c <= right; c++) {
45608
- for (let r = top; r <= bottom; r++) {
45609
- const { col, row } = this.getters.getMainCellPosition({ sheetId, col: c, row: r });
45610
- cell = this.getters.getEvaluatedCell({ sheetId, col, row });
45611
- if (cell.formattedValue) {
45612
- return true;
45613
- }
45614
- }
45615
- }
45616
- }
45617
- else {
45618
- for (let cell of this.getters.getEvaluatedCellsInZone(sheetId, expandedZone)) {
45619
- if (cell.formattedValue) {
45620
- return true;
45621
- }
45622
- }
45623
- }
45624
- return false;
45625
- }
45626
- /**
45627
- * This function will expand the provided zone in directions (top, bottom, left, right) for which there
45628
- * are non-null cells on the external boundary of the zone in the given direction.
45629
- *
45630
- * Example:
45631
- * A B C D E
45632
- * ___ ___ ___ ___ ___
45633
- * 1 | | D | | | |
45634
- * ___ ___ ___ ___ ___
45635
- * 2 | 5 | | 1 | D | |
45636
- * ___ ___ ___ ___ ___
45637
- * 3 | | | A | X | |
45638
- * ___ ___ ___ ___ ___
45639
- * 4 | | | | | |
45640
- * ___ ___ ___ ___ ___
45641
- *
45642
- * Let's consider a provided zone corresponding to (C2:D3) - (left:2, right: 3, top:1, bottom:2)
45643
- * - the top external boundary is (B1:E1)
45644
- * Since we have B1='D' != "", we expand to the top: => (C1:D3)
45645
- * The top boundary having reached the top of the grid, we cannot expand in that direction anymore
45646
- *
45647
- * - the left boundary is (B1:B4)
45648
- * since we have B1 again, we expand to the left => (B1:D3)
45649
- *
45650
- * - the right and bottom boundaries are a dead end for now as (E1:E4) and (A4:E4) are empty.
45651
- *
45652
- * - the left boundary is now (A1:A4)
45653
- * Since we have A2=5 != "", we can therefore expand to the left => (A1:D3)
45654
- *
45655
- * This will be the final zone as left and top have reached the boundaries of the grid and
45656
- * the other boundaries (E1:E4) and (A4:E4) are empty.
45657
- *
45658
- * @param sheetId UID of concerned sheet
45659
- * @param zone Zone
45660
- *
45661
- */
45662
- getContiguousZone(sheetId, zone) {
45663
- let { top, bottom, left, right } = zone;
45664
- let canExpand;
45665
- let stop = false;
45666
- while (!stop) {
45667
- stop = true;
45668
- /** top row external boundary */
45669
- if (top > 0) {
45670
- canExpand = this.checkExpandedValues(sheetId, {
45671
- left: left - 1,
45672
- right: right + 1,
45673
- top: top - 1,
45674
- bottom: top - 1,
45675
- });
45676
- if (canExpand) {
45677
- stop = false;
45678
- top--;
45679
- }
45680
- }
45681
- /** left column external boundary */
45682
- if (left > 0) {
45683
- canExpand = this.checkExpandedValues(sheetId, {
45684
- left: left - 1,
45685
- right: left - 1,
45686
- top: top - 1,
45687
- bottom: bottom + 1,
45688
- });
45689
- if (canExpand) {
45690
- stop = false;
45691
- left--;
45692
- }
45693
- }
45694
- /** right column external boundary */
45695
- if (right < this.getters.getNumberCols(sheetId) - 1) {
45696
- canExpand = this.checkExpandedValues(sheetId, {
45697
- left: right + 1,
45698
- right: right + 1,
45699
- top: top - 1,
45700
- bottom: bottom + 1,
45701
- });
45702
- if (canExpand) {
45703
- stop = false;
45704
- right++;
45705
- }
45706
- }
45707
- /** bottom row external boundary */
45708
- if (bottom < this.getters.getNumberRows(sheetId) - 1) {
45709
- canExpand = this.checkExpandedValues(sheetId, {
45710
- left: left - 1,
45711
- right: right + 1,
45712
- top: bottom + 1,
45713
- bottom: bottom + 1,
45714
- });
45715
- if (canExpand) {
45716
- stop = false;
45717
- bottom++;
45718
- }
45719
- }
45720
- }
45721
- return { left, right, top, bottom };
45722
- }
45723
45635
  /**
45724
45636
  * This function evaluates if the top row of a provided zone can be considered as a `header`
45725
45637
  * by checking the following criteria:
@@ -45784,7 +45696,7 @@
45784
45696
  if (cell.isFormula) {
45785
45697
  const position = this.getters.getCellPosition(cell.id);
45786
45698
  // we only have a vertical offset
45787
- 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);
45788
45700
  }
45789
45701
  newCellValues.style = cell.style;
45790
45702
  newCellValues.content = content;
@@ -45853,6 +45765,8 @@
45853
45765
  "getTextWidth",
45854
45766
  "getCellText",
45855
45767
  "getCellMultiLineText",
45768
+ "getContiguousZone",
45769
+ "isCellEmpty",
45856
45770
  ];
45857
45771
  ctx = document.createElement("canvas").getContext("2d");
45858
45772
  // ---------------------------------------------------------------------------
@@ -45942,9 +45856,52 @@
45942
45856
  const hasListIcon = !this.getters.isReadonly() && this.getters.cellHasListDataValidationIcon(position);
45943
45857
  return isFilterHeader || hasListIcon;
45944
45858
  }
45945
- // ---------------------------------------------------------------------------
45946
- // Grid manipulation
45947
- // ---------------------------------------------------------------------------
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
+ }
45948
45905
  getColMaxWidth(sheetId, index) {
45949
45906
  const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
45950
45907
  const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
@@ -47849,6 +47806,8 @@
47849
47806
  case "EVALUATE_CELLS":
47850
47807
  case "ACTIVATE_SHEET":
47851
47808
  case "REMOVE_FILTER_TABLE":
47809
+ case "ADD_COLUMNS_ROWS":
47810
+ case "REMOVE_COLUMNS_ROWS":
47852
47811
  this.isEvaluationDirty = true;
47853
47812
  break;
47854
47813
  case "START":
@@ -53367,7 +53326,7 @@
53367
53326
  scrollIntoView: false,
53368
53327
  });
53369
53328
  }
53370
- const tableZone = this.expandZoneToTable(anchor.zone);
53329
+ const tableZone = this.getters.getContiguousZone(sheetId, anchor.zone);
53371
53330
  return !deepEquals(tableZone, anchor.zone)
53372
53331
  ? this.modifyAnchor({ ...anchor, zone: tableZone }, "updateAnchor", {
53373
53332
  scrollIntoView: false,
@@ -53380,7 +53339,8 @@
53380
53339
  * cells bordering it
53381
53340
  */
53382
53341
  selectTableAroundSelection() {
53383
- const tableZone = this.expandZoneToTable(this.anchor.zone);
53342
+ const sheetId = this.getters.getActiveSheetId();
53343
+ const tableZone = this.getters.getContiguousZone(sheetId, this.anchor.zone);
53384
53344
  return this.modifyAnchor({ ...this.anchor, zone: tableZone }, "updateAnchor", {
53385
53345
  scrollIntoView: false,
53386
53346
  });
@@ -53557,11 +53517,12 @@
53557
53517
  * next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
53558
53518
  */
53559
53519
  getEndOfCluster(startPosition, dim, dir) {
53560
- const sheet = this.getters.getActiveSheet();
53520
+ const sheetId = this.getters.getActiveSheetId();
53561
53521
  let currentPosition = startPosition;
53562
53522
  // If both the current cell and the next cell are not empty, we want to go to the end of the cluster
53563
53523
  const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
53564
- 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 })
53565
53526
  ? "endOfCluster"
53566
53527
  : "nextCluster";
53567
53528
  while (true) {
@@ -53571,7 +53532,7 @@
53571
53532
  currentPosition.row === nextCellPosition.row) {
53572
53533
  break;
53573
53534
  }
53574
- const isNextCellEmpty = this.isCellEmpty(nextCellPosition, sheet.id);
53535
+ const isNextCellEmpty = this.getters.isCellEmpty({ ...nextCellPosition, sheetId });
53575
53536
  if (mode === "endOfCluster" && isNextCellEmpty) {
53576
53537
  break;
53577
53538
  }
@@ -53584,15 +53545,6 @@
53584
53545
  }
53585
53546
  return dim === "cols" ? currentPosition.col : currentPosition.row;
53586
53547
  }
53587
- /**
53588
- * Check if a cell is empty or undefined in the model. If the cell is part of a merge,
53589
- * check if the merge containing the cell is empty.
53590
- */
53591
- isCellEmpty({ col, row }, sheetId = this.getters.getActiveSheetId()) {
53592
- const position = this.getters.getMainCellPosition({ sheetId, col, row });
53593
- const cell = this.getters.getEvaluatedCell(position);
53594
- return cell.type === CellValueType.empty;
53595
- }
53596
53548
  /** Computes the next cell position in the given direction by crossing through merges and skipping hidden cells.
53597
53549
  *
53598
53550
  * This has the same behaviour as getNextAvailablePosition() for certain arguments, but use this method instead
@@ -53611,45 +53563,6 @@
53611
53563
  getPosition() {
53612
53564
  return { ...this.anchor.cell };
53613
53565
  }
53614
- /**
53615
- * Expand the given zone to a table.
53616
- * We define a table by the smallest zone that contain the anchor and that have only empty
53617
- * cells bordering it
53618
- */
53619
- expandZoneToTable(zoneToExpand) {
53620
- /** Try to expand the zone by one col/row in any direction to include a new non-empty cell */
53621
- const expandZone = (zone) => {
53622
- for (const col of range(zone.left, zone.right + 1)) {
53623
- if (!this.isCellEmpty({ col, row: zone.top - 1 })) {
53624
- return { ...zone, top: zone.top - 1 };
53625
- }
53626
- if (!this.isCellEmpty({ col, row: zone.bottom + 1 })) {
53627
- return { ...zone, bottom: zone.bottom + 1 };
53628
- }
53629
- }
53630
- for (const row of range(zone.top, zone.bottom + 1)) {
53631
- if (!this.isCellEmpty({ col: zone.left - 1, row })) {
53632
- return { ...zone, left: zone.left - 1 };
53633
- }
53634
- if (!this.isCellEmpty({ col: zone.right + 1, row })) {
53635
- return { ...zone, right: zone.right + 1 };
53636
- }
53637
- }
53638
- return zone;
53639
- };
53640
- let hasExpanded = false;
53641
- let zone = zoneToExpand;
53642
- do {
53643
- hasExpanded = false;
53644
- const newZone = expandZone(zone);
53645
- if (!isEqual(zone, newZone)) {
53646
- hasExpanded = true;
53647
- zone = newZone;
53648
- continue;
53649
- }
53650
- } while (hasExpanded);
53651
- return zone;
53652
- }
53653
53566
  }
53654
53567
 
53655
53568
  class StateObserver {
@@ -55872,6 +55785,7 @@
55872
55785
  exports.addFunction = addFunction;
55873
55786
  exports.astToFormula = astToFormula;
55874
55787
  exports.compile = compile;
55788
+ exports.compileTokens = compileTokens;
55875
55789
  exports.components = components;
55876
55790
  exports.constants = constants;
55877
55791
  exports.convertAstNodes = convertAstNodes;
@@ -55887,6 +55801,7 @@
55887
55801
  exports.links = links;
55888
55802
  exports.load = load;
55889
55803
  exports.parse = parse;
55804
+ exports.parseTokens = parseTokens;
55890
55805
  exports.readonlyAllowedCommands = readonlyAllowedCommands;
55891
55806
  exports.registries = registries;
55892
55807
  exports.setDefaultSheetViewSize = setDefaultSheetViewSize;
@@ -55894,9 +55809,9 @@
55894
55809
  exports.tokenize = tokenize;
55895
55810
 
55896
55811
 
55897
- __info__.version = "17.1.0-alpha.2";
55898
- __info__.date = "2023-11-03T12:24:57.341Z";
55899
- __info__.hash = "0595868";
55812
+ __info__.version = "17.1.0-alpha.3";
55813
+ __info__.date = "2023-11-16T12:04:09.636Z";
55814
+ __info__.hash = "2ef5b1a";
55900
55815
 
55901
55816
 
55902
55817
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);