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