@odoo/o-spreadsheet 17.2.2 → 17.2.4

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.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.2
7
- * @date 2024-04-05T14:01:19.824Z
8
- * @hash c15836d
6
+ * @version 17.2.4
7
+ * @date 2024-04-18T16:41:38.407Z
8
+ * @hash 0c66038
9
9
  */
10
10
 
11
11
  'use strict';
@@ -562,7 +562,7 @@ function deepEquals(o1, o2) {
562
562
  if (typeof o1 !== typeof o2)
563
563
  return false;
564
564
  if (typeof o1 !== "object")
565
- return o1 === o2;
565
+ return false;
566
566
  // Objects can have different keys if the values are undefined
567
567
  for (const key in o2) {
568
568
  if (!(key in o1) && o2[key] !== undefined) {
@@ -2509,6 +2509,15 @@ function matrixMap(matrix, fn) {
2509
2509
  }
2510
2510
  return generateMatrix(matrix.length, matrix[0].length, (col, row) => fn(matrix[col][row]));
2511
2511
  }
2512
+ function matrixForEach(matrix, fn) {
2513
+ const numberOfCols = matrix.length;
2514
+ const numberOfRows = matrix[0]?.length ?? 0;
2515
+ for (let col = 0; col < numberOfCols; col++) {
2516
+ for (let row = 0; row < numberOfRows; row++) {
2517
+ fn(matrix[col][row]);
2518
+ }
2519
+ }
2520
+ }
2512
2521
  function transposeMatrix(matrix) {
2513
2522
  if (!matrix.length) {
2514
2523
  return [];
@@ -18636,7 +18645,7 @@ class FunctionRegistry extends Registry {
18636
18645
  }
18637
18646
  const descr = addMetaInfoFromArg(addDescr);
18638
18647
  validateArguments(descr.args);
18639
- this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr)), name);
18648
+ this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr), name), name);
18640
18649
  super.add(name, descr);
18641
18650
  return this;
18642
18651
  }
@@ -18675,9 +18684,7 @@ function handleError(e, functionName) {
18675
18684
  // so we fallback to a generic error
18676
18685
  if (hasStringValue(e) && isEvaluationError(e.value)) {
18677
18686
  if (hasStringMessage(e)) {
18678
- if (e.message?.includes("[[FUNCTION_NAME]]")) {
18679
- e.message = e.message.replace("[[FUNCTION_NAME]]", functionName);
18680
- }
18687
+ replaceFunctionNamePlaceholder(e, functionName);
18681
18688
  }
18682
18689
  return e;
18683
18690
  }
@@ -18692,21 +18699,29 @@ function hasStringMessage(obj) {
18692
18699
  return (obj?.message !== undefined &&
18693
18700
  typeof obj.message === "string");
18694
18701
  }
18695
- function addResultHandling(compute) {
18696
- return function (...args) {
18702
+ function addResultHandling(compute, functionName) {
18703
+ return function computeWithResultHandling(...args) {
18697
18704
  const result = compute.apply(this, args);
18698
18705
  if (!isMatrix(result)) {
18699
18706
  if (typeof result === "object" && result !== null && "value" in result) {
18707
+ replaceFunctionNamePlaceholder(result, functionName);
18700
18708
  return result;
18701
18709
  }
18702
18710
  return { value: result };
18703
18711
  }
18704
18712
  if (typeof result[0][0] === "object" && result[0][0] !== null && "value" in result[0][0]) {
18713
+ matrixForEach(result, (result) => replaceFunctionNamePlaceholder(result, functionName));
18705
18714
  return result;
18706
18715
  }
18707
18716
  return matrixMap(result, (row) => ({ value: row }));
18708
18717
  };
18709
18718
  }
18719
+ function replaceFunctionNamePlaceholder(fPayload, functionName) {
18720
+ // for performance reasons: change in place and only if needed
18721
+ if (fPayload.message?.includes("[[FUNCTION_NAME]]")) {
18722
+ fPayload.message = fPayload.message.replace("[[FUNCTION_NAME]]", functionName);
18723
+ }
18724
+ }
18710
18725
  const functionRegistry = new FunctionRegistry();
18711
18726
  for (let category of categories) {
18712
18727
  const fns = category.functions;
@@ -19474,7 +19489,7 @@ function getDefaultChartJsRuntime(chart, labels, fontColor, { format, locale })
19474
19489
  const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
19475
19490
  // tooltipItem.parsed.y can be an object or a number for pie charts
19476
19491
  const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
19477
- const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
19492
+ const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
19478
19493
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
19479
19494
  return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
19480
19495
  },
@@ -19774,7 +19789,10 @@ function getBarConfiguration(chart, labels, localeFormat) {
19774
19789
  if (isNaN(value))
19775
19790
  return value;
19776
19791
  const { locale, format } = localeFormat;
19777
- return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
19792
+ return formatValue(value, {
19793
+ locale,
19794
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
19795
+ });
19778
19796
  },
19779
19797
  },
19780
19798
  },
@@ -20295,7 +20313,10 @@ function getLineOrScatterConfiguration(chart, labels, localeFormat) {
20295
20313
  if (isNaN(value))
20296
20314
  return value;
20297
20315
  const { locale, format } = localeFormat;
20298
- return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
20316
+ return formatValue(value, {
20317
+ locale,
20318
+ format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
20319
+ });
20299
20320
  },
20300
20321
  },
20301
20322
  },
@@ -20635,7 +20656,7 @@ function getPieConfiguration(chart, labels, localeFormat) {
20635
20656
  const percentage = calculatePercentage(data, dataIndex);
20636
20657
  const xLabel = tooltipItem.label || tooltipItem.dataset.label;
20637
20658
  const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
20638
- const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
20659
+ const toolTipFormat = !format && yLabel >= 1000 ? "#,##" : format;
20639
20660
  const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
20640
20661
  return xLabel ? `${xLabel}: ${yLabelStr} (${percentage}%)` : `${yLabelStr} (${percentage}%)`;
20641
20662
  };
@@ -22887,6 +22908,7 @@ class LinkEditor extends owl.Component {
22887
22908
  this.save();
22888
22909
  }
22889
22910
  ev.stopPropagation();
22911
+ ev.preventDefault();
22890
22912
  break;
22891
22913
  case "Escape":
22892
22914
  this.cancel();
@@ -31969,6 +31991,7 @@ class Composer extends owl.Component {
31969
31991
  onComposerCellFocused: { type: Function, optional: true },
31970
31992
  onComposerContentFocused: Function,
31971
31993
  isDefaultFocus: { type: Boolean, optional: true },
31994
+ onInputContextMenu: { type: Function, optional: true },
31972
31995
  };
31973
31996
  static components = { TextValueProvider, FunctionDescriptionProvider };
31974
31997
  static defaultProps = {
@@ -32019,6 +32042,9 @@ class Composer extends owl.Component {
32019
32042
  assistantStyle.right = `0px`;
32020
32043
  }
32021
32044
  }
32045
+ else if (this.props.delimitation) {
32046
+ assistantStyle["max-height"] = `${this.props.delimitation.height}px`;
32047
+ }
32022
32048
  return cssPropertiesToCss(assistantStyle);
32023
32049
  }
32024
32050
  // we can't allow input events to be triggered while we remove and add back the content of the composer in processContent
@@ -32305,6 +32331,11 @@ class Composer extends owl.Component {
32305
32331
  }
32306
32332
  }
32307
32333
  }
32334
+ onContextMenu(ev) {
32335
+ if (this.composerStore.editionMode === "inactive") {
32336
+ this.props.onInputContextMenu?.(ev);
32337
+ }
32338
+ }
32308
32339
  // ---------------------------------------------------------------------------
32309
32340
  // Private
32310
32341
  // ---------------------------------------------------------------------------
@@ -32526,6 +32557,7 @@ class GridComposer extends owl.Component {
32526
32557
  static template = "o-spreadsheet-GridComposer";
32527
32558
  static props = {
32528
32559
  gridDims: Object,
32560
+ onInputContextMenu: Function,
32529
32561
  };
32530
32562
  static components = { Composer };
32531
32563
  rect = this.defaultRect;
@@ -32573,6 +32605,7 @@ class GridComposer extends owl.Component {
32573
32605
  isDefaultFocus: true,
32574
32606
  onComposerContentFocused: () => this.composerFocusStore.focusGridComposerContent(),
32575
32607
  onComposerCellFocused: (content) => this.composerFocusStore.focusGridComposerCell(content),
32608
+ onInputContextMenu: this.props.onInputContextMenu,
32576
32609
  };
32577
32610
  }
32578
32611
  get containerStyle() {
@@ -33152,6 +33185,10 @@ css /*SCSS*/ `
33152
33185
  height: 0px;
33153
33186
  }
33154
33187
  }
33188
+ .o-figure-container {
33189
+ -webkit-user-select: none; // safari
33190
+ user-select: none;
33191
+ }
33155
33192
  `;
33156
33193
  /**
33157
33194
  * Each figure ⭐ is positioned inside a container `div` placed and sized
@@ -37295,29 +37332,12 @@ function convertWidthFromExcel(width) {
37295
37332
  return width;
37296
37333
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
37297
37334
  }
37298
- function convertBorderDescr(descr) {
37299
- if (!descr) {
37300
- return undefined;
37301
- }
37302
- return {
37303
- style: descr.style,
37304
- color: { rgb: descr.color },
37305
- };
37306
- }
37307
37335
  function extractStyle(cell, data) {
37308
37336
  let style = {};
37309
37337
  if (cell.style) {
37310
37338
  style = data.styles[cell.style];
37311
37339
  }
37312
37340
  const format = extractFormat(cell, data);
37313
- const exportedBorder = {};
37314
- if (cell.border) {
37315
- const border = data.borders[cell.border];
37316
- exportedBorder.left = convertBorderDescr(border.left);
37317
- exportedBorder.right = convertBorderDescr(border.right);
37318
- exportedBorder.bottom = convertBorderDescr(border.bottom);
37319
- exportedBorder.top = convertBorderDescr(border.top);
37320
- }
37321
37341
  const styles = {
37322
37342
  font: {
37323
37343
  size: style?.fontSize || DEFAULT_FONT_SIZE,
@@ -37331,7 +37351,7 @@ function extractStyle(cell, data) {
37331
37351
  }
37332
37352
  : { reservedAttribute: "none" },
37333
37353
  numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
37334
- border: exportedBorder || {},
37354
+ border: cell.border || 0,
37335
37355
  alignment: {
37336
37356
  horizontal: style.align,
37337
37357
  vertical: style.verticalAlign
@@ -37353,15 +37373,12 @@ function extractFormat(cell, data) {
37353
37373
  return undefined;
37354
37374
  }
37355
37375
  function normalizeStyle(construct, styles) {
37356
- const { id: fontId } = pushElement(styles["font"], construct.fonts);
37357
- const { id: fillId } = pushElement(styles["fill"], construct.fills);
37358
- const { id: borderId } = pushElement(styles["border"], construct.borders);
37359
37376
  // Normalize this
37360
37377
  const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
37361
37378
  const style = {
37362
- fontId,
37363
- fillId,
37364
- borderId,
37379
+ fontId: pushElement(styles.font, construct.fonts),
37380
+ fillId: pushElement(styles.fill, construct.fills),
37381
+ borderId: styles.border,
37365
37382
  numFmtId,
37366
37383
  alignment: {
37367
37384
  vertical: styles.alignment.vertical,
@@ -37369,8 +37386,7 @@ function normalizeStyle(construct, styles) {
37369
37386
  wrapText: styles.alignment.wrapText,
37370
37387
  },
37371
37388
  };
37372
- const { id } = pushElement(style, construct.styles);
37373
- return id;
37389
+ return pushElement(style, construct.styles);
37374
37390
  }
37375
37391
  function convertFormat(format, numFmtStructure) {
37376
37392
  if (!format) {
@@ -37378,8 +37394,7 @@ function convertFormat(format, numFmtStructure) {
37378
37394
  }
37379
37395
  let formatId = XLSX_FORMAT_MAP[format.format];
37380
37396
  if (!formatId) {
37381
- const { id } = pushElement(format, numFmtStructure);
37382
- formatId = id + FIRST_NUMFMT_ID;
37397
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
37383
37398
  }
37384
37399
  return formatId;
37385
37400
  }
@@ -37404,20 +37419,15 @@ function addRelsToFile(relsFiles, path, rel) {
37404
37419
  return id;
37405
37420
  }
37406
37421
  function pushElement(property, propertyList) {
37407
- for (let [key, value] of Object.entries(propertyList)) {
37408
- if (JSON.stringify(value) === JSON.stringify(property)) {
37409
- return { id: parseInt(key, 10), list: propertyList };
37422
+ let len = propertyList.length;
37423
+ const operator = typeof property === "object" ? deepEquals : (a, b) => a === b;
37424
+ for (let i = 0; i < len; i++) {
37425
+ if (operator(property, propertyList[i])) {
37426
+ return i;
37410
37427
  }
37411
37428
  }
37412
- let elemId = propertyList.findIndex((elem) => JSON.stringify(elem) === JSON.stringify(property));
37413
- if (elemId === -1) {
37414
- propertyList.push(property);
37415
- elemId = propertyList.length - 1;
37416
- }
37417
- return {
37418
- id: elemId,
37419
- list: propertyList,
37420
- };
37429
+ propertyList[propertyList.length] = property;
37430
+ return propertyList.length - 1;
37421
37431
  }
37422
37432
  const chartIds = [];
37423
37433
  /**
@@ -38212,7 +38222,25 @@ function parseXML(xmlString, mimeType = "text/xml") {
38212
38222
  }
38213
38223
  return document;
38214
38224
  }
38215
- function getDefaultXLSXStructure() {
38225
+ function convertBorderDescr(descr) {
38226
+ if (!descr) {
38227
+ return undefined;
38228
+ }
38229
+ return {
38230
+ style: descr.style,
38231
+ color: { rgb: descr.color },
38232
+ };
38233
+ }
38234
+ function getDefaultXLSXStructure(data) {
38235
+ const xlsxBorders = Object.values(data.borders).map((border) => {
38236
+ return {
38237
+ left: convertBorderDescr(border.left),
38238
+ right: convertBorderDescr(border.right),
38239
+ bottom: convertBorderDescr(border.bottom),
38240
+ top: convertBorderDescr(border.top),
38241
+ };
38242
+ });
38243
+ const borders = [{}, ...xlsxBorders];
38216
38244
  return {
38217
38245
  relsFiles: [],
38218
38246
  sharedStrings: [],
@@ -38235,7 +38263,7 @@ function getDefaultXLSXStructure() {
38235
38263
  },
38236
38264
  ],
38237
38265
  fills: [{ reservedAttribute: "none" }, { reservedAttribute: "gray125" }],
38238
- borders: [{}],
38266
+ borders,
38239
38267
  numFmts: [],
38240
38268
  dxfs: [],
38241
38269
  };
@@ -45272,7 +45300,15 @@ class TablePlugin extends CorePlugin {
45272
45300
  }
45273
45301
  }
45274
45302
  exportForExcel(data) {
45275
- this.export(data);
45303
+ for (const sheet of data.sheets) {
45304
+ for (const table of this.getTables(sheet.id)) {
45305
+ if (zoneToDimension(table.range.zone).numberOfRows === 1) {
45306
+ continue;
45307
+ }
45308
+ const tableData = { range: zoneToXc(table.range.zone), filters: [] };
45309
+ sheet.tables.push(tableData);
45310
+ }
45311
+ }
45276
45312
  }
45277
45313
  }
45278
45314
 
@@ -47044,7 +47080,9 @@ class Evaluator {
47044
47080
  this.blockedArrayFormulas = this.createEmptyPositionSet();
47045
47081
  this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
47046
47082
  this.formulaDependencies = lazy(() => {
47047
- const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position).map((range) => ({
47083
+ const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
47084
+ .filter((range) => !range.invalidSheetName && !range.invalidXc)
47085
+ .map((range) => ({
47048
47086
  data: position,
47049
47087
  boundingBox: {
47050
47088
  zone: range.zone,
@@ -52074,7 +52112,7 @@ class FilterEvaluationPlugin extends UIPlugin {
52074
52112
  "isFilterActive",
52075
52113
  ];
52076
52114
  filterValues = {};
52077
- hiddenRows = new Set();
52115
+ hiddenRows = {};
52078
52116
  isEvaluationDirty = false;
52079
52117
  allowDispatch(cmd) {
52080
52118
  switch (cmd.type) {
@@ -52118,11 +52156,11 @@ class FilterEvaluationPlugin extends UIPlugin {
52118
52156
  case "UNFOLD_HEADER_GROUP":
52119
52157
  case "FOLD_ALL_HEADER_GROUPS":
52120
52158
  case "UNFOLD_ALL_HEADER_GROUPS":
52121
- this.updateHiddenRows();
52159
+ this.updateHiddenRows(cmd.sheetId);
52122
52160
  break;
52123
52161
  case "UPDATE_FILTER":
52124
52162
  this.updateFilter(cmd);
52125
- this.updateHiddenRows();
52163
+ this.updateHiddenRows(cmd.sheetId);
52126
52164
  break;
52127
52165
  case "DUPLICATE_SHEET":
52128
52166
  const filterValues = {};
@@ -52142,15 +52180,14 @@ class FilterEvaluationPlugin extends UIPlugin {
52142
52180
  }
52143
52181
  finalize() {
52144
52182
  if (this.isEvaluationDirty) {
52145
- this.updateHiddenRows();
52183
+ for (const sheetId of this.getters.getSheetIds()) {
52184
+ this.updateHiddenRows(sheetId);
52185
+ }
52146
52186
  this.isEvaluationDirty = false;
52147
52187
  }
52148
52188
  }
52149
52189
  isRowFiltered(sheetId, row) {
52150
- if (sheetId !== this.getters.getActiveSheetId()) {
52151
- return false;
52152
- }
52153
- return this.hiddenRows.has(row);
52190
+ return !!this.hiddenRows[sheetId]?.has(row);
52154
52191
  }
52155
52192
  getFilterHiddenValues(position) {
52156
52193
  const id = this.getters.getFilterId(position);
@@ -52177,8 +52214,7 @@ class FilterEvaluationPlugin extends UIPlugin {
52177
52214
  this.filterValues[sheetId] = {};
52178
52215
  this.filterValues[sheetId][id] = hiddenValues;
52179
52216
  }
52180
- updateHiddenRows() {
52181
- const sheetId = this.getters.getActiveSheetId();
52217
+ updateHiddenRows(sheetId) {
52182
52218
  const filters = this.getters
52183
52219
  .getFilters(sheetId)
52184
52220
  .sort((filter1, filter2) => filter1.rangeWithHeaders.zone.top - filter2.rangeWithHeaders.zone.top);
@@ -52200,7 +52236,7 @@ class FilterEvaluationPlugin extends UIPlugin {
52200
52236
  }
52201
52237
  }
52202
52238
  }
52203
- this.hiddenRows = hiddenRows;
52239
+ this.hiddenRows[sheetId] = hiddenRows;
52204
52240
  }
52205
52241
  getCellValueAsString(sheetId, col, row) {
52206
52242
  const value = this.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue;
@@ -53319,13 +53355,14 @@ class SheetViewPlugin extends UIPlugin {
53319
53355
  }
53320
53356
  }
53321
53357
  handleEvent(event) {
53358
+ const sheetId = this.getters.getActiveSheetId();
53322
53359
  if (event.options.scrollIntoView) {
53323
53360
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
53324
53361
  if (event.mode === "updateAnchor") {
53325
53362
  const oldZone = event.previousAnchor.zone;
53326
53363
  const newZone = event.anchor.zone;
53327
53364
  // altering a zone should not move the viewport in a dimension that wasn't changed
53328
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
53365
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
53329
53366
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
53330
53367
  col = left > col || col > right ? left : col;
53331
53368
  }
@@ -53333,7 +53370,6 @@ class SheetViewPlugin extends UIPlugin {
53333
53370
  row = top > row || row > bottom ? top : row;
53334
53371
  }
53335
53372
  }
53336
- const sheetId = this.getters.getActiveSheetId();
53337
53373
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
53338
53374
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
53339
53375
  if (!this.sheetsWithDirtyViewports.has(sheetId)) {
@@ -53370,16 +53406,16 @@ class SheetViewPlugin extends UIPlugin {
53370
53406
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
53371
53407
  break;
53372
53408
  case "SHIFT_VIEWPORT_DOWN":
53373
- const { top } = this.getActiveMainViewport();
53374
53409
  const sheetId = this.getters.getActiveSheetId();
53375
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
53376
- this.shiftVertically(shiftedOffsetY);
53410
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
53411
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
53412
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
53377
53413
  break;
53378
53414
  case "SHIFT_VIEWPORT_UP": {
53379
- const { top } = this.getActiveMainViewport();
53380
53415
  const sheetId = this.getters.getActiveSheetId();
53381
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
53382
- this.shiftVertically(shiftedOffsetY);
53416
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
53417
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
53418
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
53383
53419
  break;
53384
53420
  }
53385
53421
  case "REMOVE_TABLE":
@@ -53802,17 +53838,6 @@ class SheetViewPlugin extends UIPlugin {
53802
53838
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
53803
53839
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
53804
53840
  }
53805
- /**
53806
- * Clip the vertical offset within the allowed range.
53807
- * Not above the sheet, nor below the sheet.
53808
- */
53809
- clipOffsetY(offsetY) {
53810
- const { height } = this.getMainViewportRect();
53811
- const maxOffset = height - this.sheetViewHeight;
53812
- offsetY = Math.min(offsetY, maxOffset);
53813
- offsetY = Math.max(offsetY, 0);
53814
- return offsetY;
53815
- }
53816
53841
  getViewportOffset(sheetId) {
53817
53842
  return {
53818
53843
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -53868,12 +53893,15 @@ class SheetViewPlugin extends UIPlugin {
53868
53893
  * viewport top.
53869
53894
  */
53870
53895
  shiftVertically(offset) {
53871
- const { top } = this.getActiveMainViewport();
53896
+ const sheetId = this.getters.getActiveSheetId();
53897
+ const { top } = this.getMainInternalViewport(sheetId);
53872
53898
  const { scrollX } = this.getActiveSheetScrollInfo();
53873
53899
  this.setSheetViewOffset(scrollX, offset);
53874
53900
  const { anchor } = this.getters.getSelection();
53875
- const deltaRow = this.getActiveMainViewport().top - top;
53876
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
53901
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
53902
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
53903
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
53904
+ }
53877
53905
  }
53878
53906
  getVisibleFigures() {
53879
53907
  const sheetId = this.getters.getActiveSheetId();
@@ -54792,7 +54820,6 @@ css /* scss */ `
54792
54820
  cursor: pointer;
54793
54821
  }
54794
54822
  `;
54795
- let tKey = 1;
54796
54823
  class SpreadsheetDashboard extends owl.Component {
54797
54824
  static template = "o-spreadsheet-SpreadsheetDashboard";
54798
54825
  static props = {};
@@ -54871,13 +54898,9 @@ class SpreadsheetDashboard extends owl.Component {
54871
54898
  coordinates: rect,
54872
54899
  position: { col, row },
54873
54900
  action,
54874
- // we can't rely on position only because a row or a column could
54875
- // be inserted at any time.
54876
- tKey: `${tKey}-${col}-${row}`,
54877
54901
  });
54878
54902
  }
54879
54903
  }
54880
- tKey++;
54881
54904
  return cells;
54882
54905
  }
54883
54906
  getClickableAction(position) {
@@ -55689,6 +55712,13 @@ class TopBarComposer extends owl.Component {
55689
55712
  "border-color": SELECTION_BORDER_COLOR,
55690
55713
  });
55691
55714
  }
55715
+ get delimitation() {
55716
+ const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
55717
+ return {
55718
+ width,
55719
+ height,
55720
+ };
55721
+ }
55692
55722
  onFocus(selection) {
55693
55723
  this.composerFocusStore.focusTopBarComposer(selection);
55694
55724
  }
@@ -58320,8 +58350,7 @@ function addContent(content, sharedStrings, forceString = false) {
58320
58350
  attrs.push(["t", "b"]);
58321
58351
  }
58322
58352
  else if (forceString || !isNumber(value, DEFAULT_LOCALE)) {
58323
- const { id } = pushElement(content, sharedStrings);
58324
- value = id.toString();
58353
+ value = pushElement(content, sharedStrings);
58325
58354
  attrs.push(["t", "s"]);
58326
58355
  }
58327
58356
  return { attrs, node: escapeXml /*xml*/ `<v>${value}</v>` };
@@ -58446,8 +58475,7 @@ function addCellIsRule(cf, rule, dxfs) {
58446
58475
  if (rule.style.fillColor) {
58447
58476
  dxf.fill = { fgColor: { rgb: rule.style.fillColor } };
58448
58477
  }
58449
- const { id } = pushElement(dxf, dxfs);
58450
- ruleAttributes.push(["dxfId", id]);
58478
+ ruleAttributes.push(["dxfId", pushElement(dxf, dxfs)]);
58451
58479
  return escapeXml /*xml*/ `
58452
58480
  <conditionalFormatting sqref="${cf.ranges.join(" ")}">
58453
58481
  <cfRule ${formatAttributes(ruleAttributes)}>
@@ -59277,7 +59305,7 @@ function addSheetViews(sheet) {
59277
59305
  */
59278
59306
  function getXLSX(data) {
59279
59307
  const files = [];
59280
- const construct = getDefaultXLSXStructure();
59308
+ const construct = getDefaultXLSXStructure(data);
59281
59309
  files.push(createWorkbook(data, construct));
59282
59310
  files.push(...createWorksheets(data, construct));
59283
59311
  files.push(createStylesSheet(construct));
@@ -60212,6 +60240,6 @@ exports.tokenColors = tokenColors;
60212
60240
  exports.tokenize = tokenize;
60213
60241
 
60214
60242
 
60215
- __info__.version = "17.2.2";
60216
- __info__.date = "2024-04-05T14:01:19.824Z";
60217
- __info__.hash = "c15836d";
60243
+ __info__.version = "17.2.4";
60244
+ __info__.date = "2024-04-18T16:41:38.407Z";
60245
+ __info__.hash = "0c66038";
@@ -4151,7 +4151,7 @@ declare class ClipboardPlugin extends UIPlugin {
4151
4151
  declare class FilterEvaluationPlugin extends UIPlugin {
4152
4152
  static getters: readonly ["getFilterHiddenValues", "getFirstTableInSelection", "isRowFiltered", "isFilterActive"];
4153
4153
  private filterValues;
4154
- hiddenRows: Set<number>;
4154
+ hiddenRows: Record<UID, Set<number> | undefined>;
4155
4155
  isEvaluationDirty: boolean;
4156
4156
  allowDispatch(cmd: LocalCommand): CommandResult;
4157
4157
  handle(cmd: Command): void;
@@ -4288,8 +4288,8 @@ declare class InternalViewport {
4288
4288
  canScrollHorizontally: boolean;
4289
4289
  viewportWidth: Pixel;
4290
4290
  viewportHeight: Pixel;
4291
- private offsetCorrectionX;
4292
- private offsetCorrectionY;
4291
+ offsetCorrectionX: Pixel;
4292
+ offsetCorrectionY: Pixel;
4293
4293
  constructor(getters: Getters, sheetId: UID, boundaries: Zone, sizeInGrid: DOMDimension, options: {
4294
4294
  canScrollVertically: boolean;
4295
4295
  canScrollHorizontally: boolean;
@@ -4494,11 +4494,6 @@ declare class SheetViewPlugin extends UIPlugin {
4494
4494
  private resizeSheetView;
4495
4495
  private recomputeViewports;
4496
4496
  private setSheetViewOffset;
4497
- /**
4498
- * Clip the vertical offset within the allowed range.
4499
- * Not above the sheet, nor below the sheet.
4500
- */
4501
- private clipOffsetY;
4502
4497
  private getViewportOffset;
4503
4498
  private resetViewports;
4504
4499
  /**
@@ -6685,6 +6680,7 @@ interface ComposerProps {
6685
6680
  delimitation?: DOMDimension;
6686
6681
  onComposerContentFocused: () => void;
6687
6682
  onComposerCellFocused?: (content: String) => void;
6683
+ onInputContextMenu?: (event: MouseEvent) => void;
6688
6684
  isDefaultFocus?: boolean;
6689
6685
  }
6690
6686
  interface ComposerState {
@@ -6728,6 +6724,10 @@ declare class Composer extends Component<ComposerProps, SpreadsheetChildEnv> {
6728
6724
  type: BooleanConstructor;
6729
6725
  optional: boolean;
6730
6726
  };
6727
+ onInputContextMenu: {
6728
+ type: FunctionConstructor;
6729
+ optional: boolean;
6730
+ };
6731
6731
  };
6732
6732
  static components: {
6733
6733
  TextValueProvider: typeof TextValueProvider;
@@ -6784,6 +6784,7 @@ declare class Composer extends Component<ComposerProps, SpreadsheetChildEnv> {
6784
6784
  onMousedown(ev: MouseEvent): void;
6785
6785
  onClick(): void;
6786
6786
  onDblClick(): void;
6787
+ onContextMenu(ev: MouseEvent): void;
6787
6788
  private processContent;
6788
6789
  /**
6789
6790
  * Get the HTML content corresponding to the current composer token, divided by lines.
@@ -7088,6 +7089,7 @@ declare class ClientTag extends Component<ClientTagProps, SpreadsheetChildEnv> {
7088
7089
 
7089
7090
  interface Props$s {
7090
7091
  gridDims: DOMDimension;
7092
+ onInputContextMenu: (event: MouseEvent) => void;
7091
7093
  }
7092
7094
  /**
7093
7095
  * This component is a composer which positions itself on the grid at the anchor cell.
@@ -7097,6 +7099,7 @@ declare class GridComposer extends Component<Props$s, SpreadsheetChildEnv> {
7097
7099
  static template: string;
7098
7100
  static props: {
7099
7101
  gridDims: ObjectConstructor;
7102
+ onInputContextMenu: FunctionConstructor;
7100
7103
  };
7101
7104
  static components: {
7102
7105
  Composer: typeof Composer;
@@ -8308,7 +8311,6 @@ interface ClickableCell {
8308
8311
  coordinates: Rect;
8309
8312
  position: Position$1;
8310
8313
  action: (position: CellPosition, env: SpreadsheetChildEnv) => void;
8311
- tKey: string;
8312
8314
  }
8313
8315
  declare class SpreadsheetDashboard extends Component<Props$8, SpreadsheetChildEnv> {
8314
8316
  static template: string;
@@ -8830,6 +8832,7 @@ declare class TopBarComposer extends Component<any, SpreadsheetChildEnv> {
8830
8832
  get focus(): Omit<ComposerFocusType, "cellFocus">;
8831
8833
  get composerStyle(): string;
8832
8834
  get containerStyle(): string;
8835
+ get delimitation(): DOMDimension;
8833
8836
  onFocus(selection: ComposerSelection): void;
8834
8837
  }
8835
8838