@odoo/o-spreadsheet 16.4.33 → 16.4.36

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.
@@ -3236,8 +3236,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
3236
3236
  /**
3237
3237
  * Create a range from a xc. If the xc is empty, this function returns undefined.
3238
3238
  */
3239
- function createRange(getters, sheetId, range) {
3240
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
3239
+ function createValidRange(getters, sheetId, xc) {
3240
+ if (!xc)
3241
+ return;
3242
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
3243
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
3241
3244
  }
3242
3245
  /**
3243
3246
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5704,6 +5707,7 @@ const FilterMenuPopoverBuilder = {
5704
5707
  };
5705
5708
 
5706
5709
  const macRegex = /Mac/i;
5710
+ const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
5707
5711
  /**
5708
5712
  * Return true if the event was triggered from
5709
5713
  * a child element.
@@ -5742,6 +5746,31 @@ function* iterateChildren(el) {
5742
5746
  function getOpenedMenus() {
5743
5747
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
5744
5748
  }
5749
+ const letterRegex = /^[a-zA-Z]$/;
5750
+ /**
5751
+ * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
5752
+ *
5753
+ * @argument ev - The keyboard event to transform
5754
+ * @argument mode - Use either ev.key of ev.code to get the string shortcut
5755
+ *
5756
+ * @example
5757
+ * event : { ctrlKey: true, key: "a" } => "Ctrl+A"
5758
+ * event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
5759
+ */
5760
+ function keyboardEventToShortcutString(ev, mode = "key") {
5761
+ let keyDownString = "";
5762
+ if (!MODIFIER_KEYS.includes(ev.key)) {
5763
+ if (isCtrlKey(ev))
5764
+ keyDownString += "Ctrl+";
5765
+ if (ev.altKey)
5766
+ keyDownString += "Alt+";
5767
+ if (ev.shiftKey)
5768
+ keyDownString += "Shift+";
5769
+ }
5770
+ const key = mode === "key" ? ev.key : ev.code;
5771
+ keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
5772
+ return keyDownString;
5773
+ }
5745
5774
  function isMacOS() {
5746
5775
  return Boolean(macRegex.test(navigator.userAgent));
5747
5776
  }
@@ -5760,8 +5789,7 @@ function isCtrlKey(ev) {
5760
5789
  */
5761
5790
  function useSpreadsheetRect() {
5762
5791
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
5763
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
5764
- updatePosition();
5792
+ let spreadsheetElement = null;
5765
5793
  function updatePosition() {
5766
5794
  if (!spreadsheetElement) {
5767
5795
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -16542,7 +16570,7 @@ class BarChart extends AbstractChart {
16542
16570
  constructor(definition, sheetId, getters) {
16543
16571
  super(definition, sheetId, getters);
16544
16572
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
16545
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
16573
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
16546
16574
  this.background = definition.background;
16547
16575
  this.verticalAxisPosition = definition.verticalAxisPosition;
16548
16576
  this.legendPosition = definition.legendPosition;
@@ -16787,7 +16815,7 @@ class GaugeChart extends AbstractChart {
16787
16815
  type = "gauge";
16788
16816
  constructor(definition, sheetId, getters) {
16789
16817
  super(definition, sheetId, getters);
16790
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
16818
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
16791
16819
  this.sectionRule = definition.sectionRule;
16792
16820
  this.background = definition.background;
16793
16821
  }
@@ -17126,7 +17154,7 @@ class LineChart extends AbstractChart {
17126
17154
  constructor(definition, sheetId, getters) {
17127
17155
  super(definition, sheetId, getters);
17128
17156
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17129
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
17157
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
17130
17158
  this.background = definition.background;
17131
17159
  this.verticalAxisPosition = definition.verticalAxisPosition;
17132
17160
  this.legendPosition = definition.legendPosition;
@@ -17424,7 +17452,7 @@ class PieChart extends AbstractChart {
17424
17452
  constructor(definition, sheetId, getters) {
17425
17453
  super(definition, sheetId, getters);
17426
17454
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17427
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
17455
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
17428
17456
  this.background = definition.background;
17429
17457
  this.legendPosition = definition.legendPosition;
17430
17458
  this.aggregated = definition.aggregated;
@@ -17592,8 +17620,8 @@ class ScorecardChart extends AbstractChart {
17592
17620
  type = "scorecard";
17593
17621
  constructor(definition, sheetId, getters) {
17594
17622
  super(definition, sheetId, getters);
17595
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
17596
- this.baseline = createRange(getters, sheetId, definition.baseline);
17623
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
17624
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
17597
17625
  this.baselineMode = definition.baselineMode;
17598
17626
  this.baselineDescr = definition.baselineDescr;
17599
17627
  this.background = definition.background;
@@ -20952,7 +20980,7 @@ class LineBarPieConfigPanel extends owl.Component {
20952
20980
  }
20953
20981
  const getters = this.env.model.getters;
20954
20982
  const sheetId = getters.getActiveSheetId();
20955
- const labelRange = createRange(getters, sheetId, this.labelRange);
20983
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
20956
20984
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
20957
20985
  if (dataSets.length) {
20958
20986
  return dataSets[0].dataRange.zone.top + 1;
@@ -23417,14 +23445,14 @@ class FigureComponent extends owl.Component {
23417
23445
  }
23418
23446
  onKeyDown(ev) {
23419
23447
  const figure = this.props.figure;
23420
- switch (ev.key) {
23448
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
23449
+ switch (keyDownShortcut) {
23421
23450
  case "Delete":
23422
23451
  this.env.model.dispatch("DELETE_FIGURE", {
23423
23452
  sheetId: this.env.model.getters.getActiveSheetId(),
23424
23453
  id: figure.id,
23425
23454
  });
23426
23455
  this.props.onFigureDeleted();
23427
- ev.stopPropagation();
23428
23456
  ev.preventDefault();
23429
23457
  ev.stopPropagation();
23430
23458
  break;
@@ -23445,7 +23473,22 @@ class FigureComponent extends owl.Component {
23445
23473
  x: figure.x + delta[0],
23446
23474
  y: figure.y + delta[1],
23447
23475
  });
23476
+ ev.preventDefault();
23448
23477
  ev.stopPropagation();
23478
+ break;
23479
+ case "Ctrl+A":
23480
+ // Maybe in the future we will implement a way to select all figures
23481
+ ev.preventDefault();
23482
+ ev.stopPropagation();
23483
+ break;
23484
+ case "Ctrl+Y":
23485
+ case "Ctrl+Z":
23486
+ if (keyDownShortcut === "Ctrl+Y") {
23487
+ this.env.model.dispatch("REQUEST_REDO");
23488
+ }
23489
+ else if (keyDownShortcut === "Ctrl+Z") {
23490
+ this.env.model.dispatch("REQUEST_UNDO");
23491
+ }
23449
23492
  ev.preventDefault();
23450
23493
  ev.stopPropagation();
23451
23494
  break;
@@ -24170,7 +24213,7 @@ class Composer extends owl.Component {
24170
24213
  Enter: this.processEnterKey,
24171
24214
  Escape: this.processEscapeKey,
24172
24215
  F2: () => console.warn("Not implemented"),
24173
- F4: this.processF4Key,
24216
+ F4: (ev) => this.processF4Key(ev),
24174
24217
  Tab: (ev) => this.processTabKey(ev),
24175
24218
  };
24176
24219
  keyCodeMapping = {
@@ -24272,9 +24315,10 @@ class Composer extends owl.Component {
24272
24315
  processEscapeKey() {
24273
24316
  this.env.model.dispatch("STOP_EDITION", { cancel: true });
24274
24317
  }
24275
- processF4Key() {
24318
+ processF4Key(ev) {
24276
24319
  this.env.model.dispatch("CYCLE_EDITION_REFERENCES");
24277
24320
  this.processContent();
24321
+ ev.stopPropagation();
24278
24322
  }
24279
24323
  processNumpadDecimal(ev) {
24280
24324
  ev.stopPropagation();
@@ -24315,8 +24359,15 @@ class Composer extends owl.Component {
24315
24359
  }
24316
24360
  onPaste(ev) {
24317
24361
  if (this.env.model.getters.getEditionMode() !== "inactive") {
24362
+ // let the browser clipboard work
24318
24363
  ev.stopPropagation();
24319
24364
  }
24365
+ else {
24366
+ // the user meant to paste in the sheet, not open the composer with the pasted content
24367
+ // While we're not editing, we still have the focus and should therefore prevent
24368
+ // the native "paste" to occur.
24369
+ ev.preventDefault();
24370
+ }
24320
24371
  }
24321
24372
  /*
24322
24373
  * Triggered automatically by the content-editable between the keydown and key up
@@ -24325,10 +24376,6 @@ class Composer extends owl.Component {
24325
24376
  if (!this.shouldProcessInputEvents) {
24326
24377
  return;
24327
24378
  }
24328
- if (ev.inputType === "insertFromPaste" &&
24329
- this.env.model.getters.getEditionMode() === "inactive") {
24330
- return;
24331
- }
24332
24379
  ev.stopPropagation();
24333
24380
  let content;
24334
24381
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -24759,10 +24806,7 @@ class GridComposer extends owl.Component {
24759
24806
  }
24760
24807
  get containerStyle() {
24761
24808
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
24762
- return `
24763
- position: absolute;
24764
- z-index: -1000;
24765
- `;
24809
+ return `z-index: -1000;`;
24766
24810
  }
24767
24811
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
24768
24812
  const cell = this.env.model.getters.getActiveCell();
@@ -33990,7 +34034,12 @@ class MergePlugin extends CorePlugin {
33990
34034
  * if they have at least a common cell
33991
34035
  */
33992
34036
  doesIntersectMerge(sheetId, zone) {
33993
- return positions(zone).some(({ col, row }) => this.getMerge({ sheetId, col, row }) !== undefined);
34037
+ for (const merge of this.getMerges(sheetId)) {
34038
+ if (overlap(zone, merge)) {
34039
+ return true;
34040
+ }
34041
+ }
34042
+ return false;
33994
34043
  }
33995
34044
  /**
33996
34045
  * Returns true if two columns have at least one merge in common
@@ -34587,6 +34636,9 @@ class RangeAdapter {
34587
34636
  if (range.invalidXc) {
34588
34637
  return range.invalidXc;
34589
34638
  }
34639
+ if (!this.getters.tryGetSheet(range.sheetId)) {
34640
+ return INCORRECT_RANGE_STRING;
34641
+ }
34590
34642
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
34591
34643
  return INCORRECT_RANGE_STRING;
34592
34644
  }
@@ -37638,16 +37690,22 @@ class EvaluationPlugin extends UIPlugin {
37638
37690
  let newContent = undefined;
37639
37691
  let newFormat = undefined;
37640
37692
  let isExported = true;
37693
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37641
37694
  const formulaCell = this.getCorrespondingFormulaCell(position);
37642
37695
  if (formulaCell) {
37643
37696
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
37644
37697
  isFormula = isExported;
37645
37698
  if (!isExported) {
37646
- newContent = value.toString();
37647
- newFormat = evaluatedCell.format;
37699
+ // If the cell contains a non-exported formula and that is evaluates to
37700
+ // nothing* ,we don't export it.
37701
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
37702
+ // the empty string.
37703
+ if (value !== "") {
37704
+ newContent = value.toString();
37705
+ newFormat = evaluatedCell.format;
37706
+ }
37648
37707
  }
37649
37708
  }
37650
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37651
37709
  const exportedCellData = exportedSheetData.cells[xc] || {};
37652
37710
  const format = newFormat
37653
37711
  ? getItemId(newFormat, data.formats)
@@ -43431,7 +43489,7 @@ class ClipboardPlugin extends UIPlugin {
43431
43489
  case "ADD_COLUMNS_ROWS": {
43432
43490
  this.status = "invisible";
43433
43491
  // If we add a col/row inside or before the cut area, we invalidate the clipboard
43434
- if (this.state?.operation !== "CUT") {
43492
+ if (this.state?.operation !== "CUT" || cmd.sheetId !== this.state?.sheetId) {
43435
43493
  return;
43436
43494
  }
43437
43495
  const isClipboardDirty = this.state.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
@@ -43443,7 +43501,7 @@ class ClipboardPlugin extends UIPlugin {
43443
43501
  case "REMOVE_COLUMNS_ROWS": {
43444
43502
  this.status = "invisible";
43445
43503
  // If we remove a col/row inside or before the cut area, we invalidate the clipboard
43446
- if (this.state?.operation !== "CUT") {
43504
+ if (this.state?.operation !== "CUT" || cmd.sheetId !== this.state?.sheetId) {
43447
43505
  return;
43448
43506
  }
43449
43507
  for (let el of cmd.elements) {
@@ -46518,9 +46576,11 @@ class BottomBarSheet extends owl.Component {
46518
46576
  if (ev.key === "Enter") {
46519
46577
  ev.preventDefault();
46520
46578
  this.stopEdition();
46579
+ this.env.focusableElement.focus();
46521
46580
  }
46522
46581
  if (ev.key === "Escape") {
46523
46582
  this.cancelEdition();
46583
+ this.env.focusableElement.focus();
46524
46584
  }
46525
46585
  }
46526
46586
  onClickSheetName(ev) {
@@ -48282,6 +48342,10 @@ class Spreadsheet extends owl.Component {
48282
48342
  });
48283
48343
  owl.useExternalListener(window, "resize", () => this.render(true));
48284
48344
  owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
48345
+ // For some reason, the wheel event is not properly registered inside templates
48346
+ // in Chromium-based browsers based on chromium 125
48347
+ // This hack ensures the event declared in the template is properly registered/working
48348
+ owl.useExternalListener(document.body, "wheel", () => { });
48285
48349
  this.bindModelEvents();
48286
48350
  owl.onMounted(() => {
48287
48351
  this.checkViewportSize();
@@ -51132,7 +51196,11 @@ function addRows(construct, data, sheet) {
51132
51196
  let cellNode = escapeXml ``;
51133
51197
  // Either formula or static value inside the cell
51134
51198
  if (cell.isFormula) {
51135
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
51199
+ const res = addFormula(cell);
51200
+ if (!res) {
51201
+ continue;
51202
+ }
51203
+ ({ attrs: additionalAttrs, node: cellNode } = res);
51136
51204
  }
51137
51205
  else if (cell.content && isMarkdownLink(cell.content)) {
51138
51206
  const { label } = parseMarkdownLink(cell.content);
@@ -52127,6 +52195,6 @@ exports.setTranslationMethod = setTranslationMethod;
52127
52195
  exports.tokenize = tokenize;
52128
52196
 
52129
52197
 
52130
- __info__.version = '16.4.33';
52131
- __info__.date = '2024-05-15T09:17:20.683Z';
52132
- __info__.hash = '53b07e5';
52198
+ __info__.version = '16.4.36';
52199
+ __info__.date = '2024-06-10T09:33:43.623Z';
52200
+ __info__.hash = '3b15ed5';
@@ -3232,8 +3232,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
3232
3232
  /**
3233
3233
  * Create a range from a xc. If the xc is empty, this function returns undefined.
3234
3234
  */
3235
- function createRange(getters, sheetId, range) {
3236
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
3235
+ function createValidRange(getters, sheetId, xc) {
3236
+ if (!xc)
3237
+ return;
3238
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
3239
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
3237
3240
  }
3238
3241
  /**
3239
3242
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5700,6 +5703,7 @@ const FilterMenuPopoverBuilder = {
5700
5703
  };
5701
5704
 
5702
5705
  const macRegex = /Mac/i;
5706
+ const MODIFIER_KEYS = ["Shift", "Control", "Alt", "Meta"];
5703
5707
  /**
5704
5708
  * Return true if the event was triggered from
5705
5709
  * a child element.
@@ -5738,6 +5742,31 @@ function* iterateChildren(el) {
5738
5742
  function getOpenedMenus() {
5739
5743
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
5740
5744
  }
5745
+ const letterRegex = /^[a-zA-Z]$/;
5746
+ /**
5747
+ * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
5748
+ *
5749
+ * @argument ev - The keyboard event to transform
5750
+ * @argument mode - Use either ev.key of ev.code to get the string shortcut
5751
+ *
5752
+ * @example
5753
+ * event : { ctrlKey: true, key: "a" } => "Ctrl+A"
5754
+ * event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
5755
+ */
5756
+ function keyboardEventToShortcutString(ev, mode = "key") {
5757
+ let keyDownString = "";
5758
+ if (!MODIFIER_KEYS.includes(ev.key)) {
5759
+ if (isCtrlKey(ev))
5760
+ keyDownString += "Ctrl+";
5761
+ if (ev.altKey)
5762
+ keyDownString += "Alt+";
5763
+ if (ev.shiftKey)
5764
+ keyDownString += "Shift+";
5765
+ }
5766
+ const key = mode === "key" ? ev.key : ev.code;
5767
+ keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
5768
+ return keyDownString;
5769
+ }
5741
5770
  function isMacOS() {
5742
5771
  return Boolean(macRegex.test(navigator.userAgent));
5743
5772
  }
@@ -5756,8 +5785,7 @@ function isCtrlKey(ev) {
5756
5785
  */
5757
5786
  function useSpreadsheetRect() {
5758
5787
  const position = useState({ x: 0, y: 0, width: 0, height: 0 });
5759
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
5760
- updatePosition();
5788
+ let spreadsheetElement = null;
5761
5789
  function updatePosition() {
5762
5790
  if (!spreadsheetElement) {
5763
5791
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -16538,7 +16566,7 @@ class BarChart extends AbstractChart {
16538
16566
  constructor(definition, sheetId, getters) {
16539
16567
  super(definition, sheetId, getters);
16540
16568
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
16541
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
16569
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
16542
16570
  this.background = definition.background;
16543
16571
  this.verticalAxisPosition = definition.verticalAxisPosition;
16544
16572
  this.legendPosition = definition.legendPosition;
@@ -16783,7 +16811,7 @@ class GaugeChart extends AbstractChart {
16783
16811
  type = "gauge";
16784
16812
  constructor(definition, sheetId, getters) {
16785
16813
  super(definition, sheetId, getters);
16786
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
16814
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
16787
16815
  this.sectionRule = definition.sectionRule;
16788
16816
  this.background = definition.background;
16789
16817
  }
@@ -17122,7 +17150,7 @@ class LineChart extends AbstractChart {
17122
17150
  constructor(definition, sheetId, getters) {
17123
17151
  super(definition, sheetId, getters);
17124
17152
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17125
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
17153
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
17126
17154
  this.background = definition.background;
17127
17155
  this.verticalAxisPosition = definition.verticalAxisPosition;
17128
17156
  this.legendPosition = definition.legendPosition;
@@ -17420,7 +17448,7 @@ class PieChart extends AbstractChart {
17420
17448
  constructor(definition, sheetId, getters) {
17421
17449
  super(definition, sheetId, getters);
17422
17450
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
17423
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
17451
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
17424
17452
  this.background = definition.background;
17425
17453
  this.legendPosition = definition.legendPosition;
17426
17454
  this.aggregated = definition.aggregated;
@@ -17588,8 +17616,8 @@ class ScorecardChart extends AbstractChart {
17588
17616
  type = "scorecard";
17589
17617
  constructor(definition, sheetId, getters) {
17590
17618
  super(definition, sheetId, getters);
17591
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
17592
- this.baseline = createRange(getters, sheetId, definition.baseline);
17619
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
17620
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
17593
17621
  this.baselineMode = definition.baselineMode;
17594
17622
  this.baselineDescr = definition.baselineDescr;
17595
17623
  this.background = definition.background;
@@ -20948,7 +20976,7 @@ class LineBarPieConfigPanel extends Component {
20948
20976
  }
20949
20977
  const getters = this.env.model.getters;
20950
20978
  const sheetId = getters.getActiveSheetId();
20951
- const labelRange = createRange(getters, sheetId, this.labelRange);
20979
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
20952
20980
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
20953
20981
  if (dataSets.length) {
20954
20982
  return dataSets[0].dataRange.zone.top + 1;
@@ -23413,14 +23441,14 @@ class FigureComponent extends Component {
23413
23441
  }
23414
23442
  onKeyDown(ev) {
23415
23443
  const figure = this.props.figure;
23416
- switch (ev.key) {
23444
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
23445
+ switch (keyDownShortcut) {
23417
23446
  case "Delete":
23418
23447
  this.env.model.dispatch("DELETE_FIGURE", {
23419
23448
  sheetId: this.env.model.getters.getActiveSheetId(),
23420
23449
  id: figure.id,
23421
23450
  });
23422
23451
  this.props.onFigureDeleted();
23423
- ev.stopPropagation();
23424
23452
  ev.preventDefault();
23425
23453
  ev.stopPropagation();
23426
23454
  break;
@@ -23441,7 +23469,22 @@ class FigureComponent extends Component {
23441
23469
  x: figure.x + delta[0],
23442
23470
  y: figure.y + delta[1],
23443
23471
  });
23472
+ ev.preventDefault();
23444
23473
  ev.stopPropagation();
23474
+ break;
23475
+ case "Ctrl+A":
23476
+ // Maybe in the future we will implement a way to select all figures
23477
+ ev.preventDefault();
23478
+ ev.stopPropagation();
23479
+ break;
23480
+ case "Ctrl+Y":
23481
+ case "Ctrl+Z":
23482
+ if (keyDownShortcut === "Ctrl+Y") {
23483
+ this.env.model.dispatch("REQUEST_REDO");
23484
+ }
23485
+ else if (keyDownShortcut === "Ctrl+Z") {
23486
+ this.env.model.dispatch("REQUEST_UNDO");
23487
+ }
23445
23488
  ev.preventDefault();
23446
23489
  ev.stopPropagation();
23447
23490
  break;
@@ -24166,7 +24209,7 @@ class Composer extends Component {
24166
24209
  Enter: this.processEnterKey,
24167
24210
  Escape: this.processEscapeKey,
24168
24211
  F2: () => console.warn("Not implemented"),
24169
- F4: this.processF4Key,
24212
+ F4: (ev) => this.processF4Key(ev),
24170
24213
  Tab: (ev) => this.processTabKey(ev),
24171
24214
  };
24172
24215
  keyCodeMapping = {
@@ -24268,9 +24311,10 @@ class Composer extends Component {
24268
24311
  processEscapeKey() {
24269
24312
  this.env.model.dispatch("STOP_EDITION", { cancel: true });
24270
24313
  }
24271
- processF4Key() {
24314
+ processF4Key(ev) {
24272
24315
  this.env.model.dispatch("CYCLE_EDITION_REFERENCES");
24273
24316
  this.processContent();
24317
+ ev.stopPropagation();
24274
24318
  }
24275
24319
  processNumpadDecimal(ev) {
24276
24320
  ev.stopPropagation();
@@ -24311,8 +24355,15 @@ class Composer extends Component {
24311
24355
  }
24312
24356
  onPaste(ev) {
24313
24357
  if (this.env.model.getters.getEditionMode() !== "inactive") {
24358
+ // let the browser clipboard work
24314
24359
  ev.stopPropagation();
24315
24360
  }
24361
+ else {
24362
+ // the user meant to paste in the sheet, not open the composer with the pasted content
24363
+ // While we're not editing, we still have the focus and should therefore prevent
24364
+ // the native "paste" to occur.
24365
+ ev.preventDefault();
24366
+ }
24316
24367
  }
24317
24368
  /*
24318
24369
  * Triggered automatically by the content-editable between the keydown and key up
@@ -24321,10 +24372,6 @@ class Composer extends Component {
24321
24372
  if (!this.shouldProcessInputEvents) {
24322
24373
  return;
24323
24374
  }
24324
- if (ev.inputType === "insertFromPaste" &&
24325
- this.env.model.getters.getEditionMode() === "inactive") {
24326
- return;
24327
- }
24328
24375
  ev.stopPropagation();
24329
24376
  let content;
24330
24377
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -24755,10 +24802,7 @@ class GridComposer extends Component {
24755
24802
  }
24756
24803
  get containerStyle() {
24757
24804
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
24758
- return `
24759
- position: absolute;
24760
- z-index: -1000;
24761
- `;
24805
+ return `z-index: -1000;`;
24762
24806
  }
24763
24807
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
24764
24808
  const cell = this.env.model.getters.getActiveCell();
@@ -33986,7 +34030,12 @@ class MergePlugin extends CorePlugin {
33986
34030
  * if they have at least a common cell
33987
34031
  */
33988
34032
  doesIntersectMerge(sheetId, zone) {
33989
- return positions(zone).some(({ col, row }) => this.getMerge({ sheetId, col, row }) !== undefined);
34033
+ for (const merge of this.getMerges(sheetId)) {
34034
+ if (overlap(zone, merge)) {
34035
+ return true;
34036
+ }
34037
+ }
34038
+ return false;
33990
34039
  }
33991
34040
  /**
33992
34041
  * Returns true if two columns have at least one merge in common
@@ -34583,6 +34632,9 @@ class RangeAdapter {
34583
34632
  if (range.invalidXc) {
34584
34633
  return range.invalidXc;
34585
34634
  }
34635
+ if (!this.getters.tryGetSheet(range.sheetId)) {
34636
+ return INCORRECT_RANGE_STRING;
34637
+ }
34586
34638
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
34587
34639
  return INCORRECT_RANGE_STRING;
34588
34640
  }
@@ -37634,16 +37686,22 @@ class EvaluationPlugin extends UIPlugin {
37634
37686
  let newContent = undefined;
37635
37687
  let newFormat = undefined;
37636
37688
  let isExported = true;
37689
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37637
37690
  const formulaCell = this.getCorrespondingFormulaCell(position);
37638
37691
  if (formulaCell) {
37639
37692
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
37640
37693
  isFormula = isExported;
37641
37694
  if (!isExported) {
37642
- newContent = value.toString();
37643
- newFormat = evaluatedCell.format;
37695
+ // If the cell contains a non-exported formula and that is evaluates to
37696
+ // nothing* ,we don't export it.
37697
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
37698
+ // the empty string.
37699
+ if (value !== "") {
37700
+ newContent = value.toString();
37701
+ newFormat = evaluatedCell.format;
37702
+ }
37644
37703
  }
37645
37704
  }
37646
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
37647
37705
  const exportedCellData = exportedSheetData.cells[xc] || {};
37648
37706
  const format = newFormat
37649
37707
  ? getItemId(newFormat, data.formats)
@@ -43427,7 +43485,7 @@ class ClipboardPlugin extends UIPlugin {
43427
43485
  case "ADD_COLUMNS_ROWS": {
43428
43486
  this.status = "invisible";
43429
43487
  // If we add a col/row inside or before the cut area, we invalidate the clipboard
43430
- if (this.state?.operation !== "CUT") {
43488
+ if (this.state?.operation !== "CUT" || cmd.sheetId !== this.state?.sheetId) {
43431
43489
  return;
43432
43490
  }
43433
43491
  const isClipboardDirty = this.state.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
@@ -43439,7 +43497,7 @@ class ClipboardPlugin extends UIPlugin {
43439
43497
  case "REMOVE_COLUMNS_ROWS": {
43440
43498
  this.status = "invisible";
43441
43499
  // If we remove a col/row inside or before the cut area, we invalidate the clipboard
43442
- if (this.state?.operation !== "CUT") {
43500
+ if (this.state?.operation !== "CUT" || cmd.sheetId !== this.state?.sheetId) {
43443
43501
  return;
43444
43502
  }
43445
43503
  for (let el of cmd.elements) {
@@ -46514,9 +46572,11 @@ class BottomBarSheet extends Component {
46514
46572
  if (ev.key === "Enter") {
46515
46573
  ev.preventDefault();
46516
46574
  this.stopEdition();
46575
+ this.env.focusableElement.focus();
46517
46576
  }
46518
46577
  if (ev.key === "Escape") {
46519
46578
  this.cancelEdition();
46579
+ this.env.focusableElement.focus();
46520
46580
  }
46521
46581
  }
46522
46582
  onClickSheetName(ev) {
@@ -48278,6 +48338,10 @@ class Spreadsheet extends Component {
48278
48338
  });
48279
48339
  useExternalListener(window, "resize", () => this.render(true));
48280
48340
  useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
48341
+ // For some reason, the wheel event is not properly registered inside templates
48342
+ // in Chromium-based browsers based on chromium 125
48343
+ // This hack ensures the event declared in the template is properly registered/working
48344
+ useExternalListener(document.body, "wheel", () => { });
48281
48345
  this.bindModelEvents();
48282
48346
  onMounted(() => {
48283
48347
  this.checkViewportSize();
@@ -51128,7 +51192,11 @@ function addRows(construct, data, sheet) {
51128
51192
  let cellNode = escapeXml ``;
51129
51193
  // Either formula or static value inside the cell
51130
51194
  if (cell.isFormula) {
51131
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
51195
+ const res = addFormula(cell);
51196
+ if (!res) {
51197
+ continue;
51198
+ }
51199
+ ({ attrs: additionalAttrs, node: cellNode } = res);
51132
51200
  }
51133
51201
  else if (cell.content && isMarkdownLink(cell.content)) {
51134
51202
  const { label } = parseMarkdownLink(cell.content);
@@ -52091,6 +52159,6 @@ const constants = {
52091
52159
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
52092
52160
 
52093
52161
 
52094
- __info__.version = '16.4.33';
52095
- __info__.date = '2024-05-15T09:17:20.683Z';
52096
- __info__.hash = '53b07e5';
52162
+ __info__.version = '16.4.36';
52163
+ __info__.date = '2024-06-10T09:33:43.623Z';
52164
+ __info__.hash = '3b15ed5';