diff --git a/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js b/addons/spreadsheet/static/src/o_spreadsheet/o_spreadsheet.js index 66e9fa96ea2..27e7ab24fab 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 16.5.0-alpha.9 - * @date 2023-10-03T13:36:38.605Z - * @hash c46de914 + * @version 16.5.0-alpha.10 + * @date 2023-10-10T08:16:10.236Z + * @hash 4dc340fc */ (function (exports, owl) { @@ -131,6 +131,7 @@ const GRID_BORDER_COLOR = "#E2E3E3"; const FROZEN_PANE_HEADER_BORDER_COLOR = "#BCBCBC"; const FROZEN_PANE_BORDER_COLOR = "#DADFE8"; + const COMPOSER_ASSISTANT_COLOR = "#9B359B"; // Color picker defaults as upper case HEX to match `toHex`helper const COLOR_PICKER_DEFAULTS = [ "#000000", @@ -1242,7 +1243,17 @@ function isDateTime(str, locale) { return parseDateTime(str, locale) !== null; } + const CACHE = new Map(); function parseDateTime(str, locale) { + if (!CACHE.has(locale)) { + CACHE.set(locale, new Map()); + } + if (!CACHE.get(locale).has(str)) { + CACHE.get(locale).set(str, _parseDateTime(str, locale)); + } + return CACHE.get(locale).get(str); + } + function _parseDateTime(str, locale) { str = str.trim(); let time = null; const timeMatch = str.match(timeRegexp); @@ -2100,7 +2111,7 @@ const SORT_TYPES_ORDER = ["number", "string", "boolean", "undefined"]; function assert(condition, message) { if (!condition()) { - throw new Error(message); + throw new EvaluationError(CellErrorType.GenericError, message); } } // ----------------------------------------------------------------------------- @@ -4062,8 +4073,9 @@ } get zone() { const { left, top, bottom, right } = this._zone; - if (right !== undefined && bottom !== undefined) - return { left, top, right, bottom }; + if (right !== undefined && bottom !== undefined) { + return this._zone; + } else if (bottom === undefined && right !== undefined) { return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 }; } @@ -5169,7 +5181,7 @@ return textCell((value || "").toString(), localeFormat); } catch (error) { - return errorCell((value || "").toString(), new EvaluationError(CellErrorType.GenericError, error.message || DEFAULT_ERROR_MESSAGE)); + return errorCell(new EvaluationError(CellErrorType.GenericError, error.message || DEFAULT_ERROR_MESSAGE)); } } function textCell(value, localeFormat) { @@ -5236,7 +5248,7 @@ formattedValue, }; } - function errorCell(content, error) { + function errorCell(error) { return { type: CellValueType.error, value: error.errorType, @@ -26307,16 +26319,31 @@ row: Number, }; + function getHtmlContentFromPattern(pattern, value, highlightColor, className) { + const pendingHtmlContent = []; + pattern = pattern.toLowerCase(); + for (const patternChar of pattern) { + const index = value.toLocaleLowerCase().indexOf(patternChar); + if (index === -1) { + continue; + } + pendingHtmlContent.push({ value: value.slice(0, index), color: "" }, { value: value[index], color: highlightColor, class: className }); + value = value.slice(index + 1); + } + pendingHtmlContent.push({ value }); + const htmlContent = pendingHtmlContent.filter((content) => content.value); + return htmlContent; + } + css /* scss */ ` .o-autocomplete-dropdown { pointer-events: auto; + cursor: pointer; background-color: #fff; max-width: 400px; - & > div:hover { - background-color: #f2f2f2; - } + .o-autocomplete-value-focus { - background-color: rgba(0, 0, 0, 0.08); + background-color: #f2f2f2; } & > div { @@ -26334,7 +26361,9 @@ TextValueProvider.props = { values: Array, selectedIndex: { type: Number, optional: true }, + getHtmlContent: Function, onValueSelected: Function, + onValueHovered: Function, }; class ContentEditableHelper { @@ -26683,8 +26712,8 @@ .o-formula-assistant-focus { div:first-child, span { - color: purple; - text-shadow: 0px 0px 1px purple; + color: ${COMPOSER_ASSISTANT_COLOR}; + text-shadow: 0px 0px 1px ${COMPOSER_ASSISTANT_COLOR}; } div:last-child { color: black; @@ -26729,6 +26758,7 @@ const functions = functionRegistry.content; const ASSISTANT_WIDTH = 300; + const AUTOCOMPLETE_ENTRIES = 10; const selectionIndicatorClass = "selector-flag"; const selectionIndicatorColor = "#a9a9a9"; const selectionIndicator = "␣"; @@ -26778,6 +26808,13 @@ position: absolute; margin: 1px 4px; pointer-events: none; + + .o-semi-bold { + /** FIXME: to remove in favor of Bootstrap + * 'fw-semibold' when we upgrade to Bootstrap 5.2 + */ + font-weight: 600 !important; + } } } `; @@ -26798,6 +26835,7 @@ values: [], selectedIndex: undefined, type: "function", + getHtmlContent: () => [], }); functionDescriptionState = owl.useState({ showDescription: false, @@ -27040,24 +27078,27 @@ text, description, }; + }) + .sort((a, b) => { + return a.text.length - b.text.length || a.text.localeCompare(b.text); }); if (searchTerm) { - values = fuzzyLookup(searchTerm, values, (t) => t.text); + values = fuzzyLookup(searchTerm, values, (t) => t.text).slice(0, AUTOCOMPLETE_ENTRIES); } - else { - // alphabetical order - values = values.sort((a, b) => a.text.localeCompare(b.text)); - } - this.autoCompleteState.values = values.slice(0, 10); + this.autoCompleteState.values = values.slice(0, AUTOCOMPLETE_ENTRIES); + this.autoCompleteState.getHtmlContent = (value) => getHtmlContentFromPattern(searchTerm, value, COMPOSER_ASSISTANT_COLOR, "o-semi-bold"); this.autoCompleteState.selectedIndex = 0; } + updateAutoCompleteIndex(index) { + this.autoCompleteState.selectedIndex = clip(0, index, 10); + } /** * This is required to ensure the content helper selection is * properly updated on "onclick" events. Depending on the browser, * the callback onClick from the composer will be executed before * the selection was updated in the dom, which means we capture an * wrong selection which is then forced upon the content helper on - * patchContent. + * processContent. */ onMousedown(ev) { if (ev.button > 0) { @@ -27327,6 +27368,7 @@ this.autoCompleteState.type = "dataValidation"; this.autoCompleteState.selectedIndex = undefined; this.autoCompleteState.values = values.map((value) => ({ text: value, description: "" })); + this.autoCompleteState.getHtmlContent = (value) => [{ value }]; } } Composer.props = { @@ -34971,10 +35013,11 @@ * Reconstructs the original formula string based on a normalized form and its dependencies */ getFormulaCellContent(sheetId, cell, dependencies) { - const ranges = dependencies || [...cell.dependencies]; + const ranges = dependencies || cell.dependencies; + let rangeIndex = 0; return concat(cell.compiledFormula.tokens.map((token) => { if (token.type === "REFERENCE") { - const range = ranges.shift(); + const range = ranges[rangeIndex++]; return this.getters.getRangeString(range, sheetId); } return token.value; @@ -39188,7 +39231,7 @@ const evaluatedCell = this.getEvaluatedCell(position); if (evaluatedCell.type === CellValueType.empty) { const cell = this.getters.getCell(position); - if (!cell || cell.content === "") { + if (!cell || (!cell.isFormula && cell.content === "")) { return undefined; } } @@ -39401,7 +39444,7 @@ constructor(context, getters) { this.context = context; this.getters = getters; - this.compilationParams = buildCompilationParameters(context, getters, (position) => this.computeCell(this.encodePosition(position))); + this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this)); } getEvaluatedCell(position) { return (this.evaluatedCells.get(this.encodePosition(position)) || @@ -39429,7 +39472,7 @@ this.formulaDependencies().addDependencies(positionId, dependencies); } updateCompilationParameters() { - this.compilationParams = buildCompilationParameters(this.context, this.getters, (position) => this.computeCell(this.encodePosition(position))); + this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this)); } evaluateCells(positions) { const cells = positions.map(this.encodePosition.bind(this)); @@ -39545,15 +39588,21 @@ this.cellsBeingComputed.delete(cellId); } } - handleError(e, cell) { - if (!(e instanceof Error)) { - e = new Error(e); + computeAndSave(position) { + const positionId = this.encodePosition(position); + const evaluatedCell = this.computeCell(positionId); + if (!this.evaluatedCells.has(positionId)) { + this.setEvaluatedCell(positionId, evaluatedCell); + } + return evaluatedCell; + } + handleError(e, cell) { + if (!(e instanceof EvaluationError)) { + e = new EvaluationError(CellErrorType.GenericError, e.message); } - const msg = e?.errorType || CellErrorType.GenericError; - // apply function name const __lastFnCalled = this.compilationParams[2].__lastFnCalled || ""; - const error = new EvaluationError(msg, e.message.replace("[[FUNCTION_NAME]]", __lastFnCalled), e.logLevel !== undefined ? e.logLevel : CellErrorLevel.error); - return errorCell(cell.content, error); + e.message = e.message.replace("[[FUNCTION_NAME]]", __lastFnCalled); + return errorCell(e); } computeFormulaCell(cellData) { const cellId = cellData.id; @@ -55110,9 +55159,9 @@ exports.tokenize = tokenize; - __info__.version = "16.5.0-alpha.9"; - __info__.date = "2023-10-03T13:36:38.605Z"; - __info__.hash = "c46de914"; + __info__.version = "16.5.0-alpha.10"; + __info__.date = "2023-10-10T08:16:10.236Z"; + __info__.hash = "4dc340fc"; })(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 674b18f9234..e4590b97755 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 @@ @@ -430,8 +430,19 @@
-
+ t-on-click="() => this.props.onValueSelected(v.text)" + t-on-mousemove="() => this.props.onValueHovered(v_index)"> +
+ + +