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