@odoo/o-spreadsheet 16.3.31 → 16.3.34

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.
@@ -1123,7 +1123,7 @@ function deepEquals(o1, o2) {
1123
1123
  if (typeof o1 !== typeof o2)
1124
1124
  return false;
1125
1125
  if (typeof o1 !== "object")
1126
- return o1 === o2;
1126
+ return false;
1127
1127
  // Objects can have different keys if the values are undefined
1128
1128
  const keys = new Set();
1129
1129
  Object.keys(o1).forEach((key) => keys.add(key));
@@ -6282,6 +6282,7 @@ class LinkEditor extends Component {
6282
6282
  this.save();
6283
6283
  }
6284
6284
  ev.stopPropagation();
6285
+ ev.preventDefault();
6285
6286
  break;
6286
6287
  case "Escape":
6287
6288
  this.cancel();
@@ -6866,7 +6867,7 @@ function truncateLabel(label) {
6866
6867
  /**
6867
6868
  * Get a default chart js configuration
6868
6869
  */
6869
- function getDefaultChartJsRuntime(chart, labels, fontColor, dataSetsFormat) {
6870
+ function getDefaultChartJsRuntime(chart, labels, fontColor, dataSetsFormat, truncateLabels = true) {
6870
6871
  return {
6871
6872
  type: chart.type,
6872
6873
  options: {
@@ -6919,7 +6920,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, dataSetsFormat) {
6919
6920
  },
6920
6921
  },
6921
6922
  data: {
6922
- labels: labels.map(truncateLabel),
6923
+ labels: truncateLabels ? labels.map(truncateLabel) : labels,
6923
6924
  datasets: [],
6924
6925
  },
6925
6926
  };
@@ -7758,9 +7759,9 @@ function canBeLinearChart(labelRange, getters) {
7758
7759
  }
7759
7760
  return true;
7760
7761
  }
7761
- function getLineConfiguration(chart, labels, dataSetFormat) {
7762
+ function getLineConfiguration(chart, labels, dataSetFormat, truncateLabels) {
7762
7763
  const fontColor = chartFontColor(chart.background);
7763
- const config = getDefaultChartJsRuntime(chart, labels, fontColor, dataSetFormat);
7764
+ const config = getDefaultChartJsRuntime(chart, labels, fontColor, dataSetFormat, truncateLabels);
7764
7765
  const legend = {
7765
7766
  labels: {
7766
7767
  fontColor,
@@ -7835,8 +7836,9 @@ function createLineChartRuntime(chart, getters) {
7835
7836
  if (chart.aggregated) {
7836
7837
  ({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
7837
7838
  }
7839
+ const truncateLabels = axisType === "category";
7838
7840
  const dataSetFormat = getChartDatasetFormat(getters, chart.dataSets);
7839
- const config = getLineConfiguration(chart, labels, dataSetFormat);
7841
+ const config = getLineConfiguration(chart, labels, dataSetFormat, truncateLabels);
7840
7842
  const labelFormat = getChartLabelFormat(getters, chart.labelRange);
7841
7843
  if (axisType === "time") {
7842
7844
  config.options.scales.xAxes[0].type = "time";
@@ -9470,9 +9472,12 @@ const INSERT_LINK_NAME = (env) => {
9470
9472
  // Filters action
9471
9473
  //------------------------------------------------------------------------------
9472
9474
  const FILTERS_CREATE_FILTER_TABLE = (env) => {
9475
+ const zones = env.model.getters.getSelectedZones();
9476
+ if (zones.length === 1 && getZoneArea(zones[0]) === 1) {
9477
+ env.model.selection.selectTableAroundSelection();
9478
+ }
9473
9479
  const sheetId = env.model.getters.getActiveSheetId();
9474
- const selection = env.model.getters.getSelection().zones;
9475
- interactiveAddFilter(env, sheetId, selection);
9480
+ interactiveAddFilter(env, sheetId, env.model.getters.getSelectedZones());
9476
9481
  };
9477
9482
  const FILTERS_REMOVE_FILTER_TABLE = (env) => {
9478
9483
  const sheetId = env.model.getters.getActiveSheetId();
@@ -21336,6 +21341,11 @@ class Composer extends Component {
21336
21341
  onBlur() {
21337
21342
  this.isKeyStillDown = false;
21338
21343
  }
21344
+ onContextMenu(ev) {
21345
+ if (this.env.model.getters.getEditionMode() === "inactive") {
21346
+ this.props.onInputContextMenu?.(ev);
21347
+ }
21348
+ }
21339
21349
  // ---------------------------------------------------------------------------
21340
21350
  // Private
21341
21351
  // ---------------------------------------------------------------------------
@@ -21557,6 +21567,7 @@ Composer.props = {
21557
21567
  onComposerCellFocused: { type: Function, optional: true },
21558
21568
  onComposerContentFocused: Function,
21559
21569
  isDefaultFocus: { type: Boolean, optional: true },
21570
+ onInputContextMenu: { type: Function, optional: true },
21560
21571
  };
21561
21572
 
21562
21573
  const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
@@ -21633,6 +21644,7 @@ class GridComposer extends Component {
21633
21644
  isDefaultFocus: true,
21634
21645
  onComposerContentFocused: this.props.onComposerContentFocused,
21635
21646
  onComposerCellFocused: this.props.onComposerCellFocused,
21647
+ onInputContextMenu: this.props.onInputContextMenu,
21636
21648
  };
21637
21649
  }
21638
21650
  get containerStyle() {
@@ -21721,6 +21733,7 @@ GridComposer.props = {
21721
21733
  onComposerContentFocused: Function,
21722
21734
  gridDims: Object,
21723
21735
  onComposerCellFocused: Function,
21736
+ onInputContextMenu: Function,
21724
21737
  };
21725
21738
 
21726
21739
  const CSS$1 = css /* scss */ `
@@ -24056,8 +24069,8 @@ class Grid extends Component {
24056
24069
  else if (this.env.model.getters.getActiveRows().has(row)) {
24057
24070
  type = "ROW";
24058
24071
  }
24059
- const { x, y, width, height } = this.env.model.getters.getVisibleRect(lastZone);
24060
- this.toggleContextMenu(type, x + width, y + height);
24072
+ const { x, y, width } = this.env.model.getters.getVisibleRect(lastZone);
24073
+ this.toggleContextMenu(type, this.canvasPosition.x + x + width, this.canvasPosition.y + y);
24061
24074
  }
24062
24075
  onCellRightClicked(col, row, { x, y }) {
24063
24076
  const zones = this.env.model.getters.getSelectedZones();
@@ -26384,29 +26397,12 @@ function convertWidthFromExcel(width) {
26384
26397
  return width;
26385
26398
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
26386
26399
  }
26387
- function convertBorderDescr(descr) {
26388
- if (!descr) {
26389
- return undefined;
26390
- }
26391
- return {
26392
- style: descr.style,
26393
- color: { rgb: descr.color },
26394
- };
26395
- }
26396
26400
  function extractStyle(cell, data) {
26397
26401
  let style = {};
26398
26402
  if (cell.style) {
26399
26403
  style = data.styles[cell.style];
26400
26404
  }
26401
26405
  const format = extractFormat(cell, data);
26402
- const exportedBorder = {};
26403
- if (cell.border) {
26404
- const border = data.borders[cell.border];
26405
- exportedBorder.left = convertBorderDescr(border.left);
26406
- exportedBorder.right = convertBorderDescr(border.right);
26407
- exportedBorder.bottom = convertBorderDescr(border.bottom);
26408
- exportedBorder.top = convertBorderDescr(border.top);
26409
- }
26410
26406
  const styles = {
26411
26407
  font: {
26412
26408
  size: style?.fontSize || DEFAULT_FONT_SIZE,
@@ -26420,7 +26416,7 @@ function extractStyle(cell, data) {
26420
26416
  }
26421
26417
  : { reservedAttribute: "none" },
26422
26418
  numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
26423
- border: exportedBorder || {},
26419
+ border: cell.border || 0,
26424
26420
  alignment: {
26425
26421
  horizontal: style.align,
26426
26422
  vertical: style.verticalAlign
@@ -26452,15 +26448,12 @@ function extractFormat(cell, data) {
26452
26448
  return undefined;
26453
26449
  }
26454
26450
  function normalizeStyle(construct, styles) {
26455
- const { id: fontId } = pushElement(styles["font"], construct.fonts);
26456
- const { id: fillId } = pushElement(styles["fill"], construct.fills);
26457
- const { id: borderId } = pushElement(styles["border"], construct.borders);
26458
26451
  // Normalize this
26459
26452
  const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
26460
26453
  const style = {
26461
- fontId,
26462
- fillId,
26463
- borderId,
26454
+ fontId: pushElement(styles.font, construct.fonts),
26455
+ fillId: pushElement(styles.fill, construct.fills),
26456
+ borderId: styles.border,
26464
26457
  numFmtId,
26465
26458
  alignment: {
26466
26459
  vertical: styles.alignment.vertical,
@@ -26468,8 +26461,7 @@ function normalizeStyle(construct, styles) {
26468
26461
  wrapText: styles.alignment.wrapText,
26469
26462
  },
26470
26463
  };
26471
- const { id } = pushElement(style, construct.styles);
26472
- return id;
26464
+ return pushElement(style, construct.styles);
26473
26465
  }
26474
26466
  function convertFormat(format, numFmtStructure) {
26475
26467
  if (!format) {
@@ -26477,8 +26469,7 @@ function convertFormat(format, numFmtStructure) {
26477
26469
  }
26478
26470
  let formatId = XLSX_FORMAT_MAP[format.format];
26479
26471
  if (!formatId) {
26480
- const { id } = pushElement(format, numFmtStructure);
26481
- formatId = id + FIRST_NUMFMT_ID;
26472
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
26482
26473
  }
26483
26474
  return formatId;
26484
26475
  }
@@ -26503,20 +26494,15 @@ function addRelsToFile(relsFiles, path, rel) {
26503
26494
  return id;
26504
26495
  }
26505
26496
  function pushElement(property, propertyList) {
26506
- for (let [key, value] of Object.entries(propertyList)) {
26507
- if (JSON.stringify(value) === JSON.stringify(property)) {
26508
- return { id: parseInt(key, 10), list: propertyList };
26497
+ let len = propertyList.length;
26498
+ const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
26499
+ for (let i = 0; i < len; i++) {
26500
+ if (operator(property, propertyList[i])) {
26501
+ return i;
26509
26502
  }
26510
26503
  }
26511
- let elemId = propertyList.findIndex((elem) => JSON.stringify(elem) === JSON.stringify(property));
26512
- if (elemId === -1) {
26513
- propertyList.push(property);
26514
- elemId = propertyList.length - 1;
26515
- }
26516
- return {
26517
- id: elemId,
26518
- list: propertyList,
26519
- };
26504
+ propertyList[propertyList.length] = property;
26505
+ return propertyList.length - 1;
26520
26506
  }
26521
26507
  const chartIds = [];
26522
26508
  /**
@@ -27222,7 +27208,25 @@ function parseXML(xmlString, mimeType = "text/xml") {
27222
27208
  }
27223
27209
  return document;
27224
27210
  }
27225
- function getDefaultXLSXStructure() {
27211
+ function convertBorderDescr(descr) {
27212
+ if (!descr) {
27213
+ return undefined;
27214
+ }
27215
+ return {
27216
+ style: descr.style,
27217
+ color: { rgb: descr.color },
27218
+ };
27219
+ }
27220
+ function getDefaultXLSXStructure(data) {
27221
+ const xlsxBorders = Object.values(data.borders).map((border) => {
27222
+ return {
27223
+ left: convertBorderDescr(border.left),
27224
+ right: convertBorderDescr(border.right),
27225
+ bottom: convertBorderDescr(border.bottom),
27226
+ top: convertBorderDescr(border.top),
27227
+ };
27228
+ });
27229
+ const borders = [{}, ...xlsxBorders];
27226
27230
  return {
27227
27231
  relsFiles: [],
27228
27232
  sharedStrings: [],
@@ -27245,7 +27249,7 @@ function getDefaultXLSXStructure() {
27245
27249
  },
27246
27250
  ],
27247
27251
  fills: [{ reservedAttribute: "none" }, { reservedAttribute: "gray125" }],
27248
- borders: [{}],
27252
+ borders,
27249
27253
  numFmts: [],
27250
27254
  dxfs: [],
27251
27255
  };
@@ -29243,7 +29247,7 @@ class BordersPlugin extends CorePlugin {
29243
29247
  this.clearBorders(cmd.sheetId, cmd.target);
29244
29248
  break;
29245
29249
  case "REMOVE_COLUMNS_ROWS":
29246
- for (let el of cmd.elements) {
29250
+ for (let el of [...cmd.elements].sort((a, b) => b - a)) {
29247
29251
  if (cmd.dimension === "COL") {
29248
29252
  this.shiftBordersHorizontally(cmd.sheetId, el + 1, -1);
29249
29253
  }
@@ -31196,7 +31200,17 @@ class FiltersPlugin extends CorePlugin {
31196
31200
  }
31197
31201
  }
31198
31202
  exportForExcel(data) {
31199
- this.export(data);
31203
+ for (const sheet of data.sheets) {
31204
+ for (const filterTable of this.getFilterTables(sheet.id)) {
31205
+ if (zoneToDimension(filterTable.zone).numberOfRows === 1) {
31206
+ continue;
31207
+ }
31208
+ sheet.filterTables.push({
31209
+ range: zoneToXc(filterTable.zone),
31210
+ filters: [],
31211
+ });
31212
+ }
31213
+ }
31200
31214
  }
31201
31215
  }
31202
31216
 
@@ -35064,12 +35078,13 @@ class SheetViewPlugin extends UIPlugin {
35064
35078
  case "AlterZone":
35065
35079
  break;
35066
35080
  case "ZonesSelected":
35081
+ const sheetId = this.getters.getActiveSheetId();
35067
35082
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
35068
35083
  if (event.mode === "updateAnchor") {
35069
35084
  const oldZone = event.previousAnchor.zone;
35070
35085
  const newZone = event.anchor.zone;
35071
35086
  // altering a zone should not move the viewport in a dimension that wasn't changed
35072
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
35087
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
35073
35088
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
35074
35089
  col = left > col || col > right ? left : col;
35075
35090
  }
@@ -35077,10 +35092,9 @@ class SheetViewPlugin extends UIPlugin {
35077
35092
  row = top > row || row > bottom ? top : row;
35078
35093
  }
35079
35094
  }
35080
- const sheetId = this.getters.getActiveSheetId();
35081
35095
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
35082
35096
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
35083
- this.refreshViewport(this.getters.getActiveSheetId(), { col, row });
35097
+ this.refreshViewport(sheetId, { col, row });
35084
35098
  break;
35085
35099
  }
35086
35100
  }
@@ -35104,16 +35118,16 @@ class SheetViewPlugin extends UIPlugin {
35104
35118
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
35105
35119
  break;
35106
35120
  case "SHIFT_VIEWPORT_DOWN":
35107
- const { top } = this.getActiveMainViewport();
35108
35121
  const sheetId = this.getters.getActiveSheetId();
35109
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
35110
- this.shiftVertically(shiftedOffsetY);
35122
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
35123
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
35124
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
35111
35125
  break;
35112
35126
  case "SHIFT_VIEWPORT_UP": {
35113
- const { top } = this.getActiveMainViewport();
35114
35127
  const sheetId = this.getters.getActiveSheetId();
35115
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
35116
- this.shiftVertically(shiftedOffsetY);
35128
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
35129
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
35130
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
35117
35131
  break;
35118
35132
  }
35119
35133
  case "REMOVE_COLUMNS_ROWS":
@@ -35475,17 +35489,6 @@ class SheetViewPlugin extends UIPlugin {
35475
35489
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
35476
35490
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
35477
35491
  }
35478
- /**
35479
- * Clip the vertical offset within the allowed range.
35480
- * Not above the sheet, nor below the sheet.
35481
- */
35482
- clipOffsetY(offsetY) {
35483
- const { height } = this.getMainViewportRect();
35484
- const maxOffset = height - this.sheetViewHeight;
35485
- offsetY = Math.min(offsetY, maxOffset);
35486
- offsetY = Math.max(offsetY, 0);
35487
- return offsetY;
35488
- }
35489
35492
  getViewportOffset(sheetId) {
35490
35493
  return {
35491
35494
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -35541,12 +35544,15 @@ class SheetViewPlugin extends UIPlugin {
35541
35544
  * viewport top.
35542
35545
  */
35543
35546
  shiftVertically(offset) {
35544
- const { top } = this.getActiveMainViewport();
35547
+ const sheetId = this.getters.getActiveSheetId();
35548
+ const { top } = this.getMainInternalViewport(sheetId);
35545
35549
  const { scrollX } = this.getActiveSheetScrollInfo();
35546
35550
  this.setSheetViewOffset(scrollX, offset);
35547
35551
  const { anchor } = this.getters.getSelection();
35548
- const deltaRow = this.getActiveMainViewport().top - top;
35549
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
35552
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
35553
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
35554
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
35555
+ }
35550
35556
  }
35551
35557
  getVisibleFigures() {
35552
35558
  const sheetId = this.getters.getActiveSheetId();
@@ -43096,7 +43102,6 @@ css /* scss */ `
43096
43102
  cursor: pointer;
43097
43103
  }
43098
43104
  `;
43099
- let tKey = 1;
43100
43105
  class SpreadsheetDashboard extends Component {
43101
43106
  static template = "o-spreadsheet-SpreadsheetDashboard";
43102
43107
  static components = {
@@ -43174,13 +43179,9 @@ class SpreadsheetDashboard extends Component {
43174
43179
  coordinates: rect,
43175
43180
  position: { col, row },
43176
43181
  action,
43177
- // we can't rely on position only because a row or a column could
43178
- // be inserted at any time.
43179
- tKey: `${tKey}-${col}-${row}`,
43180
43182
  });
43181
43183
  }
43182
43184
  }
43183
- tKey++;
43184
43185
  return cells;
43185
43186
  }
43186
43187
  getClickableAction(position) {
@@ -46318,8 +46319,7 @@ function addContent(content, sharedStrings, forceString = false) {
46318
46319
  attrs.push(["t", "b"]);
46319
46320
  }
46320
46321
  else if (forceString || !isNumber(value)) {
46321
- const { id } = pushElement(content, sharedStrings);
46322
- value = id.toString();
46322
+ value = pushElement(content, sharedStrings);
46323
46323
  attrs.push(["t", "s"]);
46324
46324
  }
46325
46325
  return { attrs, node: escapeXml /*xml*/ `<v>${value}</v>` };
@@ -46444,8 +46444,7 @@ function addCellIsRule(cf, rule, dxfs) {
46444
46444
  if (rule.style.fillColor) {
46445
46445
  dxf.fill = { fgColor: { rgb: rule.style.fillColor } };
46446
46446
  }
46447
- const { id } = pushElement(dxf, dxfs);
46448
- ruleAttributes.push(["dxfId", id]);
46447
+ ruleAttributes.push(["dxfId", pushElement(dxf, dxfs)]);
46449
46448
  return escapeXml /*xml*/ `
46450
46449
  <conditionalFormatting sqref="${cf.ranges.join(" ")}">
46451
46450
  <cfRule ${formatAttributes(ruleAttributes)}>
@@ -47249,7 +47248,7 @@ function addSheetViews(sheet) {
47249
47248
  */
47250
47249
  function getXLSX(data) {
47251
47250
  const files = [];
47252
- const construct = getDefaultXLSXStructure();
47251
+ const construct = getDefaultXLSXStructure(data);
47253
47252
  files.push(createWorkbook(data, construct));
47254
47253
  files.push(...createWorksheets(data, construct));
47255
47254
  files.push(createStylesSheet(construct));
@@ -48062,6 +48061,6 @@ function addFunction(functionName, functionDescription) {
48062
48061
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
48063
48062
 
48064
48063
 
48065
- __info__.version = '16.3.31';
48066
- __info__.date = '2024-04-05T13:57:05.657Z';
48067
- __info__.hash = '052efd4';
48064
+ __info__.version = '16.3.34';
48065
+ __info__.date = '2024-04-26T07:37:12.329Z';
48066
+ __info__.hash = '196324c';