@odoo/o-spreadsheet 18.2.16 → 18.2.18
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.
- package/dist/o-spreadsheet.cjs.js +118 -55
- package/dist/o-spreadsheet.esm.js +118 -55
- package/dist/o-spreadsheet.iife.js +118 -55
- package/dist/o-spreadsheet.iife.min.js +114 -114
- package/dist/o_spreadsheet.xml +3 -3
- package/package.json +1 -1
|
@@ -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 18.2.
|
|
6
|
-
* @date 2025-06-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.2.18
|
|
6
|
+
* @date 2025-06-19T18:24:41.051Z
|
|
7
|
+
* @hash 024c134
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -5856,7 +5856,9 @@ function isTextFormat(format) {
|
|
|
5856
5856
|
}
|
|
5857
5857
|
|
|
5858
5858
|
function evaluateLiteral(literalCell, localeFormat) {
|
|
5859
|
-
const value = isTextFormat(localeFormat.format)
|
|
5859
|
+
const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
|
|
5860
|
+
? literalCell.content
|
|
5861
|
+
: literalCell.parsedValue;
|
|
5860
5862
|
const functionResult = { value, format: localeFormat.format };
|
|
5861
5863
|
return createEvaluatedCell(functionResult, localeFormat.locale);
|
|
5862
5864
|
}
|
|
@@ -5905,6 +5907,9 @@ function _createEvaluatedCell(functionResult, locale, cell) {
|
|
|
5905
5907
|
if (isEvaluationError(value)) {
|
|
5906
5908
|
return errorCell(value, message);
|
|
5907
5909
|
}
|
|
5910
|
+
if (value === null) {
|
|
5911
|
+
return emptyCell(format);
|
|
5912
|
+
}
|
|
5908
5913
|
if (isTextFormat(format)) {
|
|
5909
5914
|
// TO DO:
|
|
5910
5915
|
// with the next line, the value of the cell is transformed depending on the format.
|
|
@@ -5912,9 +5917,6 @@ function _createEvaluatedCell(functionResult, locale, cell) {
|
|
|
5912
5917
|
// to interpret the value as a number.
|
|
5913
5918
|
return textCell(toString(value), format, formattedValue);
|
|
5914
5919
|
}
|
|
5915
|
-
if (value === null) {
|
|
5916
|
-
return emptyCell(format);
|
|
5917
|
-
}
|
|
5918
5920
|
if (typeof value === "number") {
|
|
5919
5921
|
if (isDateTimeFormat(format || "")) {
|
|
5920
5922
|
return dateTimeCell(value, format, formattedValue);
|
|
@@ -10366,6 +10368,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10366
10368
|
if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
|
|
10367
10369
|
continue;
|
|
10368
10370
|
}
|
|
10371
|
+
const yAxisScale = chart.scales[dataset.yAxisID];
|
|
10369
10372
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10370
10373
|
const parsedValue = dataset._parsed[i];
|
|
10371
10374
|
const value = Number(chart.config.type === "radar" ? parsedValue.r : parsedValue.y);
|
|
@@ -10376,10 +10379,18 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10376
10379
|
const xPosition = point.x;
|
|
10377
10380
|
let yPosition = 0;
|
|
10378
10381
|
if (chart.config.type === "line" || chart.config.type === "radar") {
|
|
10379
|
-
yPosition = point.y - 10;
|
|
10382
|
+
yPosition = value < 0 ? point.y + 10 : point.y - 10;
|
|
10380
10383
|
}
|
|
10381
10384
|
else {
|
|
10382
|
-
|
|
10385
|
+
const yZeroLine = yAxisScale.getPixelForValue(0);
|
|
10386
|
+
const distanceFromAxisOrigin = Math.abs(yZeroLine - point.y);
|
|
10387
|
+
const textHeight = 12; // ChartJS default text height
|
|
10388
|
+
if (distanceFromAxisOrigin < textHeight) {
|
|
10389
|
+
yPosition = value < 0 ? yZeroLine + textHeight / 2 : yZeroLine - textHeight / 2;
|
|
10390
|
+
}
|
|
10391
|
+
else {
|
|
10392
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
10393
|
+
}
|
|
10383
10394
|
}
|
|
10384
10395
|
yPosition = Math.min(yPosition, yMax);
|
|
10385
10396
|
yPosition = Math.max(yPosition, yMin);
|
|
@@ -10389,7 +10400,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10389
10400
|
}
|
|
10390
10401
|
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
10391
10402
|
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
10392
|
-
yPosition = otherPosition - 13;
|
|
10403
|
+
yPosition = value < 0 ? otherPosition + 13 : otherPosition - 13;
|
|
10393
10404
|
}
|
|
10394
10405
|
}
|
|
10395
10406
|
textsPositions[xPosition].push(yPosition);
|
|
@@ -10408,6 +10419,8 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10408
10419
|
if (isTrendLineAxis(dataset.xAxisID)) {
|
|
10409
10420
|
return; // ignore trend lines
|
|
10410
10421
|
}
|
|
10422
|
+
const xAxisScale = chart.scales[dataset.xAxisID];
|
|
10423
|
+
const xZeroLine = xAxisScale.getPixelForValue(0);
|
|
10411
10424
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10412
10425
|
const value = Number(dataset._parsed[i].x);
|
|
10413
10426
|
if (isNaN(value)) {
|
|
@@ -10416,17 +10429,27 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10416
10429
|
const displayValue = options.callback(value, dataset, i);
|
|
10417
10430
|
const point = dataset.data[i];
|
|
10418
10431
|
const yPosition = point.y;
|
|
10419
|
-
|
|
10420
|
-
|
|
10421
|
-
|
|
10432
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10433
|
+
const distanceFromAxisOrigin = Math.abs(point.x - xZeroLine);
|
|
10434
|
+
const PADDING = 3;
|
|
10435
|
+
let xPosition;
|
|
10436
|
+
if (distanceFromAxisOrigin < textWidth) {
|
|
10437
|
+
xPosition =
|
|
10438
|
+
value < 0 ? xZeroLine - textWidth / 2 - PADDING : xZeroLine + textWidth / 2 + PADDING;
|
|
10439
|
+
}
|
|
10440
|
+
else {
|
|
10441
|
+
xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
10442
|
+
xPosition = Math.min(xPosition, xMax);
|
|
10443
|
+
xPosition = Math.max(xPosition, xMin);
|
|
10444
|
+
}
|
|
10422
10445
|
// Avoid overlapping texts with same Y
|
|
10423
10446
|
if (!textsPositions[yPosition]) {
|
|
10424
10447
|
textsPositions[yPosition] = [];
|
|
10425
10448
|
}
|
|
10426
|
-
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10427
10449
|
for (const otherPosition of textsPositions[yPosition]) {
|
|
10428
10450
|
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
10429
|
-
xPosition =
|
|
10451
|
+
xPosition =
|
|
10452
|
+
value < 0 ? otherPosition - textWidth - PADDING : otherPosition + textWidth + PADDING;
|
|
10430
10453
|
}
|
|
10431
10454
|
}
|
|
10432
10455
|
textsPositions[yPosition].push(xPosition);
|
|
@@ -10448,10 +10471,22 @@ function drawPieChartValues(chart, options, ctx) {
|
|
|
10448
10471
|
const midAngle = (startAngle + endAngle) / 2;
|
|
10449
10472
|
const midRadius = (innerRadius + outerRadius) / 2;
|
|
10450
10473
|
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
10451
|
-
const y = bar.y + midRadius * Math.sin(midAngle)
|
|
10474
|
+
const y = bar.y + midRadius * Math.sin(midAngle);
|
|
10475
|
+
const displayValue = options.callback(value, dataset, i);
|
|
10476
|
+
const textHeight = 12; // ChartJS default
|
|
10477
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
|
|
10478
|
+
const radius = outerRadius - innerRadius;
|
|
10479
|
+
// Check if the text fits in the slice. Not perfect, but good enough heuristic.
|
|
10480
|
+
if (textWidth >= radius || radius < textHeight) {
|
|
10481
|
+
continue;
|
|
10482
|
+
}
|
|
10483
|
+
const sliceAngle = endAngle - startAngle;
|
|
10484
|
+
const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
|
|
10485
|
+
if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
|
|
10486
|
+
continue;
|
|
10487
|
+
}
|
|
10452
10488
|
ctx.fillStyle = chartFontColor(options.background);
|
|
10453
10489
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
10454
|
-
const displayValue = options.callback(value, dataset, i);
|
|
10455
10490
|
drawTextWithBackground(displayValue, x, y, ctx);
|
|
10456
10491
|
}
|
|
10457
10492
|
}
|
|
@@ -26217,7 +26252,7 @@ class XlsxBaseExtractor {
|
|
|
26217
26252
|
*/
|
|
26218
26253
|
handleMissingValue(parentElement, missingElementName, optionalArgs) {
|
|
26219
26254
|
if (optionalArgs?.required) {
|
|
26220
|
-
if (optionalArgs?.default) {
|
|
26255
|
+
if (optionalArgs?.default !== undefined) {
|
|
26221
26256
|
this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
|
|
26222
26257
|
}
|
|
26223
26258
|
else {
|
|
@@ -30098,7 +30133,9 @@ function getPyramidChartShowValues(definition, args) {
|
|
|
30098
30133
|
background: definition.background,
|
|
30099
30134
|
callback: (value, dataset) => {
|
|
30100
30135
|
value = Math.abs(Number(value));
|
|
30101
|
-
return
|
|
30136
|
+
return value === 0
|
|
30137
|
+
? ""
|
|
30138
|
+
: formatChartDatasetValue(axisFormats, locale)(value, dataset.xAxisID || "x");
|
|
30102
30139
|
},
|
|
30103
30140
|
};
|
|
30104
30141
|
}
|
|
@@ -33414,19 +33451,26 @@ class FilterMenu extends owl.Component {
|
|
|
33414
33451
|
.filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
|
|
33415
33452
|
.map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
|
|
33416
33453
|
const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
|
|
33417
|
-
const
|
|
33418
|
-
const
|
|
33419
|
-
|
|
33420
|
-
const
|
|
33421
|
-
|
|
33422
|
-
|
|
33423
|
-
|
|
33424
|
-
|
|
33425
|
-
|
|
33426
|
-
|
|
33427
|
-
|
|
33428
|
-
|
|
33429
|
-
|
|
33454
|
+
const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
|
|
33455
|
+
const set = new Set();
|
|
33456
|
+
const values = [];
|
|
33457
|
+
const addValue = (value) => {
|
|
33458
|
+
const normalizedValue = toLowerCase(value);
|
|
33459
|
+
if (!set.has(normalizedValue)) {
|
|
33460
|
+
values.push({
|
|
33461
|
+
string: value || "",
|
|
33462
|
+
checked: !normalizedFilteredValues.has(normalizedValue),
|
|
33463
|
+
normalizedValue,
|
|
33464
|
+
});
|
|
33465
|
+
set.add(normalizedValue);
|
|
33466
|
+
}
|
|
33467
|
+
};
|
|
33468
|
+
cellValues.forEach(addValue);
|
|
33469
|
+
filterValues.forEach(addValue);
|
|
33470
|
+
return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
|
|
33471
|
+
numeric: true,
|
|
33472
|
+
sensitivity: "base",
|
|
33473
|
+
}));
|
|
33430
33474
|
}
|
|
33431
33475
|
checkValue(value) {
|
|
33432
33476
|
this.state.selectedValue = value.string;
|
|
@@ -34760,6 +34804,10 @@ const REMOVE_ROWS_ACTION = (env) => {
|
|
|
34760
34804
|
});
|
|
34761
34805
|
};
|
|
34762
34806
|
const CAN_REMOVE_COLUMNS_ROWS = (dimension, env) => {
|
|
34807
|
+
if ((dimension === "COL" && env.model.getters.getActiveRows().size > 0) ||
|
|
34808
|
+
(dimension === "ROW" && env.model.getters.getActiveCols().size > 0)) {
|
|
34809
|
+
return false;
|
|
34810
|
+
}
|
|
34763
34811
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34764
34812
|
const selectedElements = env.model.getters.getElementsFromSelection(dimension);
|
|
34765
34813
|
const includesAllVisibleHeaders = env.model.getters.checkElementsIncludeAllVisibleHeaders(sheetId, dimension, selectedElements);
|
|
@@ -37739,11 +37787,11 @@ class OTRegistry extends Registry {
|
|
|
37739
37787
|
* transformation function given
|
|
37740
37788
|
*/
|
|
37741
37789
|
addTransformation(executed, toTransforms, fn) {
|
|
37742
|
-
|
|
37743
|
-
|
|
37744
|
-
|
|
37745
|
-
|
|
37746
|
-
this.content[
|
|
37790
|
+
if (!this.content[executed]) {
|
|
37791
|
+
this.content[executed] = new Map();
|
|
37792
|
+
}
|
|
37793
|
+
for (const toTransform of toTransforms) {
|
|
37794
|
+
this.content[executed].set(toTransform, fn);
|
|
37747
37795
|
}
|
|
37748
37796
|
return this;
|
|
37749
37797
|
}
|
|
@@ -37752,7 +37800,7 @@ class OTRegistry extends Registry {
|
|
|
37752
37800
|
* that the executed command happened.
|
|
37753
37801
|
*/
|
|
37754
37802
|
getTransformation(toTransform, executed) {
|
|
37755
|
-
return this.content[
|
|
37803
|
+
return this.content[executed] && this.content[executed].get(toTransform);
|
|
37756
37804
|
}
|
|
37757
37805
|
}
|
|
37758
37806
|
const otRegistry = new OTRegistry();
|
|
@@ -58593,7 +58641,9 @@ class TablePlugin extends CorePlugin {
|
|
|
58593
58641
|
const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
|
|
58594
58642
|
const union = this.getters.getRangesUnion(ranges);
|
|
58595
58643
|
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
|
|
58596
|
-
|
|
58644
|
+
if (mergesInTarget.length) {
|
|
58645
|
+
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
58646
|
+
}
|
|
58597
58647
|
const id = this.consumeNextId();
|
|
58598
58648
|
const config = cmd.config || DEFAULT_TABLE_CONFIG;
|
|
58599
58649
|
const newTable = cmd.tableType === "dynamic"
|
|
@@ -58692,14 +58742,16 @@ class TablePlugin extends CorePlugin {
|
|
|
58692
58742
|
const zoneToCheckIfEmpty = direction === "down"
|
|
58693
58743
|
? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
|
|
58694
58744
|
: { ...zone, right: zone.right + 1, left: zone.right + 1 };
|
|
58695
|
-
for (
|
|
58696
|
-
|
|
58697
|
-
|
|
58698
|
-
|
|
58699
|
-
|
|
58700
|
-
|
|
58701
|
-
|
|
58702
|
-
|
|
58745
|
+
for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
|
|
58746
|
+
for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
|
|
58747
|
+
const cellPosition = { sheetId, col, row };
|
|
58748
|
+
// Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
|
|
58749
|
+
const cellContent = this.getters.getCell(cellPosition)?.content;
|
|
58750
|
+
if (cellContent ||
|
|
58751
|
+
this.getters.isInMerge(cellPosition) ||
|
|
58752
|
+
this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
|
|
58753
|
+
return "none";
|
|
58754
|
+
}
|
|
58703
58755
|
}
|
|
58704
58756
|
}
|
|
58705
58757
|
return direction;
|
|
@@ -64742,10 +64794,20 @@ function transform(toTransform, executed) {
|
|
|
64742
64794
|
*/
|
|
64743
64795
|
function transformAll(toTransform, executed) {
|
|
64744
64796
|
let transformedCommands = [...toTransform];
|
|
64797
|
+
const possibleTransformations = new Set(otRegistry.getKeys());
|
|
64745
64798
|
for (const executedCommand of executed) {
|
|
64746
|
-
|
|
64747
|
-
|
|
64748
|
-
|
|
64799
|
+
// If the executed command is not in the registry, we skip it
|
|
64800
|
+
// because we know there won't be any transformation impacting the
|
|
64801
|
+
// commands to transform.
|
|
64802
|
+
if (possibleTransformations.has(executedCommand.type)) {
|
|
64803
|
+
transformedCommands = transformedCommands.reduce((acc, cmd) => {
|
|
64804
|
+
const transformed = transform(cmd, executedCommand);
|
|
64805
|
+
if (transformed) {
|
|
64806
|
+
acc.push(transformed);
|
|
64807
|
+
}
|
|
64808
|
+
return acc;
|
|
64809
|
+
}, []);
|
|
64810
|
+
}
|
|
64749
64811
|
}
|
|
64750
64812
|
return transformedCommands;
|
|
64751
64813
|
}
|
|
@@ -66434,7 +66496,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
66434
66496
|
}
|
|
66435
66497
|
const position = this.getters.getCellPosition(cell.id);
|
|
66436
66498
|
const colSize = this.getters.getColSize(sheetId, position.col);
|
|
66437
|
-
if (cell.isFormula) {
|
|
66499
|
+
if (cell.isFormula || this.getters.getArrayFormulaSpreadingOn(position)) {
|
|
66438
66500
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
66439
66501
|
const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
|
|
66440
66502
|
if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
|
|
@@ -68073,9 +68135,10 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
68073
68135
|
const filteredZone = filter.filteredRange?.zone;
|
|
68074
68136
|
if (!filteredValues || !filteredZone)
|
|
68075
68137
|
continue;
|
|
68138
|
+
const filteredValuesSet = new Set(filteredValues);
|
|
68076
68139
|
for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
|
|
68077
68140
|
const value = this.getCellValueAsString(sheetId, filter.col, row);
|
|
68078
|
-
if (
|
|
68141
|
+
if (filteredValuesSet.has(value)) {
|
|
68079
68142
|
hiddenRows.add(row);
|
|
68080
68143
|
}
|
|
68081
68144
|
}
|
|
@@ -76989,6 +77052,6 @@ exports.tokenColors = tokenColors;
|
|
|
76989
77052
|
exports.tokenize = tokenize;
|
|
76990
77053
|
|
|
76991
77054
|
|
|
76992
|
-
__info__.version = "18.2.
|
|
76993
|
-
__info__.date = "2025-06-
|
|
76994
|
-
__info__.hash = "
|
|
77055
|
+
__info__.version = "18.2.18";
|
|
77056
|
+
__info__.date = "2025-06-19T18:24:41.051Z";
|
|
77057
|
+
__info__.hash = "024c134";
|