@odoo/o-spreadsheet 16.1.20 → 16.1.23

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.
@@ -317,7 +317,16 @@ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY;
317
317
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
318
318
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
319
319
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
320
+ const CACHE = {};
320
321
  function parseDateTime(str) {
322
+ if (str in CACHE) {
323
+ return CACHE[str];
324
+ }
325
+ const date = _parseDateTime(str);
326
+ CACHE[str] = date;
327
+ return date;
328
+ }
329
+ function _parseDateTime(str) {
321
330
  str = str.trim();
322
331
  let time;
323
332
  const timeMatch = str.match(timeRegexp);
@@ -1002,13 +1011,17 @@ function getAddHeaderStartIndex(position, base) {
1002
1011
  return position === "after" ? base + 1 : base;
1003
1012
  }
1004
1013
  /**
1005
- * Compare two objects.
1014
+ * Compares two objects.
1006
1015
  */
1007
1016
  function deepEquals(o1, o2) {
1008
1017
  if (o1 === o2)
1009
1018
  return true;
1010
1019
  if ((o1 && !o2) || (o2 && !o1))
1011
1020
  return false;
1021
+ if (typeof o1 !== typeof o2)
1022
+ return false;
1023
+ if (typeof o1 !== "object")
1024
+ return o1 === o2;
1012
1025
  // Objects can have different keys if the values are undefined
1013
1026
  const keys = new Set();
1014
1027
  Object.keys(o1).forEach((key) => keys.add(key));
@@ -2117,8 +2130,9 @@ class RangeImpl {
2117
2130
  }
2118
2131
  get zone() {
2119
2132
  const { left, top, bottom, right } = this._zone;
2120
- if (right !== undefined && bottom !== undefined)
2121
- return { left, top, right, bottom };
2133
+ if (right !== undefined && bottom !== undefined) {
2134
+ return this._zone;
2135
+ }
2122
2136
  else if (bottom === undefined && right !== undefined) {
2123
2137
  return { right, top, left, bottom: this.getSheetSize(this.sheetId).height - 1 };
2124
2138
  }
@@ -3644,6 +3658,9 @@ var CommandResult;
3644
3658
  CommandResult[CommandResult["InvalidQuantity"] = 87] = "InvalidQuantity";
3645
3659
  })(CommandResult || (CommandResult = {}));
3646
3660
 
3661
+ function isMatrix(x) {
3662
+ return Array.isArray(x) && Array.isArray(x[0]);
3663
+ }
3647
3664
  var DIRECTION;
3648
3665
  (function (DIRECTION) {
3649
3666
  DIRECTION["UP"] = "up";
@@ -14113,6 +14130,36 @@ const HLOOKUP = {
14113
14130
  isExported: true,
14114
14131
  };
14115
14132
  // -----------------------------------------------------------------------------
14133
+ // INDEX
14134
+ // -----------------------------------------------------------------------------
14135
+ const INDEX = {
14136
+ description: _lt(`Returns the content of a cell, specified by row and column offset.`),
14137
+ args: args(`
14138
+ reference (any, range) ${_lt("The range of cells from which the value is returned.")}
14139
+ row (number) ${_lt("The index of the row to be returned from within the reference range of cells.")}
14140
+ column (number) ${_lt("The index of the column to be returned from within the reference range of cells.")}
14141
+ `),
14142
+ returns: ["ANY"],
14143
+ computeFormat: (reference, row, column) => {
14144
+ var _a;
14145
+ const _row = toNumber(row.value);
14146
+ const _column = toNumber(column.value);
14147
+ return (_a = reference[_column - 1][_row - 1]) === null || _a === void 0 ? void 0 : _a.format;
14148
+ },
14149
+ compute: function (reference, row, column) {
14150
+ const _reference = isMatrix(reference) ? reference : [[reference]];
14151
+ const _row = toNumber(row);
14152
+ const _column = toNumber(column);
14153
+ assert(() => _column >= 0 &&
14154
+ _column - 1 < _reference.length &&
14155
+ _row >= 0 &&
14156
+ _row - 1 < _reference[0].length, _lt("Index out of range."));
14157
+ assert(() => row !== 0 && column !== 0, _lt("This function can only return a single cell value, not an array. Provide valid row and column indices."));
14158
+ return _reference[_column - 1][_row - 1];
14159
+ },
14160
+ isExported: true,
14161
+ };
14162
+ // -----------------------------------------------------------------------------
14116
14163
  // LOOKUP
14117
14164
  // -----------------------------------------------------------------------------
14118
14165
  const LOOKUP = {
@@ -14306,6 +14353,7 @@ var lookup = /*#__PURE__*/Object.freeze({
14306
14353
  COLUMN: COLUMN,
14307
14354
  COLUMNS: COLUMNS,
14308
14355
  HLOOKUP: HLOOKUP,
14356
+ INDEX: INDEX,
14309
14357
  LOOKUP: LOOKUP,
14310
14358
  MATCH: MATCH,
14311
14359
  ROW: ROW,
@@ -18283,6 +18331,7 @@ css /* scss */ `
18283
18331
  padding: 10px;
18284
18332
  width: ${ERROR_TOOLTIP_WIDTH}px;
18285
18333
  box-sizing: border-box !important;
18334
+ overflow-wrap: break-word;
18286
18335
  }
18287
18336
  `;
18288
18337
  class ErrorToolTip extends Component {
@@ -18463,6 +18512,9 @@ class FilterMenu extends Component {
18463
18512
  });
18464
18513
  this.state.values = this.getFilterValues(this.props.filterPosition);
18465
18514
  }
18515
+ get isReadonly() {
18516
+ return this.env.model.getters.isReadonly();
18517
+ }
18466
18518
  getFilterValues(position) {
18467
18519
  const sheetId = this.env.model.getters.getActiveSheetId();
18468
18520
  const filter = this.env.model.getters.getFilter({ sheetId, ...position });
@@ -21725,9 +21777,9 @@ class FindAndReplacePanel extends Component {
21725
21777
  }
21726
21778
  setup() {
21727
21779
  this.showFormulaState = this.env.model.getters.shouldShowFormulas();
21728
- this.debouncedUpdateSearch = debounce(this.updateSearch.bind(this), 200);
21729
21780
  onMounted(() => this.focusInput());
21730
21781
  onWillUnmount(() => {
21782
+ clearTimeout(this.debounceTimeoutId);
21731
21783
  this.env.model.dispatch("CLEAR_SEARCH");
21732
21784
  this.env.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.showFormulaState });
21733
21785
  });
@@ -21772,6 +21824,13 @@ class FindAndReplacePanel extends Component {
21772
21824
  searchOptions: this.state.searchOptions,
21773
21825
  });
21774
21826
  }
21827
+ debouncedUpdateSearch() {
21828
+ clearTimeout(this.debounceTimeoutId);
21829
+ this.debounceTimeoutId = setTimeout(() => {
21830
+ this.updateSearch();
21831
+ this.debounceTimeoutId = undefined;
21832
+ }, 200);
21833
+ }
21775
21834
  replace() {
21776
21835
  this.env.model.dispatch("REPLACE_SEARCH", {
21777
21836
  replaceWith: this.state.replaceWith,
@@ -22422,9 +22481,11 @@ function useCellHovered(env, gridRef, callback) {
22422
22481
  }
22423
22482
  }
22424
22483
  function updateMousePosition(e) {
22425
- x = e.offsetX;
22426
- y = e.offsetY;
22427
- lastMoved = Date.now();
22484
+ if (gridRef.el === e.target) {
22485
+ x = e.offsetX;
22486
+ y = e.offsetY;
22487
+ lastMoved = Date.now();
22488
+ }
22428
22489
  }
22429
22490
  function recompute() {
22430
22491
  const { col, row } = getPosition();
@@ -22707,7 +22768,14 @@ class AbstractResizer extends Component {
22707
22768
  return;
22708
22769
  }
22709
22770
  if (this.state.waitingForMove === true) {
22710
- this.startMovement(ev);
22771
+ if (!this.env.model.getters.isGridSelectionActive()) {
22772
+ this._selectElement(index, false);
22773
+ }
22774
+ else {
22775
+ // FIXME: Consider reintroducing this feature for all type of selection if we find
22776
+ // a way to have the grid selection follow the other selections evolution
22777
+ this.startMovement(ev);
22778
+ }
22711
22779
  return;
22712
22780
  }
22713
22781
  if (this.env.model.getters.getEditionMode() === "editing") {
@@ -28541,10 +28609,11 @@ class CellPlugin extends CorePlugin {
28541
28609
  * Reconstructs the original formula string based on a normalized form and its dependencies
28542
28610
  */
28543
28611
  buildFormulaContent(sheetId, cell, dependencies) {
28544
- const ranges = dependencies || [...cell.dependencies];
28612
+ const ranges = dependencies || cell.dependencies;
28613
+ let rangeIndex = 0;
28545
28614
  return concat(cell.compiledFormula.tokens.map((token) => {
28546
28615
  if (token.type === "REFERENCE") {
28547
- const range = ranges.shift();
28616
+ const range = ranges[rangeIndex++];
28548
28617
  return this.getters.getRangeString(range, sheetId);
28549
28618
  }
28550
28619
  return token.value;
@@ -32619,6 +32688,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
32619
32688
  // stores the computed styles in the format of computedStyles.sheetName[col][row] = Style
32620
32689
  this.computedStyles = {};
32621
32690
  this.computedIcons = {};
32691
+ this.uuidGenerator = new UuidGenerator();
32622
32692
  /**
32623
32693
  * Execute the predicate to know if a conditional formatting rule should be applied to a cell
32624
32694
  */
@@ -32971,13 +33041,20 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
32971
33041
  this.adaptRules(origin.sheetId, cf, [xc], toRemoveRange);
32972
33042
  }
32973
33043
  else {
32974
- this.adaptRules(target.sheetId, cf, [xc], []);
32975
33044
  this.adaptRules(origin.sheetId, cf, [], toRemoveRange);
33045
+ const cfToCopyTo = this.getCFToCopyTo(target.sheetId, cf);
33046
+ this.adaptRules(target.sheetId, cfToCopyTo, [xc], []);
32976
33047
  }
32977
33048
  }
32978
33049
  }
32979
33050
  }
32980
33051
  }
33052
+ getCFToCopyTo(targetSheetId, originCF) {
33053
+ const cfInTarget = this.getters
33054
+ .getConditionalFormats(targetSheetId)
33055
+ .find((cf) => cf.stopIfTrue === originCF.stopIfTrue && deepEquals(cf.rule, originCF.rule));
33056
+ return cfInTarget ? cfInTarget : { ...originCF, id: this.uuidGenerator.uuidv4(), ranges: [] };
33057
+ }
32981
33058
  }
32982
33059
  EvaluationConditionalFormatPlugin.getters = ["getConditionalIcon", "getCellComputedStyle"];
32983
33060
 
@@ -33325,30 +33402,26 @@ class InternalViewport {
33325
33402
  const { end } = this.getters.getColDimensions(sheetId, targetCol);
33326
33403
  const maxCol = this.getters.getNumberCols(sheetId);
33327
33404
  if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
33328
- for (let col = this.left; this.offsetX + this.offsetCorrectionX + this.viewportWidth < end; col++) {
33329
- if (col > maxCol) {
33330
- break;
33331
- }
33332
- if (this.getters.isColHidden(sheetId, col)) {
33333
- continue;
33334
- }
33335
- this.offsetX = this.getters.getColDimensions(sheetId, col).end - this.offsetCorrectionX;
33336
- this.offsetScrollbarX = this.offsetX;
33337
- this.adjustViewportZoneX();
33405
+ let finalTarget = targetCol;
33406
+ while (this.getters.isColHidden(sheetId, finalTarget) && targetCol < maxCol) {
33407
+ finalTarget++;
33338
33408
  }
33409
+ const finalTargetEnd = this.getters.getColDimensions(sheetId, finalTarget).end;
33410
+ const startIndex = this.searchHeaderIndex("COL", finalTargetEnd - this.viewportWidth - this.offsetCorrectionX, this.boundaries.left, true);
33411
+ this.offsetX =
33412
+ this.getters.getColDimensions(sheetId, startIndex).end - this.offsetCorrectionX;
33413
+ this.offsetScrollbarX = this.offsetX;
33414
+ this.adjustViewportZoneX();
33339
33415
  }
33340
33416
  else if (this.left > targetCol) {
33341
- for (let col = this.left; col >= targetCol; col--) {
33342
- if (col < 0) {
33343
- break;
33344
- }
33345
- if (this.getters.isColHidden(sheetId, col)) {
33346
- continue;
33347
- }
33348
- this.offsetX = this.getters.getColDimensions(sheetId, col).start - this.offsetCorrectionX;
33349
- this.offsetScrollbarX = this.offsetX;
33350
- this.adjustViewportZoneX();
33417
+ let finalTarget = targetCol;
33418
+ while (this.getters.isColHidden(sheetId, finalTarget) && targetCol > 0) {
33419
+ finalTarget--;
33351
33420
  }
33421
+ this.offsetX =
33422
+ this.getters.getColDimensions(sheetId, finalTarget).start - this.offsetCorrectionX;
33423
+ this.offsetScrollbarX = this.offsetX;
33424
+ this.adjustViewportZoneX();
33352
33425
  }
33353
33426
  }
33354
33427
  adjustPositionY(targetRow) {
@@ -33356,30 +33429,26 @@ class InternalViewport {
33356
33429
  const { end } = this.getters.getRowDimensions(sheetId, targetRow);
33357
33430
  const maxRow = this.getters.getNumberRows(sheetId);
33358
33431
  if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
33359
- for (let row = this.top; this.offsetY + this.viewportHeight + this.offsetCorrectionY < end; row++) {
33360
- if (row > maxRow) {
33361
- break;
33362
- }
33363
- if (this.getters.isRowHidden(sheetId, row)) {
33364
- continue;
33365
- }
33366
- this.offsetY = this.getters.getRowDimensions(sheetId, row).end - this.offsetCorrectionY;
33367
- this.offsetScrollbarY = this.offsetY;
33368
- this.adjustViewportZoneY();
33432
+ let finalTarget = targetRow;
33433
+ while (this.getters.isRowHidden(sheetId, finalTarget) && targetRow < maxRow) {
33434
+ finalTarget++;
33369
33435
  }
33436
+ const finalTargetEnd = this.getters.getRowDimensions(sheetId, finalTarget).end;
33437
+ const startIndex = this.searchHeaderIndex("ROW", finalTargetEnd - this.viewportHeight - this.offsetCorrectionY, this.boundaries.top, true);
33438
+ this.offsetY =
33439
+ this.getters.getRowDimensions(sheetId, startIndex).end - this.offsetCorrectionY;
33440
+ this.offsetScrollbarY = this.offsetY;
33441
+ this.adjustViewportZoneY();
33370
33442
  }
33371
33443
  else if (this.top > targetRow) {
33372
- for (let row = this.top; row >= targetRow; row--) {
33373
- if (row < 0) {
33374
- break;
33375
- }
33376
- if (this.getters.isRowHidden(sheetId, row)) {
33377
- continue;
33378
- }
33379
- this.offsetY = this.getters.getRowDimensions(sheetId, row).start - this.offsetCorrectionY;
33380
- this.offsetScrollbarY = this.offsetY;
33381
- this.adjustViewportZoneY();
33444
+ let finalTarget = targetRow;
33445
+ while (this.getters.isRowHidden(sheetId, finalTarget) && targetRow > 0) {
33446
+ finalTarget--;
33382
33447
  }
33448
+ this.offsetY =
33449
+ this.getters.getRowDimensions(sheetId, finalTarget).start - this.offsetCorrectionY;
33450
+ this.offsetScrollbarY = this.offsetY;
33451
+ this.adjustViewportZoneY();
33383
33452
  }
33384
33453
  }
33385
33454
  setViewportOffset(offsetX, offsetY) {
@@ -34953,14 +35022,10 @@ class FindAndReplacePlugin extends UIPlugin {
34953
35022
  case "REPLACE_ALL_SEARCH":
34954
35023
  this.replaceAll(cmd.replaceWith);
34955
35024
  break;
34956
- case "EVALUATE_CELLS":
34957
- case "UPDATE_CELL":
34958
- case "REMOVE_FILTER_TABLE":
34959
- case "UPDATE_FILTER":
34960
- this.isSearchDirty = true;
34961
- break;
34962
35025
  case "UNDO":
34963
35026
  case "REDO":
35027
+ case "REMOVE_FILTER_TABLE":
35028
+ case "UPDATE_FILTER":
34964
35029
  case "REMOVE_COLUMNS_ROWS":
34965
35030
  case "HIDE_COLUMNS_ROWS":
34966
35031
  case "UNHIDE_COLUMNS_ROWS":
@@ -37952,7 +38017,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
37952
38017
  });
37953
38018
  for (const filterTable of this.copiedTables) {
37954
38019
  this.dispatch("REMOVE_FILTER_TABLE", {
37955
- sheetId: this.getters.getActiveSheetId(),
38020
+ sheetId: this.sheetId,
37956
38021
  target: [filterTable.zone],
37957
38022
  });
37958
38023
  }
@@ -38430,7 +38495,7 @@ class ClipboardPlugin extends UIPlugin {
38430
38495
  allowDispatch(cmd) {
38431
38496
  switch (cmd.type) {
38432
38497
  case "CUT":
38433
- const zones = cmd.target || this.getters.getSelectedZones();
38498
+ const zones = this.getters.getSelectedZones();
38434
38499
  const state = this.getClipboardState(zones, cmd.type);
38435
38500
  return state.isCutAllowed(zones);
38436
38501
  case "PASTE":
@@ -38461,7 +38526,7 @@ class ClipboardPlugin extends UIPlugin {
38461
38526
  switch (cmd.type) {
38462
38527
  case "COPY":
38463
38528
  case "CUT":
38464
- const zones = ("target" in cmd && cmd.target) || this.getters.getSelectedZones();
38529
+ const zones = this.getters.getSelectedZones();
38465
38530
  this.state = this.getClipboardState(zones, cmd.type);
38466
38531
  this.status = "visible";
38467
38532
  break;
@@ -38892,6 +38957,9 @@ class GridSelectionPlugin extends UIPlugin {
38892
38957
  // ---------------------------------------------------------------------------
38893
38958
  // Getters
38894
38959
  // ---------------------------------------------------------------------------
38960
+ isGridSelectionActive() {
38961
+ return this.selection.isListening(this);
38962
+ }
38895
38963
  getActiveSheet() {
38896
38964
  return this.activeSheet;
38897
38965
  }
@@ -39122,26 +39190,24 @@ class GridSelectionPlugin extends UIPlugin {
39122
39190
  const isBasedBefore = cmd.base < start;
39123
39191
  const deltaCol = isBasedBefore && isCol ? thickness : 0;
39124
39192
  const deltaRow = isBasedBefore && !isCol ? thickness : 0;
39125
- this.dispatch("CUT", {
39126
- target: [
39127
- {
39128
- left: isCol ? start + deltaCol : 0,
39129
- right: isCol ? end + deltaCol : this.getters.getNumberCols(cmd.sheetId) - 1,
39130
- top: !isCol ? start + deltaRow : 0,
39131
- bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
39132
- },
39133
- ],
39134
- });
39135
- this.dispatch("PASTE", {
39136
- target: [
39137
- {
39138
- left: isCol ? cmd.base : 0,
39139
- right: isCol ? cmd.base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
39140
- top: !isCol ? cmd.base : 0,
39141
- bottom: !isCol ? cmd.base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
39142
- },
39143
- ],
39144
- });
39193
+ const target = [
39194
+ {
39195
+ left: isCol ? start + deltaCol : 0,
39196
+ right: isCol ? end + deltaCol : this.getters.getNumberCols(cmd.sheetId) - 1,
39197
+ top: !isCol ? start + deltaRow : 0,
39198
+ bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
39199
+ },
39200
+ ];
39201
+ const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
39202
+ const pasteTarget = [
39203
+ {
39204
+ left: isCol ? cmd.base : 0,
39205
+ right: isCol ? cmd.base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
39206
+ top: !isCol ? cmd.base : 0,
39207
+ bottom: !isCol ? cmd.base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
39208
+ },
39209
+ ];
39210
+ state.paste(pasteTarget, { selectTarget: true });
39145
39211
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
39146
39212
  let currentIndex = cmd.base;
39147
39213
  for (const element of toRemove) {
@@ -39268,6 +39334,7 @@ GridSelectionPlugin.getters = [
39268
39334
  "getSheetPosition",
39269
39335
  "isSelected",
39270
39336
  "getElementsFromSelection",
39337
+ "isGridSelectionActive",
39271
39338
  ];
39272
39339
 
39273
39340
  const corePluginRegistry = new Registry()
@@ -42060,6 +42127,9 @@ class SelectionStreamProcessor {
42060
42127
  anchor: { zone, cell: this.anchor.cell },
42061
42128
  });
42062
42129
  }
42130
+ isListening(owner) {
42131
+ return this.stream.isListening(owner);
42132
+ }
42063
42133
  /**
42064
42134
  * Process a new anchor selection event. If the new anchor is inside
42065
42135
  * the sheet boundaries, the event is pushed to the event stream to
@@ -44318,6 +44388,6 @@ function addFunction(functionName, functionDescription) {
44318
44388
  export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, 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, setTranslationMethod, tokenize };
44319
44389
 
44320
44390
 
44321
- __info__.version = '16.1.20';
44322
- __info__.date = '2023-09-12T11:43:40.624Z';
44323
- __info__.hash = '7d7b841';
44391
+ __info__.version = '16.1.23';
44392
+ __info__.date = '2023-10-10T07:27:03.376Z';
44393
+ __info__.hash = '13bfa8f';