[FIX] spreadsheet: update o_spreadsheet to latest version
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/33f09d7c4 [REL] 17.0.17 https://github.com/odoo/o-spreadsheet/commit/1767b3728 [FIX] chart: preserve label order when aggregate https://github.com/odoo/o-spreadsheet/commit/6c96ded0b [PERF] helpers: faster default cell height Task: 3845472 https://github.com/odoo/o-spreadsheet/commit/b48eb1cf7 [IMP] package: update owl to version 2.2.10 https://github.com/odoo/o-spreadsheet/commit/c2f6da219 [FIX] *: Compute max/min on huge arrays Task: 3802691 https://github.com/odoo/o-spreadsheet/commit/06db89656 [FIX] Charts: format of negative values https://github.com/odoo/o-spreadsheet/commit/c2eed35cb [FIX] EditionPlugin: data validation duplicate values https://github.com/odoo/o-spreadsheet/commit/ed7d3fa63 [FIX] BottomBarSheet: Rename a sheet with style content on Firefox Task: 3754944 https://github.com/odoo/o-spreadsheet/commit/33ed353a9 [FIX] bottom_bar: disable sheet drag & drop in readonly Task: 3820888 https://github.com/odoo/o-spreadsheet/commit/261616dfa [FIX] menu: non-aligned menu items Task: 3814222 closes odoo/odoo#160740 Signed-off-by: Vincent Schippefilt (vsc) <vsc@odoo.com>
This commit is contained in:
@@ -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.16
|
||||
* @date 2024-03-25T11:04:46.936Z
|
||||
* @hash 9b128f8c
|
||||
* @version 17.0.17
|
||||
* @date 2024-04-05T14:13:49.946Z
|
||||
* @hash 33f09d7c4
|
||||
*/
|
||||
|
||||
(function (exports, owl) {
|
||||
@@ -558,7 +558,7 @@
|
||||
}
|
||||
// Generate new Id if the item didn't exist in the dictionary
|
||||
const ids = Object.keys(itemsDic);
|
||||
const maxId = ids.length === 0 ? 0 : Math.max(...ids.map((id) => parseInt(id, 10)));
|
||||
const maxId = ids.length === 0 ? 0 : largeMax(ids.map((id) => parseInt(id, 10)));
|
||||
itemsDic[maxId + 1] = item;
|
||||
return maxId + 1;
|
||||
}
|
||||
@@ -775,6 +775,34 @@
|
||||
}
|
||||
return value >= min && value <= max;
|
||||
}
|
||||
/**
|
||||
* Alternative to Math.max that works with large arrays.
|
||||
* Typically useful for arrays bigger than 100k elements.
|
||||
*/
|
||||
function largeMax(array) {
|
||||
let len = array.length;
|
||||
if (len < 100000)
|
||||
return Math.max(...array);
|
||||
let max = -Infinity;
|
||||
while (len--) {
|
||||
max = array[len] > max ? array[len] : max;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
/**
|
||||
* Alternative to Math.min that works with large arrays.
|
||||
* Typically useful for arrays bigger than 100k elements.
|
||||
*/
|
||||
function largeMin(array) {
|
||||
let len = array.length;
|
||||
if (len < 100000)
|
||||
return Math.min(...array);
|
||||
let min = +Infinity;
|
||||
while (len--) {
|
||||
min = array[len] < min ? array[len] : min;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
||||
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
|
||||
@@ -4421,8 +4449,9 @@
|
||||
* Get the default height of the cell given its style.
|
||||
*/
|
||||
function getDefaultCellHeight(ctx, cell, colSize) {
|
||||
if (!cell || !cell.content)
|
||||
if (!cell || (!cell.isFormula && !cell.content)) {
|
||||
return DEFAULT_CELL_HEIGHT;
|
||||
}
|
||||
const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
||||
const numberOfLines = cell.isFormula
|
||||
? 1
|
||||
@@ -8325,10 +8354,10 @@
|
||||
}
|
||||
}
|
||||
return {
|
||||
labels: Object.keys(labelMap),
|
||||
labels: Array.from(labelSet),
|
||||
dataSetsValues: datasets.map((dataset, indexOfDataset) => ({
|
||||
...dataset,
|
||||
data: Object.values(labelMap).map((dataOfLabel) => dataOfLabel[indexOfDataset]),
|
||||
data: Array.from(labelSet).map((label) => labelMap[label][indexOfDataset]),
|
||||
})),
|
||||
};
|
||||
}
|
||||
@@ -8379,7 +8408,7 @@
|
||||
const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
|
||||
// tooltipItem.parsed.y can be an object or a number for pie charts
|
||||
const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
|
||||
const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
|
||||
const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
|
||||
const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
|
||||
return xLabel ? `${xLabel}: ${yLabelStr}` : yLabelStr;
|
||||
},
|
||||
@@ -8665,7 +8694,10 @@
|
||||
if (isNaN(value))
|
||||
return value;
|
||||
const { locale, format } = localeFormat;
|
||||
return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
|
||||
return formatValue(value, {
|
||||
locale,
|
||||
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -9079,7 +9111,7 @@
|
||||
return undefined;
|
||||
}
|
||||
const labelsTimestamps = labelDates.map((date) => date.getTime());
|
||||
const period = Math.max(...labelsTimestamps) - Math.min(...labelsTimestamps);
|
||||
const period = largeMax(labelsTimestamps) - largeMin(labelsTimestamps);
|
||||
const minUnit = getFormatMinDisplayUnit(format);
|
||||
if (UNIT_LENGTH.second >= UNIT_LENGTH[minUnit] && Milliseconds.inSeconds(period) < 180) {
|
||||
return "second";
|
||||
@@ -9316,7 +9348,10 @@
|
||||
if (isNaN(value))
|
||||
return value;
|
||||
const { locale, format } = localeFormat;
|
||||
return formatValue(value, { locale, format: !format && value > 1000 ? "#,##" : format });
|
||||
return formatValue(value, {
|
||||
locale,
|
||||
format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -9543,7 +9578,7 @@
|
||||
const percentage = calculatePercentage(data, dataIndex);
|
||||
const xLabel = tooltipItem.label || tooltipItem.dataset.label;
|
||||
const yLabel = tooltipItem.parsed.y ?? tooltipItem.parsed;
|
||||
const toolTipFormat = !format && yLabel > 1000 ? "#,##" : format;
|
||||
const toolTipFormat = !format && Math.abs(yLabel) >= 1000 ? "#,##" : format;
|
||||
const yLabelStr = formatValue(yLabel, { format: toolTipFormat, locale });
|
||||
return xLabel ? `${xLabel}: ${yLabelStr} (${percentage}%)` : `${yLabelStr} (${percentage}%)`;
|
||||
};
|
||||
@@ -9551,7 +9586,7 @@
|
||||
}
|
||||
function getPieColors(colors, dataSetsValues) {
|
||||
const pieColors = [];
|
||||
const maxLength = Math.max(...dataSetsValues.map((ds) => ds.data.length));
|
||||
const maxLength = largeMax(dataSetsValues.map((ds) => ds.data.length));
|
||||
for (let i = 0; i <= maxLength; i++) {
|
||||
pieColors.push(colors.next());
|
||||
}
|
||||
@@ -10453,8 +10488,8 @@
|
||||
let last;
|
||||
const activesRows = env.model.getters.getActiveRows();
|
||||
if (activesRows.size !== 0) {
|
||||
first = Math.min(...activesRows);
|
||||
last = Math.max(...activesRows);
|
||||
first = largeMin([...activesRows]);
|
||||
last = largeMax([...activesRows]);
|
||||
}
|
||||
else {
|
||||
const zone = env.model.getters.getSelectedZones()[0];
|
||||
@@ -10482,8 +10517,8 @@
|
||||
let last;
|
||||
const activeCols = env.model.getters.getActiveCols();
|
||||
if (activeCols.size !== 0) {
|
||||
first = Math.min(...activeCols);
|
||||
last = Math.max(...activeCols);
|
||||
first = largeMin([...activeCols]);
|
||||
last = largeMax([...activeCols]);
|
||||
}
|
||||
else {
|
||||
const zone = env.model.getters.getSelectedZones()[0];
|
||||
@@ -10511,8 +10546,8 @@
|
||||
let last;
|
||||
const activesRows = env.model.getters.getActiveRows();
|
||||
if (activesRows.size !== 0) {
|
||||
first = Math.min(...activesRows);
|
||||
last = Math.max(...activesRows);
|
||||
first = largeMin([...activesRows]);
|
||||
last = largeMax([...activesRows]);
|
||||
}
|
||||
else {
|
||||
const zone = env.model.getters.getSelectedZones()[0];
|
||||
@@ -10553,8 +10588,8 @@
|
||||
let last;
|
||||
const activeCols = env.model.getters.getActiveCols();
|
||||
if (activeCols.size !== 0) {
|
||||
first = Math.min(...activeCols);
|
||||
last = Math.max(...activeCols);
|
||||
first = largeMin([...activeCols]);
|
||||
last = largeMax([...activeCols]);
|
||||
}
|
||||
else {
|
||||
const zone = env.model.getters.getSelectedZones()[0];
|
||||
@@ -10595,7 +10630,7 @@
|
||||
let row;
|
||||
let quantity;
|
||||
if (activeRows.size) {
|
||||
row = Math.min(...activeRows);
|
||||
row = largeMin([...activeRows]);
|
||||
quantity = activeRows.size;
|
||||
}
|
||||
else {
|
||||
@@ -10616,7 +10651,7 @@
|
||||
let row;
|
||||
let quantity;
|
||||
if (activeRows.size) {
|
||||
row = Math.max(...activeRows);
|
||||
row = largeMax([...activeRows]);
|
||||
quantity = activeRows.size;
|
||||
}
|
||||
else {
|
||||
@@ -10637,7 +10672,7 @@
|
||||
let column;
|
||||
let quantity;
|
||||
if (activeCols.size) {
|
||||
column = Math.min(...activeCols);
|
||||
column = largeMin([...activeCols]);
|
||||
quantity = activeCols.size;
|
||||
}
|
||||
else {
|
||||
@@ -10658,7 +10693,7 @@
|
||||
let column;
|
||||
let quantity;
|
||||
if (activeCols.size) {
|
||||
column = Math.max(...activeCols);
|
||||
column = largeMax([...activeCols]);
|
||||
quantity = activeCols.size;
|
||||
}
|
||||
else {
|
||||
@@ -31855,7 +31890,7 @@
|
||||
function getSheetDims(sheet) {
|
||||
const dims = [0, 0];
|
||||
for (let row of sheet.rows) {
|
||||
dims[0] = Math.max(dims[0], ...row.cells.map((cell) => toCartesian(cell.xc).col));
|
||||
dims[0] = Math.max(dims[0], largeMax(row.cells.map((cell) => toCartesian(cell.xc).col)));
|
||||
dims[1] = Math.max(dims[1], row.index);
|
||||
}
|
||||
dims[0] = Math.max(dims[0], EXCEL_IMPORT_DEFAULT_NUMBER_OF_COLS);
|
||||
@@ -36745,6 +36780,9 @@
|
||||
if (newRule.criterion.type === "isBoolean") {
|
||||
this.setCenterStyleToBooleanCells(newRule);
|
||||
}
|
||||
else if (newRule.criterion.type === "isValueInList") {
|
||||
newRule.criterion.values = Array.from(new Set(newRule.criterion.values));
|
||||
}
|
||||
const adaptedRules = this.removeRangesFromRules(sheetId, newRule.ranges, rules);
|
||||
const ruleIndex = adaptedRules.findIndex((rule) => rule.id === newRule.id);
|
||||
if (ruleIndex !== -1) {
|
||||
@@ -37471,7 +37509,7 @@
|
||||
if (hiddenElements.size >= elements) {
|
||||
return "TooManyHiddenElements" /* CommandResult.TooManyHiddenElements */;
|
||||
}
|
||||
else if (Math.min(...cmd.elements) < 0 || Math.max(...cmd.elements) > elements) {
|
||||
else if (largeMin(cmd.elements) < 0 || largeMax(cmd.elements) > elements) {
|
||||
return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
|
||||
}
|
||||
else {
|
||||
@@ -38286,8 +38324,8 @@
|
||||
let newRange = range;
|
||||
let changeType = "NONE";
|
||||
for (let group of groups) {
|
||||
const min = Math.min(...group);
|
||||
const max = Math.max(...group);
|
||||
const min = largeMin(group);
|
||||
const max = largeMax(group);
|
||||
if (range.zone[start] <= min && min <= range.zone[end]) {
|
||||
const toRemove = Math.min(range.zone[end], max) - min + 1;
|
||||
changeType = "RESIZE";
|
||||
@@ -38710,8 +38748,8 @@
|
||||
}
|
||||
return "Success" /* CommandResult.Success */;
|
||||
case "REMOVE_COLUMNS_ROWS": {
|
||||
const min = Math.min(...cmd.elements);
|
||||
const max = Math.max(...cmd.elements);
|
||||
const min = largeMin(cmd.elements);
|
||||
const max = largeMax(cmd.elements);
|
||||
if (min < 0 || !this.doesHeaderExist(cmd.sheetId, cmd.dimension, max)) {
|
||||
return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
|
||||
}
|
||||
@@ -42043,13 +42081,13 @@
|
||||
.map((cell) => cell.value);
|
||||
switch (threshold.type) {
|
||||
case "value":
|
||||
const result = functionName === "max" ? Math.max(...rangeValues) : Math.min(...rangeValues);
|
||||
const result = functionName === "max" ? largeMax(rangeValues) : largeMin(rangeValues);
|
||||
return result;
|
||||
case "number":
|
||||
return Number(threshold.value);
|
||||
case "percentage":
|
||||
const min = Math.min(...rangeValues);
|
||||
const max = Math.max(...rangeValues);
|
||||
const min = largeMin(rangeValues);
|
||||
const max = largeMax(rangeValues);
|
||||
const delta = max - min;
|
||||
return min + (delta * Number(threshold.value)) / 100;
|
||||
case "percentile":
|
||||
@@ -43101,13 +43139,13 @@
|
||||
const cells = this.getters.getEvaluatedCellsInZone(sheet.id, zone);
|
||||
const cellPositions = range(end, -1, -1);
|
||||
const invalidCells = cellPositions.filter((position) => cells[position] && !cells[position].isAutoSummable);
|
||||
const maxValidPosition = Math.max(...invalidCells);
|
||||
const maxValidPosition = largeMax(invalidCells);
|
||||
const numberSequences = groupConsecutive(cellPositions.filter((position) => this.isNumber(cells[position])));
|
||||
const firstSequence = numberSequences[0] || [];
|
||||
if (Math.max(...firstSequence) < maxValidPosition) {
|
||||
if (largeMax(firstSequence) < maxValidPosition) {
|
||||
return Infinity;
|
||||
}
|
||||
return Math.min(...firstSequence);
|
||||
return largeMin(firstSequence);
|
||||
}
|
||||
shouldFindData(sheetId, zone) {
|
||||
return this.getters.isEmpty(sheetId, zone) || this.getters.isSingleCellOrMerge(sheetId, zone);
|
||||
@@ -45511,7 +45549,7 @@
|
||||
* column of the current viewport
|
||||
*/
|
||||
getColDimensionsInViewport(sheetId, col) {
|
||||
const left = Math.min(...this.getters.getSheetViewVisibleCols());
|
||||
const left = largeMin(this.getters.getSheetViewVisibleCols());
|
||||
const start = this.getters.getColRowOffsetInViewport("COL", left, col);
|
||||
const size = this.getters.getColSize(sheetId, col);
|
||||
const isColHidden = this.getters.isColHidden(sheetId, col);
|
||||
@@ -45526,7 +45564,7 @@
|
||||
* of the current viewport
|
||||
*/
|
||||
getRowDimensionsInViewport(sheetId, row) {
|
||||
const top = Math.min(...this.getters.getSheetViewVisibleRows());
|
||||
const top = largeMin(this.getters.getSheetViewVisibleRows());
|
||||
const start = this.getters.getColRowOffsetInViewport("ROW", top, row);
|
||||
const size = this.getters.getRowSize(sheetId, row);
|
||||
const isRowHidden = this.getters.isRowHidden(sheetId, row);
|
||||
@@ -46990,7 +47028,7 @@
|
||||
getColMaxWidth(sheetId, index) {
|
||||
const cellsPositions = positions(this.getters.getColsZone(sheetId, index, index));
|
||||
const sizes = cellsPositions.map((position) => this.getCellWidth({ sheetId, ...position }));
|
||||
return Math.max(0, ...sizes);
|
||||
return Math.max(0, largeMax(sizes));
|
||||
}
|
||||
/**
|
||||
* Check that any "sheetId" in the command matches an existing
|
||||
@@ -47755,7 +47793,7 @@
|
||||
}
|
||||
getPasteZone(target) {
|
||||
const height = this.values.length;
|
||||
const width = Math.max(...this.values.map((a) => a.length));
|
||||
const width = largeMax(this.values.map((a) => a.length));
|
||||
const { left: activeCol, top: activeRow } = target[0];
|
||||
return {
|
||||
top: activeRow,
|
||||
@@ -48792,11 +48830,11 @@
|
||||
}
|
||||
else {
|
||||
const range = this.getters.getRangeFromSheetXC(this.sheetId, rule.criterion.values[0]);
|
||||
values = this.getters
|
||||
values = Array.from(new Set(this.getters
|
||||
.getRangeValues(range)
|
||||
.filter(isNotNull)
|
||||
.map((value) => value.toString())
|
||||
.filter((val) => val !== "");
|
||||
.filter((val) => val !== "")));
|
||||
}
|
||||
const composerContent = this.getCurrentContent();
|
||||
if (composerContent && composerContent !== this.getInitialComposerContent()) {
|
||||
@@ -51253,12 +51291,14 @@
|
||||
this.editionState = "initializing";
|
||||
}
|
||||
stopEdition() {
|
||||
if (!this.state.isEditing)
|
||||
const input = this.sheetNameRef.el;
|
||||
if (!this.state.isEditing || !input)
|
||||
return;
|
||||
this.state.isEditing = false;
|
||||
this.editionState = "initializing";
|
||||
this.sheetNameRef.el?.blur();
|
||||
input.blur();
|
||||
const inputValue = this.getInputContent() || "";
|
||||
input.innerText = inputValue;
|
||||
interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
|
||||
}
|
||||
cancelEdition() {
|
||||
@@ -51552,7 +51592,7 @@
|
||||
this.sheetListRef.el.scrollTo({ top: 0, left: scroll, behavior: "smooth" });
|
||||
}
|
||||
onSheetMouseDown(sheetId, event) {
|
||||
if (event.button !== 0)
|
||||
if (event.button !== 0 || this.env.model.getters.isReadonly())
|
||||
return;
|
||||
this.closeMenu();
|
||||
const visibleSheets = this.getVisibleSheets();
|
||||
@@ -55057,7 +55097,7 @@
|
||||
}
|
||||
function addDoughnutChart(chart, chartSheetIndex, data, { holeSize } = { holeSize: 50 }) {
|
||||
const colors = new ChartColors();
|
||||
const maxLength = Math.max(...chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
||||
const maxLength = largeMax(chart.dataSets.map((ds) => getRangeSize(ds.range, chartSheetIndex, data)));
|
||||
const doughnutColors = range(0, maxLength).map(() => toXlsxHexColor(colors.next()));
|
||||
const dataSetsNodes = [];
|
||||
for (const [dsIndex, dataset] of Object.entries(chart.dataSets).reverse()) {
|
||||
@@ -57011,9 +57051,9 @@
|
||||
exports.tokenize = tokenize;
|
||||
|
||||
|
||||
__info__.version = "17.0.16";
|
||||
__info__.date = "2024-03-25T11:04:46.936Z";
|
||||
__info__.hash = "9b128f8c";
|
||||
__info__.version = "17.0.17";
|
||||
__info__.date = "2024-04-05T14:13:49.946Z";
|
||||
__info__.hash = "33f09d7c4";
|
||||
|
||||
|
||||
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<!--
|
||||
This file is generated by o-spreadsheet build tools. Do not edit it.
|
||||
@see https://github.com/odoo/o-spreadsheet
|
||||
@version 17.0.16
|
||||
@date 2024-03-25T11:04:49.559Z
|
||||
@hash 9b128f8c
|
||||
@version 17.0.17
|
||||
@date 2024-04-05T14:13:52.721Z
|
||||
@hash 33f09d7c4
|
||||
-->
|
||||
<odoo>
|
||||
<t t-name="o-spreadsheet-ActionButton">
|
||||
@@ -276,7 +276,7 @@
|
||||
t-on-dblclick="() => this.onDblClick()"
|
||||
t-on-focusout="() => this.onFocusOut()"
|
||||
t-on-keydown="(ev) => this.onKeyDown(ev)"
|
||||
t-att-contenteditable="state.isEditing ? 'plaintext-only': 'false'"
|
||||
t-att-contenteditable="state.isEditing ? 'true': 'false'"
|
||||
/>
|
||||
<span class="o-sheet-icon ms-1" t-on-click.stop="(ev) => this.onIconClick(ev)">
|
||||
<t t-call="o-spreadsheet-Icon.TRIANGLE_DOWN"/>
|
||||
@@ -2424,7 +2424,7 @@ https://fontawesome.com/license -->
|
||||
t-att-class="{ 'o-menu-root': isMenuRoot, 'disabled': !isMenuEnabled, 'o-menu-item-active': isParentMenu(subMenu, menuItem)}"
|
||||
t-att-style="getColor(menuItem)">
|
||||
<div class="d-flex w-100">
|
||||
<div t-if="childrenHaveIcon" class="o-menu-item-icon align-middle">
|
||||
<div t-if="childrenHaveIcon" class="o-menu-item-icon align-middle flex-shrink-0">
|
||||
<t t-if="getIconName(menuItem)" t-call="{{getIconName(menuItem)}}"/>
|
||||
</div>
|
||||
<div class="o-menu-item-name align-middle text-truncate" t-esc="getName(menuItem)"/>
|
||||
|
||||
Reference in New Issue
Block a user