@odoo/o-spreadsheet 17.0.4 → 17.0.5

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.0.4
6
- * @date 2023-11-24T13:13:42.575Z
7
- * @hash 7346d0a
5
+ * @version 17.0.5
6
+ * @date 2023-12-05T09:51:44.657Z
7
+ * @hash 2480a5d
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -3388,8 +3388,10 @@
3388
3388
  const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
3389
3389
  // Same as above, but matches the exact string (nothing before or after)
3390
3390
  const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
3391
- /** Reference of a column header (eg. A, AB) */
3392
- const colHeader = new RegExp(/^([A-Z]{1,3})+$/, "i");
3391
+ /** Reference of a column header (eg. A, AB, $A) */
3392
+ const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
3393
+ /** Reference of a row header (eg. 1, $1) */
3394
+ const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
3393
3395
  /** Reference of a column (eg. A, $CA, Sheet1!B) */
3394
3396
  const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
3395
3397
  /** Reference of a row (eg. 1, 59, Sheet1!9) */
@@ -3419,6 +3421,9 @@
3419
3421
  function isColHeader(str) {
3420
3422
  return colHeader.test(str);
3421
3423
  }
3424
+ function isRowHeader(str) {
3425
+ return rowHeader.test(str);
3426
+ }
3422
3427
  /**
3423
3428
  * Return true if the given xc is the reference of a single cell,
3424
3429
  * without any specified sheet (e.g. A1)
@@ -4102,18 +4107,10 @@
4102
4107
  if (isFullCol) {
4103
4108
  parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
4104
4109
  parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
4105
- if (zone.left === zone.right) {
4106
- parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
4107
- parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
4108
- }
4109
4110
  }
4110
4111
  if (isFullRow) {
4111
4112
  parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
4112
4113
  parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
4113
- if (zone.top === zone.bottom) {
4114
- parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
4115
- parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
4116
- }
4117
4114
  }
4118
4115
  return parts;
4119
4116
  }
@@ -4355,7 +4352,7 @@
4355
4352
  function getDefaultCellHeight(ctx, cell, colSize) {
4356
4353
  if (!cell || !cell.content)
4357
4354
  return DEFAULT_CELL_HEIGHT;
4358
- const maxWidth = cell.style?.wrapping ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
4355
+ const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
4359
4356
  const numberOfLines = cell.isFormula
4360
4357
  ? 1
4361
4358
  : splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
@@ -6250,10 +6247,6 @@
6250
6247
 
6251
6248
  .o-error-tooltip-message {
6252
6249
  overflow: hidden;
6253
- display: -webkit-box; /* Limit to 3 lines */
6254
- -webkit-line-clamp: 3;
6255
- line-clamp: 3;
6256
- -webkit-box-orient: vertical;
6257
6250
  }
6258
6251
  }
6259
6252
  `;
@@ -6636,6 +6629,9 @@
6636
6629
  function getOpenedMenus() {
6637
6630
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
6638
6631
  }
6632
+ function isMacOS() {
6633
+ return navigator.userAgent.toUpperCase().indexOf("MAC") >= 0;
6634
+ }
6639
6635
 
6640
6636
  /**
6641
6637
  * Return the o-spreadsheet element position relative
@@ -28280,6 +28276,7 @@
28280
28276
  draggerShadowThickness: 0,
28281
28277
  delta: 0,
28282
28278
  base: 0,
28279
+ position: "before",
28283
28280
  });
28284
28281
  _computeHandleDisplay(ev) {
28285
28282
  const position = this._getEvOffset(ev);
@@ -28404,11 +28401,13 @@
28404
28401
  this.state.draggerLinePosition = dimensions.start;
28405
28402
  this.state.draggerShadowPosition = dimensions.start;
28406
28403
  this.state.base = elementIndex;
28404
+ this.state.position = "before";
28407
28405
  }
28408
28406
  else if (this._getSelectedZoneEnd() < elementIndex) {
28409
28407
  this.state.draggerLinePosition = dimensions.end;
28410
28408
  this.state.draggerShadowPosition = dimensions.end - this.state.draggerShadowThickness;
28411
- this.state.base = elementIndex + 1;
28409
+ this.state.base = elementIndex;
28410
+ this.state.position = "after";
28412
28411
  }
28413
28412
  else {
28414
28413
  this.state.draggerLinePosition = startDimensions.start;
@@ -28590,6 +28589,7 @@
28590
28589
  dimension: "COL",
28591
28590
  base: this.state.base,
28592
28591
  elements,
28592
+ position: this.state.position,
28593
28593
  });
28594
28594
  if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
28595
28595
  this.env.raiseError(MergeErrorMessage);
@@ -28763,6 +28763,7 @@
28763
28763
  dimension: "ROW",
28764
28764
  base: this.state.base,
28765
28765
  elements,
28766
+ position: this.state.position,
28766
28767
  });
28767
28768
  if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
28768
28769
  this.env.raiseError(MergeErrorMessage);
@@ -28870,8 +28871,8 @@
28870
28871
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
28871
28872
  }
28872
28873
  const onMouseWheel = (ev) => {
28873
- const deltaX = normalize(ev.shiftKey ? ev.deltaY : ev.deltaX, ev.deltaMode);
28874
- const deltaY = normalize(ev.shiftKey ? ev.deltaX : ev.deltaY, ev.deltaMode);
28874
+ const deltaX = normalize(ev.shiftKey && !isMacOS() ? ev.deltaY : ev.deltaX, ev.deltaMode);
28875
+ const deltaY = normalize(ev.shiftKey && !isMacOS() ? ev.deltaX : ev.deltaY, ev.deltaMode);
28875
28876
  handler(deltaX, deltaY);
28876
28877
  };
28877
28878
  return onMouseWheel;
@@ -33325,7 +33326,7 @@
33325
33326
  SPACE: goTo(State.RightRef),
33326
33327
  NUMBER: goTo(State.Found),
33327
33328
  REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
33328
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
33329
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
33329
33330
  },
33330
33331
  [State.RightColumnRef]: {
33331
33332
  SPACE: goTo(State.RightColumnRef),
@@ -33336,6 +33337,7 @@
33336
33337
  SPACE: goTo(State.RightRowRef),
33337
33338
  NUMBER: goTo(State.Found),
33338
33339
  REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
33340
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
33339
33341
  },
33340
33342
  [State.Found]: {},
33341
33343
  };
@@ -37317,7 +37319,16 @@
37317
37319
  return consecutiveIndexes;
37318
37320
  }
37319
37321
  getAllVisibleHeaders(sheetId, dimension) {
37320
- return range(0, this.hiddenHeaders[sheetId][dimension].length).filter((i) => !this.hiddenHeaders[sheetId][dimension][i]);
37322
+ const headers = range(0, this.getters.getNumberHeaders(sheetId, dimension));
37323
+ const foldedHeaders = [];
37324
+ this.getters.getHeaderGroups(sheetId, dimension).forEach((group) => {
37325
+ if (group.isFolded) {
37326
+ foldedHeaders.push(...range(group.start, group.end + 1));
37327
+ }
37328
+ });
37329
+ return headers.filter((i) => {
37330
+ return !this.hiddenHeaders[sheetId][dimension][i] && !foldedHeaders.includes(i);
37331
+ });
37321
37332
  }
37322
37333
  import(data) {
37323
37334
  for (let sheet of data.sheets) {
@@ -39777,10 +39788,13 @@
39777
39788
  if (evaluatedCell === undefined) {
39778
39789
  return { value: null, format: this.getters.getCell(position)?.format };
39779
39790
  }
39791
+ if (evaluatedCell.type === CellValueType.error) {
39792
+ throw evaluatedCell.error;
39793
+ }
39780
39794
  return evaluatedCell;
39781
39795
  }
39782
39796
  getEvaluatedCellIfNotEmpty(position) {
39783
- const evaluatedCell = this.getEvaluatedCell(position);
39797
+ const evaluatedCell = this.computeCell(position);
39784
39798
  if (evaluatedCell.type === CellValueType.empty) {
39785
39799
  const cell = this.getters.getCell(position);
39786
39800
  if (!cell || (!cell.isFormula && cell.content === "")) {
@@ -39789,13 +39803,6 @@
39789
39803
  }
39790
39804
  return evaluatedCell;
39791
39805
  }
39792
- getEvaluatedCell(position) {
39793
- const evaluatedCell = this.computeCell(position);
39794
- if (evaluatedCell.type === CellValueType.error) {
39795
- throw evaluatedCell.error;
39796
- }
39797
- return evaluatedCell;
39798
- }
39799
39806
  /**
39800
39807
  * Return the values of the cell(s) used in reference, but always in the format of a range even
39801
39808
  * if a single cell is referenced. It is a list of col values. This is useful for the formulas that describe parameters as
@@ -39818,7 +39825,11 @@
39818
39825
  const { top, left, bottom, right } = zone;
39819
39826
  const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
39820
39827
  if (cacheKey in this.rangeCache) {
39821
- return this.rangeCache[cacheKey];
39828
+ const result = this.rangeCache[cacheKey];
39829
+ if (result instanceof EvaluationError) {
39830
+ throw result;
39831
+ }
39832
+ return result;
39822
39833
  }
39823
39834
  const height = _zone.bottom - _zone.top + 1;
39824
39835
  const width = _zone.right - _zone.left + 1;
@@ -39828,6 +39839,11 @@
39828
39839
  const colIndex = col - _zone.left;
39829
39840
  matrix[colIndex] = new Array(height);
39830
39841
  for (let row = _zone.top; row <= _zone.bottom; row++) {
39842
+ const evaluatedCell = this.getEvaluatedCellIfNotEmpty({ sheetId, col, row });
39843
+ if (evaluatedCell?.type === CellValueType.error) {
39844
+ this.rangeCache[cacheKey] = evaluatedCell.error;
39845
+ throw evaluatedCell.error;
39846
+ }
39831
39847
  const rowIndex = row - _zone.top;
39832
39848
  matrix[colIndex][rowIndex] = this.readCell({ sheetId, col, row });
39833
39849
  }
@@ -41785,19 +41801,21 @@
41785
41801
  let col = zone.left;
41786
41802
  let row = zone.bottom;
41787
41803
  if (col > 0) {
41788
- let left = this.getters.getEvaluatedCell({ sheetId, col: col - 1, row });
41789
- while (left.type !== CellValueType.empty) {
41804
+ let leftPosition = { sheetId, col: col - 1, row };
41805
+ while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty ||
41806
+ this.getters.getCell(leftPosition)?.content) {
41790
41807
  row += 1;
41791
- left = this.getters.getEvaluatedCell({ sheetId, col: col - 1, row });
41808
+ leftPosition = { sheetId, col: col - 1, row };
41792
41809
  }
41793
41810
  }
41794
41811
  if (row === zone.bottom) {
41795
41812
  col = zone.right;
41796
41813
  if (col <= this.getters.getNumberCols(sheetId)) {
41797
- let right = this.getters.getEvaluatedCell({ sheetId, col: col + 1, row });
41798
- while (right.type !== CellValueType.empty) {
41814
+ let rightPosition = { sheetId, col: col + 1, row };
41815
+ while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty ||
41816
+ this.getters.getCell(rightPosition)?.content) {
41799
41817
  row += 1;
41800
- right = this.getters.getEvaluatedCell({ sheetId, col: col + 1, row });
41818
+ rightPosition = { sheetId, col: col + 1, row };
41801
41819
  }
41802
41820
  }
41803
41821
  }
@@ -42789,6 +42807,7 @@
42789
42807
  isReplayingInitialRevisions = false;
42790
42808
  processedRevisions = new Set();
42791
42809
  uuidGenerator = new UuidGenerator();
42810
+ lastLocalOperation;
42792
42811
  /**
42793
42812
  * Manages the collaboration between multiple users on the same spreadsheet.
42794
42813
  * It can forward local state changes to other users to ensure they all eventually
@@ -42821,6 +42840,11 @@
42821
42840
  return;
42822
42841
  const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes, Date.now());
42823
42842
  this.revisions.append(revision.id, revision);
42843
+ // REQUEST_REDO just repeats the last operation, the
42844
+ // last operation is still the same and should not change.
42845
+ if (rootCommand.type !== "REQUEST_REDO") {
42846
+ this.lastLocalOperation = revision;
42847
+ }
42824
42848
  this.trigger("new-local-state-update", { id: revision.id });
42825
42849
  this.sendUpdateMessage({
42826
42850
  type: "REMOTE_REVISION",
@@ -42917,19 +42941,10 @@
42917
42941
  return this.pendingMessages.length === 0;
42918
42942
  }
42919
42943
  /**
42920
- * Get the last local revision whose root command isn't in the given list of ignored commands
42944
+ * Get the last local revision
42921
42945
  * */
42922
- getLastLocalNonEmptyRevision(ignoredRootCommands) {
42923
- const revisions = this.revisions.getRevertedExecution();
42924
- for (const rev of revisions) {
42925
- if (rev.rootCommand === "SNAPSHOT")
42926
- return undefined;
42927
- if (!rev.rootCommand || rev.rootCommand === "REMOTE")
42928
- continue;
42929
- if (!ignoredRootCommands.includes(rev.rootCommand?.type) && rev.commands.length)
42930
- return rev;
42931
- }
42932
- return undefined;
42946
+ getLastLocalNonEmptyRevision() {
42947
+ return this.lastLocalOperation;
42933
42948
  }
42934
42949
  _move(position) {
42935
42950
  // this method is debounced and might be called after the client
@@ -42989,7 +43004,7 @@
42989
43004
  break;
42990
43005
  case "REMOTE_REVISION":
42991
43006
  const { clientId, commands, timestamp } = message;
42992
- const revision = new Revision(message.nextRevisionId, clientId, commands, "REMOTE", undefined, timestamp);
43007
+ const revision = new Revision(message.nextRevisionId, clientId, commands, undefined, undefined, timestamp);
42993
43008
  if (revision.clientId !== this.clientId) {
42994
43009
  this.revisions.insert(revision.id, revision, message.serverRevisionId);
42995
43010
  const pendingCommands = this.pendingMessages
@@ -43002,10 +43017,11 @@
43002
43017
  }
43003
43018
  break;
43004
43019
  case "SNAPSHOT_CREATED": {
43005
- const revision = new Revision(message.nextRevisionId, "server", [], "SNAPSHOT", undefined, Date.now());
43020
+ const revision = new Revision(message.nextRevisionId, "server", [], undefined, undefined, Date.now());
43006
43021
  this.revisions.insert(revision.id, revision, message.serverRevisionId);
43007
43022
  this.dropPendingHistoryMessages();
43008
43023
  this.trigger("snapshot");
43024
+ this.lastLocalOperation = undefined;
43009
43025
  break;
43010
43026
  }
43011
43027
  }
@@ -45560,6 +45576,9 @@
45560
45576
  // Other
45561
45577
  // ---------------------------------------------------------------------------
45562
45578
  initInput(id, initialRanges, inputHasSingleRange = false) {
45579
+ if (this.inputs[id]) {
45580
+ this.unfocus();
45581
+ }
45563
45582
  this.inputs[id] = new SelectionInputPlugin(this.config, initialRanges, inputHasSingleRange);
45564
45583
  if (initialRanges.length === 0) {
45565
45584
  const input = this.inputs[id];
@@ -46358,7 +46377,7 @@
46358
46377
  * Ignore standard undo/redo revisions (that are empty)
46359
46378
  */
46360
46379
  getPossibleRevisionToRepeat() {
46361
- return this.session.getLastLocalNonEmptyRevision(["REQUEST_REDO"]);
46380
+ return this.session.getLastLocalNonEmptyRevision();
46362
46381
  }
46363
46382
  }
46364
46383
 
@@ -47143,6 +47162,10 @@
47143
47162
  return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
47144
47163
  case "colrow":
47145
47164
  indexOfNumber = xc.search(/[0-9]/);
47165
+ if (indexOfNumber === -1 || indexOfNumber === 0) {
47166
+ // no row number (eg. A) or no column (eg. 1)
47167
+ return "$" + xc;
47168
+ }
47146
47169
  xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
47147
47170
  return "$" + xc;
47148
47171
  case "none":
@@ -47913,6 +47936,12 @@
47913
47936
  break;
47914
47937
  case "HIDE_COLUMNS_ROWS":
47915
47938
  case "UNHIDE_COLUMNS_ROWS":
47939
+ case "GROUP_HEADERS":
47940
+ case "UNGROUP_HEADERS":
47941
+ case "FOLD_HEADER_GROUP":
47942
+ case "UNFOLD_HEADER_GROUP":
47943
+ case "FOLD_ALL_HEADER_GROUPS":
47944
+ case "UNFOLD_ALL_HEADER_GROUPS":
47916
47945
  this.updateHiddenRows();
47917
47946
  break;
47918
47947
  case "UPDATE_FILTER":
@@ -48614,7 +48643,7 @@
48614
48643
  sheetId: cmd.sheetId,
48615
48644
  base: cmd.base,
48616
48645
  quantity: thickness,
48617
- position: "before",
48646
+ position: cmd.position,
48618
48647
  });
48619
48648
  const isCol = cmd.dimension === "COL";
48620
48649
  const start = cmd.elements[0];
@@ -48631,12 +48660,13 @@
48631
48660
  },
48632
48661
  ];
48633
48662
  const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
48663
+ const base = isBasedBefore ? cmd.base : cmd.base + 1;
48634
48664
  const pasteTarget = [
48635
48665
  {
48636
- left: isCol ? cmd.base : 0,
48637
- right: isCol ? cmd.base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
48638
- top: !isCol ? cmd.base : 0,
48639
- bottom: !isCol ? cmd.base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
48666
+ left: isCol ? base : 0,
48667
+ right: isCol ? base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
48668
+ top: !isCol ? base : 0,
48669
+ bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
48640
48670
  },
48641
48671
  ];
48642
48672
  state.paste(pasteTarget, { selectTarget: true });
@@ -48671,6 +48701,11 @@
48671
48701
  doesElementsHaveCommonMerges(id, cmd.base - 1, cmd.base)) {
48672
48702
  return "WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */;
48673
48703
  }
48704
+ const headers = [cmd.base, ...cmd.elements];
48705
+ const maxHeaderValue = isCol ? this.getters.getNumberCols(id) : this.getters.getNumberRows(id);
48706
+ if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
48707
+ return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
48708
+ }
48674
48709
  return "Success" /* CommandResult.Success */;
48675
48710
  }
48676
48711
  //-------------------------------------------
@@ -49716,10 +49751,13 @@
49716
49751
  }
49717
49752
  break;
49718
49753
  case "UPDATE_CELL":
49719
- if ("content" in cmd || "format" in cmd || cmd.style?.fontSize !== undefined) {
49754
+ if ("content" in cmd || "format" in cmd) {
49720
49755
  this.headerPositions = {};
49721
49756
  this.isDirty = true;
49722
49757
  }
49758
+ else {
49759
+ this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
49760
+ }
49723
49761
  break;
49724
49762
  case "UPDATE_FILTER":
49725
49763
  case "REMOVE_FILTER_TABLE":
@@ -51876,6 +51914,8 @@
51876
51914
  *:before,
51877
51915
  *:after {
51878
51916
  box-sizing: content-box;
51917
+ /** rtl not supported ATM */
51918
+ direction: ltr;
51879
51919
  }
51880
51920
  .o-separator {
51881
51921
  border-bottom: ${MENU_SEPARATOR_BORDER_WIDTH}px solid ${SEPARATOR_COLOR};
@@ -55948,9 +55988,9 @@
55948
55988
  exports.tokenize = tokenize;
55949
55989
 
55950
55990
 
55951
- __info__.version = "17.0.4";
55952
- __info__.date = "2023-11-24T13:13:42.575Z";
55953
- __info__.hash = "7346d0a";
55991
+ __info__.version = "17.0.5";
55992
+ __info__.date = "2023-12-05T09:51:44.657Z";
55993
+ __info__.hash = "2480a5d";
55954
55994
 
55955
55995
 
55956
55996
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);