@odoo/o-spreadsheet 17.1.2 → 17.1.4

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.1.2
6
- * @date 2024-01-29T13:54:42.679Z
7
- * @hash 043a0d5
5
+ * @version 17.1.4
6
+ * @date 2024-02-09T13:09:13.430Z
7
+ * @hash 16d3ece
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -2939,6 +2939,9 @@
2939
2939
  }
2940
2940
  switch (typeof value) {
2941
2941
  case "string":
2942
+ if (value.includes('\\"')) {
2943
+ return value.replace(/\\"/g, '"');
2944
+ }
2942
2945
  return value;
2943
2946
  case "boolean":
2944
2947
  return value ? "TRUE" : "FALSE";
@@ -4992,14 +4995,8 @@
4992
4995
  : undefined));
4993
4996
  }
4994
4997
  }
4995
- else if (zone.left === zone.right && zone.top === zone.bottom) {
4996
- // A single cell. If it's only the title, the dataset is not added.
4997
- if (!dataSetsHaveTitle) {
4998
- dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
4999
- }
5000
- }
5001
4998
  else {
5002
- /* 1 row or 1 column */
4999
+ /* 1 cell, 1 row or 1 column */
5003
5000
  dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
5004
5001
  ? {
5005
5002
  top: zone.top,
@@ -5048,8 +5045,10 @@
5048
5045
  }
5049
5046
  const dataRange = ds.dataRange.clone({ zone: dataZone });
5050
5047
  return {
5051
- label: ds.labelCell ? getters.getRangeString(ds.labelCell, "forceSheetReference") : undefined,
5052
- range: getters.getRangeString(dataRange, "forceSheetReference"),
5048
+ label: ds.labelCell
5049
+ ? getters.getRangeString(ds.labelCell, "forceSheetReference", { useFixedReference: true })
5050
+ : undefined,
5051
+ range: getters.getRangeString(dataRange, "forceSheetReference", { useFixedReference: true }),
5053
5052
  };
5054
5053
  }
5055
5054
  function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
@@ -5062,7 +5061,7 @@
5062
5061
  zone.top = zone.top + 1;
5063
5062
  }
5064
5063
  const range = labelRange.clone({ zone });
5065
- return getters.getRangeString(range, "forceSheetReference");
5064
+ return getters.getRangeString(range, "forceSheetReference", { useFixedReference: true });
5066
5065
  }
5067
5066
  /**
5068
5067
  * Transform a chart definition which supports dataSets (dataSets and LabelRange)
@@ -6697,6 +6696,7 @@
6697
6696
  };
6698
6697
 
6699
6698
  const macRegex = /Mac/i;
6699
+ const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
6700
6700
  /**
6701
6701
  * Return true if the event was triggered from
6702
6702
  * a child element.
@@ -6748,14 +6748,14 @@
6748
6748
  */
6749
6749
  function keyboardEventToShortcutString(ev, mode = "key") {
6750
6750
  let keyDownString = "";
6751
- if (isCtrlKey(ev) && ev.key !== "Ctrl")
6752
- keyDownString += "Ctrl+";
6753
- if (ev.metaKey)
6754
- keyDownString += "Ctrl+";
6755
- if (ev.altKey && ev.key !== "Alt")
6756
- keyDownString += "Alt+";
6757
- if (ev.shiftKey && ev.key !== "Shift")
6758
- keyDownString += "Shift+";
6751
+ if (!MODIFIER_KEYS.includes(ev.key)) {
6752
+ if (isCtrlKey(ev))
6753
+ keyDownString += "Ctrl+";
6754
+ if (ev.altKey)
6755
+ keyDownString += "Alt+";
6756
+ if (ev.shiftKey)
6757
+ keyDownString += "Shift+";
6758
+ }
6759
6759
  const key = mode === "key" ? ev.key : ev.code;
6760
6760
  keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
6761
6761
  return keyDownString;
@@ -7439,7 +7439,7 @@
7439
7439
  while (!chars.isOver()) {
7440
7440
  let token = tokenizeSpace(chars) ||
7441
7441
  tokenizeArgsSeparator(chars, locale) ||
7442
- tokenizeMisc(chars) ||
7442
+ tokenizeParenthesis(chars) ||
7443
7443
  tokenizeOperator(chars) ||
7444
7444
  tokenizeString(chars) ||
7445
7445
  tokenizeDebugger(chars) ||
@@ -7460,15 +7460,14 @@
7460
7460
  }
7461
7461
  return null;
7462
7462
  }
7463
- const misc$1 = {
7464
- "(": "LEFT_PAREN",
7465
- ")": "RIGHT_PAREN",
7463
+ const parenthesis = {
7464
+ "(": { type: "LEFT_PAREN", value: "(" },
7465
+ ")": { type: "RIGHT_PAREN", value: ")" },
7466
7466
  };
7467
- function tokenizeMisc(chars) {
7468
- if (chars.current in misc$1) {
7467
+ function tokenizeParenthesis(chars) {
7468
+ if (chars.current === "(" || chars.current === ")") {
7469
7469
  const value = chars.shift();
7470
- const type = misc$1[value];
7471
- return { type, value };
7470
+ return parenthesis[value];
7472
7471
  }
7473
7472
  return null;
7474
7473
  }
@@ -7489,7 +7488,12 @@
7489
7488
  }
7490
7489
  return null;
7491
7490
  }
7491
+ const FIRST_POSSIBLE_NUMBER_CHARS = new Set("0123456789");
7492
7492
  function tokenizeNumber(chars, locale) {
7493
+ if (!FIRST_POSSIBLE_NUMBER_CHARS.has(chars.current) &&
7494
+ chars.current !== locale.decimalSeparator) {
7495
+ return null;
7496
+ }
7493
7497
  const match = chars.remaining().match(getFormulaNumberRegex(locale.decimalSeparator));
7494
7498
  if (match) {
7495
7499
  chars.advanceBy(match[0].length);
@@ -7514,7 +7518,7 @@
7514
7518
  }
7515
7519
  return null;
7516
7520
  }
7517
- const separatorRegexp = /\w|\.|!|\$/;
7521
+ const separatorRegexp = /^[\w\.!\$]+/;
7518
7522
  /**
7519
7523
  * A "Symbol" is just basically any word-like element that can appear in a
7520
7524
  * formula, which is not a string. So:
@@ -7554,8 +7558,11 @@
7554
7558
  };
7555
7559
  }
7556
7560
  }
7557
- while (chars.current && separatorRegexp.test(chars.current)) {
7558
- result += chars.shift();
7561
+ const match = chars.remaining().match(separatorRegexp);
7562
+ if (match) {
7563
+ const value = match[0];
7564
+ result += value;
7565
+ chars.advanceBy(value.length);
7559
7566
  }
7560
7567
  if (result.length) {
7561
7568
  const value = result;
@@ -7617,7 +7624,10 @@
7617
7624
  return this.text.substring(this.currentIndex);
7618
7625
  }
7619
7626
  currentStartsWith(str) {
7620
- for (let j = 0; j < str.length; j++) {
7627
+ if (this.current !== str[0]) {
7628
+ return false;
7629
+ }
7630
+ for (let j = 1; j < str.length; j++) {
7621
7631
  if (this.text[this.currentIndex + j] !== str[j]) {
7622
7632
  return false;
7623
7633
  }
@@ -8649,7 +8659,7 @@
8649
8659
  return undefined;
8650
8660
  const dataSets = this.dataSets
8651
8661
  .map((ds) => toExcelDataset(this.getters, ds))
8652
- .filter((ds) => ds.range !== ""); // && range !== CellErrorType.InvalidReference ? show incorrect #ref ?
8662
+ .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
8653
8663
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
8654
8664
  return {
8655
8665
  ...this.getDefinition(),
@@ -9227,7 +9237,7 @@
9227
9237
  return undefined;
9228
9238
  const dataSets = this.dataSets
9229
9239
  .map((ds) => toExcelDataset(this.getters, ds))
9230
- .filter((ds) => ds.range !== ""); // && range !== CellErrorType.InvalidReference ? show incorrect #ref ?
9240
+ .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
9231
9241
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
9232
9242
  return {
9233
9243
  ...this.getDefinition(),
@@ -9533,7 +9543,7 @@
9533
9543
  return undefined;
9534
9544
  const dataSets = this.dataSets
9535
9545
  .map((ds) => toExcelDataset(this.getters, ds))
9536
- .filter((ds) => ds.range !== ""); // && range !== CellErrorType.InvalidReference ? show incorrect #ref ?
9546
+ .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
9537
9547
  const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
9538
9548
  return {
9539
9549
  ...this.getDefinition(),
@@ -18680,6 +18690,9 @@
18680
18690
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18681
18691
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18682
18692
  assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18693
+ if (searchKey && isEvaluationError(searchKey.value)) {
18694
+ return searchKey;
18695
+ }
18683
18696
  const getValueFromRange = (range, index) => range[index][0].value;
18684
18697
  const _isSorted = toBoolean(isSorted.value);
18685
18698
  const colIndex = _isSorted
@@ -18847,6 +18860,9 @@
18847
18860
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18848
18861
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18849
18862
  assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
18863
+ if (searchKey && isEvaluationError(searchKey.value)) {
18864
+ return searchKey;
18865
+ }
18850
18866
  const getValueFromRange = (range, index) => range[0][index].value;
18851
18867
  const _isSorted = toBoolean(isSorted.value);
18852
18868
  const rowIndex = _isSorted
@@ -18886,6 +18902,9 @@
18886
18902
  assert(() => lookupDirection === "col"
18887
18903
  ? returnRange[0].length === lookupRange[0].length
18888
18904
  : returnRange.length === lookupRange.length, _t("return_range should have the same dimensions as lookup_range."));
18905
+ if (searchKey && isEvaluationError(searchKey.value)) {
18906
+ return [[searchKey]];
18907
+ }
18889
18908
  const getElement = lookupDirection === "col"
18890
18909
  ? (range, index) => range[0][index].value
18891
18910
  : (range, index) => range[index][0].value;
@@ -20207,19 +20226,20 @@
20207
20226
  const formatNumberCurrency = createFormatActionSpec({
20208
20227
  name: _t("Currency"),
20209
20228
  descriptionValue: 1000.12,
20210
- format: (env) => env.model.config.defaultCurrencyFormat,
20229
+ format: (env) => env.model.config.defaultCurrencyFormat ?? DEFAULT_CURRENCY_FORMAT,
20211
20230
  });
20212
20231
  const formatNumberCurrencyRounded = {
20213
20232
  ...createFormatActionSpec({
20214
20233
  name: _t("Currency rounded"),
20215
20234
  descriptionValue: 1000,
20216
- format: (env) => roundFormat(env.model.config.defaultCurrencyFormat),
20235
+ format: (env) => roundFormat(env.model.config.defaultCurrencyFormat ?? DEFAULT_CURRENCY_FORMAT),
20217
20236
  }),
20218
20237
  isVisible: (env) => {
20219
20238
  const currencyFormat = env.model.config.defaultCurrencyFormat;
20220
- return currencyFormat !== roundFormat(currencyFormat);
20239
+ return currencyFormat !== roundFormat(currencyFormat ?? DEFAULT_CURRENCY_FORMAT);
20221
20240
  },
20222
20241
  };
20242
+ const DEFAULT_CURRENCY_FORMAT = "[$$]#,##0.00";
20223
20243
  const EXAMPLE_DATE = parseLiteral("2023/09/26 10:43:00 PM", DEFAULT_LOCALE);
20224
20244
  const formatCustomCurrency = {
20225
20245
  name: _t("Custom currency"),
@@ -26966,15 +26986,17 @@
26966
26986
  focus: {
26967
26987
  validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
26968
26988
  },
26969
- onComposerContentFocused: Function,
26970
26989
  inputStyle: { type: String, optional: true },
26971
26990
  rect: { type: Object, optional: true },
26972
26991
  delimitation: { type: Object, optional: true },
26973
- onComposerUnmounted: { type: Function, optional: true },
26992
+ onComposerCellFocused: { type: Function, optional: true },
26993
+ onComposerContentFocused: Function,
26994
+ isDefaultFocus: { type: Boolean, optional: true },
26974
26995
  };
26975
26996
  static components = { TextValueProvider, FunctionDescriptionProvider };
26976
26997
  static defaultProps = {
26977
26998
  inputStyle: "",
26999
+ isDefaultFocus: false,
26978
27000
  };
26979
27001
  composerRef = owl.useRef("o_composer");
26980
27002
  contentHelper = new ContentEditableHelper(this.composerRef.el);
@@ -27031,7 +27053,6 @@
27031
27053
  F4: this.processF4Key,
27032
27054
  Tab: (ev) => this.processTabKey(ev, "right"),
27033
27055
  "Shift+Tab": (ev) => this.processTabKey(ev, "left"),
27034
- "Ctrl+ ": this.processSpaceKey,
27035
27056
  };
27036
27057
  keyCodeMapping = {
27037
27058
  NumpadDecimal: this.processNumpadDecimal,
@@ -27039,12 +27060,12 @@
27039
27060
  setup() {
27040
27061
  owl.onMounted(() => {
27041
27062
  const el = this.composerRef.el;
27063
+ if (this.props.isDefaultFocus) {
27064
+ this.env.focusableElement.setFocusableElement(el);
27065
+ }
27042
27066
  this.contentHelper.updateEl(el);
27043
27067
  this.processTokenAtCursor();
27044
27068
  });
27045
- owl.onWillUnmount(() => {
27046
- this.props.onComposerUnmounted?.();
27047
- });
27048
27069
  owl.useEffect(() => {
27049
27070
  this.processContent();
27050
27071
  });
@@ -27053,7 +27074,8 @@
27053
27074
  // Handlers
27054
27075
  // ---------------------------------------------------------------------------
27055
27076
  processArrowKeys(ev) {
27056
- if (this.env.model.getters.isSelectingForComposer()) {
27077
+ if (this.env.model.getters.isSelectingForComposer() ||
27078
+ this.env.model.getters.getEditionMode() === "inactive") {
27057
27079
  this.functionDescriptionState.showDescription = false;
27058
27080
  // Prevent the default content editable behavior which moves the cursor
27059
27081
  ev.preventDefault();
@@ -27096,23 +27118,19 @@
27096
27118
  processTabKey(ev, direction) {
27097
27119
  ev.preventDefault();
27098
27120
  ev.stopPropagation();
27099
- const state = this.autoCompleteState;
27100
- if (state.showProvider && state.selectedIndex !== undefined) {
27101
- const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
27102
- if (autoCompleteValue) {
27103
- this.autoComplete(autoCompleteValue);
27104
- return;
27121
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
27122
+ const state = this.autoCompleteState;
27123
+ if (state.showProvider && state.selectedIndex !== undefined) {
27124
+ const autoCompleteValue = this.autoCompleteState.values[state.selectedIndex]?.text;
27125
+ if (autoCompleteValue) {
27126
+ this.autoComplete(autoCompleteValue);
27127
+ return;
27128
+ }
27105
27129
  }
27130
+ interactiveStopEdition(this.env);
27106
27131
  }
27107
- interactiveStopEdition(this.env);
27108
27132
  this.env.model.selection.moveAnchorCell(direction, 1);
27109
27133
  }
27110
- processSpaceKey(ev) {
27111
- ev.preventDefault();
27112
- ev.stopPropagation();
27113
- this.showFunctionAutocomplete("");
27114
- this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
27115
- }
27116
27134
  processEnterKey(ev, direction) {
27117
27135
  ev.preventDefault();
27118
27136
  ev.stopPropagation();
@@ -27174,6 +27192,9 @@
27174
27192
  this.compositionActive = false;
27175
27193
  }
27176
27194
  onKeydown(ev) {
27195
+ if (this.env.model.getters.getEditionMode() === "inactive") {
27196
+ return;
27197
+ }
27177
27198
  if (ev.key.startsWith("Arrow")) {
27178
27199
  this.processArrowKeys(ev);
27179
27200
  return;
@@ -27187,14 +27208,33 @@
27187
27208
  ev.stopPropagation();
27188
27209
  }
27189
27210
  }
27211
+ onPaste(ev) {
27212
+ if (this.env.model.getters.getEditionMode() !== "inactive") {
27213
+ ev.stopPropagation();
27214
+ }
27215
+ }
27190
27216
  /*
27191
27217
  * Triggered automatically by the content-editable between the keydown and key up
27192
27218
  * */
27193
27219
  onInput(ev) {
27194
- if (this.props.focus === "inactive" || !this.shouldProcessInputEvents) {
27220
+ if (!this.shouldProcessInputEvents) {
27221
+ return;
27222
+ }
27223
+ if (ev.inputType === "insertFromPaste" &&
27224
+ this.env.model.getters.getEditionMode() === "inactive") {
27195
27225
  return;
27196
27226
  }
27197
- let content = this.contentHelper.getText();
27227
+ ev.stopPropagation();
27228
+ let content;
27229
+ if (this.env.model.getters.getEditionMode() === "inactive") {
27230
+ content = ev.data || "";
27231
+ }
27232
+ else {
27233
+ content = this.contentHelper.getText();
27234
+ }
27235
+ if (this.props.focus === "inactive") {
27236
+ return this.props.onComposerCellFocused?.(content);
27237
+ }
27198
27238
  let selection = this.contentHelper.getCurrentSelection();
27199
27239
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
27200
27240
  this.env.model.dispatch("SET_CURRENT_CONTENT", {
@@ -27270,9 +27310,8 @@
27270
27310
  }
27271
27311
  const newSelection = this.contentHelper.getCurrentSelection();
27272
27312
  this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
27273
- if (this.props.focus === "inactive") {
27274
- this.props.onComposerContentFocused(newSelection);
27275
- }
27313
+ this.props.onComposerContentFocused();
27314
+ if (this.props.focus === "inactive") ;
27276
27315
  this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
27277
27316
  this.processTokenAtCursor();
27278
27317
  }
@@ -27439,7 +27478,7 @@
27439
27478
  const highlights = this.env.model.getters.getHighlights();
27440
27479
  const refSheet = sheetName
27441
27480
  ? this.env.model.getters.getSheetIdByName(sheetName)
27442
- : this.env.model.getters.getCurrentEditedCell().sheetId;
27481
+ : this.env.model.getters.getCurrentEditedCell()?.sheetId;
27443
27482
  const highlight = highlights.find((highlight) => {
27444
27483
  if (highlight.sheetId !== refSheet)
27445
27484
  return false;
@@ -27566,56 +27605,30 @@
27566
27605
  focus: {
27567
27606
  validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
27568
27607
  },
27569
- onComposerUnmounted: Function,
27608
+ onComposerCellFocused: Function,
27570
27609
  onComposerContentFocused: Function,
27571
27610
  gridDims: Object,
27572
27611
  };
27573
27612
  static components = { Composer };
27574
- gridComposerRef;
27575
- zone;
27576
- rect;
27613
+ rect = this.defaultRect;
27614
+ isEditing = false;
27577
27615
  isCellReferenceVisible;
27578
- composerState;
27616
+ get defaultRect() {
27617
+ return { x: 0, y: 0, width: 0, height: 0 };
27618
+ }
27579
27619
  setup() {
27580
- this.gridComposerRef = owl.useRef("gridComposer");
27581
- this.composerState = owl.useState({
27582
- rect: undefined,
27583
- delimitation: undefined,
27584
- });
27585
- const { sheetId, col, row } = this.env.model.getters.getActivePosition();
27586
- this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
27587
- this.rect = this.env.model.getters.getVisibleRect(this.zone);
27588
- this.isCellReferenceVisible = false;
27589
- owl.onMounted(() => {
27590
- const el = this.gridComposerRef.el;
27591
- this.composerState.rect = {
27592
- x: this.rect.x,
27593
- y: this.rect.y,
27594
- width: el.clientWidth,
27595
- height: el.clientHeight,
27596
- };
27597
- this.composerState.delimitation = {
27598
- width: this.props.gridDims.width,
27599
- height: this.props.gridDims.height,
27600
- };
27601
- });
27602
27620
  owl.onWillUpdateProps(() => {
27603
- if (this.isCellReferenceVisible) {
27604
- return;
27605
- }
27606
- const sheetId = this.env.model.getters.getActiveSheetId();
27607
- const zone = this.env.model.getters.getSelectedZone();
27608
- const rect = this.env.model.getters.getVisibleRect(zone);
27609
- if (!deepEquals(rect, this.rect) ||
27610
- sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
27611
- this.isCellReferenceVisible = true;
27612
- }
27621
+ this.updateComponentPosition();
27622
+ this.updateCellReferenceVisibility();
27613
27623
  });
27614
27624
  }
27615
27625
  get shouldDisplayCellReference() {
27616
27626
  return this.isCellReferenceVisible;
27617
27627
  }
27618
27628
  get cellReference() {
27629
+ if (!this.env.model.getters.getCurrentEditedCell()) {
27630
+ return "";
27631
+ }
27619
27632
  const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
27620
27633
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
27621
27634
  return getFullReference(prefixSheet ? this.env.model.getters.getSheetName(sheetId) : undefined, toXC(col, row));
@@ -27627,7 +27640,27 @@
27627
27640
  top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
27628
27641
  });
27629
27642
  }
27643
+ get composerProps() {
27644
+ const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
27645
+ return {
27646
+ rect: { ...this.rect },
27647
+ delimitation: {
27648
+ width,
27649
+ height,
27650
+ },
27651
+ focus: this.props.focus,
27652
+ isDefaultFocus: true,
27653
+ onComposerContentFocused: this.props.onComposerContentFocused,
27654
+ onComposerCellFocused: this.props.onComposerCellFocused,
27655
+ };
27656
+ }
27630
27657
  get containerStyle() {
27658
+ if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27659
+ return `
27660
+ position: absolute;
27661
+ z-index: -1000;
27662
+ `;
27663
+ }
27631
27664
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27632
27665
  const cell = this.env.model.getters.getActiveCell();
27633
27666
  const position = this.env.model.getters.getActivePosition();
@@ -27647,6 +27680,8 @@
27647
27680
  if (!isFormula) {
27648
27681
  textAlign = style.align || cell.defaultAlign;
27649
27682
  }
27683
+ const maxHeight = this.props.gridDims.height - this.rect.y;
27684
+ const maxWidth = this.props.gridDims.width - this.rect.x;
27650
27685
  /**
27651
27686
  * min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
27652
27687
  * including all the paddings/margins of the composer
@@ -27658,6 +27693,8 @@
27658
27693
  top: `${top}px`,
27659
27694
  "min-width": `${width + 1}px`,
27660
27695
  "min-height": `${height + 1}px`,
27696
+ "max-width": `${maxWidth}px`,
27697
+ "max-height": `${maxHeight}px`,
27661
27698
  background,
27662
27699
  color,
27663
27700
  "font-size": `${fontSizeInPixels(fontSize)}px`,
@@ -27667,13 +27704,31 @@
27667
27704
  "text-align": textAlign,
27668
27705
  });
27669
27706
  }
27670
- get composerStyle() {
27671
- const maxHeight = this.props.gridDims.height - this.rect.y;
27672
- const maxWidth = this.props.gridDims.width - this.rect.x;
27673
- return cssPropertiesToCss({
27674
- "max-width": `${maxWidth}px`,
27675
- "max-height": `${maxHeight}px`,
27676
- });
27707
+ updateComponentPosition() {
27708
+ const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
27709
+ if (this.isEditing !== isEditing) {
27710
+ this.isEditing = isEditing;
27711
+ if (!isEditing) {
27712
+ this.rect = this.defaultRect;
27713
+ this.env.focusableElement.focus();
27714
+ return;
27715
+ }
27716
+ const position = this.env.model.getters.getActivePosition();
27717
+ const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
27718
+ this.rect = this.env.model.getters.getVisibleRect(zone);
27719
+ }
27720
+ }
27721
+ updateCellReferenceVisibility() {
27722
+ if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
27723
+ return;
27724
+ }
27725
+ const sheetId = this.env.model.getters.getActiveSheetId();
27726
+ const zone = this.env.model.getters.getSelectedZone();
27727
+ const rect = this.env.model.getters.getVisibleRect(zone);
27728
+ if (!deepEquals(rect, this.rect) ||
27729
+ sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
27730
+ this.isCellReferenceVisible = true;
27731
+ }
27677
27732
  }
27678
27733
  }
27679
27734
 
@@ -28773,7 +28828,6 @@
28773
28828
  this.props.onCellDoubleClicked(col, row);
28774
28829
  }
28775
28830
  onContextMenu(ev) {
28776
- ev.preventDefault();
28777
28831
  const [col, row] = this.getCartesianCoordinates(ev);
28778
28832
  this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
28779
28833
  }
@@ -29838,7 +29892,6 @@
29838
29892
  HEADER_WIDTH = HEADER_WIDTH;
29839
29893
  menuState;
29840
29894
  gridRef;
29841
- hiddenInput;
29842
29895
  onMouseWheel;
29843
29896
  canvasPosition;
29844
29897
  hoveredCell;
@@ -29849,15 +29902,14 @@
29849
29902
  menuItems: [],
29850
29903
  });
29851
29904
  this.gridRef = owl.useRef("grid");
29852
- this.hiddenInput = owl.useRef("hiddenInput");
29853
29905
  this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
29854
29906
  this.hoveredCell = owl.useState({ col: undefined, row: undefined });
29855
29907
  owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
29856
29908
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
29857
29909
  owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
29858
29910
  owl.useExternalListener(document.body, "paste", this.paste);
29859
- owl.onMounted(() => this.focus());
29860
- this.props.exposeFocus(() => this.focus());
29911
+ owl.onMounted(() => this.focusDefaultElement());
29912
+ this.props.exposeFocus(() => this.focusDefaultElement());
29861
29913
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
29862
29914
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
29863
29915
  this.moveCanvas(deltaX, deltaY);
@@ -29881,7 +29933,7 @@
29881
29933
  if (this.env.model.getters.hasOpenedPopover()) {
29882
29934
  this.closeOpenedPopover();
29883
29935
  }
29884
- this.focus();
29936
+ this.focusDefaultElement();
29885
29937
  }
29886
29938
  // this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
29887
29939
  // down itself
@@ -30060,10 +30112,10 @@
30060
30112
  "Alt+Shift+ArrowUp": () => this.processHeaderGroupingKey("up"),
30061
30113
  "Alt+Shift+ArrowDown": () => this.processHeaderGroupingKey("down"),
30062
30114
  };
30063
- focus() {
30115
+ focusDefaultElement() {
30064
30116
  if (!this.env.model.getters.getSelectedFigureId() &&
30065
30117
  this.env.model.getters.getEditionMode() === "inactive") {
30066
- this.hiddenInput.el?.focus();
30118
+ this.env.focusableElement.focus();
30067
30119
  }
30068
30120
  }
30069
30121
  get gridEl() {
@@ -30199,19 +30251,6 @@
30199
30251
  return;
30200
30252
  }
30201
30253
  }
30202
- onInput(ev) {
30203
- // the user meant to paste in the sheet, not open the composer with the pasted content
30204
- if (!ev.isComposing && ev.inputType === "insertFromPaste") {
30205
- return;
30206
- }
30207
- if (ev.data) {
30208
- // if the user types a character on the grid, it means he wants to start composing the selected cell with that
30209
- // character
30210
- ev.preventDefault();
30211
- ev.stopPropagation();
30212
- this.props.onGridComposerCellFocused(ev.data);
30213
- }
30214
- }
30215
30254
  // ---------------------------------------------------------------------------
30216
30255
  // Context Menu
30217
30256
  // ---------------------------------------------------------------------------
@@ -30326,7 +30365,7 @@
30326
30365
  }
30327
30366
  closeMenu() {
30328
30367
  this.menuState.isOpen = false;
30329
- this.focus();
30368
+ this.focusDefaultElement();
30330
30369
  }
30331
30370
  processHeaderGroupingKey(direction) {
30332
30371
  if (this.env.model.getters.getSelectedZones().length !== 1) {
@@ -34243,6 +34282,31 @@
34243
34282
  return data;
34244
34283
  },
34245
34284
  },
34285
+ {
34286
+ description: "Fix datafilter duplication",
34287
+ from: 12,
34288
+ to: 12.5,
34289
+ applyMigration(data) {
34290
+ for (let sheet of data.sheets || []) {
34291
+ let knownDataFilterZones = [];
34292
+ for (let filterTable of sheet.filterTables || []) {
34293
+ const zone = toZone(filterTable.range);
34294
+ // See commit message for the details
34295
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34296
+ if (intersectZoneIndex !== -1) {
34297
+ knownDataFilterZones[intersectZoneIndex] = zone;
34298
+ }
34299
+ else {
34300
+ knownDataFilterZones.push(zone);
34301
+ }
34302
+ }
34303
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
34304
+ range: zoneToXc(zone),
34305
+ }));
34306
+ }
34307
+ return data;
34308
+ },
34309
+ },
34246
34310
  {
34247
34311
  description: "Change Border description structure",
34248
34312
  from: 12,
@@ -36072,12 +36136,12 @@
36072
36136
  /*
36073
36137
  * Reconstructs the original formula string based on a normalized form and its dependencies
36074
36138
  */
36075
- getFormulaCellContent(sheetId, compiledFormula, dependencies) {
36139
+ getFormulaCellContent(sheetId, compiledFormula, dependencies, useFixedReference = false) {
36076
36140
  let rangeIndex = 0;
36077
36141
  return concat(compiledFormula.tokens.map((token) => {
36078
36142
  if (token.type === "REFERENCE") {
36079
36143
  const range = dependencies[rangeIndex++];
36080
- return this.getters.getRangeString(range, sheetId);
36144
+ return this.getters.getRangeString(range, sheetId, { useFixedReference });
36081
36145
  }
36082
36146
  return token.value;
36083
36147
  }));
@@ -36280,8 +36344,11 @@
36280
36344
  * being a computed property to rebuild the dependencies XC.
36281
36345
  */
36282
36346
  createFormulaCellWithDependencies(id, compiledFormula, format, style, sheetId) {
36283
- const dependencies = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
36284
- return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString.bind(this));
36347
+ const dependencies = [];
36348
+ for (const xc of compiledFormula.dependencies) {
36349
+ dependencies.push(this.getters.getRangeFromSheetXC(sheetId, xc));
36350
+ }
36351
+ return new FormulaCellWithDependencies(id, compiledFormula, format, style, dependencies, sheetId, this.getters.getRangeString);
36285
36352
  }
36286
36353
  createErrorFormula(id, content, format, style, error) {
36287
36354
  return {
@@ -36335,7 +36402,7 @@
36335
36402
  const tokens = compiledFormula.tokens.map((token) => {
36336
36403
  if (token.type === "REFERENCE") {
36337
36404
  const index = rangeIndex++;
36338
- return new RangeReferenceToken(() => this.getRangeString(dependencies[index], this.sheetId));
36405
+ return new RangeReferenceToken(dependencies, index, this.sheetId, this.getRangeString);
36339
36406
  }
36340
36407
  return token;
36341
36408
  });
@@ -36348,15 +36415,34 @@
36348
36415
  get content() {
36349
36416
  return concat(this.compiledFormula.tokens.map((token) => token.value));
36350
36417
  }
36418
+ get contentWithFixedReferences() {
36419
+ let rangeIndex = 0;
36420
+ return concat(this.compiledFormula.tokens.map((token) => {
36421
+ if (token.type === "REFERENCE") {
36422
+ const index = rangeIndex++;
36423
+ return this.getRangeString(this.compiledFormula.dependencies[index], this.sheetId, {
36424
+ useFixedReference: true,
36425
+ });
36426
+ }
36427
+ return token.value;
36428
+ }));
36429
+ }
36351
36430
  }
36352
36431
  class RangeReferenceToken {
36353
- getValue;
36432
+ ranges;
36433
+ rangeIndex;
36434
+ sheetId;
36435
+ getRangeString;
36354
36436
  type = "REFERENCE";
36355
- constructor(getValue) {
36356
- this.getValue = getValue;
36437
+ constructor(ranges, rangeIndex, sheetId, getRangeString) {
36438
+ this.ranges = ranges;
36439
+ this.rangeIndex = rangeIndex;
36440
+ this.sheetId = sheetId;
36441
+ this.getRangeString = getRangeString;
36357
36442
  }
36358
36443
  get value() {
36359
- return this.getValue();
36444
+ const range = this.ranges[this.rangeIndex];
36445
+ return this.getRangeString(range, this.sheetId);
36360
36446
  }
36361
36447
  }
36362
36448
 
@@ -36652,7 +36738,13 @@
36652
36738
  }
36653
36739
  }
36654
36740
  exportForExcel(data) {
36655
- this.export(data);
36741
+ if (data.sheets) {
36742
+ for (let sheet of data.sheets) {
36743
+ if (this.cfRules[sheet.id]) {
36744
+ sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useFixedReference: true }));
36745
+ }
36746
+ }
36747
+ }
36656
36748
  }
36657
36749
  // ---------------------------------------------------------------------------
36658
36750
  // Getters
@@ -36717,11 +36809,11 @@
36717
36809
  // ---------------------------------------------------------------------------
36718
36810
  // Private
36719
36811
  // ---------------------------------------------------------------------------
36720
- mapToConditionalFormat(sheetId, cf) {
36812
+ mapToConditionalFormat(sheetId, cf, { useFixedReference } = { useFixedReference: false }) {
36721
36813
  return {
36722
36814
  ...cf,
36723
36815
  ranges: cf.ranges.map((range) => {
36724
- return this.getters.getRangeString(range, sheetId);
36816
+ return this.getters.getRangeString(range, sheetId, { useFixedReference });
36725
36817
  }),
36726
36818
  };
36727
36819
  }
@@ -38789,8 +38881,10 @@
38789
38881
  *
38790
38882
  * @param range the range (received from getRangeFromXC or getRangeFromZone)
38791
38883
  * @param forSheetId the id of the sheet where the range string is supposed to be used.
38884
+ * @param options
38885
+ * @param options.useFixedReference if true, the range will be returned with fixed row and column
38792
38886
  */
38793
- getRangeString(range, forSheetId) {
38887
+ getRangeString(range, forSheetId, options = { useFixedReference: false }) {
38794
38888
  if (!range) {
38795
38889
  return CellErrorType.InvalidReference;
38796
38890
  }
@@ -38817,7 +38911,7 @@
38817
38911
  if (prefixSheet && !sheetName) {
38818
38912
  return CellErrorType.InvalidReference;
38819
38913
  }
38820
- let rangeString = this.getRangePartString(rangeImpl, 0);
38914
+ let rangeString = this.getRangePartString(rangeImpl, 0, options);
38821
38915
  if (rangeImpl.parts && rangeImpl.parts.length === 2) {
38822
38916
  // this if converts A2:A2 into A2 except if any part of the original range had fixed row or column (with $)
38823
38917
  if (rangeImpl.zone.top !== rangeImpl.zone.bottom ||
@@ -38827,7 +38921,7 @@
38827
38921
  rangeImpl.parts[1].rowFixed ||
38828
38922
  rangeImpl.parts[1].colFixed) {
38829
38923
  rangeString += ":";
38830
- rangeString += this.getRangePartString(rangeImpl, 1);
38924
+ rangeString += this.getRangePartString(rangeImpl, 1, options);
38831
38925
  }
38832
38926
  }
38833
38927
  return `${prefixSheet ? sheetName + "!" : ""}${rangeString}`;
@@ -38868,13 +38962,13 @@
38868
38962
  /**
38869
38963
  * Get a Xc string that represent a part of a range
38870
38964
  */
38871
- getRangePartString(range, part) {
38965
+ getRangePartString(range, part, options = { useFixedReference: false }) {
38872
38966
  const colFixed = range.parts && range.parts[part]?.colFixed ? "$" : "";
38873
38967
  const col = part === 0 ? numberToLetters(range.zone.left) : numberToLetters(range.zone.right);
38874
38968
  const rowFixed = range.parts && range.parts[part]?.rowFixed ? "$" : "";
38875
38969
  const row = part === 0 ? String(range.zone.top + 1) : String(range.zone.bottom + 1);
38876
38970
  let str = "";
38877
- if (range.isFullCol) {
38971
+ if (range.isFullCol && !options.useFixedReference) {
38878
38972
  if (part === 0 && range.unboundedZone.hasHeader) {
38879
38973
  str = colFixed + col + rowFixed + row;
38880
38974
  }
@@ -38882,7 +38976,7 @@
38882
38976
  str = colFixed + col;
38883
38977
  }
38884
38978
  }
38885
- else if (range.isFullRow) {
38979
+ else if (range.isFullRow && !options.useFixedReference) {
38886
38980
  if (part === 0 && range.unboundedZone.hasHeader) {
38887
38981
  str = colFixed + col + rowFixed + row;
38888
38982
  }
@@ -41883,7 +41977,13 @@
41883
41977
  const format = newFormat
41884
41978
  ? getItemId(newFormat, data.formats)
41885
41979
  : exportedCellData.format;
41886
- const content = !isExported ? newContent : exportedCellData.content;
41980
+ let content;
41981
+ if (formulaCell instanceof FormulaCellWithDependencies) {
41982
+ content = formulaCell.contentWithFixedReferences;
41983
+ }
41984
+ else {
41985
+ content = !isExported ? newContent : exportedCellData.content;
41986
+ }
41887
41987
  exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
41888
41988
  }
41889
41989
  }
@@ -51067,6 +51167,16 @@
51067
51167
  }
51068
51168
  }
51069
51169
 
51170
+ class FocusableElement {
51171
+ focusableElement = undefined;
51172
+ setFocusableElement(element) {
51173
+ this.focusableElement = element;
51174
+ }
51175
+ focus() {
51176
+ this.focusableElement?.focus();
51177
+ }
51178
+ }
51179
+
51070
51180
  const RIPPLE_KEY_FRAMES = [
51071
51181
  { transform: "scale(0)" },
51072
51182
  { transform: "scale(0.8)", offset: 0.33 },
@@ -53221,6 +53331,7 @@
53221
53331
  toggleSidePanel: this.toggleSidePanel.bind(this),
53222
53332
  clipboard: this.env.clipboard || instantiateClipboard(),
53223
53333
  startCellEdition: (content) => this.onGridComposerCellFocused(content),
53334
+ focusableElement: new FocusableElement(),
53224
53335
  });
53225
53336
  owl.useEffect(() => {
53226
53337
  /**
@@ -53339,16 +53450,17 @@
53339
53450
  }
53340
53451
  this.composer.topBarFocus = "contentFocus";
53341
53452
  this.composer.gridFocusMode = "inactive";
53342
- this.setComposerContent({ selection } || {});
53453
+ this.setComposerContent({ selection });
53343
53454
  }
53344
- onGridComposerContentFocused() {
53455
+ onGridComposerContentFocused(selection) {
53345
53456
  if (this.model.getters.isReadonly()) {
53346
53457
  return;
53347
53458
  }
53348
53459
  this.composer.topBarFocus = "inactive";
53349
53460
  this.composer.gridFocusMode = "contentFocus";
53350
- this.setComposerContent({});
53461
+ this.setComposerContent({ selection });
53351
53462
  }
53463
+ // TODO: either both are defined or none of them. change those args to an object
53352
53464
  onGridComposerCellFocused(content, selection) {
53353
53465
  if (this.model.getters.isReadonly()) {
53354
53466
  return;
@@ -55234,12 +55346,7 @@
55234
55346
  attrs.push(["t", "str"]);
55235
55347
  cycle = escapeXml /*xml*/ `<v>${cell.value}</v>`;
55236
55348
  }
55237
- node = escapeXml /*xml*/ `
55238
- <f>
55239
- ${XlsxFormula}
55240
- </f>
55241
- ${cycle}
55242
- `;
55349
+ node = escapeXml /*xml*/ `<f>${XlsxFormula}</f>${cycle}`;
55243
55350
  return { attrs, node };
55244
55351
  }
55245
55352
  function addContent(content, sharedStrings, forceString = false) {
@@ -56059,11 +56166,10 @@
56059
56166
  ({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader || isPlainText));
56060
56167
  }
56061
56168
  attributes.push(...additionalAttrs);
56062
- cellNodes.push(escapeXml /*xml*/ `
56063
- <c ${formatAttributes(attributes)}>
56064
- ${cellNode}
56065
- </c>
56066
- `);
56169
+ // prettier-ignore
56170
+ cellNodes.push(escapeXml /*xml*/ `<c ${formatAttributes(attributes)}>
56171
+ ${cellNode}
56172
+ </c>`);
56067
56173
  }
56068
56174
  }
56069
56175
  if (cellNodes.length || row.size !== DEFAULT_CELL_HEIGHT || row.isHidden) {
@@ -56659,7 +56765,6 @@
56659
56765
  ...config,
56660
56766
  mode: config.mode || "normal",
56661
56767
  custom: config.custom || {},
56662
- defaultCurrencyFormat: config.defaultCurrencyFormat || "[$$]#,##0.00",
56663
56768
  external: this.setupExternalConfig(config.external || {}),
56664
56769
  transportService,
56665
56770
  client,
@@ -56697,6 +56802,7 @@
56697
56802
  custom: this.config.custom,
56698
56803
  uiActions: this.config,
56699
56804
  session: this.session,
56805
+ defaultCurrencyFormat: this.config.defaultCurrencyFormat,
56700
56806
  };
56701
56807
  }
56702
56808
  // ---------------------------------------------------------------------------
@@ -57078,9 +57184,9 @@
57078
57184
  exports.tokenize = tokenize;
57079
57185
 
57080
57186
 
57081
- __info__.version = "17.1.2";
57082
- __info__.date = "2024-01-29T13:54:42.679Z";
57083
- __info__.hash = "043a0d5";
57187
+ __info__.version = "17.1.4";
57188
+ __info__.date = "2024-02-09T13:09:13.430Z";
57189
+ __info__.hash = "16d3ece";
57084
57190
 
57085
57191
 
57086
57192
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);