@odoo/o-spreadsheet 16.3.12 → 16.3.14

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.
@@ -314,7 +314,16 @@ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY;
314
314
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
315
315
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
316
316
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
317
+ const CACHE = {};
317
318
  function parseDateTime(str) {
319
+ if (str in CACHE) {
320
+ return CACHE[str];
321
+ }
322
+ const date = _parseDateTime(str);
323
+ CACHE[str] = date;
324
+ return date;
325
+ }
326
+ function _parseDateTime(str) {
318
327
  str = str.trim();
319
328
  let time;
320
329
  const timeMatch = str.match(timeRegexp);
@@ -2251,8 +2260,9 @@ class RangeImpl {
2251
2260
  }
2252
2261
  get zone() {
2253
2262
  const { left, top, bottom, right } = this._zone;
2254
- if (right !== undefined && bottom !== undefined)
2255
- return { left, top, right, bottom };
2263
+ if (right !== undefined && bottom !== undefined) {
2264
+ return this._zone;
2265
+ }
2256
2266
  else if (bottom === undefined && right !== undefined) {
2257
2267
  return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
2258
2268
  }
@@ -4423,6 +4433,9 @@ exports.CommandResult = void 0;
4423
4433
  })(exports.CommandResult || (exports.CommandResult = {}));
4424
4434
 
4425
4435
  const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
4436
+ function isMatrix(x) {
4437
+ return Array.isArray(x) && Array.isArray(x[0]);
4438
+ }
4426
4439
  var DIRECTION;
4427
4440
  (function (DIRECTION) {
4428
4441
  DIRECTION["UP"] = "up";
@@ -15348,6 +15361,35 @@ const HLOOKUP = {
15348
15361
  isExported: true,
15349
15362
  };
15350
15363
  // -----------------------------------------------------------------------------
15364
+ // INDEX
15365
+ // -----------------------------------------------------------------------------
15366
+ const INDEX = {
15367
+ description: _lt(`Returns the content of a cell, specified by row and column offset.`),
15368
+ args: [
15369
+ arg("reference (any, range)", _lt("The range of cells from which the values are returned.")),
15370
+ arg("row (number)", _lt("The index of the row to be returned from within the reference range of cells.")),
15371
+ arg("column (number)", _lt("The index of the column to be returned from within the reference range of cells.")),
15372
+ ],
15373
+ returns: ["ANY"],
15374
+ computeFormat: (reference, row, column) => {
15375
+ const _row = toNumber(row.value);
15376
+ const _column = toNumber(column.value);
15377
+ return reference[_column - 1][_row - 1]?.format;
15378
+ },
15379
+ compute: function (reference, row, column) {
15380
+ const _reference = isMatrix(reference) ? reference : [[reference]];
15381
+ const _row = toNumber(row);
15382
+ const _column = toNumber(column);
15383
+ assert(() => _column >= 0 &&
15384
+ _column - 1 < _reference.length &&
15385
+ _row >= 0 &&
15386
+ _row - 1 < _reference[0].length, _lt("Index out of range."));
15387
+ assert(() => row !== 0 && column !== 0, _lt("This function can only return a single cell value, not an array. Provide valid row and column indices."));
15388
+ return _reference[_column - 1][_row - 1];
15389
+ },
15390
+ isExported: true,
15391
+ };
15392
+ // -----------------------------------------------------------------------------
15351
15393
  // LOOKUP
15352
15394
  // -----------------------------------------------------------------------------
15353
15395
  const LOOKUP = {
@@ -15542,6 +15584,7 @@ var lookup = /*#__PURE__*/Object.freeze({
15542
15584
  COLUMN: COLUMN,
15543
15585
  COLUMNS: COLUMNS,
15544
15586
  HLOOKUP: HLOOKUP,
15587
+ INDEX: INDEX,
15545
15588
  LOOKUP: LOOKUP,
15546
15589
  MATCH: MATCH,
15547
15590
  ROW: ROW,
@@ -22517,7 +22560,14 @@ class AbstractResizer extends owl.Component {
22517
22560
  return;
22518
22561
  }
22519
22562
  if (this.state.waitingForMove === true) {
22520
- this.startMovement(ev);
22563
+ if (!this.env.model.getters.isGridSelectionActive()) {
22564
+ this._selectElement(index, false);
22565
+ }
22566
+ else {
22567
+ // FIXME: Consider reintroducing this feature for all type of selection if we find
22568
+ // a way to have the grid selection follow the other selections evolution
22569
+ this.startMovement(ev);
22570
+ }
22521
22571
  return;
22522
22572
  }
22523
22573
  if (this.env.model.getters.getEditionMode() === "editing") {
@@ -26972,12 +27022,15 @@ function createXMLFile(doc, path, contentType) {
26972
27022
  };
26973
27023
  }
26974
27024
  function xmlEscape(str) {
26975
- return String(str)
27025
+ return (String(str)
26976
27026
  .replace(/\&/g, "&amp;")
26977
27027
  .replace(/\</g, "&lt;")
26978
27028
  .replace(/\>/g, "&gt;")
26979
27029
  .replace(/\"/g, "&quot;")
26980
- .replace(/\'/g, "&apos;");
27030
+ .replace(/\'/g, "&apos;")
27031
+ // Delete all ASCII control characters except for TAB (\x09), LF (\x0A) and CR (\x0D)
27032
+ // They are not valid at all in XML 1.0 (even escaped)
27033
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, ""));
26981
27034
  }
26982
27035
  function formatAttributes(attrs) {
26983
27036
  return new XMLString(attrs.map(([key, val]) => `${key}="${xmlEscape(val)}"`).join(" "));
@@ -29642,10 +29695,11 @@ class CellPlugin extends CorePlugin {
29642
29695
  * Reconstructs the original formula string based on a normalized form and its dependencies
29643
29696
  */
29644
29697
  buildFormulaContent(sheetId, cell, dependencies) {
29645
- const ranges = dependencies || [...cell.dependencies];
29698
+ const ranges = dependencies || cell.dependencies;
29699
+ let rangeIndex = 0;
29646
29700
  return concat(cell.compiledFormula.tokens.map((token) => {
29647
29701
  if (token.type === "REFERENCE") {
29648
- const range = ranges.shift();
29702
+ const range = ranges[rangeIndex++];
29649
29703
  return this.getters.getRangeString(range, sheetId);
29650
29704
  }
29651
29705
  return token.value;
@@ -34066,6 +34120,10 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
34066
34120
  }
34067
34121
  currentRanges = currentRanges.concat(toAdd);
34068
34122
  const newRangesXC = recomputeZones(currentRanges, toRemove);
34123
+ if (newRangesXC.length === 0) {
34124
+ this.dispatch("REMOVE_CONDITIONAL_FORMAT", { id: cf.id, sheetId });
34125
+ return;
34126
+ }
34069
34127
  this.dispatch("ADD_CONDITIONAL_FORMAT", {
34070
34128
  cf: {
34071
34129
  id: cf.id,
@@ -41197,6 +41255,7 @@ class GridSelectionPlugin extends UIPlugin {
41197
41255
  "isSingleColSelected",
41198
41256
  "getElementsFromSelection",
41199
41257
  "tryGetActiveSheetId",
41258
+ "isGridSelectionActive",
41200
41259
  ];
41201
41260
  gridSelection = {
41202
41261
  anchor: {
@@ -41406,6 +41465,9 @@ class GridSelectionPlugin extends UIPlugin {
41406
41465
  // ---------------------------------------------------------------------------
41407
41466
  // Getters
41408
41467
  // ---------------------------------------------------------------------------
41468
+ isGridSelectionActive() {
41469
+ return this.selection.isListening(this);
41470
+ }
41409
41471
  getActiveSheet() {
41410
41472
  return this.activeSheet;
41411
41473
  }
@@ -45261,6 +45323,9 @@ class SelectionStreamProcessorImpl {
45261
45323
  anchor: { zone, cell: this.anchor.cell },
45262
45324
  });
45263
45325
  }
45326
+ isListening(owner) {
45327
+ return this.stream.isListening(owner);
45328
+ }
45264
45329
  /**
45265
45330
  * Process a new anchor selection event. If the new anchor is inside
45266
45331
  * the sheet boundaries, the event is pushed to the event stream to
@@ -47721,6 +47786,6 @@ exports.setTranslationMethod = setTranslationMethod;
47721
47786
  exports.tokenize = tokenize;
47722
47787
 
47723
47788
 
47724
- __info__.version = '16.3.12';
47725
- __info__.date = '2023-10-03T12:43:02.230Z';
47726
- __info__.hash = '70a91d9';
47789
+ __info__.version = '16.3.14';
47790
+ __info__.date = '2023-10-19T14:21:33.996Z';
47791
+ __info__.hash = '7b90b3d';
@@ -958,7 +958,7 @@ declare class RangeImpl implements Range {
958
958
  constructor(args: ConstructorArgs, getSheetSize: (sheetId: UID) => ZoneDimension);
959
959
  static fromRange(range: Range, getters: CoreGetters): RangeImpl;
960
960
  get unboundedZone(): UnboundedZone;
961
- get zone(): Zone;
961
+ get zone(): Readonly<Zone>;
962
962
  static getRangeParts(xc: string, zone: UnboundedZone): RangePart[];
963
963
  get isFullCol(): boolean;
964
964
  get isFullRow(): boolean;
@@ -1056,6 +1056,7 @@ interface SelectionProcessor {
1056
1056
  selectAll(): DispatchResult;
1057
1057
  loopSelection(): DispatchResult;
1058
1058
  selectTableAroundSelection(): DispatchResult;
1059
+ isListening(owner: unknown): boolean;
1059
1060
  }
1060
1061
  type SelectionStreamProcessor = SelectionProcessor & StatefulStream<SelectionEvent, AnchorZone>;
1061
1062
 
@@ -4664,7 +4665,7 @@ declare class ClipboardPlugin extends UIPlugin {
4664
4665
  */
4665
4666
  declare class GridSelectionPlugin extends UIPlugin {
4666
4667
  static layers: LAYERS[];
4667
- static getters: readonly ["getActiveSheet", "getActiveSheetId", "getActiveCell", "getActiveCols", "getActiveRows", "getCurrentStyle", "getSelectedZones", "getSelectedZone", "getSelectedCells", "getStatisticFnResults", "getAggregate", "getSelectedFigureId", "getSelection", "getActivePosition", "getSheetPosition", "isSelected", "isSingleColSelected", "getElementsFromSelection", "tryGetActiveSheetId"];
4668
+ static getters: readonly ["getActiveSheet", "getActiveSheetId", "getActiveCell", "getActiveCols", "getActiveRows", "getCurrentStyle", "getSelectedZones", "getSelectedZone", "getSelectedCells", "getStatisticFnResults", "getAggregate", "getSelectedFigureId", "getSelection", "getActivePosition", "getSheetPosition", "isSelected", "isSingleColSelected", "getElementsFromSelection", "tryGetActiveSheetId", "isGridSelectionActive"];
4668
4669
  private gridSelection;
4669
4670
  private selectedFigureId;
4670
4671
  private sheetsData;
@@ -4674,6 +4675,7 @@ declare class GridSelectionPlugin extends UIPlugin {
4674
4675
  allowDispatch(cmd: LocalCommand): CommandResult;
4675
4676
  private handleEvent;
4676
4677
  handle(cmd: Command): void;
4678
+ isGridSelectionActive(): boolean;
4677
4679
  getActiveSheet(): Readonly<Sheet>;
4678
4680
  getActiveSheetId(): UID;
4679
4681
  tryGetActiveSheetId(): UID | undefined;
@@ -310,7 +310,16 @@ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY;
310
310
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
311
311
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
312
312
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
313
+ const CACHE = {};
313
314
  function parseDateTime(str) {
315
+ if (str in CACHE) {
316
+ return CACHE[str];
317
+ }
318
+ const date = _parseDateTime(str);
319
+ CACHE[str] = date;
320
+ return date;
321
+ }
322
+ function _parseDateTime(str) {
314
323
  str = str.trim();
315
324
  let time;
316
325
  const timeMatch = str.match(timeRegexp);
@@ -2247,8 +2256,9 @@ class RangeImpl {
2247
2256
  }
2248
2257
  get zone() {
2249
2258
  const { left, top, bottom, right } = this._zone;
2250
- if (right !== undefined && bottom !== undefined)
2251
- return { left, top, right, bottom };
2259
+ if (right !== undefined && bottom !== undefined) {
2260
+ return this._zone;
2261
+ }
2252
2262
  else if (bottom === undefined && right !== undefined) {
2253
2263
  return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
2254
2264
  }
@@ -4419,6 +4429,9 @@ var CommandResult;
4419
4429
  })(CommandResult || (CommandResult = {}));
4420
4430
 
4421
4431
  const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
4432
+ function isMatrix(x) {
4433
+ return Array.isArray(x) && Array.isArray(x[0]);
4434
+ }
4422
4435
  var DIRECTION;
4423
4436
  (function (DIRECTION) {
4424
4437
  DIRECTION["UP"] = "up";
@@ -15344,6 +15357,35 @@ const HLOOKUP = {
15344
15357
  isExported: true,
15345
15358
  };
15346
15359
  // -----------------------------------------------------------------------------
15360
+ // INDEX
15361
+ // -----------------------------------------------------------------------------
15362
+ const INDEX = {
15363
+ description: _lt(`Returns the content of a cell, specified by row and column offset.`),
15364
+ args: [
15365
+ arg("reference (any, range)", _lt("The range of cells from which the values are returned.")),
15366
+ arg("row (number)", _lt("The index of the row to be returned from within the reference range of cells.")),
15367
+ arg("column (number)", _lt("The index of the column to be returned from within the reference range of cells.")),
15368
+ ],
15369
+ returns: ["ANY"],
15370
+ computeFormat: (reference, row, column) => {
15371
+ const _row = toNumber(row.value);
15372
+ const _column = toNumber(column.value);
15373
+ return reference[_column - 1][_row - 1]?.format;
15374
+ },
15375
+ compute: function (reference, row, column) {
15376
+ const _reference = isMatrix(reference) ? reference : [[reference]];
15377
+ const _row = toNumber(row);
15378
+ const _column = toNumber(column);
15379
+ assert(() => _column >= 0 &&
15380
+ _column - 1 < _reference.length &&
15381
+ _row >= 0 &&
15382
+ _row - 1 < _reference[0].length, _lt("Index out of range."));
15383
+ assert(() => row !== 0 && column !== 0, _lt("This function can only return a single cell value, not an array. Provide valid row and column indices."));
15384
+ return _reference[_column - 1][_row - 1];
15385
+ },
15386
+ isExported: true,
15387
+ };
15388
+ // -----------------------------------------------------------------------------
15347
15389
  // LOOKUP
15348
15390
  // -----------------------------------------------------------------------------
15349
15391
  const LOOKUP = {
@@ -15538,6 +15580,7 @@ var lookup = /*#__PURE__*/Object.freeze({
15538
15580
  COLUMN: COLUMN,
15539
15581
  COLUMNS: COLUMNS,
15540
15582
  HLOOKUP: HLOOKUP,
15583
+ INDEX: INDEX,
15541
15584
  LOOKUP: LOOKUP,
15542
15585
  MATCH: MATCH,
15543
15586
  ROW: ROW,
@@ -22513,7 +22556,14 @@ class AbstractResizer extends Component {
22513
22556
  return;
22514
22557
  }
22515
22558
  if (this.state.waitingForMove === true) {
22516
- this.startMovement(ev);
22559
+ if (!this.env.model.getters.isGridSelectionActive()) {
22560
+ this._selectElement(index, false);
22561
+ }
22562
+ else {
22563
+ // FIXME: Consider reintroducing this feature for all type of selection if we find
22564
+ // a way to have the grid selection follow the other selections evolution
22565
+ this.startMovement(ev);
22566
+ }
22517
22567
  return;
22518
22568
  }
22519
22569
  if (this.env.model.getters.getEditionMode() === "editing") {
@@ -26968,12 +27018,15 @@ function createXMLFile(doc, path, contentType) {
26968
27018
  };
26969
27019
  }
26970
27020
  function xmlEscape(str) {
26971
- return String(str)
27021
+ return (String(str)
26972
27022
  .replace(/\&/g, "&amp;")
26973
27023
  .replace(/\</g, "&lt;")
26974
27024
  .replace(/\>/g, "&gt;")
26975
27025
  .replace(/\"/g, "&quot;")
26976
- .replace(/\'/g, "&apos;");
27026
+ .replace(/\'/g, "&apos;")
27027
+ // Delete all ASCII control characters except for TAB (\x09), LF (\x0A) and CR (\x0D)
27028
+ // They are not valid at all in XML 1.0 (even escaped)
27029
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, ""));
26977
27030
  }
26978
27031
  function formatAttributes(attrs) {
26979
27032
  return new XMLString(attrs.map(([key, val]) => `${key}="${xmlEscape(val)}"`).join(" "));
@@ -29638,10 +29691,11 @@ class CellPlugin extends CorePlugin {
29638
29691
  * Reconstructs the original formula string based on a normalized form and its dependencies
29639
29692
  */
29640
29693
  buildFormulaContent(sheetId, cell, dependencies) {
29641
- const ranges = dependencies || [...cell.dependencies];
29694
+ const ranges = dependencies || cell.dependencies;
29695
+ let rangeIndex = 0;
29642
29696
  return concat(cell.compiledFormula.tokens.map((token) => {
29643
29697
  if (token.type === "REFERENCE") {
29644
- const range = ranges.shift();
29698
+ const range = ranges[rangeIndex++];
29645
29699
  return this.getters.getRangeString(range, sheetId);
29646
29700
  }
29647
29701
  return token.value;
@@ -34062,6 +34116,10 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
34062
34116
  }
34063
34117
  currentRanges = currentRanges.concat(toAdd);
34064
34118
  const newRangesXC = recomputeZones(currentRanges, toRemove);
34119
+ if (newRangesXC.length === 0) {
34120
+ this.dispatch("REMOVE_CONDITIONAL_FORMAT", { id: cf.id, sheetId });
34121
+ return;
34122
+ }
34065
34123
  this.dispatch("ADD_CONDITIONAL_FORMAT", {
34066
34124
  cf: {
34067
34125
  id: cf.id,
@@ -41193,6 +41251,7 @@ class GridSelectionPlugin extends UIPlugin {
41193
41251
  "isSingleColSelected",
41194
41252
  "getElementsFromSelection",
41195
41253
  "tryGetActiveSheetId",
41254
+ "isGridSelectionActive",
41196
41255
  ];
41197
41256
  gridSelection = {
41198
41257
  anchor: {
@@ -41402,6 +41461,9 @@ class GridSelectionPlugin extends UIPlugin {
41402
41461
  // ---------------------------------------------------------------------------
41403
41462
  // Getters
41404
41463
  // ---------------------------------------------------------------------------
41464
+ isGridSelectionActive() {
41465
+ return this.selection.isListening(this);
41466
+ }
41405
41467
  getActiveSheet() {
41406
41468
  return this.activeSheet;
41407
41469
  }
@@ -45257,6 +45319,9 @@ class SelectionStreamProcessorImpl {
45257
45319
  anchor: { zone, cell: this.anchor.cell },
45258
45320
  });
45259
45321
  }
45322
+ isListening(owner) {
45323
+ return this.stream.isListening(owner);
45324
+ }
45260
45325
  /**
45261
45326
  * Process a new anchor selection event. If the new anchor is inside
45262
45327
  * the sheet boundaries, the event is pushed to the event stream to
@@ -47689,6 +47754,6 @@ function addFunction(functionName, functionDescription) {
47689
47754
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
47690
47755
 
47691
47756
 
47692
- __info__.version = '16.3.12';
47693
- __info__.date = '2023-10-03T12:43:02.230Z';
47694
- __info__.hash = '70a91d9';
47757
+ __info__.version = '16.3.14';
47758
+ __info__.date = '2023-10-19T14:21:33.996Z';
47759
+ __info__.hash = '7b90b3d';
@@ -311,7 +311,16 @@
311
311
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
312
312
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
313
313
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
314
+ const CACHE = {};
314
315
  function parseDateTime(str) {
316
+ if (str in CACHE) {
317
+ return CACHE[str];
318
+ }
319
+ const date = _parseDateTime(str);
320
+ CACHE[str] = date;
321
+ return date;
322
+ }
323
+ function _parseDateTime(str) {
315
324
  str = str.trim();
316
325
  let time;
317
326
  const timeMatch = str.match(timeRegexp);
@@ -2248,8 +2257,9 @@
2248
2257
  }
2249
2258
  get zone() {
2250
2259
  const { left, top, bottom, right } = this._zone;
2251
- if (right !== undefined && bottom !== undefined)
2252
- return { left, top, right, bottom };
2260
+ if (right !== undefined && bottom !== undefined) {
2261
+ return this._zone;
2262
+ }
2253
2263
  else if (bottom === undefined && right !== undefined) {
2254
2264
  return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
2255
2265
  }
@@ -4420,6 +4430,9 @@
4420
4430
  })(exports.CommandResult || (exports.CommandResult = {}));
4421
4431
 
4422
4432
  const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
4433
+ function isMatrix(x) {
4434
+ return Array.isArray(x) && Array.isArray(x[0]);
4435
+ }
4423
4436
  var DIRECTION;
4424
4437
  (function (DIRECTION) {
4425
4438
  DIRECTION["UP"] = "up";
@@ -15345,6 +15358,35 @@
15345
15358
  isExported: true,
15346
15359
  };
15347
15360
  // -----------------------------------------------------------------------------
15361
+ // INDEX
15362
+ // -----------------------------------------------------------------------------
15363
+ const INDEX = {
15364
+ description: _lt(`Returns the content of a cell, specified by row and column offset.`),
15365
+ args: [
15366
+ arg("reference (any, range)", _lt("The range of cells from which the values are returned.")),
15367
+ arg("row (number)", _lt("The index of the row to be returned from within the reference range of cells.")),
15368
+ arg("column (number)", _lt("The index of the column to be returned from within the reference range of cells.")),
15369
+ ],
15370
+ returns: ["ANY"],
15371
+ computeFormat: (reference, row, column) => {
15372
+ const _row = toNumber(row.value);
15373
+ const _column = toNumber(column.value);
15374
+ return reference[_column - 1][_row - 1]?.format;
15375
+ },
15376
+ compute: function (reference, row, column) {
15377
+ const _reference = isMatrix(reference) ? reference : [[reference]];
15378
+ const _row = toNumber(row);
15379
+ const _column = toNumber(column);
15380
+ assert(() => _column >= 0 &&
15381
+ _column - 1 < _reference.length &&
15382
+ _row >= 0 &&
15383
+ _row - 1 < _reference[0].length, _lt("Index out of range."));
15384
+ assert(() => row !== 0 && column !== 0, _lt("This function can only return a single cell value, not an array. Provide valid row and column indices."));
15385
+ return _reference[_column - 1][_row - 1];
15386
+ },
15387
+ isExported: true,
15388
+ };
15389
+ // -----------------------------------------------------------------------------
15348
15390
  // LOOKUP
15349
15391
  // -----------------------------------------------------------------------------
15350
15392
  const LOOKUP = {
@@ -15539,6 +15581,7 @@
15539
15581
  COLUMN: COLUMN,
15540
15582
  COLUMNS: COLUMNS,
15541
15583
  HLOOKUP: HLOOKUP,
15584
+ INDEX: INDEX,
15542
15585
  LOOKUP: LOOKUP,
15543
15586
  MATCH: MATCH,
15544
15587
  ROW: ROW,
@@ -22514,7 +22557,14 @@
22514
22557
  return;
22515
22558
  }
22516
22559
  if (this.state.waitingForMove === true) {
22517
- this.startMovement(ev);
22560
+ if (!this.env.model.getters.isGridSelectionActive()) {
22561
+ this._selectElement(index, false);
22562
+ }
22563
+ else {
22564
+ // FIXME: Consider reintroducing this feature for all type of selection if we find
22565
+ // a way to have the grid selection follow the other selections evolution
22566
+ this.startMovement(ev);
22567
+ }
22518
22568
  return;
22519
22569
  }
22520
22570
  if (this.env.model.getters.getEditionMode() === "editing") {
@@ -26969,12 +27019,15 @@
26969
27019
  };
26970
27020
  }
26971
27021
  function xmlEscape(str) {
26972
- return String(str)
27022
+ return (String(str)
26973
27023
  .replace(/\&/g, "&amp;")
26974
27024
  .replace(/\</g, "&lt;")
26975
27025
  .replace(/\>/g, "&gt;")
26976
27026
  .replace(/\"/g, "&quot;")
26977
- .replace(/\'/g, "&apos;");
27027
+ .replace(/\'/g, "&apos;")
27028
+ // Delete all ASCII control characters except for TAB (\x09), LF (\x0A) and CR (\x0D)
27029
+ // They are not valid at all in XML 1.0 (even escaped)
27030
+ .replace(/[\x00-\x08\x0B\x0C\x0E-\x1F]/g, ""));
26978
27031
  }
26979
27032
  function formatAttributes(attrs) {
26980
27033
  return new XMLString(attrs.map(([key, val]) => `${key}="${xmlEscape(val)}"`).join(" "));
@@ -29639,10 +29692,11 @@
29639
29692
  * Reconstructs the original formula string based on a normalized form and its dependencies
29640
29693
  */
29641
29694
  buildFormulaContent(sheetId, cell, dependencies) {
29642
- const ranges = dependencies || [...cell.dependencies];
29695
+ const ranges = dependencies || cell.dependencies;
29696
+ let rangeIndex = 0;
29643
29697
  return concat(cell.compiledFormula.tokens.map((token) => {
29644
29698
  if (token.type === "REFERENCE") {
29645
- const range = ranges.shift();
29699
+ const range = ranges[rangeIndex++];
29646
29700
  return this.getters.getRangeString(range, sheetId);
29647
29701
  }
29648
29702
  return token.value;
@@ -34063,6 +34117,10 @@
34063
34117
  }
34064
34118
  currentRanges = currentRanges.concat(toAdd);
34065
34119
  const newRangesXC = recomputeZones(currentRanges, toRemove);
34120
+ if (newRangesXC.length === 0) {
34121
+ this.dispatch("REMOVE_CONDITIONAL_FORMAT", { id: cf.id, sheetId });
34122
+ return;
34123
+ }
34066
34124
  this.dispatch("ADD_CONDITIONAL_FORMAT", {
34067
34125
  cf: {
34068
34126
  id: cf.id,
@@ -41194,6 +41252,7 @@
41194
41252
  "isSingleColSelected",
41195
41253
  "getElementsFromSelection",
41196
41254
  "tryGetActiveSheetId",
41255
+ "isGridSelectionActive",
41197
41256
  ];
41198
41257
  gridSelection = {
41199
41258
  anchor: {
@@ -41403,6 +41462,9 @@
41403
41462
  // ---------------------------------------------------------------------------
41404
41463
  // Getters
41405
41464
  // ---------------------------------------------------------------------------
41465
+ isGridSelectionActive() {
41466
+ return this.selection.isListening(this);
41467
+ }
41406
41468
  getActiveSheet() {
41407
41469
  return this.activeSheet;
41408
41470
  }
@@ -45258,6 +45320,9 @@
45258
45320
  anchor: { zone, cell: this.anchor.cell },
45259
45321
  });
45260
45322
  }
45323
+ isListening(owner) {
45324
+ return this.stream.isListening(owner);
45325
+ }
45261
45326
  /**
45262
45327
  * Process a new anchor selection event. If the new anchor is inside
45263
45328
  * the sheet boundaries, the event is pushed to the event stream to
@@ -47720,9 +47785,9 @@
47720
47785
  Object.defineProperty(exports, '__esModule', { value: true });
47721
47786
 
47722
47787
 
47723
- __info__.version = '16.3.12';
47724
- __info__.date = '2023-10-03T12:43:02.230Z';
47725
- __info__.hash = '70a91d9';
47788
+ __info__.version = '16.3.14';
47789
+ __info__.date = '2023-10-19T14:21:33.996Z';
47790
+ __info__.hash = '7b90b3d';
47726
47791
 
47727
47792
 
47728
47793
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);