@odoo/o-spreadsheet 16.4.20 → 16.4.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.
@@ -702,18 +702,18 @@
702
702
  return true;
703
703
  }
704
704
  class JetSet extends Set {
705
- add(...iterable) {
705
+ addMany(iterable) {
706
706
  for (const element of iterable) {
707
707
  super.add(element);
708
708
  }
709
709
  return this;
710
710
  }
711
- delete(...iterable) {
712
- let deleted = false;
711
+ deleteMany(iterable) {
712
+ let wasDeleted = false;
713
713
  for (const element of iterable) {
714
- deleted ||= super.delete(element);
714
+ wasDeleted ||= super.delete(element);
715
715
  }
716
- return deleted;
716
+ return wasDeleted;
717
717
  }
718
718
  }
719
719
  /**
@@ -1839,6 +1839,9 @@
1839
1839
  function formatValue(value, { format, locale }) {
1840
1840
  switch (typeof value) {
1841
1841
  case "string":
1842
+ if (value.includes('\\"')) {
1843
+ return value.replace(/\\"/g, '"');
1844
+ }
1842
1845
  return value;
1843
1846
  case "boolean":
1844
1847
  return value ? "TRUE" : "FALSE";
@@ -15236,6 +15239,9 @@
15236
15239
  if (locale.formulaArgSeparator === locale.decimalSeparator) {
15237
15240
  return false;
15238
15241
  }
15242
+ if (locale.thousandsSeparator === locale.decimalSeparator) {
15243
+ return false;
15244
+ }
15239
15245
  try {
15240
15246
  formatValue(1, { locale, format: "#,##0.00" });
15241
15247
  formatValue(1, { locale, format: locale.dateFormat });
@@ -15326,7 +15332,7 @@
15326
15332
  if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
15327
15333
  return content;
15328
15334
  }
15329
- return content.replace(locale.decimalSeparator, ".");
15335
+ return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
15330
15336
  }
15331
15337
  /**
15332
15338
  * Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
@@ -15972,14 +15978,8 @@
15972
15978
  : undefined));
15973
15979
  }
15974
15980
  }
15975
- else if (zone.left === zone.right && zone.top === zone.bottom) {
15976
- // A single cell. If it's only the title, the dataset is not added.
15977
- if (!dataSetsHaveTitle) {
15978
- dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
15979
- }
15980
- }
15981
15981
  else {
15982
- /* 1 row or 1 column */
15982
+ /* 1 cell, 1 row or 1 column */
15983
15983
  dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
15984
15984
  ? {
15985
15985
  top: zone.top,
@@ -16028,8 +16028,10 @@
16028
16028
  }
16029
16029
  const dataRange = ds.dataRange.clone({ zone: dataZone });
16030
16030
  return {
16031
- label: ds.labelCell ? getters.getRangeString(ds.labelCell, "forceSheetReference") : undefined,
16032
- range: getters.getRangeString(dataRange, "forceSheetReference"),
16031
+ label: ds.labelCell
16032
+ ? getters.getRangeString(ds.labelCell, "forceSheetReference", true)
16033
+ : undefined,
16034
+ range: getters.getRangeString(dataRange, "forceSheetReference", true),
16033
16035
  };
16034
16036
  }
16035
16037
  function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
@@ -16042,7 +16044,7 @@
16042
16044
  zone.top = zone.top + 1;
16043
16045
  }
16044
16046
  const range = labelRange.clone({ zone });
16045
- return getters.getRangeString(range, "forceSheetReference");
16047
+ return getters.getRangeString(range, "forceSheetReference", true);
16046
16048
  }
16047
16049
  /**
16048
16050
  * Transform a chart definition which supports dataSets (dataSets and LabelRange)
@@ -16579,7 +16581,7 @@
16579
16581
  return undefined;
16580
16582
  const dataSets = this.dataSets
16581
16583
  .map((ds) => toExcelDataset(this.getters, ds))
16582
- .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
16584
+ .filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
16583
16585
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
16584
16586
  return {
16585
16587
  ...this.getDefinition(),
@@ -17167,7 +17169,7 @@
17167
17169
  return undefined;
17168
17170
  const dataSets = this.dataSets
17169
17171
  .map((ds) => toExcelDataset(this.getters, ds))
17170
- .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
17172
+ .filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
17171
17173
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
17172
17174
  return {
17173
17175
  ...this.getDefinition(),
@@ -17454,7 +17456,7 @@
17454
17456
  return undefined;
17455
17457
  const dataSets = this.dataSets
17456
17458
  .map((ds) => toExcelDataset(this.getters, ds))
17457
- .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
17459
+ .filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
17458
17460
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
17459
17461
  return {
17460
17462
  ...this.getDefinition(),
@@ -18632,6 +18634,12 @@
18632
18634
  let { col, row } = env.model.getters.getActivePosition();
18633
18635
  env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
18634
18636
  };
18637
+ const INSERT_LINK_NAME = (env) => {
18638
+ const sheetId = env.model.getters.getActiveSheetId();
18639
+ const { col, row } = env.model.getters.getActivePosition();
18640
+ const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
18641
+ return cell && cell.link ? _lt("Edit link") : _lt("Insert link");
18642
+ };
18635
18643
  //------------------------------------------------------------------------------
18636
18644
  // Filters action
18637
18645
  //------------------------------------------------------------------------------
@@ -19172,7 +19180,7 @@
19172
19180
  })
19173
19181
  .add("insert_link", {
19174
19182
  ...insertLink,
19175
- name: _lt("Insert link"),
19183
+ name: INSERT_LINK_NAME,
19176
19184
  sequence: 150,
19177
19185
  separator: true,
19178
19186
  });
@@ -24083,6 +24091,7 @@
24083
24091
  static components = { TextValueProvider, FunctionDescriptionProvider };
24084
24092
  static defaultProps = {
24085
24093
  inputStyle: "",
24094
+ isDefaultFocus: false,
24086
24095
  };
24087
24096
  composerRef = owl.useRef("o_composer");
24088
24097
  contentHelper = new ContentEditableHelper(this.composerRef.el);
@@ -24135,7 +24144,6 @@
24135
24144
  F2: () => console.warn("Not implemented"),
24136
24145
  F4: this.processF4Key,
24137
24146
  Tab: (ev) => this.processTabKey(ev),
24138
- " ": (ev) => this.processSpaceKey(ev),
24139
24147
  };
24140
24148
  keyCodeMapping = {
24141
24149
  NumpadDecimal: this.processNumpadDecimal,
@@ -24143,11 +24151,11 @@
24143
24151
  setup() {
24144
24152
  owl.onMounted(() => {
24145
24153
  const el = this.composerRef.el;
24154
+ if (this.props.isDefaultFocus) {
24155
+ this.env.focusableElement.setFocusableElement(el);
24156
+ }
24146
24157
  this.contentHelper.updateEl(el);
24147
24158
  });
24148
- owl.onWillUnmount(() => {
24149
- this.props.onComposerUnmounted?.();
24150
- });
24151
24159
  owl.useEffect(() => {
24152
24160
  this.processContent();
24153
24161
  });
@@ -24156,7 +24164,8 @@
24156
24164
  // Handlers
24157
24165
  // ---------------------------------------------------------------------------
24158
24166
  processArrowKeys(ev) {
24159
- if (this.env.model.getters.isSelectingForComposer()) {
24167
+ if (this.env.model.getters.isSelectingForComposer() ||
24168
+ this.env.model.getters.getEditionMode() === "inactive") {
24160
24169
  this.functionDescriptionState.showDescription = false;
24161
24170
  // Prevent the default content editable behavior which moves the cursor
24162
24171
  ev.preventDefault();
@@ -24195,25 +24204,19 @@
24195
24204
  processTabKey(ev) {
24196
24205
  ev.preventDefault();
24197
24206
  ev.stopPropagation();
24198
- if (this.autoCompleteState.showProvider) {
24199
- const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
24200
- if (autoCompleteValue) {
24201
- this.autoComplete(autoCompleteValue);
24202
- return;
24207
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
24208
+ if (this.autoCompleteState.showProvider) {
24209
+ const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
24210
+ if (autoCompleteValue) {
24211
+ this.autoComplete(autoCompleteValue);
24212
+ return;
24213
+ }
24203
24214
  }
24215
+ this.env.model.dispatch("STOP_EDITION");
24204
24216
  }
24205
24217
  const direction = ev.shiftKey ? "left" : "right";
24206
- this.env.model.dispatch("STOP_EDITION");
24207
24218
  this.env.model.selection.moveAnchorCell(direction, 1);
24208
24219
  }
24209
- processSpaceKey(ev) {
24210
- if (ev.ctrlKey) {
24211
- ev.preventDefault();
24212
- ev.stopPropagation();
24213
- this.showAutocomplete("");
24214
- this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
24215
- }
24216
- }
24217
24220
  processEnterKey(ev) {
24218
24221
  ev.preventDefault();
24219
24222
  ev.stopPropagation();
@@ -24265,6 +24268,9 @@
24265
24268
  this.compositionActive = false;
24266
24269
  }
24267
24270
  onKeydown(ev) {
24271
+ if (this.env.model.getters.getEditionMode() === "inactive") {
24272
+ return;
24273
+ }
24268
24274
  let handler = this.keyMapping[ev.key] || this.keyCodeMapping[ev.code];
24269
24275
  if (handler) {
24270
24276
  handler.call(this, ev);
@@ -24273,14 +24279,33 @@
24273
24279
  ev.stopPropagation();
24274
24280
  }
24275
24281
  }
24282
+ onPaste(ev) {
24283
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
24284
+ ev.stopPropagation();
24285
+ }
24286
+ }
24276
24287
  /*
24277
24288
  * Triggered automatically by the content-editable between the keydown and key up
24278
24289
  * */
24279
24290
  onInput(ev) {
24280
- if (this.props.focus === "inactive" || !this.shouldProcessInputEvents) {
24291
+ if (!this.shouldProcessInputEvents) {
24292
+ return;
24293
+ }
24294
+ if (ev.inputType === "insertFromPaste" &&
24295
+ this.env.model.getters.getEditionMode() === "inactive") {
24281
24296
  return;
24282
24297
  }
24283
- let content = this.contentHelper.getText();
24298
+ ev.stopPropagation();
24299
+ let content;
24300
+ if (this.env.model.getters.getEditionMode() === "inactive") {
24301
+ content = ev.data || "";
24302
+ }
24303
+ else {
24304
+ content = this.contentHelper.getText();
24305
+ }
24306
+ if (this.props.focus === "inactive") {
24307
+ return this.props.onComposerCellFocused?.(content);
24308
+ }
24284
24309
  let selection = this.contentHelper.getCurrentSelection();
24285
24310
  if (ev.inputType === "insertParagraph") {
24286
24311
  const start = Math.min(selection.start, selection.end);
@@ -24358,9 +24383,8 @@
24358
24383
  }
24359
24384
  const newSelection = this.contentHelper.getCurrentSelection();
24360
24385
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
24361
- if (this.props.focus === "inactive") {
24362
- this.props.onComposerContentFocused(newSelection);
24363
- }
24386
+ this.props.onComposerContentFocused();
24387
+ if (this.props.focus === "inactive") ;
24364
24388
  this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
24365
24389
  this.processTokenAtCursor();
24366
24390
  }
@@ -24527,7 +24551,7 @@
24527
24551
  const highlights = this.env.model.getters.getHighlights();
24528
24552
  const refSheet = sheetName
24529
24553
  ? this.env.model.getters.getSheetIdByName(sheetName)
24530
- : this.env.model.getters.getCurrentEditedCell().sheetId;
24554
+ : this.env.model.getters.getCurrentEditedCell()?.sheetId;
24531
24555
  const highlight = highlights.find((highlight) => {
24532
24556
  if (highlight.sheetId !== refSheet)
24533
24557
  return false;
@@ -24607,12 +24631,13 @@
24607
24631
  }
24608
24632
  }
24609
24633
  Composer.props = {
24610
- focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
24611
- onComposerContentFocused: Function,
24612
24634
  inputStyle: { type: String, optional: true },
24613
24635
  rect: { type: Object, optional: true },
24614
24636
  delimitation: { type: Object, optional: true },
24615
- onComposerUnmounted: { type: Function, optional: true },
24637
+ focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
24638
+ onComposerCellFocused: { type: Function, optional: true },
24639
+ onComposerContentFocused: Function,
24640
+ isDefaultFocus: { type: Boolean, optional: true },
24616
24641
  };
24617
24642
 
24618
24643
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
@@ -24646,51 +24671,26 @@
24646
24671
  class GridComposer extends owl.Component {
24647
24672
  static template = "o-spreadsheet-GridComposer";
24648
24673
  static components = { Composer };
24649
- gridComposerRef;
24650
- zone;
24651
- rect;
24674
+ // TODORAR see if we can keep it undefined
24675
+ rect = this.defaultRect;
24676
+ isEditing = false;
24652
24677
  isCellReferenceVisible;
24653
- composerState;
24678
+ get defaultRect() {
24679
+ return { x: 0, y: 0, width: 0, height: 0 };
24680
+ }
24654
24681
  setup() {
24655
- this.gridComposerRef = owl.useRef("gridComposer");
24656
- this.composerState = owl.useState({
24657
- rect: undefined,
24658
- delimitation: undefined,
24659
- });
24660
- const { sheetId, col, row } = this.env.model.getters.getActivePosition();
24661
- this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
24662
- this.rect = this.env.model.getters.getVisibleRect(this.zone);
24663
- this.isCellReferenceVisible = false;
24664
- owl.onMounted(() => {
24665
- const el = this.gridComposerRef.el;
24666
- this.composerState.rect = {
24667
- x: this.rect.x,
24668
- y: this.rect.y,
24669
- width: el.clientWidth,
24670
- height: el.clientHeight,
24671
- };
24672
- this.composerState.delimitation = {
24673
- width: this.props.gridDims.width,
24674
- height: this.props.gridDims.height,
24675
- };
24676
- });
24677
24682
  owl.onWillUpdateProps(() => {
24678
- if (this.isCellReferenceVisible) {
24679
- return;
24680
- }
24681
- const sheetId = this.env.model.getters.getActiveSheetId();
24682
- const zone = this.env.model.getters.getSelectedZone();
24683
- const rect = this.env.model.getters.getVisibleRect(zone);
24684
- if (!deepEquals(rect, this.rect) ||
24685
- sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
24686
- this.isCellReferenceVisible = true;
24687
- }
24683
+ this.updateComponentPosition();
24684
+ this.updateCellReferenceVisibility();
24688
24685
  });
24689
24686
  }
24690
24687
  get shouldDisplayCellReference() {
24691
24688
  return this.isCellReferenceVisible;
24692
24689
  }
24693
24690
  get cellReference() {
24691
+ if (!this.env.model.getters.getCurrentEditedCell()) {
24692
+ return "";
24693
+ }
24694
24694
  const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
24695
24695
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
24696
24696
  return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
@@ -24702,7 +24702,27 @@
24702
24702
  top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
24703
24703
  });
24704
24704
  }
24705
+ get composerProps() {
24706
+ const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
24707
+ return {
24708
+ rect: { ...this.rect },
24709
+ delimitation: {
24710
+ width,
24711
+ height,
24712
+ },
24713
+ focus: this.props.focus,
24714
+ isDefaultFocus: true,
24715
+ onComposerContentFocused: this.props.onComposerContentFocused,
24716
+ onComposerCellFocused: this.props.onComposerCellFocused,
24717
+ };
24718
+ }
24705
24719
  get containerStyle() {
24720
+ if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
24721
+ return `
24722
+ position: absolute;
24723
+ z-index: -1000;
24724
+ `;
24725
+ }
24706
24726
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
24707
24727
  const cell = this.env.model.getters.getActiveCell();
24708
24728
  const position = this.env.model.getters.getActivePosition();
@@ -24722,6 +24742,8 @@
24722
24742
  if (!isFormula) {
24723
24743
  textAlign = style.align || cell.defaultAlign;
24724
24744
  }
24745
+ const maxHeight = this.props.gridDims.height - this.rect.y;
24746
+ const maxWidth = this.props.gridDims.width - this.rect.x;
24725
24747
  /**
24726
24748
  * min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
24727
24749
  * including all the paddings/margins of the composer
@@ -24733,6 +24755,8 @@
24733
24755
  top: `${top}px`,
24734
24756
  "min-width": `${width + 1}px`,
24735
24757
  "min-height": `${height + 1}px`,
24758
+ "max-width": `${maxWidth}px`,
24759
+ "max-height": `${maxHeight}px`,
24736
24760
  background,
24737
24761
  color,
24738
24762
  "font-size": `${fontSizeInPixels(fontSize)}px`,
@@ -24742,20 +24766,38 @@
24742
24766
  "text-align": textAlign,
24743
24767
  });
24744
24768
  }
24745
- get composerStyle() {
24746
- const maxHeight = this.props.gridDims.height - this.rect.y;
24747
- const maxWidth = this.props.gridDims.width - this.rect.x;
24748
- return cssPropertiesToCss({
24749
- "max-width": `${maxWidth}px`,
24750
- "max-height": `${maxHeight}px`,
24751
- });
24769
+ updateComponentPosition() {
24770
+ const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
24771
+ if (this.isEditing !== isEditing) {
24772
+ this.isEditing = isEditing;
24773
+ if (!isEditing) {
24774
+ this.rect = this.defaultRect;
24775
+ this.env.focusableElement.focus();
24776
+ return;
24777
+ }
24778
+ const position = this.env.model.getters.getActivePosition();
24779
+ const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
24780
+ this.rect = this.env.model.getters.getVisibleRect(zone);
24781
+ }
24782
+ }
24783
+ updateCellReferenceVisibility() {
24784
+ if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
24785
+ return;
24786
+ }
24787
+ const sheetId = this.env.model.getters.getActiveSheetId();
24788
+ const zone = this.env.model.getters.getSelectedZone();
24789
+ const rect = this.env.model.getters.getVisibleRect(zone);
24790
+ if (!deepEquals(rect, this.rect) ||
24791
+ sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
24792
+ this.isCellReferenceVisible = true;
24793
+ }
24752
24794
  }
24753
24795
  }
24754
24796
  GridComposer.props = {
24755
24797
  focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
24756
- onComposerUnmounted: Function,
24757
24798
  onComposerContentFocused: Function,
24758
24799
  gridDims: Object,
24800
+ onComposerCellFocused: Function,
24759
24801
  };
24760
24802
 
24761
24803
  const CSS$1 = css /* scss */ `
@@ -25636,7 +25678,6 @@
25636
25678
  this.props.onCellDoubleClicked(col, row);
25637
25679
  }
25638
25680
  onContextMenu(ev) {
25639
- ev.preventDefault();
25640
25681
  const [col, row] = this.getCartesianCoordinates(ev);
25641
25682
  this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
25642
25683
  }
@@ -26729,7 +26770,6 @@
26729
26770
  HEADER_WIDTH = HEADER_WIDTH;
26730
26771
  menuState;
26731
26772
  gridRef;
26732
- hiddenInput;
26733
26773
  onMouseWheel;
26734
26774
  canvasPosition;
26735
26775
  hoveredCell;
@@ -26740,17 +26780,16 @@
26740
26780
  menuItems: [],
26741
26781
  });
26742
26782
  this.gridRef = owl.useRef("grid");
26743
- this.hiddenInput = owl.useRef("hiddenInput");
26744
26783
  this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
26745
26784
  this.hoveredCell = owl.useState({ col: undefined, row: undefined });
26746
26785
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
26747
26786
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
26748
26787
  owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
26749
26788
  owl.useExternalListener(document.body, "paste", this.paste);
26750
- owl.onMounted(() => this.focus());
26751
- this.props.exposeFocus(() => this.focus());
26789
+ owl.onMounted(() => this.focusDefaultElement());
26790
+ this.props.exposeFocus(() => this.focusDefaultElement());
26752
26791
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
26753
- owl.useEffect(() => this.focus(), () => [this.env.model.getters.getActiveSheetId()]);
26792
+ owl.useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
26754
26793
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
26755
26794
  this.moveCanvas(deltaX, deltaY);
26756
26795
  this.hoveredCell.col = undefined;
@@ -26773,7 +26812,7 @@
26773
26812
  if (this.env.model.getters.hasOpenedPopover()) {
26774
26813
  this.closeOpenedPopover();
26775
26814
  }
26776
- this.focus();
26815
+ this.focusDefaultElement();
26777
26816
  }
26778
26817
  // this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
26779
26818
  // down itself
@@ -26946,10 +26985,10 @@
26946
26985
  PAGEUP: () => this.env.model.dispatch("SHIFT_VIEWPORT_UP"),
26947
26986
  "CTRL+K": () => INSERT_LINK(this.env),
26948
26987
  };
26949
- focus() {
26988
+ focusDefaultElement() {
26950
26989
  if (!this.env.model.getters.getSelectedFigureId() &&
26951
26990
  this.env.model.getters.getEditionMode() === "inactive") {
26952
- this.hiddenInput.el?.focus();
26991
+ this.env.focusableElement.focus();
26953
26992
  }
26954
26993
  }
26955
26994
  get gridEl() {
@@ -27093,19 +27132,6 @@
27093
27132
  return;
27094
27133
  }
27095
27134
  }
27096
- onInput(ev) {
27097
- // the user meant to paste in the sheet, not open the composer with the pasted content
27098
- if (!ev.isComposing && ev.inputType === "insertFromPaste") {
27099
- return;
27100
- }
27101
- if (ev.data) {
27102
- // if the user types a character on the grid, it means he wants to start composing the selected cell with that
27103
- // character
27104
- ev.preventDefault();
27105
- ev.stopPropagation();
27106
- this.props.onGridComposerCellFocused(ev.data);
27107
- }
27108
- }
27109
27135
  // ---------------------------------------------------------------------------
27110
27136
  // Context Menu
27111
27137
  // ---------------------------------------------------------------------------
@@ -27218,7 +27244,7 @@
27218
27244
  }
27219
27245
  closeMenu() {
27220
27246
  this.menuState.isOpen = false;
27221
- this.focus();
27247
+ this.focusDefaultElement();
27222
27248
  }
27223
27249
  }
27224
27250
  Grid.props = {
@@ -30878,6 +30904,31 @@
30878
30904
  return data;
30879
30905
  },
30880
30906
  },
30907
+ {
30908
+ description: "Fix datafilter duplication",
30909
+ from: 12,
30910
+ to: 12.5,
30911
+ applyMigration(data) {
30912
+ for (let sheet of data.sheets || []) {
30913
+ let knownDataFilterZones = [];
30914
+ for (let filterTable of sheet.filterTables || []) {
30915
+ const zone = toZone(filterTable.range);
30916
+ // See commit message for the details
30917
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
30918
+ if (intersectZoneIndex !== -1) {
30919
+ knownDataFilterZones[intersectZoneIndex] = zone;
30920
+ }
30921
+ else {
30922
+ knownDataFilterZones.push(zone);
30923
+ }
30924
+ }
30925
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
30926
+ range: zoneToXc(zone),
30927
+ }));
30928
+ }
30929
+ return data;
30930
+ },
30931
+ },
30881
30932
  {
30882
30933
  description: "Change Border description structure",
30883
30934
  from: 12,
@@ -31797,9 +31848,9 @@
31797
31848
  allowDispatch(cmd) {
31798
31849
  switch (cmd.type) {
31799
31850
  case "UPDATE_CELL":
31800
- return this.checkCellOutOfSheet(cmd);
31851
+ return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
31801
31852
  case "CLEAR_CELL":
31802
- return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
31853
+ return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
31803
31854
  default:
31804
31855
  return 0 /* CommandResult.Success */;
31805
31856
  }
@@ -31965,13 +32016,13 @@
31965
32016
  /*
31966
32017
  * Reconstructs the original formula string based on a normalized form and its dependencies
31967
32018
  */
31968
- buildFormulaContent(sheetId, cell, dependencies) {
32019
+ buildFormulaContent(sheetId, cell, dependencies, useFixedZone = false) {
31969
32020
  const ranges = dependencies || cell.dependencies;
31970
32021
  let rangeIndex = 0;
31971
32022
  return concat(cell.compiledFormula.tokens.map((token) => {
31972
32023
  if (token.type === "REFERENCE") {
31973
32024
  const range = ranges[rangeIndex++];
31974
- return this.getters.getRangeString(range, sheetId);
32025
+ return this.getters.getRangeString(range, sheetId, useFixedZone);
31975
32026
  }
31976
32027
  return token.value;
31977
32028
  }));
@@ -32093,10 +32144,7 @@
32093
32144
  else {
32094
32145
  style = before ? before.style : undefined;
32095
32146
  }
32096
- const locale = this.getters.getLocale();
32097
- let format = ("format" in after ? after.format : before && before.format) ||
32098
- detectDateFormat(afterContent, locale) ||
32099
- detectNumberFormat(afterContent);
32147
+ const format = "format" in after ? after.format : before && before.format;
32100
32148
  /* Read the following IF as:
32101
32149
  * we need to remove the cell if it is completely empty, but we can know if it completely empty if:
32102
32150
  * - the command says the new content is empty and has no border/format/style
@@ -32137,12 +32185,11 @@
32137
32185
  }
32138
32186
  createLiteralCell(id, content, format, style) {
32139
32187
  const locale = this.getters.getLocale();
32140
- content = parseLiteral(content, locale).toString();
32141
32188
  return {
32142
32189
  id,
32143
- content,
32190
+ content: parseLiteral(content, locale).toString(),
32144
32191
  style,
32145
- format,
32192
+ format: format || detectDateFormat(content, locale) || detectNumberFormat(content),
32146
32193
  isFormula: false,
32147
32194
  };
32148
32195
  }
@@ -32203,6 +32250,18 @@
32203
32250
  }
32204
32251
  return 0 /* CommandResult.Success */;
32205
32252
  }
32253
+ checkUselessUpdateCell(cmd) {
32254
+ const cell = this.getters.getCell(cmd);
32255
+ const hasContent = "content" in cmd || "formula" in cmd;
32256
+ const hasStyle = "style" in cmd;
32257
+ const hasFormat = "format" in cmd;
32258
+ if ((!hasContent || cell?.content === cmd.content) &&
32259
+ (!hasStyle || deepEquals(cell?.style, cmd.style)) &&
32260
+ (!hasFormat || cell?.format === cmd.format)) {
32261
+ return 98 /* CommandResult.NoChanges */;
32262
+ }
32263
+ return 0 /* CommandResult.Success */;
32264
+ }
32206
32265
  }
32207
32266
  class FormulaCellWithDependencies {
32208
32267
  id;
@@ -32540,7 +32599,13 @@
32540
32599
  }
32541
32600
  }
32542
32601
  exportForExcel(data) {
32543
- this.export(data);
32602
+ if (data.sheets) {
32603
+ for (let sheet of data.sheets) {
32604
+ if (this.cfRules[sheet.id]) {
32605
+ sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useFixedReference: true }));
32606
+ }
32607
+ }
32608
+ }
32544
32609
  }
32545
32610
  // ---------------------------------------------------------------------------
32546
32611
  // Getters
@@ -32605,11 +32670,11 @@
32605
32670
  // ---------------------------------------------------------------------------
32606
32671
  // Private
32607
32672
  // ---------------------------------------------------------------------------
32608
- mapToConditionalFormat(sheetId, cf) {
32673
+ mapToConditionalFormat(sheetId, cf, options = { useFixedReference: false }) {
32609
32674
  return {
32610
32675
  ...cf,
32611
32676
  ranges: cf.ranges.map((range) => {
32612
- return this.getters.getRangeString(range, sheetId);
32677
+ return this.getters.getRangeString(range, sheetId, options.useFixedReference);
32613
32678
  }),
32614
32679
  };
32615
32680
  }
@@ -34446,8 +34511,9 @@
34446
34511
  *
34447
34512
  * @param range the range (received from getRangeFromXC or getRangeFromZone)
34448
34513
  * @param forSheetId the id of the sheet where the range string is supposed to be used.
34514
+ * @param [useFixedZone=false] if true, the range will be returned with fixed row and column
34449
34515
  */
34450
- getRangeString(range, forSheetId) {
34516
+ getRangeString(range, forSheetId, useFixedZone = false) {
34451
34517
  if (!range) {
34452
34518
  return INCORRECT_RANGE_STRING;
34453
34519
  }
@@ -34474,7 +34540,7 @@
34474
34540
  if (prefixSheet && !sheetName) {
34475
34541
  return INCORRECT_RANGE_STRING;
34476
34542
  }
34477
- let rangeString = this.getRangePartString(rangeImpl, 0);
34543
+ let rangeString = this.getRangePartString(rangeImpl, 0, useFixedZone);
34478
34544
  if (rangeImpl.parts && rangeImpl.parts.length === 2) {
34479
34545
  // this if converts A2:A2 into A2 except if any part of the original range had fixed row or column (with $)
34480
34546
  if (rangeImpl.zone.top !== rangeImpl.zone.bottom ||
@@ -34484,7 +34550,7 @@
34484
34550
  rangeImpl.parts[1].rowFixed ||
34485
34551
  rangeImpl.parts[1].colFixed) {
34486
34552
  rangeString += ":";
34487
- rangeString += this.getRangePartString(rangeImpl, 1);
34553
+ rangeString += this.getRangePartString(rangeImpl, 1, useFixedZone);
34488
34554
  }
34489
34555
  }
34490
34556
  return `${prefixSheet ? sheetName + "!" : ""}${rangeString}`;
@@ -34525,13 +34591,13 @@
34525
34591
  /**
34526
34592
  * Get a Xc string that represent a part of a range
34527
34593
  */
34528
- getRangePartString(range, part) {
34594
+ getRangePartString(range, part, useFixedZone = false) {
34529
34595
  const colFixed = range.parts && range.parts[part]?.colFixed ? "$" : "";
34530
34596
  const col = part === 0 ? numberToLetters(range.zone.left) : numberToLetters(range.zone.right);
34531
34597
  const rowFixed = range.parts && range.parts[part]?.rowFixed ? "$" : "";
34532
34598
  const row = part === 0 ? String(range.zone.top + 1) : String(range.zone.bottom + 1);
34533
34599
  let str = "";
34534
- if (range.isFullCol) {
34600
+ if (range.isFullCol && !useFixedZone) {
34535
34601
  if (part === 0 && range.unboundedZone.hasHeader) {
34536
34602
  str = colFixed + col + rowFixed + row;
34537
34603
  }
@@ -34539,7 +34605,7 @@
34539
34605
  str = colFixed + col;
34540
34606
  }
34541
34607
  }
34542
- else if (range.isFullRow) {
34608
+ else if (range.isFullRow && !useFixedZone) {
34543
34609
  if (part === 0 && range.unboundedZone.hasHeader) {
34544
34610
  str = colFixed + col + rowFixed + row;
34545
34611
  }
@@ -36336,7 +36402,15 @@
36336
36402
  if (!this.rTrees[sheetId]) {
36337
36403
  return;
36338
36404
  }
36339
- this.rTrees[sheetId].remove(item, deepEquals);
36405
+ this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
36406
+ }
36407
+ rtreeItemComparer(left, right) {
36408
+ return (left.data == right.data &&
36409
+ left.boundingBox.sheetId === right.boundingBox.sheetId &&
36410
+ left.boundingBox?.zone.left === right.boundingBox.zone.left &&
36411
+ left.boundingBox?.zone.top === right.boundingBox.zone.top &&
36412
+ left.boundingBox?.zone.right === right.boundingBox.zone.right &&
36413
+ left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
36340
36414
  }
36341
36415
  }
36342
36416
  /**
@@ -36414,7 +36488,7 @@
36414
36488
  const queue = Array.from(ranges).reverse();
36415
36489
  while (queue.length > 0) {
36416
36490
  const range = queue.pop();
36417
- visited.add(...this.encoder.encodeBoundingBox(range));
36491
+ visited.addMany(this.encoder.encodeBoundingBox(range));
36418
36492
  const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
36419
36493
  for (const positionId of impactedPositionIds) {
36420
36494
  if (!visited.has(positionId)) {
@@ -36422,7 +36496,7 @@
36422
36496
  }
36423
36497
  }
36424
36498
  }
36425
- visited.delete(...ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
36499
+ visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
36426
36500
  return visited;
36427
36501
  }
36428
36502
  }
@@ -36553,9 +36627,9 @@
36553
36627
  const cells = positions.map((p) => this.encoder.encode(p));
36554
36628
  const cellsToCompute = new JetSet(cells);
36555
36629
  const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
36556
- cellsToCompute.add(...this.getCellsDependingOn(cells));
36557
- cellsToCompute.add(...arrayFormulasPositionIds);
36558
- cellsToCompute.add(...this.getCellsDependingOn(arrayFormulasPositionIds));
36630
+ cellsToCompute.addMany(this.getCellsDependingOn(cells));
36631
+ cellsToCompute.addMany(arrayFormulasPositionIds);
36632
+ cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
36559
36633
  this.evaluate(cellsToCompute);
36560
36634
  }
36561
36635
  getArrayFormulasImpactedByChangesOf(positionIds) {
@@ -36569,7 +36643,7 @@
36569
36643
  }
36570
36644
  if (!content) {
36571
36645
  // The previous content could have blocked some array formulas
36572
- impactedPositionIds.add(...this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
36646
+ impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
36573
36647
  }
36574
36648
  }
36575
36649
  return impactedPositionIds;
@@ -36617,7 +36691,7 @@
36617
36691
  }
36618
36692
  const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
36619
36693
  const cells = new JetSet(arrayFormulas);
36620
- cells.add(...this.getCellsDependingOn(arrayFormulas));
36694
+ cells.addMany(this.getCellsDependingOn(arrayFormulas));
36621
36695
  return cells;
36622
36696
  }
36623
36697
  nextPositionsToUpdate = new JetSet();
@@ -36768,7 +36842,7 @@
36768
36842
  this.setEvaluatedCell(positionId, evaluatedCell);
36769
36843
  // check if formula dependencies present in the spread zone
36770
36844
  // if so, they need to be recomputed
36771
- this.nextPositionsToUpdate.add(...this.getCellsDependingOn([positionId]));
36845
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
36772
36846
  };
36773
36847
  }
36774
36848
  invalidateSpreading(positionId) {
@@ -36783,8 +36857,8 @@
36783
36857
  continue;
36784
36858
  }
36785
36859
  this.evaluatedCells.delete(child);
36786
- this.nextPositionsToUpdate.add(...this.getCellsDependingOn([child]));
36787
- this.nextPositionsToUpdate.add(...this.getArrayFormulasBlockedByOrSpreadingOn(child));
36860
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
36861
+ this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
36788
36862
  }
36789
36863
  this.spreadingRelations.removeNode(positionId);
36790
36864
  }
@@ -37144,7 +37218,13 @@
37144
37218
  const format = newFormat
37145
37219
  ? getItemId(newFormat, data.formats)
37146
37220
  : exportedCellData.format;
37147
- const content = !isExported ? newContent : exportedCellData.content;
37221
+ let content;
37222
+ if (formulaCell instanceof FormulaCellWithDependencies) {
37223
+ content = this.getters.buildFormulaContent(exportedSheetData.id, formulaCell, formulaCell.dependencies, true);
37224
+ }
37225
+ else {
37226
+ content = !isExported ? newContent : exportedCellData.content;
37227
+ }
37148
37228
  exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
37149
37229
  }
37150
37230
  }
@@ -43663,7 +43743,7 @@
43663
43743
  this.replaceText(ref, this.selectionInitialStart, this.selectionEnd);
43664
43744
  }
43665
43745
  getZoneReference(zone) {
43666
- const inputSheetId = this.getters.getCurrentEditedCell().sheetId;
43746
+ const inputSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
43667
43747
  const sheetId = this.getters.getActiveSheetId();
43668
43748
  const range = this.getters.getRangeFromZone(sheetId, zone);
43669
43749
  return this.getters.getSelectionRangeString(range, inputSheetId);
@@ -43677,7 +43757,7 @@
43677
43757
  _fixedParts.pop();
43678
43758
  }
43679
43759
  const newRange = range.clone({ parts: _fixedParts });
43680
- return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().sheetId);
43760
+ return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId());
43681
43761
  }
43682
43762
  /**
43683
43763
  * Replace the current selection by a new text.
@@ -43710,7 +43790,7 @@
43710
43790
  if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
43711
43791
  return;
43712
43792
  }
43713
- const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
43793
+ const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
43714
43794
  const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
43715
43795
  const colorsToKeep = {};
43716
43796
  for (const xc of XCs) {
@@ -43739,7 +43819,7 @@
43739
43819
  if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
43740
43820
  return [];
43741
43821
  }
43742
- const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
43822
+ const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
43743
43823
  const rangeColor = (rangeString) => {
43744
43824
  const colorIndex = this.colorIndexByRange[rangeString];
43745
43825
  return colors$1[colorIndex % colors$1.length];
@@ -43757,7 +43837,7 @@
43757
43837
  * Return ranges currently referenced in the composer
43758
43838
  */
43759
43839
  getReferencedRanges() {
43760
- const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
43840
+ const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
43761
43841
  const referenceRanges = this.currentTokens
43762
43842
  .filter((token) => token.type === "REFERENCE")
43763
43843
  .map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
@@ -45721,6 +45801,16 @@
45721
45801
  }
45722
45802
  }
45723
45803
 
45804
+ class FocusableElement {
45805
+ focusableElement = undefined;
45806
+ setFocusableElement(element) {
45807
+ this.focusableElement = element;
45808
+ }
45809
+ focus() {
45810
+ this.focusableElement?.focus();
45811
+ }
45812
+ }
45813
+
45724
45814
  const RIPPLE_KEY_FRAMES = [
45725
45815
  { transform: "scale(0)" },
45726
45816
  { transform: "scale(0.8)", offset: 0.33 },
@@ -47763,6 +47853,7 @@
47763
47853
  _t: Spreadsheet._t,
47764
47854
  clipboard: this.env.clipboard || instantiateClipboard(),
47765
47855
  startCellEdition: (content) => this.onGridComposerCellFocused(content),
47856
+ focusableElement: new FocusableElement(),
47766
47857
  });
47767
47858
  owl.useExternalListener(window, "resize", () => this.render(true));
47768
47859
  owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
@@ -47869,17 +47960,18 @@
47869
47960
  this.model.dispatch("UNFOCUS_SELECTION_INPUT");
47870
47961
  this.composer.topBarFocus = "contentFocus";
47871
47962
  this.composer.gridFocusMode = "inactive";
47872
- this.setComposerContent({ selection } || {});
47963
+ this.setComposerContent({ selection });
47873
47964
  }
47874
- onGridComposerContentFocused() {
47965
+ onGridComposerContentFocused(selection) {
47875
47966
  if (this.model.getters.isReadonly()) {
47876
47967
  return;
47877
47968
  }
47878
47969
  this.model.dispatch("UNFOCUS_SELECTION_INPUT");
47879
47970
  this.composer.topBarFocus = "inactive";
47880
47971
  this.composer.gridFocusMode = "contentFocus";
47881
- this.setComposerContent({});
47972
+ this.setComposerContent({ selection });
47882
47973
  }
47974
+ // TODO: either both are defined or none of them. change those args to an object
47883
47975
  onGridComposerCellFocused(content, selection) {
47884
47976
  if (this.model.getters.isReadonly()) {
47885
47977
  return;
@@ -49291,11 +49383,10 @@
49291
49383
  * next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
49292
49384
  */
49293
49385
  getEndOfCluster(startPosition, dim, dir) {
49294
- const sheet = this.getters.getActiveSheet();
49295
49386
  let currentPosition = startPosition;
49296
49387
  // If both the current cell and the next cell are not empty, we want to go to the end of the cluster
49297
49388
  const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
49298
- let mode = !this.isCellEmpty(currentPosition, sheet.id) && !this.isCellEmpty(nextCellPosition, sheet.id)
49389
+ let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
49299
49390
  ? "endOfCluster"
49300
49391
  : "nextCluster";
49301
49392
  while (true) {
@@ -49305,7 +49396,7 @@
49305
49396
  currentPosition.row === nextCellPosition.row) {
49306
49397
  break;
49307
49398
  }
49308
- const isNextCellEmpty = this.isCellEmpty(nextCellPosition, sheet.id);
49399
+ const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
49309
49400
  if (mode === "endOfCluster" && isNextCellEmpty) {
49310
49401
  break;
49311
49402
  }
@@ -49319,10 +49410,20 @@
49319
49410
  return dim === "cols" ? currentPosition.col : currentPosition.row;
49320
49411
  }
49321
49412
  /**
49322
- * Check if a cell is empty or undefined in the model. If the cell is part of a merge,
49323
- * check if the merge containing the cell is empty.
49413
+ * Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
49414
+ * the check applies to the main cell of the merge.
49324
49415
  */
49325
- isCellEmpty({ col, row }, sheetId = this.getters.getActiveSheetId()) {
49416
+ isCellEmpty({ col, row }) {
49417
+ const sheetId = this.getters.getActiveSheetId();
49418
+ const position = this.getters.getMainCellPosition({ sheetId, col, row });
49419
+ return !(this.getters.getCorrespondingFormulaCell(position) || this.getters.getCell(position)?.content);
49420
+ }
49421
+ /**
49422
+ * Checks if a cell evaluated value is empty. If the cell is part of a merge,
49423
+ * the check applies to the main cell of the merge.
49424
+ */
49425
+ isEvaluatedCellEmpty({ col, row }) {
49426
+ const sheetId = this.getters.getActiveSheetId();
49326
49427
  const position = this.getters.getMainCellPosition({ sheetId, col, row });
49327
49428
  const cell = this.getters.getEvaluatedCell(position);
49328
49429
  return cell.type === CellValueType.empty;
@@ -49800,12 +49901,7 @@
49800
49901
  attrs.push(["t", "str"]);
49801
49902
  cycle = escapeXml /*xml*/ `<v>${cell.value}</v>`;
49802
49903
  }
49803
- node = escapeXml /*xml*/ `
49804
- <f>
49805
- ${XlsxFormula}
49806
- </f>
49807
- ${cycle}
49808
- `;
49904
+ node = escapeXml /*xml*/ ` <f> ${XlsxFormula} </f> ${cycle} `;
49809
49905
  return { attrs, node };
49810
49906
  }
49811
49907
  function addContent(content, sharedStrings, forceString = false) {
@@ -50624,11 +50720,10 @@
50624
50720
  ({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader));
50625
50721
  }
50626
50722
  attributes.push(...additionalAttrs);
50627
- cellNodes.push(escapeXml /*xml*/ `
50628
- <c ${formatAttributes(attributes)}>
50629
- ${cellNode}
50630
- </c>
50631
- `);
50723
+ // prettier-ignore
50724
+ cellNodes.push(escapeXml /*xml*/ `<c ${formatAttributes(attributes)}>
50725
+ ${cellNode}
50726
+ </c>`);
50632
50727
  }
50633
50728
  }
50634
50729
  if (cellNodes.length || row.size !== DEFAULT_CELL_HEIGHT || row.isHidden) {
@@ -51611,9 +51706,9 @@
51611
51706
  Object.defineProperty(exports, '__esModule', { value: true });
51612
51707
 
51613
51708
 
51614
- __info__.version = '16.4.20';
51615
- __info__.date = '2024-01-29T13:50:12.345Z';
51616
- __info__.hash = '06c0ecf';
51709
+ __info__.version = '16.4.23';
51710
+ __info__.date = '2024-02-16T14:23:29.521Z';
51711
+ __info__.hash = 'cb5db1a';
51617
51712
 
51618
51713
 
51619
51714
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);