From 8b1f8737885e152f49733b7208ddc7de4e7f1282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9mi=20Rahir=20=28rar=29?= Date: Tue, 12 Mar 2024 09:05:12 +0100 Subject: [PATCH] [FIX] spreadsheet: update o_spreadsheet to latest version ### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/6f6e1b9dd [REL] 17.0.14 https://github.com/odoo/o-spreadsheet/commit/540c525ed [FIX] header_positions: perfs of update style Task: 3797400 https://github.com/odoo/o-spreadsheet/commit/fdafd66c0 [FIX] automatic_sum: wrong behaviour with spreaded values Task: 3782971 https://github.com/odoo/o-spreadsheet/commit/8ac8ce53b [FIX] DataValidationCheckbox: Fix input positioning in FF Task: 3774645 https://github.com/odoo/o-spreadsheet/commit/4769c9ed4 [FIX] GridComposer: Reset the cell reference visibility on stop edition Task: 3736211 https://github.com/odoo/o-spreadsheet/commit/cd9bcee12 [FIX] data validation: checkbox not disabled in readonly Task: 3773923 https://github.com/odoo/o-spreadsheet/commit/cb53fc249 [IMP] data validation: performance of icons Task: 3773923 https://github.com/odoo/o-spreadsheet/commit/035f42e00 [PERF] evaluation: apply compute function Task: 3775636 https://github.com/odoo/o-spreadsheet/commit/70c51deb6 [FIX] autofill: allow to autofill a mix of number values and formulas Task: 3700733 closes odoo/odoo#157342 Signed-off-by: Vincent Schippefilt (vsc) --- .../static/src/o_spreadsheet/o_spreadsheet.js | 155 ++++++++++-------- .../src/o_spreadsheet/o_spreadsheet.xml | 6 +- 2 files changed, 88 insertions(+), 73 deletions(-) diff --git a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js index ffd8a83f615..112d959f3cb 100644 --- a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js +++ b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js @@ -2,9 +2,9 @@ /** * This file is generated by o-spreadsheet build tools. Do not edit it. * @see https://github.com/odoo/o-spreadsheet - * @version 17.0.13 - * @date 2024-02-28T12:48:27.246Z - * @hash ed67be7d1 + * @version 17.0.14 + * @date 2024-03-12T08:05:09.046Z + * @hash 6f6e1b9dd */ (function (exports, owl) { @@ -6058,8 +6058,10 @@ if (x === cell) { found = true; } - const cellValue = evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE }); - if (filter(cellValue)) { + const cellValue = x?.isFormula + ? undefined + : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE }); + if (cellValue && filter(cellValue)) { group.push(cellValue); } else { @@ -19442,10 +19444,8 @@ } function buildComputeFunctionFromDescription(descr) { return function (...args) { - const computeValue = descr.compute.bind(this); - const computeFormat = descr.computeFormat?.bind(this) || (() => undefined); - const value = computeValue(...extractArgValuesFromArgs(args)); - const format = computeFormat(...args); + const value = descr.compute.apply(this, extractArgValuesFromArgs(args)); + const format = descr.computeFormat?.apply(this, args); if (isMatrix(value)) { if (format === undefined || isMatrix(format)) { return value.map((col, i) => col.map((row, j) => ({ value: row, format: format?.[i]?.[j] }))); @@ -27270,7 +27270,11 @@ } } updateCellReferenceVisibility() { - if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") { + if (this.env.model.getters.getEditionMode() === "inactive") { + this.isCellReferenceVisible = false; + return; + } + if (this.isCellReferenceVisible) { return; } const sheetId = this.env.model.getters.getActiveSheetId(); @@ -27299,19 +27303,21 @@ static style = CSS$1; static template = "o-spreadsheet-GridCellIcon"; get iconStyle() { - const x = this.getIconHorizontalPosition(); - const y = this.getIconVerticalPosition(); + const cellPosition = this.props.cellPosition; + const merge = this.env.model.getters.getMerge(cellPosition); + const zone = merge || positionToZone(cellPosition); + const rect = this.env.model.getters.getVisibleRectWithoutHeaders(zone); + const x = this.getIconHorizontalPosition(rect, cellPosition); + const y = this.getIconVerticalPosition(rect, cellPosition); return cssPropertiesToCss({ top: `${y + (this.props.offset?.y || 0)}px`, left: `${x + (this.props.offset?.x || 0)}px`, }); } - getIconVerticalPosition() { - const { sheetId, row } = this.props.cellPosition; - const merge = this.env.model.getters.getMerge(this.props.cellPosition); - const start = this.env.model.getters.getRowDimensionsInViewport(sheetId, row).start; - const end = this.env.model.getters.getRowDimensionsInViewport(sheetId, merge ? merge.bottom : row).end; - const cell = this.env.model.getters.getCell(this.props.cellPosition); + getIconVerticalPosition(rect, cellPosition) { + const start = rect.y; + const end = rect.y + rect.height; + const cell = this.env.model.getters.getCell(cellPosition); const align = this.props.verticalAlign || cell?.style?.verticalAlign || DEFAULT_VERTICAL_ALIGN; switch (align) { case "bottom": @@ -27323,13 +27329,11 @@ return end - GRID_ICON_EDGE_LENGTH - centeringOffset; } } - getIconHorizontalPosition() { - const { sheetId, col } = this.props.cellPosition; - const merge = this.env.model.getters.getMerge(this.props.cellPosition); - const start = this.env.model.getters.getColDimensionsInViewport(sheetId, col).start; - const end = this.env.model.getters.getColDimensionsInViewport(sheetId, merge ? merge.right : col).end; - const cell = this.env.model.getters.getCell(this.props.cellPosition); - const evaluatedCell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition); + getIconHorizontalPosition(rect, cellPosition) { + const start = rect.x; + const end = rect.x + rect.width; + const cell = this.env.model.getters.getCell(cellPosition); + const evaluatedCell = this.env.model.getters.getEvaluatedCell(cellPosition); const align = this.props.horizontalAlign || cell?.style?.align || evaluatedCell.defaultAlign; switch (align) { case "right": @@ -27421,6 +27425,8 @@ height: ${CHECKBOX_WIDTH}px; accent-color: #808080; margin: ${MARGIN}px; + /** required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */ + position: absolute; } `; class DataValidationCheckbox extends owl.Component { @@ -27436,7 +27442,7 @@ } get isDisabled() { const cell = this.env.model.getters.getCell(this.props.cellPosition); - return !!cell?.isFormula; + return this.env.model.getters.isReadonly() || !!cell?.isFormula; } } DataValidationCheckbox.props = { @@ -27478,12 +27484,17 @@ static template = "o-spreadsheet-DataValidationOverlay"; static components = { GridCellIcon, DataValidationCheckbox, DataValidationListIcon }; get checkBoxCellPositions() { - return this.env.model.getters.getDataValidationCheckBoxCellPositions(); + return this.env.model.getters + .getVisibleCellPositions() + .filter(this.env.model.getters.isCellValidCheckbox); } get listIconsCellPositions() { - return this.env.model.getters.isReadonly() - ? [] - : this.env.model.getters.getDataValidationListCellsPositions(); + if (this.env.model.getters.isReadonly()) { + return []; + } + return this.env.model.getters + .getVisibleCellPositions() + .filter(this.env.model.getters.cellHasListDataValidationIcon); } } DataValidationOverlay.props = {}; @@ -38599,7 +38610,6 @@ "getNumberHeaders", "getGridLinesVisibility", "getNextSheetName", - "isEmpty", "getSheetSize", "getSheetZone", "getPaneDivisions", @@ -38974,14 +38984,6 @@ // --------------------------------------------------------------------------- // Row/Col manipulation // --------------------------------------------------------------------------- - /** - * Check if a zone only contains empty cells - */ - isEmpty(sheetId, zone) { - return positions(zone) - .map(({ col, row }) => this.getCell({ sheetId, col, row })) - .every((cell) => !cell || cell.content === ""); - } getCommandZones(cmd) { const zones = []; if ("zone" in cmd) { @@ -41435,6 +41437,7 @@ "getEvaluatedCellsInZone", "getSpreadPositionsOf", "getArrayFormulaSpreadingOn", + "isEmpty", ]; shouldRebuildDependenciesGraph = true; evaluator; @@ -41539,6 +41542,14 @@ getArrayFormulaSpreadingOn(position) { return this.evaluator.getArrayFormulaSpreadingOn(position); } + /** + * Check if a zone only contains empty cells + */ + isEmpty(sheetId, zone) { + return positions(zone) + .map(({ col, row }) => this.getEvaluatedCell({ sheetId, col, row })) + .every((cell) => cell.type === CellValueType.empty); + } // --------------------------------------------------------------------------- // Export // --------------------------------------------------------------------------- @@ -42185,8 +42196,6 @@ class EvaluationDataValidationPlugin extends UIPlugin { static getters = [ "getDataValidationInvalidCriterionValueMessage", - "getDataValidationCheckBoxCellPositions", - "getDataValidationListCellsPositions", "getInvalidDataValidationMessage", "getValidationResultForCellValue", "isCellValidCheckbox", @@ -42250,19 +42259,6 @@ const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule); return error ? { error, rule, isValid: false } : VALID_RESULT; } - getDataValidationCheckBoxCellPositions() { - const rules = this.getters - .getDataValidationRules(this.getters.getActiveSheetId()) - .filter((rule) => rule.criterion.type === "isBoolean"); - return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat()).filter((position) => this.isCellValidCheckbox(position)); - } - getDataValidationListCellsPositions() { - const rules = this.getters - .getDataValidationRules(this.getters.getActiveSheetId()) - .filter((rule) => (rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") && - rule.criterion.displayStyle === "arrow"); - return getCellPositionsInRanges(rules.map((rule) => rule.ranges).flat()); - } getValidationResultForCell(cellPosition) { const { col, row, sheetId } = cellPosition; if (!this.validationResults[sheetId]) { @@ -50085,6 +50081,8 @@ "getEdgeScrollRow", "getVisibleFigures", "getVisibleRect", + "getVisibleRectWithoutHeaders", + "getVisibleCellPositions", "getColRowOffsetInViewport", "getMainViewportCoordinates", "getActiveSheetScrollInfo", @@ -50328,6 +50326,26 @@ const viewports = this.getSubViewports(sheetId); return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row)); } + /** + * Get the positions of all the cells that are visible in the viewport, taking merges into account. + */ + getVisibleCellPositions() { + const visibleCols = this.getSheetViewVisibleCols(); + const visibleRows = this.getSheetViewVisibleRows(); + const sheetId = this.getters.getActiveSheetId(); + const positions = []; + for (const col of visibleCols) { + for (const row of visibleRows) { + const position = { sheetId, col, row }; + const mainPosition = this.getters.getMainCellPosition(position); + if (mainPosition.row !== row || mainPosition.col !== col) { + continue; + } + positions.push(position); + } + } + return positions; + } /** * Return the main viewport maximum size relative to the client size. */ @@ -50447,6 +50465,13 @@ * Computes the coordinates and size to draw the zone on the canvas */ getVisibleRect(zone) { + const rect = this.getVisibleRectWithoutHeaders(zone); + return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY }; + } + /** + * Computes the coordinates and size to draw the zone without taking the grid offset into account + */ + getVisibleRectWithoutHeaders(zone) { const sheetId = this.getters.getActiveSheetId(); const viewportRects = this.getSubViewports(sheetId) .map((viewport) => viewport.getRect(zone)) @@ -50458,12 +50483,7 @@ const y = Math.min(...viewportRects.map((rect) => rect.y)); const width = Math.max(...viewportRects.map((rect) => rect.x + rect.width)) - x; const height = Math.max(...viewportRects.map((rect) => rect.y + rect.height)) - y; - return { - x: x + this.gridOffsetX, - y: y + this.gridOffsetY, - width, - height, - }; + return { x, y, width, height }; } /** * Returns the position of the MainViewport relatively to the start of the grid (without headers) @@ -50687,13 +50707,8 @@ } break; case "UPDATE_CELL": - if ("content" in cmd || "format" in cmd) { - this.headerPositions = {}; - this.isDirty = true; - } - else { - this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId); - } + this.headerPositions = {}; + this.isDirty = true; break; case "UPDATE_FILTER": case "REMOVE_FILTER_TABLE": @@ -56940,9 +56955,9 @@ exports.tokenize = tokenize; - __info__.version = "17.0.13"; - __info__.date = "2024-02-28T12:48:27.246Z"; - __info__.hash = "ed67be7d1"; + __info__.version = "17.0.14"; + __info__.date = "2024-03-12T08:05:09.046Z"; + __info__.hash = "6f6e1b9dd"; })(this.o_spreadsheet = this.o_spreadsheet || {}, owl); diff --git a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.xml b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.xml index 22b5ca0a414..34f09ea472c 100644 --- a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.xml +++ b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.xml @@ -1,9 +1,9 @@