@odoo/o-spreadsheet 17.0.22 → 17.0.25

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.0.22
6
- * @date 2024-05-15T09:18:36.212Z
7
- * @hash 1f90749
5
+ * @version 17.0.25
6
+ * @date 2024-06-10T09:33:40.022Z
7
+ * @hash 1f01394
8
8
  */
9
9
 
10
10
  'use strict';
@@ -47,7 +47,7 @@ class LazyTranslatedString extends String {
47
47
  }
48
48
  valueOf() {
49
49
  const str = super.valueOf();
50
- return _loaded() ? sprintf(_translate(str), ...this.values) : str;
50
+ return _loaded() ? sprintf(_translate(str), ...this.values) : sprintf(str, ...this.values);
51
51
  }
52
52
  toString() {
53
53
  return this.valueOf();
@@ -394,7 +394,10 @@ function deepCopy(obj) {
394
394
  * Check if the object is a plain old javascript object.
395
395
  */
396
396
  function isPlainObject(obj) {
397
- return typeof obj === "object" && obj?.constructor === Object;
397
+ return (typeof obj === "object" &&
398
+ obj !== null &&
399
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
400
+ (obj?.constructor === Object || obj?.constructor === undefined));
398
401
  }
399
402
  /**
400
403
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -666,8 +669,9 @@ function deepEquals(o1, o2, ignoreFunctions) {
666
669
  return false;
667
670
  }
668
671
  else {
669
- if (ignoreFunctions && typeOfO1Key === "function")
670
- return true;
672
+ if (ignoreFunctions && typeOfO1Key === "function") {
673
+ continue;
674
+ }
671
675
  if (o1[key] !== o2[key])
672
676
  return false;
673
677
  }
@@ -4305,8 +4309,11 @@ function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
4305
4309
  /**
4306
4310
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4307
4311
  */
4308
- function createRange(getters, sheetId, range) {
4309
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4312
+ function createValidRange(getters, sheetId, xc) {
4313
+ if (!xc)
4314
+ return;
4315
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4316
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4310
4317
  }
4311
4318
  /**
4312
4319
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5234,8 +5241,8 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
5234
5241
  type = "scorecard";
5235
5242
  constructor(definition, sheetId, getters) {
5236
5243
  super(definition, sheetId, getters);
5237
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
5238
- this.baseline = createRange(getters, sheetId, definition.baseline);
5244
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
5245
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
5239
5246
  this.baselineMode = definition.baselineMode;
5240
5247
  this.baselineDescr = definition.baselineDescr;
5241
5248
  this.background = definition.background;
@@ -6706,6 +6713,7 @@ const FilterMenuPopoverBuilder = {
6706
6713
  };
6707
6714
 
6708
6715
  const macRegex = /Mac/i;
6716
+ const MODIFIER_KEYS$1 = ["Shift", "Control", "Alt", "Meta"];
6709
6717
  /**
6710
6718
  * Return true if the event was triggered from
6711
6719
  * a child element.
@@ -6744,6 +6752,31 @@ function* iterateChildren(el) {
6744
6752
  function getOpenedMenus() {
6745
6753
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
6746
6754
  }
6755
+ const letterRegex = /^[a-zA-Z]$/;
6756
+ /**
6757
+ * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
6758
+ *
6759
+ * @argument ev - The keyboard event to transform
6760
+ * @argument mode - Use either ev.key of ev.code to get the string shortcut
6761
+ *
6762
+ * @example
6763
+ * event : { ctrlKey: true, key: "a" } => "Ctrl+A"
6764
+ * event : { shift: true, alt: true, key: "Home" } => "Alt+Shift+Home"
6765
+ */
6766
+ function keyboardEventToShortcutString(ev, mode = "key") {
6767
+ let keyDownString = "";
6768
+ if (!MODIFIER_KEYS$1.includes(ev.key)) {
6769
+ if (isCtrlKey(ev))
6770
+ keyDownString += "Ctrl+";
6771
+ if (ev.altKey)
6772
+ keyDownString += "Alt+";
6773
+ if (ev.shiftKey)
6774
+ keyDownString += "Shift+";
6775
+ }
6776
+ const key = mode === "key" ? ev.key : ev.code;
6777
+ keyDownString += letterRegex.test(key) ? key.toUpperCase() : key;
6778
+ return keyDownString;
6779
+ }
6747
6780
  function isMacOS() {
6748
6781
  return Boolean(macRegex.test(navigator.userAgent));
6749
6782
  }
@@ -6762,8 +6795,7 @@ function isCtrlKey(ev) {
6762
6795
  */
6763
6796
  function useSpreadsheetRect() {
6764
6797
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
6765
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
6766
- updatePosition();
6798
+ let spreadsheetElement = null;
6767
6799
  function updatePosition() {
6768
6800
  if (!spreadsheetElement) {
6769
6801
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -8536,7 +8568,7 @@ function chartToImage(runtime, figure, type) {
8536
8568
  if ("chartJsConfig" in runtime) {
8537
8569
  runtime.chartJsConfig.plugins = [backgroundColorChartJSPlugin];
8538
8570
  // @ts-ignore
8539
- const chart = new window.Chart(canvas, runtime.chartJsConfig);
8571
+ const chart = new window.Chart(canvas, deepCopy(runtime.chartJsConfig));
8540
8572
  const imgContent = chart.toBase64Image();
8541
8573
  chart.destroy();
8542
8574
  div.remove();
@@ -8580,7 +8612,7 @@ class BarChart extends AbstractChart {
8580
8612
  constructor(definition, sheetId, getters) {
8581
8613
  super(definition, sheetId, getters);
8582
8614
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
8583
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
8615
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
8584
8616
  this.background = definition.background;
8585
8617
  this.verticalAxisPosition = definition.verticalAxisPosition;
8586
8618
  this.legendPosition = definition.legendPosition;
@@ -8823,7 +8855,7 @@ class GaugeChart extends AbstractChart {
8823
8855
  type = "gauge";
8824
8856
  constructor(definition, sheetId, getters) {
8825
8857
  super(definition, sheetId, getters);
8826
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
8858
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
8827
8859
  this.sectionRule = definition.sectionRule;
8828
8860
  this.background = definition.background;
8829
8861
  }
@@ -9157,7 +9189,7 @@ class LineChart extends AbstractChart {
9157
9189
  constructor(definition, sheetId, getters) {
9158
9190
  super(definition, sheetId, getters);
9159
9191
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9160
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
9192
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
9161
9193
  this.background = definition.background;
9162
9194
  this.verticalAxisPosition = definition.verticalAxisPosition;
9163
9195
  this.legendPosition = definition.legendPosition;
@@ -9477,7 +9509,7 @@ class PieChart extends AbstractChart {
9477
9509
  constructor(definition, sheetId, getters) {
9478
9510
  super(definition, sheetId, getters);
9479
9511
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9480
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
9512
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
9481
9513
  this.background = definition.background;
9482
9514
  this.legendPosition = definition.legendPosition;
9483
9515
  this.aggregated = definition.aggregated;
@@ -21724,7 +21756,7 @@ class LineBarPieConfigPanel extends owl.Component {
21724
21756
  }
21725
21757
  const getters = this.env.model.getters;
21726
21758
  const sheetId = getters.getActiveSheetId();
21727
- const labelRange = createRange(getters, sheetId, this.labelRange);
21759
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
21728
21760
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
21729
21761
  if (dataSets.length) {
21730
21762
  return dataSets[0].dataRange.zone.top + 1;
@@ -25766,14 +25798,14 @@ class FigureComponent extends owl.Component {
25766
25798
  }
25767
25799
  onKeyDown(ev) {
25768
25800
  const figure = this.props.figure;
25769
- switch (ev.key) {
25801
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
25802
+ switch (keyDownShortcut) {
25770
25803
  case "Delete":
25771
25804
  this.env.model.dispatch("DELETE_FIGURE", {
25772
25805
  sheetId: this.env.model.getters.getActiveSheetId(),
25773
25806
  id: figure.id,
25774
25807
  });
25775
25808
  this.props.onFigureDeleted();
25776
- ev.stopPropagation();
25777
25809
  ev.preventDefault();
25778
25810
  ev.stopPropagation();
25779
25811
  break;
@@ -25794,7 +25826,22 @@ class FigureComponent extends owl.Component {
25794
25826
  x: figure.x + delta[0],
25795
25827
  y: figure.y + delta[1],
25796
25828
  });
25829
+ ev.preventDefault();
25797
25830
  ev.stopPropagation();
25831
+ break;
25832
+ case "Ctrl+A":
25833
+ // Maybe in the future we will implement a way to select all figures
25834
+ ev.preventDefault();
25835
+ ev.stopPropagation();
25836
+ break;
25837
+ case "Ctrl+Y":
25838
+ case "Ctrl+Z":
25839
+ if (keyDownShortcut === "Ctrl+Y") {
25840
+ this.env.model.dispatch("REQUEST_REDO");
25841
+ }
25842
+ else if (keyDownShortcut === "Ctrl+Z") {
25843
+ this.env.model.dispatch("REQUEST_UNDO");
25844
+ }
25798
25845
  ev.preventDefault();
25799
25846
  ev.stopPropagation();
25800
25847
  break;
@@ -26665,7 +26712,7 @@ class Composer extends owl.Component {
26665
26712
  Enter: this.processEnterKey,
26666
26713
  Escape: this.processEscapeKey,
26667
26714
  F2: () => console.warn("Not implemented"),
26668
- F4: this.processF4Key,
26715
+ F4: (ev) => this.processF4Key(ev),
26669
26716
  Tab: (ev) => this.processTabKey(ev),
26670
26717
  };
26671
26718
  keyCodeMapping = {
@@ -26770,9 +26817,10 @@ class Composer extends owl.Component {
26770
26817
  processEscapeKey() {
26771
26818
  this.env.model.dispatch("CANCEL_EDITION");
26772
26819
  }
26773
- processF4Key() {
26820
+ processF4Key(ev) {
26774
26821
  this.env.model.dispatch("CYCLE_EDITION_REFERENCES");
26775
26822
  this.processContent();
26823
+ ev.stopPropagation();
26776
26824
  }
26777
26825
  processNumpadDecimal(ev) {
26778
26826
  ev.stopPropagation();
@@ -26813,8 +26861,15 @@ class Composer extends owl.Component {
26813
26861
  }
26814
26862
  onPaste(ev) {
26815
26863
  if (this.env.model.getters.getEditionMode() !== "inactive") {
26864
+ // let the browser clipboard work
26816
26865
  ev.stopPropagation();
26817
26866
  }
26867
+ else {
26868
+ // the user meant to paste in the sheet, not open the composer with the pasted content
26869
+ // While we're not editing, we still have the focus and should therefore prevent
26870
+ // the native "paste" to occur.
26871
+ ev.preventDefault();
26872
+ }
26818
26873
  }
26819
26874
  /*
26820
26875
  * Triggered automatically by the content-editable between the keydown and key up
@@ -26823,10 +26878,6 @@ class Composer extends owl.Component {
26823
26878
  if (!this.shouldProcessInputEvents) {
26824
26879
  return;
26825
26880
  }
26826
- if (ev.inputType === "insertFromPaste" &&
26827
- this.env.model.getters.getEditionMode() === "inactive") {
26828
- return;
26829
- }
26830
26881
  ev.stopPropagation();
26831
26882
  let content;
26832
26883
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -27274,10 +27325,7 @@ class GridComposer extends owl.Component {
27274
27325
  }
27275
27326
  get containerStyle() {
27276
27327
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27277
- return `
27278
- position: absolute;
27279
- z-index: -1000;
27280
- `;
27328
+ return `z-index: -1000;`;
27281
27329
  }
27282
27330
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27283
27331
  const cell = this.env.model.getters.getActiveCell();
@@ -37964,7 +38012,12 @@ class MergePlugin extends CorePlugin {
37964
38012
  * if they have at least a common cell
37965
38013
  */
37966
38014
  doesIntersectMerge(sheetId, zone) {
37967
- return positions(zone).some(({ col, row }) => this.getMerge({ sheetId, col, row }) !== undefined);
38015
+ for (const merge of this.getMerges(sheetId)) {
38016
+ if (overlap(zone, merge)) {
38017
+ return true;
38018
+ }
38019
+ }
38020
+ return false;
37968
38021
  }
37969
38022
  /**
37970
38023
  * Returns true if two columns have at least one merge in common
@@ -38565,6 +38618,9 @@ class RangeAdapter {
38565
38618
  if (range.invalidXc) {
38566
38619
  return range.invalidXc;
38567
38620
  }
38621
+ if (!this.getters.tryGetSheet(range.sheetId)) {
38622
+ return INCORRECT_RANGE_STRING;
38623
+ }
38568
38624
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
38569
38625
  return INCORRECT_RANGE_STRING;
38570
38626
  }
@@ -42016,16 +42072,22 @@ class EvaluationPlugin extends UIPlugin {
42016
42072
  let newContent = undefined;
42017
42073
  let newFormat = undefined;
42018
42074
  let isExported = true;
42075
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42019
42076
  const formulaCell = this.getCorrespondingFormulaCell(position);
42020
42077
  if (formulaCell) {
42021
42078
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
42022
42079
  isFormula = isExported;
42023
42080
  if (!isExported) {
42024
- newContent = value.toString();
42025
- newFormat = evaluatedCell.format;
42081
+ // If the cell contains a non-exported formula and that is evaluates to
42082
+ // nothing* ,we don't export it.
42083
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
42084
+ // the empty string.
42085
+ if (value !== "") {
42086
+ newContent = value.toString();
42087
+ newFormat = evaluatedCell.format;
42088
+ }
42026
42089
  }
42027
42090
  }
42028
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42029
42091
  const exportedCellData = exportedSheetData.cells[xc] || {};
42030
42092
  const format = newFormat
42031
42093
  ? getItemId(newFormat, data.formats)
@@ -48326,7 +48388,7 @@ class ClipboardPlugin extends UIPlugin {
48326
48388
  case "ADD_COLUMNS_ROWS": {
48327
48389
  this.status = "invisible";
48328
48390
  // If we add a col/row inside or before the cut area, we invalidate the clipboard
48329
- if (this.state?.operation !== "CUT") {
48391
+ if (this.state?.operation !== "CUT" || cmd.sheetId !== this.state?.sheetId) {
48330
48392
  return;
48331
48393
  }
48332
48394
  const isClipboardDirty = this.state.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
@@ -48338,7 +48400,7 @@ class ClipboardPlugin extends UIPlugin {
48338
48400
  case "REMOVE_COLUMNS_ROWS": {
48339
48401
  this.status = "invisible";
48340
48402
  // If we remove a col/row inside or before the cut area, we invalidate the clipboard
48341
- if (this.state?.operation !== "CUT") {
48403
+ if (this.state?.operation !== "CUT" || cmd.sheetId !== this.state?.sheetId) {
48342
48404
  return;
48343
48405
  }
48344
48406
  for (let el of cmd.elements) {
@@ -51637,9 +51699,11 @@ class BottomBarSheet extends owl.Component {
51637
51699
  if (ev.key === "Enter") {
51638
51700
  ev.preventDefault();
51639
51701
  this.stopEdition();
51702
+ this.env.focusableElement.focus();
51640
51703
  }
51641
51704
  if (ev.key === "Escape") {
51642
51705
  this.cancelEdition();
51706
+ this.env.focusableElement.focus();
51643
51707
  }
51644
51708
  }
51645
51709
  onClickSheetName(ev) {
@@ -53521,6 +53585,10 @@ class Spreadsheet extends owl.Component {
53521
53585
  });
53522
53586
  owl.useExternalListener(window, "resize", () => this.render(true));
53523
53587
  owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
53588
+ // For some reason, the wheel event is not properly registered inside templates
53589
+ // in Chromium-based browsers based on chromium 125
53590
+ // This hack ensures the event declared in the template is properly registered/working
53591
+ owl.useExternalListener(document.body, "wheel", () => { });
53524
53592
  this.bindModelEvents();
53525
53593
  owl.onWillUpdateProps((nextProps) => {
53526
53594
  if (nextProps.model !== this.props.model) {
@@ -56384,7 +56452,11 @@ function addRows(construct, data, sheet) {
56384
56452
  let cellNode = escapeXml ``;
56385
56453
  // Either formula or static value inside the cell
56386
56454
  if (cell.isFormula) {
56387
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
56455
+ const res = addFormula(cell);
56456
+ if (!res) {
56457
+ continue;
56458
+ }
56459
+ ({ attrs: additionalAttrs, node: cellNode } = res);
56388
56460
  }
56389
56461
  else if (cell.content && isMarkdownLink(cell.content)) {
56390
56462
  const { label } = parseMarkdownLink(cell.content);
@@ -57404,6 +57476,6 @@ exports.setTranslationMethod = setTranslationMethod;
57404
57476
  exports.tokenize = tokenize;
57405
57477
 
57406
57478
 
57407
- __info__.version = "17.0.22";
57408
- __info__.date = "2024-05-15T09:18:36.212Z";
57409
- __info__.hash = "1f90749";
57479
+ __info__.version = "17.0.25";
57480
+ __info__.date = "2024-06-10T09:33:40.022Z";
57481
+ __info__.hash = "1f01394";