@odoo/o-spreadsheet 16.2.29 → 16.2.31

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.
@@ -1692,6 +1692,9 @@
1692
1692
  function formatValue(value, format) {
1693
1693
  switch (typeof value) {
1694
1694
  case "string":
1695
+ if (value.includes('\\"')) {
1696
+ return value.replace(/\\"/g, '"');
1697
+ }
1695
1698
  return value;
1696
1699
  case "boolean":
1697
1700
  return value ? "TRUE" : "FALSE";
@@ -6272,14 +6275,8 @@
6272
6275
  : undefined));
6273
6276
  }
6274
6277
  }
6275
- else if (zone.left === zone.right && zone.top === zone.bottom) {
6276
- // A single cell. If it's only the title, the dataset is not added.
6277
- if (!dataSetsHaveTitle) {
6278
- dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
6279
- }
6280
- }
6281
6278
  else {
6282
- /* 1 row or 1 column */
6279
+ /* 1 cell, 1 row or 1 column */
6283
6280
  dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
6284
6281
  ? {
6285
6282
  top: zone.top,
@@ -6329,8 +6326,10 @@
6329
6326
  }
6330
6327
  const dataRange = ds.dataRange.clone({ zone: dataZone });
6331
6328
  return {
6332
- label: ds.labelCell ? getters.getRangeString(ds.labelCell, "forceSheetReference") : undefined,
6333
- range: getters.getRangeString(dataRange, "forceSheetReference"),
6329
+ label: ds.labelCell
6330
+ ? getters.getRangeString(ds.labelCell, "forceSheetReference", true)
6331
+ : undefined,
6332
+ range: getters.getRangeString(dataRange, "forceSheetReference", true),
6334
6333
  };
6335
6334
  }
6336
6335
  /**
@@ -6855,6 +6854,9 @@
6855
6854
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
6856
6855
  return {
6857
6856
  ...this.getDefinition(),
6857
+ labelRange: this.labelRange
6858
+ ? this.getters.getRangeString(this.labelRange, this.sheetId, true)
6859
+ : undefined,
6858
6860
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
6859
6861
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
6860
6862
  dataSets,
@@ -7419,6 +7421,9 @@
7419
7421
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
7420
7422
  return {
7421
7423
  ...this.getDefinition(),
7424
+ labelRange: this.labelRange
7425
+ ? this.getters.getRangeString(this.labelRange, this.sheetId, true)
7426
+ : undefined,
7422
7427
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
7423
7428
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
7424
7429
  dataSets,
@@ -7692,6 +7697,9 @@
7692
7697
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
7693
7698
  return {
7694
7699
  ...this.getDefinition(),
7700
+ labelRange: this.labelRange
7701
+ ? this.getters.getRangeString(this.labelRange, this.sheetId, true)
7702
+ : undefined,
7695
7703
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
7696
7704
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
7697
7705
  verticalAxisPosition: "left",
@@ -9135,6 +9143,12 @@
9135
9143
  let { col, row } = env.model.getters.getActivePosition();
9136
9144
  env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
9137
9145
  };
9146
+ const INSERT_LINK_NAME = (env) => {
9147
+ const sheetId = env.model.getters.getActiveSheetId();
9148
+ const { col, row } = env.model.getters.getActivePosition();
9149
+ const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
9150
+ return cell && cell.link ? _lt("Edit link") : _lt("Insert link");
9151
+ };
9138
9152
  //------------------------------------------------------------------------------
9139
9153
  // Filters action
9140
9154
  //------------------------------------------------------------------------------
@@ -9272,7 +9286,7 @@
9272
9286
  action: DELETE_CELL_SHIFT_LEFT,
9273
9287
  })
9274
9288
  .add("insert_link", {
9275
- name: _lt("Insert link"),
9289
+ name: INSERT_LINK_NAME,
9276
9290
  separator: true,
9277
9291
  sequence: 150,
9278
9292
  action: INSERT_LINK,
@@ -19958,14 +19972,13 @@
19958
19972
  setup() {
19959
19973
  owl.onMounted(() => {
19960
19974
  const el = this.composerRef.el;
19975
+ if (this.props.isDefaultFocus) {
19976
+ this.env.focusableElement.setFocusableElement(el);
19977
+ }
19961
19978
  this.contentHelper.updateEl(el);
19962
19979
  this.processContent();
19963
19980
  this.contentHelper.scrollSelectionIntoView();
19964
19981
  });
19965
- owl.onWillUnmount(() => {
19966
- var _a, _b;
19967
- (_b = (_a = this.props).onComposerUnmounted) === null || _b === void 0 ? void 0 : _b.call(_a);
19968
- });
19969
19982
  owl.onPatched(() => {
19970
19983
  if (!this.isKeyStillDown) {
19971
19984
  this.processContent();
@@ -19976,7 +19989,8 @@
19976
19989
  // Handlers
19977
19990
  // ---------------------------------------------------------------------------
19978
19991
  processArrowKeys(ev) {
19979
- if (this.env.model.getters.isSelectingForComposer()) {
19992
+ if (this.env.model.getters.isSelectingForComposer() ||
19993
+ this.env.model.getters.getEditionMode() === "inactive") {
19980
19994
  this.functionDescriptionState.showDescription = false;
19981
19995
  // Prevent the default content editable behavior which moves the cursor
19982
19996
  ev.preventDefault();
@@ -20017,21 +20031,23 @@
20017
20031
  var _a;
20018
20032
  ev.preventDefault();
20019
20033
  ev.stopPropagation();
20020
- if (this.autoCompleteState.showProvider) {
20021
- const autoCompleteValue = (_a = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]) === null || _a === void 0 ? void 0 : _a.text;
20022
- if (autoCompleteValue) {
20023
- this.autoComplete(autoCompleteValue);
20024
- return;
20034
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
20035
+ if (this.autoCompleteState.showProvider) {
20036
+ const autoCompleteValue = (_a = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]) === null || _a === void 0 ? void 0 : _a.text;
20037
+ if (autoCompleteValue) {
20038
+ this.autoComplete(autoCompleteValue);
20039
+ return;
20040
+ }
20025
20041
  }
20026
- }
20027
- else {
20028
- // when completing with tab, if there is no value to complete, the active cell will be moved to the right.
20029
- // we can't let the model think that it is for a ref selection.
20030
- // todo: check if this can be removed someday
20031
- this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
20042
+ else {
20043
+ // when completing with tab, if there is no value to complete, the active cell will be moved to the right.
20044
+ // we can't let the model think that it is for a ref selection.
20045
+ // todo: check if this can be removed someday
20046
+ this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
20047
+ }
20048
+ this.env.model.dispatch("STOP_EDITION");
20032
20049
  }
20033
20050
  const direction = ev.shiftKey ? "left" : "right";
20034
- this.env.model.dispatch("STOP_EDITION");
20035
20051
  this.env.model.selection.moveAnchorCell(direction, 1);
20036
20052
  }
20037
20053
  processEnterKey(ev) {
@@ -20076,6 +20092,9 @@
20076
20092
  this.compositionActive = false;
20077
20093
  }
20078
20094
  onKeydown(ev) {
20095
+ if (this.env.model.getters.getEditionMode() === "inactive") {
20096
+ return;
20097
+ }
20079
20098
  let handler = this.keyMapping[ev.key];
20080
20099
  if (handler) {
20081
20100
  handler.call(this, ev);
@@ -20086,22 +20105,45 @@
20086
20105
  }
20087
20106
  }
20088
20107
  updateCursorIfNeeded() {
20089
- if (!this.env.model.getters.isSelectingForComposer()) {
20108
+ const moveCursor = !this.env.model.getters.isSelectingForComposer() &&
20109
+ !(this.env.model.getters.getEditionMode() === "inactive");
20110
+ if (moveCursor) {
20090
20111
  const { start, end } = this.contentHelper.getCurrentSelection();
20091
20112
  this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
20092
20113
  this.isKeyStillDown = true;
20093
20114
  }
20094
20115
  }
20116
+ onPaste(ev) {
20117
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
20118
+ ev.stopPropagation();
20119
+ }
20120
+ }
20095
20121
  /*
20096
20122
  * Triggered automatically by the content-editable between the keydown and key up
20097
20123
  * */
20098
- onInput() {
20099
- if (this.props.focus === "inactive" || !this.shouldProcessInputEvents) {
20124
+ onInput(ev) {
20125
+ var _a, _b;
20126
+ if (!this.shouldProcessInputEvents) {
20127
+ return;
20128
+ }
20129
+ if (ev.inputType === "insertFromPaste" &&
20130
+ this.env.model.getters.getEditionMode() === "inactive") {
20100
20131
  return;
20101
20132
  }
20133
+ ev.stopPropagation();
20134
+ let content;
20135
+ if (this.env.model.getters.getEditionMode() === "inactive") {
20136
+ content = ev.data || "";
20137
+ }
20138
+ else {
20139
+ content = this.contentHelper.getText();
20140
+ }
20141
+ if (this.props.focus === "inactive") {
20142
+ return (_b = (_a = this.props).onComposerCellFocused) === null || _b === void 0 ? void 0 : _b.call(_a, content);
20143
+ }
20102
20144
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
20103
20145
  this.env.model.dispatch("SET_CURRENT_CONTENT", {
20104
- content: this.contentHelper.getText(),
20146
+ content,
20105
20147
  selection: this.contentHelper.getCurrentSelection(),
20106
20148
  });
20107
20149
  }
@@ -20172,9 +20214,8 @@
20172
20214
  }
20173
20215
  const newSelection = this.contentHelper.getCurrentSelection();
20174
20216
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
20175
- if (this.props.focus === "inactive") {
20176
- this.props.onComposerContentFocused(newSelection);
20177
- }
20217
+ this.props.onComposerContentFocused();
20218
+ if (this.props.focus === "inactive") ;
20178
20219
  this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
20179
20220
  this.processTokenAtCursor();
20180
20221
  }
@@ -20398,14 +20439,16 @@
20398
20439
  Composer.components = { TextValueProvider, FunctionDescriptionProvider };
20399
20440
  Composer.defaultProps = {
20400
20441
  inputStyle: "",
20442
+ isDefaultFocus: false,
20401
20443
  };
20402
20444
  Composer.props = {
20403
- focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
20404
- onComposerContentFocused: Function,
20405
20445
  inputStyle: { type: String, optional: true },
20406
20446
  rect: { type: Object, optional: true },
20407
20447
  delimitation: { type: Object, optional: true },
20408
- onComposerUnmounted: { type: Function, optional: true },
20448
+ focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
20449
+ onComposerCellFocused: { type: Function, optional: true },
20450
+ onComposerContentFocused: Function,
20451
+ isDefaultFocus: { type: Boolean, optional: true },
20409
20452
  };
20410
20453
 
20411
20454
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
@@ -20437,46 +20480,28 @@
20437
20480
  * It also applies the style of the cell to the composer input.
20438
20481
  */
20439
20482
  class GridComposer extends owl.Component {
20483
+ constructor() {
20484
+ super(...arguments);
20485
+ // TODORAR see if we can keep it undefined
20486
+ this.rect = this.defaultRect;
20487
+ this.isEditing = false;
20488
+ }
20489
+ get defaultRect() {
20490
+ return { x: 0, y: 0, width: 0, height: 0 };
20491
+ }
20440
20492
  setup() {
20441
- this.gridComposerRef = owl.useRef("gridComposer");
20442
- this.composerState = owl.useState({
20443
- rect: undefined,
20444
- delimitation: undefined,
20445
- });
20446
- const { sheetId, col, row } = this.env.model.getters.getActivePosition();
20447
- this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
20448
- this.rect = this.env.model.getters.getVisibleRect(this.zone);
20449
- this.isCellReferenceVisible = false;
20450
- owl.onMounted(() => {
20451
- const el = this.gridComposerRef.el;
20452
- this.composerState.rect = {
20453
- x: this.rect.x,
20454
- y: this.rect.y,
20455
- width: el.clientWidth,
20456
- height: el.clientHeight,
20457
- };
20458
- this.composerState.delimitation = {
20459
- width: el.parentElement.clientWidth,
20460
- height: el.parentElement.clientHeight,
20461
- };
20462
- });
20463
20493
  owl.onWillUpdateProps(() => {
20464
- if (this.isCellReferenceVisible) {
20465
- return;
20466
- }
20467
- const sheetId = this.env.model.getters.getActiveSheetId();
20468
- const zone = this.env.model.getters.getSelectedZone();
20469
- const rect = this.env.model.getters.getVisibleRect(zone);
20470
- if (!deepEquals(rect, this.rect) ||
20471
- sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
20472
- this.isCellReferenceVisible = true;
20473
- }
20494
+ this.updateComponentPosition();
20495
+ this.updateCellReferenceVisibility();
20474
20496
  });
20475
20497
  }
20476
20498
  get shouldDisplayCellReference() {
20477
20499
  return this.isCellReferenceVisible;
20478
20500
  }
20479
20501
  get cellReference() {
20502
+ if (!this.env.model.getters.getCurrentEditedCell()) {
20503
+ return "";
20504
+ }
20480
20505
  const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
20481
20506
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
20482
20507
  return `${prefixSheet ? getComposerSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
@@ -20488,7 +20513,27 @@
20488
20513
  top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
20489
20514
  });
20490
20515
  }
20516
+ get composerProps() {
20517
+ const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
20518
+ return {
20519
+ rect: { ...this.rect },
20520
+ delimitation: {
20521
+ width,
20522
+ height,
20523
+ },
20524
+ focus: this.props.focus,
20525
+ isDefaultFocus: true,
20526
+ onComposerContentFocused: this.props.onComposerContentFocused,
20527
+ onComposerCellFocused: this.props.onComposerCellFocused,
20528
+ };
20529
+ }
20491
20530
  get containerStyle() {
20531
+ if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
20532
+ return `
20533
+ position: absolute;
20534
+ z-index: -1000;
20535
+ `;
20536
+ }
20492
20537
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
20493
20538
  const cell = this.env.model.getters.getActiveCell();
20494
20539
  const position = this.env.model.getters.getActivePosition();
@@ -20508,6 +20553,8 @@
20508
20553
  if (!isFormula) {
20509
20554
  textAlign = style.align || cell.defaultAlign;
20510
20555
  }
20556
+ const maxHeight = this.props.gridDims.height - this.rect.y;
20557
+ const maxWidth = this.props.gridDims.width - this.rect.x;
20511
20558
  /**
20512
20559
  * min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
20513
20560
  * including all the paddings/margins of the composer
@@ -20519,6 +20566,8 @@
20519
20566
  top: `${top}px`,
20520
20567
  "min-width": `${width + 1}px`,
20521
20568
  "min-height": `${height + 1}px`,
20569
+ "max-width": `${maxWidth}px`,
20570
+ "max-height": `${maxHeight}px`,
20522
20571
  background,
20523
20572
  color,
20524
20573
  "font-size": `${fontSizeInPixels(fontSize)}px`,
@@ -20528,22 +20577,40 @@
20528
20577
  "text-align": textAlign,
20529
20578
  });
20530
20579
  }
20531
- get composerStyle() {
20532
- const maxHeight = this.props.gridDims.height - this.rect.y;
20533
- const maxWidth = this.props.gridDims.width - this.rect.x;
20534
- return cssPropertiesToCss({
20535
- "max-width": `${maxWidth}px`,
20536
- "max-height": `${maxHeight}px`,
20537
- });
20580
+ updateComponentPosition() {
20581
+ const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
20582
+ if (this.isEditing !== isEditing) {
20583
+ this.isEditing = isEditing;
20584
+ if (!isEditing) {
20585
+ this.rect = this.defaultRect;
20586
+ this.env.focusableElement.focus();
20587
+ return;
20588
+ }
20589
+ const position = this.env.model.getters.getActivePosition();
20590
+ const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
20591
+ this.rect = this.env.model.getters.getVisibleRect(zone);
20592
+ }
20593
+ }
20594
+ updateCellReferenceVisibility() {
20595
+ if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
20596
+ return;
20597
+ }
20598
+ const sheetId = this.env.model.getters.getActiveSheetId();
20599
+ const zone = this.env.model.getters.getSelectedZone();
20600
+ const rect = this.env.model.getters.getVisibleRect(zone);
20601
+ if (!deepEquals(rect, this.rect) ||
20602
+ sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
20603
+ this.isCellReferenceVisible = true;
20604
+ }
20538
20605
  }
20539
20606
  }
20540
20607
  GridComposer.template = "o-spreadsheet-GridComposer";
20541
20608
  GridComposer.components = { Composer };
20542
20609
  GridComposer.props = {
20543
20610
  focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
20544
- onComposerUnmounted: Function,
20545
20611
  onComposerContentFocused: Function,
20546
20612
  gridDims: Object,
20613
+ onComposerCellFocused: Function,
20547
20614
  };
20548
20615
 
20549
20616
  const CSS$1 = css /* scss */ `
@@ -21134,7 +21201,6 @@
21134
21201
  this.props.onCellDoubleClicked(col, row);
21135
21202
  }
21136
21203
  onContextMenu(ev) {
21137
- ev.preventDefault();
21138
21204
  const [col, row] = this.getCartesianCoordinates(ev);
21139
21205
  this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
21140
21206
  }
@@ -22361,17 +22427,16 @@
22361
22427
  menuItems: [],
22362
22428
  });
22363
22429
  this.gridRef = owl.useRef("grid");
22364
- this.hiddenInput = owl.useRef("hiddenInput");
22365
22430
  this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
22366
22431
  this.hoveredCell = owl.useState({ col: undefined, row: undefined });
22367
22432
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
22368
22433
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
22369
22434
  owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
22370
22435
  owl.useExternalListener(document.body, "paste", this.paste);
22371
- owl.onMounted(() => this.focus());
22372
- this.props.exposeFocus(() => this.focus());
22436
+ owl.onMounted(() => this.focusDefaultElement());
22437
+ this.props.exposeFocus(() => this.focusDefaultElement());
22373
22438
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
22374
- owl.useEffect(() => this.focus(), () => [this.env.model.getters.getActiveSheetId()]);
22439
+ owl.useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
22375
22440
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
22376
22441
  this.moveCanvas(deltaX, deltaY);
22377
22442
  this.hoveredCell.col = undefined;
@@ -22394,13 +22459,12 @@
22394
22459
  if (this.env.model.getters.hasOpenedPopover()) {
22395
22460
  this.closeOpenedPopover();
22396
22461
  }
22397
- this.focus();
22462
+ this.focusDefaultElement();
22398
22463
  }
22399
- focus() {
22400
- var _a;
22464
+ focusDefaultElement() {
22401
22465
  if (!this.env.model.getters.getSelectedFigureId() &&
22402
22466
  this.env.model.getters.getEditionMode() === "inactive") {
22403
- (_a = this.hiddenInput.el) === null || _a === void 0 ? void 0 : _a.focus();
22467
+ this.env.focusableElement.focus();
22404
22468
  }
22405
22469
  }
22406
22470
  get gridEl() {
@@ -22545,19 +22609,6 @@
22545
22609
  return;
22546
22610
  }
22547
22611
  }
22548
- onInput(ev) {
22549
- // the user meant to paste in the sheet, not open the composer with the pasted content
22550
- if (!ev.isComposing && ev.inputType === "insertFromPaste") {
22551
- return;
22552
- }
22553
- if (ev.data) {
22554
- // if the user types a character on the grid, it means he wants to start composing the selected cell with that
22555
- // character
22556
- ev.preventDefault();
22557
- ev.stopPropagation();
22558
- this.props.onGridComposerCellFocused(ev.data);
22559
- }
22560
- }
22561
22612
  // ---------------------------------------------------------------------------
22562
22613
  // Context Menu
22563
22614
  // ---------------------------------------------------------------------------
@@ -22654,7 +22705,7 @@
22654
22705
  }
22655
22706
  closeMenu() {
22656
22707
  this.menuState.isOpen = false;
22657
- this.focus();
22708
+ this.focusDefaultElement();
22658
22709
  }
22659
22710
  }
22660
22711
  Grid.template = "o-spreadsheet-Grid";
@@ -27006,7 +27057,7 @@
27006
27057
  * a breaking change is made in the way the state is handled, and an upgrade
27007
27058
  * function should be defined
27008
27059
  */
27009
- const CURRENT_VERSION = 12;
27060
+ const CURRENT_VERSION = 12.5;
27010
27061
  const INITIAL_SHEET_ID = "Sheet1";
27011
27062
  /**
27012
27063
  * This function tries to load anything that could look like a valid
@@ -27272,6 +27323,31 @@
27272
27323
  return data;
27273
27324
  },
27274
27325
  },
27326
+ {
27327
+ description: "Fix datafilter duplication",
27328
+ from: 12,
27329
+ to: 12.5,
27330
+ applyMigration(data) {
27331
+ for (let sheet of data.sheets || []) {
27332
+ let knownDataFilterZones = [];
27333
+ for (let filterTable of sheet.filterTables || []) {
27334
+ const zone = toZone(filterTable.range);
27335
+ // See commit message for the details
27336
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
27337
+ if (intersectZoneIndex !== -1) {
27338
+ knownDataFilterZones[intersectZoneIndex] = zone;
27339
+ }
27340
+ else {
27341
+ knownDataFilterZones.push(zone);
27342
+ }
27343
+ }
27344
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
27345
+ range: zoneToXc(zone),
27346
+ }));
27347
+ }
27348
+ return data;
27349
+ },
27350
+ },
27275
27351
  ];
27276
27352
  /**
27277
27353
  * This function is used to repair faulty data independently of the migration.
@@ -28292,13 +28368,13 @@
28292
28368
  /*
28293
28369
  * Reconstructs the original formula string based on a normalized form and its dependencies
28294
28370
  */
28295
- buildFormulaContent(sheetId, cell, dependencies) {
28371
+ buildFormulaContent(sheetId, cell, dependencies, useFixedZone = false) {
28296
28372
  const ranges = dependencies || cell.dependencies;
28297
28373
  let rangeIndex = 0;
28298
28374
  return concat(cell.compiledFormula.tokens.map((token) => {
28299
28375
  if (token.type === "REFERENCE") {
28300
28376
  const range = ranges[rangeIndex++];
28301
- return this.getters.getRangeString(range, sheetId);
28377
+ return this.getters.getRangeString(range, sheetId, useFixedZone);
28302
28378
  }
28303
28379
  return token.value;
28304
28380
  }));
@@ -28868,7 +28944,13 @@
28868
28944
  }
28869
28945
  }
28870
28946
  exportForExcel(data) {
28871
- this.export(data);
28947
+ if (data.sheets) {
28948
+ for (let sheet of data.sheets) {
28949
+ if (this.cfRules[sheet.id]) {
28950
+ sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useFixedReference: true }));
28951
+ }
28952
+ }
28953
+ }
28872
28954
  }
28873
28955
  // ---------------------------------------------------------------------------
28874
28956
  // Getters
@@ -28918,11 +29000,11 @@
28918
29000
  // ---------------------------------------------------------------------------
28919
29001
  // Private
28920
29002
  // ---------------------------------------------------------------------------
28921
- mapToConditionalFormat(sheetId, cf) {
29003
+ mapToConditionalFormat(sheetId, cf, options = { useFixedReference: false }) {
28922
29004
  return {
28923
29005
  ...cf,
28924
29006
  ranges: cf.ranges.map((range) => {
28925
- return this.getters.getRangeString(range, sheetId);
29007
+ return this.getters.getRangeString(range, sheetId, options.useFixedReference);
28926
29008
  }),
28927
29009
  };
28928
29010
  }
@@ -30851,8 +30933,9 @@
30851
30933
  *
30852
30934
  * @param range the range (received from getRangeFromXC or getRangeFromZone)
30853
30935
  * @param forSheetId the id of the sheet where the range string is supposed to be used.
30936
+ * @param [useFixedZone=false] if true, the range will be returned with fixed row and column
30854
30937
  */
30855
- getRangeString(range, forSheetId) {
30938
+ getRangeString(range, forSheetId, useFixedZone = false) {
30856
30939
  if (!range) {
30857
30940
  return INCORRECT_RANGE_STRING;
30858
30941
  }
@@ -30879,7 +30962,7 @@
30879
30962
  if (prefixSheet && !sheetName) {
30880
30963
  return INCORRECT_RANGE_STRING;
30881
30964
  }
30882
- let rangeString = this.getRangePartString(rangeImpl, 0);
30965
+ let rangeString = this.getRangePartString(rangeImpl, 0, useFixedZone);
30883
30966
  if (rangeImpl.parts && rangeImpl.parts.length === 2) {
30884
30967
  // this if converts A2:A2 into A2 except if any part of the original range had fixed row or column (with $)
30885
30968
  if (rangeImpl.zone.top !== rangeImpl.zone.bottom ||
@@ -30889,7 +30972,7 @@
30889
30972
  rangeImpl.parts[1].rowFixed ||
30890
30973
  rangeImpl.parts[1].colFixed) {
30891
30974
  rangeString += ":";
30892
- rangeString += this.getRangePartString(rangeImpl, 1);
30975
+ rangeString += this.getRangePartString(rangeImpl, 1, useFixedZone);
30893
30976
  }
30894
30977
  }
30895
30978
  return `${prefixSheet ? sheetName + "!" : ""}${rangeString}`;
@@ -30919,14 +31002,14 @@
30919
31002
  /**
30920
31003
  * Get a Xc string that represent a part of a range
30921
31004
  */
30922
- getRangePartString(range, part) {
31005
+ getRangePartString(range, part, useFixedZone = false) {
30923
31006
  var _a, _b;
30924
31007
  const colFixed = range.parts && ((_a = range.parts[part]) === null || _a === void 0 ? void 0 : _a.colFixed) ? "$" : "";
30925
31008
  const col = part === 0 ? numberToLetters(range.zone.left) : numberToLetters(range.zone.right);
30926
31009
  const rowFixed = range.parts && ((_b = range.parts[part]) === null || _b === void 0 ? void 0 : _b.rowFixed) ? "$" : "";
30927
31010
  const row = part === 0 ? String(range.zone.top + 1) : String(range.zone.bottom + 1);
30928
31011
  let str = "";
30929
- if (range.isFullCol) {
31012
+ if (range.isFullCol && !useFixedZone) {
30930
31013
  if (part === 0 && range.unboundedZone.hasHeader) {
30931
31014
  str = colFixed + col + rowFixed + row;
30932
31015
  }
@@ -30934,7 +31017,7 @@
30934
31017
  str = colFixed + col;
30935
31018
  }
30936
31019
  }
30937
- else if (range.isFullRow) {
31020
+ else if (range.isFullRow && !useFixedZone) {
30938
31021
  if (part === 0 && range.unboundedZone.hasHeader) {
30939
31022
  str = colFixed + col + rowFixed + row;
30940
31023
  }
@@ -32323,6 +32406,10 @@
32323
32406
  if (cell.format !== evaluatedCell.format) {
32324
32407
  exportedCellData.computedFormat = evaluatedCell.format;
32325
32408
  }
32409
+ // if there is a formula but no dependencies (maybe because the cell is in error), no need to recompute the formula text
32410
+ if (cell.isFormula && cell.dependencies.length) {
32411
+ exportedCellData.content = this.getters.buildFormulaContent(sheet.id, cell, cell.dependencies, true);
32412
+ }
32326
32413
  }
32327
32414
  }
32328
32415
  }
@@ -39914,6 +40001,19 @@
39914
40001
  }
39915
40002
  }
39916
40003
 
40004
+ class FocusableElement {
40005
+ constructor() {
40006
+ this.focusableElement = undefined;
40007
+ }
40008
+ setFocusableElement(element) {
40009
+ this.focusableElement = element;
40010
+ }
40011
+ focus() {
40012
+ var _a;
40013
+ (_a = this.focusableElement) === null || _a === void 0 ? void 0 : _a.focus();
40014
+ }
40015
+ }
40016
+
39917
40017
  const RIPPLE_KEY_FRAMES = [
39918
40018
  { transform: "scale(0)" },
39919
40019
  { transform: "scale(0.8)", offset: 0.33 },
@@ -41889,6 +41989,7 @@
41889
41989
  _t: Spreadsheet._t,
41890
41990
  clipboard: this.env.clipboard || instantiateClipboard(),
41891
41991
  startCellEdition: (content) => this.onGridComposerCellFocused(content),
41992
+ focusableElement: new FocusableElement(),
41892
41993
  });
41893
41994
  owl.useExternalListener(window, "resize", () => this.render(true));
41894
41995
  owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
@@ -41987,17 +42088,18 @@
41987
42088
  this.model.dispatch("UNFOCUS_SELECTION_INPUT");
41988
42089
  this.composer.topBarFocus = "contentFocus";
41989
42090
  this.composer.gridFocusMode = "inactive";
41990
- this.setComposerContent({ selection } || {});
42091
+ this.setComposerContent({ selection });
41991
42092
  }
41992
- onGridComposerContentFocused() {
42093
+ onGridComposerContentFocused(selection) {
41993
42094
  if (this.model.getters.isReadonly()) {
41994
42095
  return;
41995
42096
  }
41996
42097
  this.model.dispatch("UNFOCUS_SELECTION_INPUT");
41997
42098
  this.composer.topBarFocus = "inactive";
41998
42099
  this.composer.gridFocusMode = "contentFocus";
41999
- this.setComposerContent({});
42100
+ this.setComposerContent({ selection });
42000
42101
  }
42102
+ // TODO: either both are defined or none of them. change those args to an object
42001
42103
  onGridComposerCellFocused(content, selection) {
42002
42104
  if (this.model.getters.isReadonly()) {
42003
42105
  return;
@@ -43973,12 +44075,7 @@
43973
44075
  attrs.push(["t", "str"]);
43974
44076
  cycle = escapeXml /*xml*/ `<v>${cell.value}</v>`;
43975
44077
  }
43976
- node = escapeXml /*xml*/ `
43977
- <f>
43978
- ${XlsxFormula}
43979
- </f>
43980
- ${cycle}
43981
- `;
44078
+ node = escapeXml /*xml*/ `<f> ${XlsxFormula} </f> ${cycle}`;
43982
44079
  return { attrs, node };
43983
44080
  }
43984
44081
  else {
@@ -44774,11 +44871,10 @@
44774
44871
  ({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader));
44775
44872
  }
44776
44873
  attributes.push(...additionalAttrs);
44777
- cellNodes.push(escapeXml /*xml*/ `
44778
- <c ${formatAttributes(attributes)}>
44779
- ${cellNode}
44780
- </c>
44781
- `);
44874
+ // prettier-ignore
44875
+ cellNodes.push(escapeXml /*xml*/ `<c ${formatAttributes(attributes)}>
44876
+ ${cellNode}
44877
+ </c>`);
44782
44878
  }
44783
44879
  }
44784
44880
  if (cellNodes.length || row.size !== DEFAULT_CELL_HEIGHT || row.isHidden) {
@@ -45674,9 +45770,9 @@
45674
45770
  Object.defineProperty(exports, '__esModule', { value: true });
45675
45771
 
45676
45772
 
45677
- __info__.version = '16.2.29';
45678
- __info__.date = '2024-01-29T13:49:36.240Z';
45679
- __info__.hash = '27b2ec1';
45773
+ __info__.version = '16.2.31';
45774
+ __info__.date = '2024-02-09T13:05:40.161Z';
45775
+ __info__.hash = '2e76bdf';
45680
45776
 
45681
45777
 
45682
45778
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);