@odoo/o-spreadsheet 17.0.12 → 17.0.14

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.12
6
- * @date 2024-02-16T14:24:02.984Z
7
- * @hash 8fa2bab
5
+ * @version 17.0.14
6
+ * @date 2024-03-12T07:56:15.364Z
7
+ * @hash 6f6e1b9
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -6057,8 +6057,10 @@ function getGroup(cell, cells, filter) {
6057
6057
  if (x === cell) {
6058
6058
  found = true;
6059
6059
  }
6060
- const cellValue = evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
6061
- if (filter(cellValue)) {
6060
+ const cellValue = x?.isFormula
6061
+ ? undefined
6062
+ : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
6063
+ if (cellValue && filter(cellValue)) {
6062
6064
  group.push(cellValue);
6063
6065
  }
6064
6066
  else {
@@ -6282,11 +6284,14 @@ function cellTextStyleToCss(style) {
6282
6284
  * Transform CSS properties into a CSS string.
6283
6285
  */
6284
6286
  function cssPropertiesToCss(attributes) {
6285
- const str = Object.entries(attributes)
6286
- .filter(([attName, attValue]) => attValue !== undefined)
6287
- .map(([attName, attValue]) => `${attName}:${attValue};`)
6288
- .join(" ");
6289
- return str;
6287
+ let styleStr = "";
6288
+ for (const attName in attributes) {
6289
+ if (!attributes[attName]) {
6290
+ continue;
6291
+ }
6292
+ styleStr += `${attName}:${attributes[attName]}; `;
6293
+ }
6294
+ return styleStr;
6290
6295
  }
6291
6296
  function getElementMargins(el) {
6292
6297
  const style = window.getComputedStyle(el);
@@ -12923,6 +12928,18 @@ const TRUNC = {
12923
12928
  },
12924
12929
  isExported: true,
12925
12930
  };
12931
+ // -----------------------------------------------------------------------------
12932
+ // INT
12933
+ // -----------------------------------------------------------------------------
12934
+ const INT = {
12935
+ description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
12936
+ args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
12937
+ returns: ["NUMBER"],
12938
+ compute: function (value) {
12939
+ return Math.floor(toNumber(value, this.locale));
12940
+ },
12941
+ isExported: true,
12942
+ };
12926
12943
 
12927
12944
  var math = /*#__PURE__*/Object.freeze({
12928
12945
  __proto__: null,
@@ -12956,6 +12973,7 @@ var math = /*#__PURE__*/Object.freeze({
12956
12973
  FLOOR: FLOOR,
12957
12974
  FLOOR_MATH: FLOOR_MATH,
12958
12975
  FLOOR_PRECISE: FLOOR_PRECISE,
12976
+ INT: INT,
12959
12977
  ISEVEN: ISEVEN,
12960
12978
  ISODD: ISODD,
12961
12979
  ISO_CEILING: ISO_CEILING,
@@ -19425,10 +19443,8 @@ function createComputeFunctionFromDescription(descr) {
19425
19443
  }
19426
19444
  function buildComputeFunctionFromDescription(descr) {
19427
19445
  return function (...args) {
19428
- const computeValue = descr.compute.bind(this);
19429
- const computeFormat = descr.computeFormat?.bind(this) || (() => undefined);
19430
- const value = computeValue(...extractArgValuesFromArgs(args));
19431
- const format = computeFormat(...args);
19446
+ const value = descr.compute.apply(this, extractArgValuesFromArgs(args));
19447
+ const format = descr.computeFormat?.apply(this, args);
19432
19448
  if (isMatrix(value)) {
19433
19449
  if (format === undefined || isMatrix(format)) {
19434
19450
  return value.map((col, i) => col.map((row, j) => ({ value: row, format: format?.[i]?.[j] })));
@@ -21394,7 +21410,7 @@ class SelectionInput extends Component {
21394
21410
  ? existingSelectionRanges
21395
21411
  : this.props.ranges().map((xc, id) => ({
21396
21412
  xc,
21397
- id,
21413
+ id: id + 1,
21398
21414
  isFocused: false,
21399
21415
  }));
21400
21416
  return ranges.map((range) => ({
@@ -27253,7 +27269,11 @@ class GridComposer extends Component {
27253
27269
  }
27254
27270
  }
27255
27271
  updateCellReferenceVisibility() {
27256
- if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
27272
+ if (this.env.model.getters.getEditionMode() === "inactive") {
27273
+ this.isCellReferenceVisible = false;
27274
+ return;
27275
+ }
27276
+ if (this.isCellReferenceVisible) {
27257
27277
  return;
27258
27278
  }
27259
27279
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -27282,19 +27302,21 @@ class GridCellIcon extends Component {
27282
27302
  static style = CSS$1;
27283
27303
  static template = "o-spreadsheet-GridCellIcon";
27284
27304
  get iconStyle() {
27285
- const x = this.getIconHorizontalPosition();
27286
- const y = this.getIconVerticalPosition();
27305
+ const cellPosition = this.props.cellPosition;
27306
+ const merge = this.env.model.getters.getMerge(cellPosition);
27307
+ const zone = merge || positionToZone(cellPosition);
27308
+ const rect = this.env.model.getters.getVisibleRectWithoutHeaders(zone);
27309
+ const x = this.getIconHorizontalPosition(rect, cellPosition);
27310
+ const y = this.getIconVerticalPosition(rect, cellPosition);
27287
27311
  return cssPropertiesToCss({
27288
27312
  top: `${y + (this.props.offset?.y || 0)}px`,
27289
27313
  left: `${x + (this.props.offset?.x || 0)}px`,
27290
27314
  });
27291
27315
  }
27292
- getIconVerticalPosition() {
27293
- const { sheetId, row } = this.props.cellPosition;
27294
- const merge = this.env.model.getters.getMerge(this.props.cellPosition);
27295
- const start = this.env.model.getters.getRowDimensionsInViewport(sheetId, row).start;
27296
- const end = this.env.model.getters.getRowDimensionsInViewport(sheetId, merge ? merge.bottom : row).end;
27297
- const cell = this.env.model.getters.getCell(this.props.cellPosition);
27316
+ getIconVerticalPosition(rect, cellPosition) {
27317
+ const start = rect.y;
27318
+ const end = rect.y + rect.height;
27319
+ const cell = this.env.model.getters.getCell(cellPosition);
27298
27320
  const align = this.props.verticalAlign || cell?.style?.verticalAlign || DEFAULT_VERTICAL_ALIGN;
27299
27321
  switch (align) {
27300
27322
  case "bottom":
@@ -27306,13 +27328,11 @@ class GridCellIcon extends Component {
27306
27328
  return end - GRID_ICON_EDGE_LENGTH - centeringOffset;
27307
27329
  }
27308
27330
  }
27309
- getIconHorizontalPosition() {
27310
- const { sheetId, col } = this.props.cellPosition;
27311
- const merge = this.env.model.getters.getMerge(this.props.cellPosition);
27312
- const start = this.env.model.getters.getColDimensionsInViewport(sheetId, col).start;
27313
- const end = this.env.model.getters.getColDimensionsInViewport(sheetId, merge ? merge.right : col).end;
27314
- const cell = this.env.model.getters.getCell(this.props.cellPosition);
27315
- const evaluatedCell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition);
27331
+ getIconHorizontalPosition(rect, cellPosition) {
27332
+ const start = rect.x;
27333
+ const end = rect.x + rect.width;
27334
+ const cell = this.env.model.getters.getCell(cellPosition);
27335
+ const evaluatedCell = this.env.model.getters.getEvaluatedCell(cellPosition);
27316
27336
  const align = this.props.horizontalAlign || cell?.style?.align || evaluatedCell.defaultAlign;
27317
27337
  switch (align) {
27318
27338
  case "right":
@@ -27404,6 +27424,8 @@ css /* scss */ `
27404
27424
  height: ${CHECKBOX_WIDTH}px;
27405
27425
  accent-color: #808080;
27406
27426
  margin: ${MARGIN}px;
27427
+ /** required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */
27428
+ position: absolute;
27407
27429
  }
27408
27430
  `;
27409
27431
  class DataValidationCheckbox extends Component {
@@ -27419,7 +27441,7 @@ class DataValidationCheckbox extends Component {
27419
27441
  }
27420
27442
  get isDisabled() {
27421
27443
  const cell = this.env.model.getters.getCell(this.props.cellPosition);
27422
- return !!cell?.isFormula;
27444
+ return this.env.model.getters.isReadonly() || !!cell?.isFormula;
27423
27445
  }
27424
27446
  }
27425
27447
  DataValidationCheckbox.props = {
@@ -27461,12 +27483,17 @@ class DataValidationOverlay extends Component {
27461
27483
  static template = "o-spreadsheet-DataValidationOverlay";
27462
27484
  static components = { GridCellIcon, DataValidationCheckbox, DataValidationListIcon };
27463
27485
  get checkBoxCellPositions() {
27464
- return this.env.model.getters.getDataValidationCheckBoxCellPositions();
27486
+ return this.env.model.getters
27487
+ .getVisibleCellPositions()
27488
+ .filter(this.env.model.getters.isCellValidCheckbox);
27465
27489
  }
27466
27490
  get listIconsCellPositions() {
27467
- return this.env.model.getters.isReadonly()
27468
- ? []
27469
- : this.env.model.getters.getDataValidationListCellsPositions();
27491
+ if (this.env.model.getters.isReadonly()) {
27492
+ return [];
27493
+ }
27494
+ return this.env.model.getters
27495
+ .getVisibleCellPositions()
27496
+ .filter(this.env.model.getters.cellHasListDataValidationIcon);
27470
27497
  }
27471
27498
  }
27472
27499
  DataValidationOverlay.props = {};
@@ -33827,29 +33854,12 @@ const MIGRATIONS = [
33827
33854
  from: 12,
33828
33855
  to: 12.5,
33829
33856
  applyMigration(data) {
33830
- for (let sheet of data.sheets || []) {
33831
- let knownDataFilterZones = [];
33832
- for (let filterTable of sheet.filterTables || []) {
33833
- const zone = toZone(filterTable.range);
33834
- // See commit message for the details
33835
- const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
33836
- if (intersectZoneIndex !== -1) {
33837
- knownDataFilterZones[intersectZoneIndex] = zone;
33838
- }
33839
- else {
33840
- knownDataFilterZones.push(zone);
33841
- }
33842
- }
33843
- sheet.filterTables = knownDataFilterZones.map((zone) => ({
33844
- range: zoneToXc(zone),
33845
- }));
33846
- }
33847
- return data;
33857
+ return fixOverlappingFilters(data);
33848
33858
  },
33849
33859
  },
33850
33860
  {
33851
33861
  description: "Change Border description structure",
33852
- from: 12,
33862
+ from: 12.5,
33853
33863
  to: 13,
33854
33864
  applyMigration(data) {
33855
33865
  for (const borderId in data.borders) {
@@ -33880,6 +33890,14 @@ const MIGRATIONS = [
33880
33890
  return data;
33881
33891
  },
33882
33892
  },
33893
+ {
33894
+ description: "Fix datafilter duplication (post saas-16.4)",
33895
+ from: 14,
33896
+ to: 14.5,
33897
+ applyMigration(data) {
33898
+ return fixOverlappingFilters(data);
33899
+ },
33900
+ },
33883
33901
  ];
33884
33902
  /**
33885
33903
  * This function is used to repair faulty data independently of the migration.
@@ -34037,6 +34055,26 @@ function fixChartDefinitions(data, initialMessages) {
34037
34055
  }
34038
34056
  return messages;
34039
34057
  }
34058
+ function fixOverlappingFilters(data) {
34059
+ for (let sheet of data.sheets || []) {
34060
+ let knownDataFilterZones = [];
34061
+ for (let filterTable of sheet.filterTables || []) {
34062
+ const zone = toZone(filterTable.range);
34063
+ // See commit message of https://github.com/odoo/o-spreadsheet/pull/3632 of more details
34064
+ const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
34065
+ if (intersectZoneIndex !== -1) {
34066
+ knownDataFilterZones[intersectZoneIndex] = zone;
34067
+ }
34068
+ else {
34069
+ knownDataFilterZones.push(zone);
34070
+ }
34071
+ }
34072
+ sheet.filterTables = knownDataFilterZones.map((zone) => ({
34073
+ range: zoneToXc(zone),
34074
+ }));
34075
+ }
34076
+ return data;
34077
+ }
34040
34078
  // -----------------------------------------------------------------------------
34041
34079
  // Helpers
34042
34080
  // -----------------------------------------------------------------------------
@@ -38571,7 +38609,6 @@ class SheetPlugin extends CorePlugin {
38571
38609
  "getNumberHeaders",
38572
38610
  "getGridLinesVisibility",
38573
38611
  "getNextSheetName",
38574
- "isEmpty",
38575
38612
  "getSheetSize",
38576
38613
  "getSheetZone",
38577
38614
  "getPaneDivisions",
@@ -38946,14 +38983,6 @@ class SheetPlugin extends CorePlugin {
38946
38983
  // ---------------------------------------------------------------------------
38947
38984
  // Row/Col manipulation
38948
38985
  // ---------------------------------------------------------------------------
38949
- /**
38950
- * Check if a zone only contains empty cells
38951
- */
38952
- isEmpty(sheetId, zone) {
38953
- return positions(zone)
38954
- .map(({ col, row }) => this.getCell({ sheetId, col, row }))
38955
- .every((cell) => !cell || cell.content === "");
38956
- }
38957
38986
  getCommandZones(cmd) {
38958
38987
  const zones = [];
38959
38988
  if ("zone" in cmd) {
@@ -41407,6 +41436,7 @@ class EvaluationPlugin extends UIPlugin {
41407
41436
  "getEvaluatedCellsInZone",
41408
41437
  "getSpreadPositionsOf",
41409
41438
  "getArrayFormulaSpreadingOn",
41439
+ "isEmpty",
41410
41440
  ];
41411
41441
  shouldRebuildDependenciesGraph = true;
41412
41442
  evaluator;
@@ -41511,6 +41541,14 @@ class EvaluationPlugin extends UIPlugin {
41511
41541
  getArrayFormulaSpreadingOn(position) {
41512
41542
  return this.evaluator.getArrayFormulaSpreadingOn(position);
41513
41543
  }
41544
+ /**
41545
+ * Check if a zone only contains empty cells
41546
+ */
41547
+ isEmpty(sheetId, zone) {
41548
+ return positions(zone)
41549
+ .map(({ col, row }) => this.getEvaluatedCell({ sheetId, col, row }))
41550
+ .every((cell) => cell.type === CellValueType.empty);
41551
+ }
41514
41552
  // ---------------------------------------------------------------------------
41515
41553
  // Export
41516
41554
  // ---------------------------------------------------------------------------
@@ -42157,8 +42195,6 @@ const VALID_RESULT = { isValid: true };
42157
42195
  class EvaluationDataValidationPlugin extends UIPlugin {
42158
42196
  static getters = [
42159
42197
  "getDataValidationInvalidCriterionValueMessage",
42160
- "getDataValidationCheckBoxCellPositions",
42161
- "getDataValidationListCellsPositions",
42162
42198
  "getInvalidDataValidationMessage",
42163
42199
  "getValidationResultForCellValue",
42164
42200
  "isCellValidCheckbox",
@@ -42222,19 +42258,6 @@ class EvaluationDataValidationPlugin extends UIPlugin {
42222
42258
  const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule);
42223
42259
  return error ? { error, rule, isValid: false } : VALID_RESULT;
42224
42260
  }
42225
- getDataValidationCheckBoxCellPositions() {
42226
- const rules = this.getters
42227
- .getDataValidationRules(this.getters.getActiveSheetId())
42228
- .filter((rule) => rule.criterion.type === "isBoolean");
42229
- return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat()).filter((position) => this.isCellValidCheckbox(position));
42230
- }
42231
- getDataValidationListCellsPositions() {
42232
- const rules = this.getters
42233
- .getDataValidationRules(this.getters.getActiveSheetId())
42234
- .filter((rule) => (rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
42235
- rule.criterion.displayStyle === "arrow");
42236
- return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat());
42237
- }
42238
42261
  getValidationResultForCell(cellPosition) {
42239
42262
  const { col, row, sheetId } = cellPosition;
42240
42263
  if (!this.validationResults[sheetId]) {
@@ -46427,19 +46450,17 @@ class SelectionInputsManagerPlugin extends UIPlugin {
46427
46450
  break;
46428
46451
  case "FOCUS_RANGE":
46429
46452
  case "CHANGE_RANGE":
46430
- if (cmd.id !== this.focusedInputId) {
46431
- const input = this.inputs[cmd.id];
46432
- const range = input.ranges.find((range) => range.id === cmd.rangeId);
46433
- if (this.isRangeValid(range?.xc || "A1")) {
46434
- const sheetId = this.getters.getActiveSheetId();
46435
- const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
46436
- this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
46437
- handleEvent: input.handleEvent.bind(input),
46438
- release: () => (this.focusedInputId = null),
46439
- });
46440
- }
46441
- this.focusedInputId = cmd.id;
46453
+ const input = this.inputs[cmd.id];
46454
+ const range = input.ranges.find((range) => range.id === cmd.rangeId);
46455
+ if (range) {
46456
+ const sheetId = this.getters.getActiveSheetId();
46457
+ const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
46458
+ this.selection.capture(input, { cell: { col: zone.left, row: zone.top }, zone }, {
46459
+ handleEvent: input.handleEvent.bind(input),
46460
+ release: () => (this.focusedInputId = null),
46461
+ });
46442
46462
  }
46463
+ this.focusedInputId = cmd.id;
46443
46464
  break;
46444
46465
  }
46445
46466
  this.currentInput?.handle(cmd);
@@ -50059,6 +50080,8 @@ class SheetViewPlugin extends UIPlugin {
50059
50080
  "getEdgeScrollRow",
50060
50081
  "getVisibleFigures",
50061
50082
  "getVisibleRect",
50083
+ "getVisibleRectWithoutHeaders",
50084
+ "getVisibleCellPositions",
50062
50085
  "getColRowOffsetInViewport",
50063
50086
  "getMainViewportCoordinates",
50064
50087
  "getActiveSheetScrollInfo",
@@ -50302,6 +50325,26 @@ class SheetViewPlugin extends UIPlugin {
50302
50325
  const viewports = this.getSubViewports(sheetId);
50303
50326
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
50304
50327
  }
50328
+ /**
50329
+ * Get the positions of all the cells that are visible in the viewport, taking merges into account.
50330
+ */
50331
+ getVisibleCellPositions() {
50332
+ const visibleCols = this.getSheetViewVisibleCols();
50333
+ const visibleRows = this.getSheetViewVisibleRows();
50334
+ const sheetId = this.getters.getActiveSheetId();
50335
+ const positions = [];
50336
+ for (const col of visibleCols) {
50337
+ for (const row of visibleRows) {
50338
+ const position = { sheetId, col, row };
50339
+ const mainPosition = this.getters.getMainCellPosition(position);
50340
+ if (mainPosition.row !== row || mainPosition.col !== col) {
50341
+ continue;
50342
+ }
50343
+ positions.push(position);
50344
+ }
50345
+ }
50346
+ return positions;
50347
+ }
50305
50348
  /**
50306
50349
  * Return the main viewport maximum size relative to the client size.
50307
50350
  */
@@ -50421,6 +50464,13 @@ class SheetViewPlugin extends UIPlugin {
50421
50464
  * Computes the coordinates and size to draw the zone on the canvas
50422
50465
  */
50423
50466
  getVisibleRect(zone) {
50467
+ const rect = this.getVisibleRectWithoutHeaders(zone);
50468
+ return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
50469
+ }
50470
+ /**
50471
+ * Computes the coordinates and size to draw the zone without taking the grid offset into account
50472
+ */
50473
+ getVisibleRectWithoutHeaders(zone) {
50424
50474
  const sheetId = this.getters.getActiveSheetId();
50425
50475
  const viewportRects = this.getSubViewports(sheetId)
50426
50476
  .map((viewport) => viewport.getRect(zone))
@@ -50432,12 +50482,7 @@ class SheetViewPlugin extends UIPlugin {
50432
50482
  const y = Math.min(...viewportRects.map((rect) => rect.y));
50433
50483
  const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x;
50434
50484
  const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y;
50435
- return {
50436
- x: x + this.gridOffsetX,
50437
- y: y + this.gridOffsetY,
50438
- width,
50439
- height,
50440
- };
50485
+ return { x, y, width, height };
50441
50486
  }
50442
50487
  /**
50443
50488
  * Returns the position of the MainViewport relatively to the start of the grid (without headers)
@@ -50661,13 +50706,8 @@ class HeaderPositionsUIPlugin extends UIPlugin {
50661
50706
  }
50662
50707
  break;
50663
50708
  case "UPDATE_CELL":
50664
- if ("content" in cmd || "format" in cmd) {
50665
- this.headerPositions = {};
50666
- this.isDirty = true;
50667
- }
50668
- else {
50669
- this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
50670
- }
50709
+ this.headerPositions = {};
50710
+ this.isDirty = true;
50671
50711
  break;
50672
50712
  case "UPDATE_FILTER":
50673
50713
  case "REMOVE_FILTER_TABLE":
@@ -56879,6 +56919,6 @@ const constants = {
56879
56919
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
56880
56920
 
56881
56921
 
56882
- __info__.version = "17.0.12";
56883
- __info__.date = "2024-02-16T14:24:02.984Z";
56884
- __info__.hash = "8fa2bab";
56922
+ __info__.version = "17.0.14";
56923
+ __info__.date = "2024-03-12T07:56:15.364Z";
56924
+ __info__.hash = "6f6e1b9";