@odoo/o-spreadsheet 17.0.23 → 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.23
6
- * @date 2024-05-24T11:27:27.416Z
7
- * @hash 6c10fec
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) {
@@ -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
@@ -4305,8 +4308,11 @@
4305
4308
  /**
4306
4309
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4307
4310
  */
4308
- function createRange(getters, sheetId, range) {
4309
- 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;
4310
4316
  }
4311
4317
  /**
4312
4318
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -5234,8 +5240,8 @@
5234
5240
  type = "scorecard";
5235
5241
  constructor(definition, sheetId, getters) {
5236
5242
  super(definition, sheetId, getters);
5237
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
5238
- this.baseline = createRange(getters, sheetId, definition.baseline);
5243
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
5244
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
5239
5245
  this.baselineMode = definition.baselineMode;
5240
5246
  this.baselineDescr = definition.baselineDescr;
5241
5247
  this.background = definition.background;
@@ -6706,6 +6712,7 @@
6706
6712
  };
6707
6713
 
6708
6714
  const macRegex = /Mac/i;
6715
+ const MODIFIER_KEYS$1 = ["Shift", "Control", "Alt", "Meta"];
6709
6716
  /**
6710
6717
  * Return true if the event was triggered from
6711
6718
  * a child element.
@@ -6744,6 +6751,31 @@
6744
6751
  function getOpenedMenus() {
6745
6752
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
6746
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
+ }
6747
6779
  function isMacOS() {
6748
6780
  return Boolean(macRegex.test(navigator.userAgent));
6749
6781
  }
@@ -6762,8 +6794,7 @@
6762
6794
  */
6763
6795
  function useSpreadsheetRect() {
6764
6796
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
6765
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
6766
- updatePosition();
6797
+ let spreadsheetElement = null;
6767
6798
  function updatePosition() {
6768
6799
  if (!spreadsheetElement) {
6769
6800
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -8536,7 +8567,7 @@
8536
8567
  if ("chartJsConfig" in runtime) {
8537
8568
  runtime.chartJsConfig.plugins = [backgroundColorChartJSPlugin];
8538
8569
  // @ts-ignore
8539
- const chart = new window.Chart(canvas, runtime.chartJsConfig);
8570
+ const chart = new window.Chart(canvas, deepCopy(runtime.chartJsConfig));
8540
8571
  const imgContent = chart.toBase64Image();
8541
8572
  chart.destroy();
8542
8573
  div.remove();
@@ -8580,7 +8611,7 @@
8580
8611
  constructor(definition, sheetId, getters) {
8581
8612
  super(definition, sheetId, getters);
8582
8613
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
8583
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
8614
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
8584
8615
  this.background = definition.background;
8585
8616
  this.verticalAxisPosition = definition.verticalAxisPosition;
8586
8617
  this.legendPosition = definition.legendPosition;
@@ -8823,7 +8854,7 @@
8823
8854
  type = "gauge";
8824
8855
  constructor(definition, sheetId, getters) {
8825
8856
  super(definition, sheetId, getters);
8826
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
8857
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
8827
8858
  this.sectionRule = definition.sectionRule;
8828
8859
  this.background = definition.background;
8829
8860
  }
@@ -9157,7 +9188,7 @@
9157
9188
  constructor(definition, sheetId, getters) {
9158
9189
  super(definition, sheetId, getters);
9159
9190
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9160
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
9191
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
9161
9192
  this.background = definition.background;
9162
9193
  this.verticalAxisPosition = definition.verticalAxisPosition;
9163
9194
  this.legendPosition = definition.legendPosition;
@@ -9477,7 +9508,7 @@
9477
9508
  constructor(definition, sheetId, getters) {
9478
9509
  super(definition, sheetId, getters);
9479
9510
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
9480
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
9511
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
9481
9512
  this.background = definition.background;
9482
9513
  this.legendPosition = definition.legendPosition;
9483
9514
  this.aggregated = definition.aggregated;
@@ -21724,7 +21755,7 @@
21724
21755
  }
21725
21756
  const getters = this.env.model.getters;
21726
21757
  const sheetId = getters.getActiveSheetId();
21727
- const labelRange = createRange(getters, sheetId, this.labelRange);
21758
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
21728
21759
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
21729
21760
  if (dataSets.length) {
21730
21761
  return dataSets[0].dataRange.zone.top + 1;
@@ -25766,14 +25797,14 @@
25766
25797
  }
25767
25798
  onKeyDown(ev) {
25768
25799
  const figure = this.props.figure;
25769
- switch (ev.key) {
25800
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
25801
+ switch (keyDownShortcut) {
25770
25802
  case "Delete":
25771
25803
  this.env.model.dispatch("DELETE_FIGURE", {
25772
25804
  sheetId: this.env.model.getters.getActiveSheetId(),
25773
25805
  id: figure.id,
25774
25806
  });
25775
25807
  this.props.onFigureDeleted();
25776
- ev.stopPropagation();
25777
25808
  ev.preventDefault();
25778
25809
  ev.stopPropagation();
25779
25810
  break;
@@ -25794,7 +25825,22 @@
25794
25825
  x: figure.x + delta[0],
25795
25826
  y: figure.y + delta[1],
25796
25827
  });
25828
+ ev.preventDefault();
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();
25797
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
+ }
25798
25844
  ev.preventDefault();
25799
25845
  ev.stopPropagation();
25800
25846
  break;
@@ -26814,8 +26860,15 @@
26814
26860
  }
26815
26861
  onPaste(ev) {
26816
26862
  if (this.env.model.getters.getEditionMode() !== "inactive") {
26863
+ // let the browser clipboard work
26817
26864
  ev.stopPropagation();
26818
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
+ }
26819
26872
  }
26820
26873
  /*
26821
26874
  * Triggered automatically by the content-editable between the keydown and key up
@@ -26824,10 +26877,6 @@
26824
26877
  if (!this.shouldProcessInputEvents) {
26825
26878
  return;
26826
26879
  }
26827
- if (ev.inputType === "insertFromPaste" &&
26828
- this.env.model.getters.getEditionMode() === "inactive") {
26829
- return;
26830
- }
26831
26880
  ev.stopPropagation();
26832
26881
  let content;
26833
26882
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -27275,10 +27324,7 @@
27275
27324
  }
27276
27325
  get containerStyle() {
27277
27326
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27278
- return `
27279
- position: absolute;
27280
- z-index: -1000;
27281
- `;
27327
+ return `z-index: -1000;`;
27282
27328
  }
27283
27329
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27284
27330
  const cell = this.env.model.getters.getActiveCell();
@@ -38571,6 +38617,9 @@
38571
38617
  if (range.invalidXc) {
38572
38618
  return range.invalidXc;
38573
38619
  }
38620
+ if (!this.getters.tryGetSheet(range.sheetId)) {
38621
+ return INCORRECT_RANGE_STRING;
38622
+ }
38574
38623
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
38575
38624
  return INCORRECT_RANGE_STRING;
38576
38625
  }
@@ -42022,16 +42071,22 @@
42022
42071
  let newContent = undefined;
42023
42072
  let newFormat = undefined;
42024
42073
  let isExported = true;
42074
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42025
42075
  const formulaCell = this.getCorrespondingFormulaCell(position);
42026
42076
  if (formulaCell) {
42027
42077
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
42028
42078
  isFormula = isExported;
42029
42079
  if (!isExported) {
42030
- newContent = value.toString();
42031
- 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
+ }
42032
42088
  }
42033
42089
  }
42034
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
42035
42090
  const exportedCellData = exportedSheetData.cells[xc] || {};
42036
42091
  const format = newFormat
42037
42092
  ? getItemId(newFormat, data.formats)
@@ -51643,9 +51698,11 @@
51643
51698
  if (ev.key === "Enter") {
51644
51699
  ev.preventDefault();
51645
51700
  this.stopEdition();
51701
+ this.env.focusableElement.focus();
51646
51702
  }
51647
51703
  if (ev.key === "Escape") {
51648
51704
  this.cancelEdition();
51705
+ this.env.focusableElement.focus();
51649
51706
  }
51650
51707
  }
51651
51708
  onClickSheetName(ev) {
@@ -56394,7 +56451,11 @@
56394
56451
  let cellNode = escapeXml ``;
56395
56452
  // Either formula or static value inside the cell
56396
56453
  if (cell.isFormula) {
56397
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
56454
+ const res = addFormula(cell);
56455
+ if (!res) {
56456
+ continue;
56457
+ }
56458
+ ({ attrs: additionalAttrs, node: cellNode } = res);
56398
56459
  }
56399
56460
  else if (cell.content && isMarkdownLink(cell.content)) {
56400
56461
  const { label } = parseMarkdownLink(cell.content);
@@ -57414,9 +57475,9 @@
57414
57475
  exports.tokenize = tokenize;
57415
57476
 
57416
57477
 
57417
- __info__.version = "17.0.23";
57418
- __info__.date = "2024-05-24T11:27:27.416Z";
57419
- __info__.hash = "6c10fec";
57478
+ __info__.version = "17.0.25";
57479
+ __info__.date = "2024-06-10T09:33:40.022Z";
57480
+ __info__.hash = "1f01394";
57420
57481
 
57421
57482
 
57422
57483
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);