@odoo/o-spreadsheet 16.4.34 → 16.4.37

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.
@@ -3233,8 +3233,11 @@
3233
3233
  /**
3234
3234
  * Create a range from a xc. If the xc is empty, this function returns undefined.
3235
3235
  */
3236
- function createRange(getters, sheetId, range) {
3237
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
3236
+ function createValidRange(getters, sheetId, xc) {
3237
+ if (!xc)
3238
+ return;
3239
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
3240
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
3238
3241
  }
3239
3242
  /**
3240
3243
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5701,6 +5704,7 @@
5701
5704
  };
5702
5705
 
5703
5706
  const macRegex = /Mac/i;
5707
+ const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
5704
5708
  /**
5705
5709
  * Return true if the event was triggered from
5706
5710
  * a child element.
@@ -5739,6 +5743,31 @@
5739
5743
  function getOpenedMenus() {
5740
5744
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
5741
5745
  }
5746
+ const letterRegex = /^[a-zA-Z]$/;
5747
+ /**
5748
+ * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
5749
+ *
5750
+ * @argument ev - The keyboard event to transform
5751
+ * @argument mode - Use either ev.key of ev.code to get the string shortcut
5752
+ *
5753
+ * @example
5754
+ * event : { ctrlKey: true, key: "a" } => "Ctrl+A"
5755
+ * event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
5756
+ */
5757
+ function keyboardEventToShortcutString(ev, mode = "key") {
5758
+ let keyDownString = "";
5759
+ if (!MODIFIER_KEYS.includes(ev.key)) {
5760
+ if (isCtrlKey(ev))
5761
+ keyDownString += "Ctrl+";
5762
+ if (ev.altKey)
5763
+ keyDownString += "Alt+";
5764
+ if (ev.shiftKey)
5765
+ keyDownString += "Shift+";
5766
+ }
5767
+ const key = mode === "key" ? ev.key : ev.code;
5768
+ keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
5769
+ return keyDownString;
5770
+ }
5742
5771
  function isMacOS() {
5743
5772
  return Boolean(macRegex.test(navigator.userAgent));
5744
5773
  }
@@ -5757,8 +5786,7 @@
5757
5786
  */
5758
5787
  function useSpreadsheetRect() {
5759
5788
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
5760
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
5761
- updatePosition();
5789
+ let spreadsheetElement = null;
5762
5790
  function updatePosition() {
5763
5791
  if (!spreadsheetElement) {
5764
5792
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -5896,7 +5924,7 @@
5896
5924
  if (!anchor)
5897
5925
  return;
5898
5926
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
5899
- const elDims = {
5927
+ let elDims = {
5900
5928
  width: el.getBoundingClientRect().width,
5901
5929
  height: el.getBoundingClientRect().height,
5902
5930
  };
@@ -5904,7 +5932,14 @@
5904
5932
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
5905
5933
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
5906
5934
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
5907
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
5935
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
5936
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
5937
+ // Re-compute the dimensions after setting the max-width and max-height
5938
+ elDims = {
5939
+ width: el.getBoundingClientRect().width,
5940
+ height: el.getBoundingClientRect().height,
5941
+ };
5942
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
5908
5943
  for (const property of Object.keys(style)) {
5909
5944
  el.style[property] = style[property];
5910
5945
  }
@@ -5980,8 +6015,6 @@
5980
6015
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
5981
6016
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
5982
6017
  const cssProperties = {
5983
- "max-height": maxHeight + "px",
5984
- "max-width": maxWidth + "px",
5985
6018
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
5986
6019
  this.spreadsheetOffset.y -
5987
6020
  verticalOffset +
@@ -16539,7 +16572,7 @@
16539
16572
  constructor(definition, sheetId, getters) {
16540
16573
  super(definition, sheetId, getters);
16541
16574
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
16542
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
16575
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
16543
16576
  this.background = definition.background;
16544
16577
  this.verticalAxisPosition = definition.verticalAxisPosition;
16545
16578
  this.legendPosition = definition.legendPosition;
@@ -16784,7 +16817,7 @@
16784
16817
  type = "gauge";
16785
16818
  constructor(definition, sheetId, getters) {
16786
16819
  super(definition, sheetId, getters);
16787
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
16820
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
16788
16821
  this.sectionRule = definition.sectionRule;
16789
16822
  this.background = definition.background;
16790
16823
  }
@@ -17123,7 +17156,7 @@
17123
17156
  constructor(definition, sheetId, getters) {
17124
17157
  super(definition, sheetId, getters);
17125
17158
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17126
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
17159
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
17127
17160
  this.background = definition.background;
17128
17161
  this.verticalAxisPosition = definition.verticalAxisPosition;
17129
17162
  this.legendPosition = definition.legendPosition;
@@ -17421,7 +17454,7 @@
17421
17454
  constructor(definition, sheetId, getters) {
17422
17455
  super(definition, sheetId, getters);
17423
17456
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17424
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
17457
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
17425
17458
  this.background = definition.background;
17426
17459
  this.legendPosition = definition.legendPosition;
17427
17460
  this.aggregated = definition.aggregated;
@@ -17589,8 +17622,8 @@
17589
17622
  type = "scorecard";
17590
17623
  constructor(definition, sheetId, getters) {
17591
17624
  super(definition, sheetId, getters);
17592
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
17593
- this.baseline = createRange(getters, sheetId, definition.baseline);
17625
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
17626
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
17594
17627
  this.baselineMode = definition.baselineMode;
17595
17628
  this.baselineDescr = definition.baselineDescr;
17596
17629
  this.background = definition.background;
@@ -20949,7 +20982,7 @@
20949
20982
  }
20950
20983
  const getters = this.env.model.getters;
20951
20984
  const sheetId = getters.getActiveSheetId();
20952
- const labelRange = createRange(getters, sheetId, this.labelRange);
20985
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
20953
20986
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
20954
20987
  if (dataSets.length) {
20955
20988
  return dataSets[0].dataRange.zone.top + 1;
@@ -23414,14 +23447,14 @@
23414
23447
  }
23415
23448
  onKeyDown(ev) {
23416
23449
  const figure = this.props.figure;
23417
- switch (ev.key) {
23450
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
23451
+ switch (keyDownShortcut) {
23418
23452
  case "Delete":
23419
23453
  this.env.model.dispatch("DELETE_FIGURE", {
23420
23454
  sheetId: this.env.model.getters.getActiveSheetId(),
23421
23455
  id: figure.id,
23422
23456
  });
23423
23457
  this.props.onFigureDeleted();
23424
- ev.stopPropagation();
23425
23458
  ev.preventDefault();
23426
23459
  ev.stopPropagation();
23427
23460
  break;
@@ -23442,7 +23475,22 @@
23442
23475
  x: figure.x + delta[0],
23443
23476
  y: figure.y + delta[1],
23444
23477
  });
23478
+ ev.preventDefault();
23445
23479
  ev.stopPropagation();
23480
+ break;
23481
+ case "Ctrl+A":
23482
+ // Maybe in the future we will implement a way to select all figures
23483
+ ev.preventDefault();
23484
+ ev.stopPropagation();
23485
+ break;
23486
+ case "Ctrl+Y":
23487
+ case "Ctrl+Z":
23488
+ if (keyDownShortcut === "Ctrl+Y") {
23489
+ this.env.model.dispatch("REQUEST_REDO");
23490
+ }
23491
+ else if (keyDownShortcut === "Ctrl+Z") {
23492
+ this.env.model.dispatch("REQUEST_UNDO");
23493
+ }
23446
23494
  ev.preventDefault();
23447
23495
  ev.stopPropagation();
23448
23496
  break;
@@ -24313,8 +24361,15 @@
24313
24361
  }
24314
24362
  onPaste(ev) {
24315
24363
  if (this.env.model.getters.getEditionMode() !== "inactive") {
24364
+ // let the browser clipboard work
24316
24365
  ev.stopPropagation();
24317
24366
  }
24367
+ else {
24368
+ // the user meant to paste in the sheet, not open the composer with the pasted content
24369
+ // While we're not editing, we still have the focus and should therefore prevent
24370
+ // the native "paste" to occur.
24371
+ ev.preventDefault();
24372
+ }
24318
24373
  }
24319
24374
  /*
24320
24375
  * Triggered automatically by the content-editable between the keydown and key up
@@ -24323,10 +24378,6 @@
24323
24378
  if (!this.shouldProcessInputEvents) {
24324
24379
  return;
24325
24380
  }
24326
- if (ev.inputType === "insertFromPaste" &&
24327
- this.env.model.getters.getEditionMode() === "inactive") {
24328
- return;
24329
- }
24330
24381
  ev.stopPropagation();
24331
24382
  let content;
24332
24383
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -24757,10 +24808,7 @@
24757
24808
  }
24758
24809
  get containerStyle() {
24759
24810
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
24760
- return `
24761
- position: absolute;
24762
- z-index: -1000;
24763
- `;
24811
+ return `z-index: -1000;`;
24764
24812
  }
24765
24813
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
24766
24814
  const cell = this.env.model.getters.getActiveCell();
@@ -25343,7 +25391,7 @@
25343
25391
  });
25344
25392
  }
25345
25393
  getContainerRect(container) {
25346
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
25394
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
25347
25395
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
25348
25396
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
25349
25397
  const width = viewWidth - x;
@@ -34590,6 +34638,9 @@
34590
34638
  if (range.invalidXc) {
34591
34639
  return range.invalidXc;
34592
34640
  }
34641
+ if (!this.getters.tryGetSheet(range.sheetId)) {
34642
+ return INCORRECT_RANGE_STRING;
34643
+ }
34593
34644
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
34594
34645
  return INCORRECT_RANGE_STRING;
34595
34646
  }
@@ -37641,16 +37692,22 @@
37641
37692
  let newContent = undefined;
37642
37693
  let newFormat = undefined;
37643
37694
  let isExported = true;
37695
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37644
37696
  const formulaCell = this.getCorrespondingFormulaCell(position);
37645
37697
  if (formulaCell) {
37646
37698
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
37647
37699
  isFormula = isExported;
37648
37700
  if (!isExported) {
37649
- newContent = value.toString();
37650
- newFormat = evaluatedCell.format;
37701
+ // If the cell contains a non-exported formula and that is evaluates to
37702
+ // nothing* ,we don't export it.
37703
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
37704
+ // the empty string.
37705
+ if (value !== "") {
37706
+ newContent = value.toString();
37707
+ newFormat = evaluatedCell.format;
37708
+ }
37651
37709
  }
37652
37710
  }
37653
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37654
37711
  const exportedCellData = exportedSheetData.cells[xc] || {};
37655
37712
  const format = newFormat
37656
37713
  ? getItemId(newFormat, data.formats)
@@ -46521,9 +46578,11 @@
46521
46578
  if (ev.key === "Enter") {
46522
46579
  ev.preventDefault();
46523
46580
  this.stopEdition();
46581
+ this.env.focusableElement.focus();
46524
46582
  }
46525
46583
  if (ev.key === "Escape") {
46526
46584
  this.cancelEdition();
46585
+ this.env.focusableElement.focus();
46527
46586
  }
46528
46587
  }
46529
46588
  onClickSheetName(ev) {
@@ -51139,7 +51198,11 @@
51139
51198
  let cellNode = escapeXml ``;
51140
51199
  // Either formula or static value inside the cell
51141
51200
  if (cell.isFormula) {
51142
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
51201
+ const res = addFormula(cell);
51202
+ if (!res) {
51203
+ continue;
51204
+ }
51205
+ ({ attrs: additionalAttrs, node: cellNode } = res);
51143
51206
  }
51144
51207
  else if (cell.content && isMarkdownLink(cell.content)) {
51145
51208
  const { label } = parseMarkdownLink(cell.content);
@@ -52067,6 +52130,7 @@
52067
52130
  isDefined: isDefined$1,
52068
52131
  lazy,
52069
52132
  genericRepeat,
52133
+ deepEquals,
52070
52134
  };
52071
52135
  const links = {
52072
52136
  isMarkdownLink,
@@ -52136,9 +52200,9 @@
52136
52200
  Object.defineProperty(exports, '__esModule', { value: true });
52137
52201
 
52138
52202
 
52139
- __info__.version = '16.4.34';
52140
- __info__.date = '2024-05-24T11:27:29.421Z';
52141
- __info__.hash = '5e74805';
52203
+ __info__.version = '16.4.37';
52204
+ __info__.date = '2024-06-14T10:00:27.521Z';
52205
+ __info__.hash = '195b41b';
52142
52206
 
52143
52207
 
52144
52208
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);