@odoo/o-spreadsheet 18.1.24 → 18.1.26
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 +6 -6
- 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.1.
|
|
6
|
-
* @date 2025-06-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.1.26
|
|
6
|
+
* @date 2025-06-19T18:21:37.648Z
|
|
7
|
+
* @hash 06479d4
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -5847,7 +5847,9 @@ function isTextFormat(format) {
|
|
|
5847
5847
|
}
|
|
5848
5848
|
|
|
5849
5849
|
function evaluateLiteral(literalCell, localeFormat) {
|
|
5850
|
-
const value = isTextFormat(localeFormat.format)
|
|
5850
|
+
const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
|
|
5851
|
+
? literalCell.content
|
|
5852
|
+
: literalCell.parsedValue;
|
|
5851
5853
|
const functionResult = { value, format: localeFormat.format };
|
|
5852
5854
|
return createEvaluatedCell(functionResult, localeFormat.locale);
|
|
5853
5855
|
}
|
|
@@ -5896,6 +5898,9 @@ function _createEvaluatedCell(functionResult, locale, cell) {
|
|
|
5896
5898
|
if (isEvaluationError(value)) {
|
|
5897
5899
|
return errorCell(value, message);
|
|
5898
5900
|
}
|
|
5901
|
+
if (value === null) {
|
|
5902
|
+
return emptyCell(format);
|
|
5903
|
+
}
|
|
5899
5904
|
if (isTextFormat(format)) {
|
|
5900
5905
|
// TO DO:
|
|
5901
5906
|
// with the next line, the value of the cell is transformed depending on the format.
|
|
@@ -5903,9 +5908,6 @@ function _createEvaluatedCell(functionResult, locale, cell) {
|
|
|
5903
5908
|
// to interpret the value as a number.
|
|
5904
5909
|
return textCell(toString(value), format, formattedValue);
|
|
5905
5910
|
}
|
|
5906
|
-
if (value === null) {
|
|
5907
|
-
return emptyCell(format);
|
|
5908
|
-
}
|
|
5909
5911
|
if (typeof value === "number") {
|
|
5910
5912
|
if (isDateTimeFormat(format || "")) {
|
|
5911
5913
|
return dateTimeCell(value, format, formattedValue);
|
|
@@ -10202,6 +10204,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10202
10204
|
if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
|
|
10203
10205
|
continue;
|
|
10204
10206
|
}
|
|
10207
|
+
const yAxisScale = chart.scales[dataset.yAxisID];
|
|
10205
10208
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10206
10209
|
const parsedValue = dataset._parsed[i];
|
|
10207
10210
|
const value = Number(chart.config.type === "radar" ? parsedValue.r : parsedValue.y);
|
|
@@ -10212,10 +10215,18 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10212
10215
|
const xPosition = point.x;
|
|
10213
10216
|
let yPosition = 0;
|
|
10214
10217
|
if (chart.config.type === "line" || chart.config.type === "radar") {
|
|
10215
|
-
yPosition = point.y - 10;
|
|
10218
|
+
yPosition = value < 0 ? point.y + 10 : point.y - 10;
|
|
10216
10219
|
}
|
|
10217
10220
|
else {
|
|
10218
|
-
|
|
10221
|
+
const yZeroLine = yAxisScale.getPixelForValue(0);
|
|
10222
|
+
const distanceFromAxisOrigin = Math.abs(yZeroLine - point.y);
|
|
10223
|
+
const textHeight = 12; // ChartJS default text height
|
|
10224
|
+
if (distanceFromAxisOrigin < textHeight) {
|
|
10225
|
+
yPosition = value < 0 ? yZeroLine + textHeight / 2 : yZeroLine - textHeight / 2;
|
|
10226
|
+
}
|
|
10227
|
+
else {
|
|
10228
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
10229
|
+
}
|
|
10219
10230
|
}
|
|
10220
10231
|
yPosition = Math.min(yPosition, yMax);
|
|
10221
10232
|
yPosition = Math.max(yPosition, yMin);
|
|
@@ -10225,7 +10236,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10225
10236
|
}
|
|
10226
10237
|
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
10227
10238
|
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
10228
|
-
yPosition = otherPosition - 13;
|
|
10239
|
+
yPosition = value < 0 ? otherPosition + 13 : otherPosition - 13;
|
|
10229
10240
|
}
|
|
10230
10241
|
}
|
|
10231
10242
|
textsPositions[xPosition].push(yPosition);
|
|
@@ -10244,6 +10255,8 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10244
10255
|
if (isTrendLineAxis(dataset.xAxisID)) {
|
|
10245
10256
|
return; // ignore trend lines
|
|
10246
10257
|
}
|
|
10258
|
+
const xAxisScale = chart.scales[dataset.xAxisID];
|
|
10259
|
+
const xZeroLine = xAxisScale.getPixelForValue(0);
|
|
10247
10260
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10248
10261
|
const value = Number(dataset._parsed[i].x);
|
|
10249
10262
|
if (isNaN(value)) {
|
|
@@ -10252,17 +10265,27 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10252
10265
|
const displayValue = options.callback(value, dataset, i);
|
|
10253
10266
|
const point = dataset.data[i];
|
|
10254
10267
|
const yPosition = point.y;
|
|
10255
|
-
|
|
10256
|
-
|
|
10257
|
-
|
|
10268
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10269
|
+
const distanceFromAxisOrigin = Math.abs(point.x - xZeroLine);
|
|
10270
|
+
const PADDING = 3;
|
|
10271
|
+
let xPosition;
|
|
10272
|
+
if (distanceFromAxisOrigin < textWidth) {
|
|
10273
|
+
xPosition =
|
|
10274
|
+
value < 0 ? xZeroLine - textWidth / 2 - PADDING : xZeroLine + textWidth / 2 + PADDING;
|
|
10275
|
+
}
|
|
10276
|
+
else {
|
|
10277
|
+
xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
10278
|
+
xPosition = Math.min(xPosition, xMax);
|
|
10279
|
+
xPosition = Math.max(xPosition, xMin);
|
|
10280
|
+
}
|
|
10258
10281
|
// Avoid overlapping texts with same Y
|
|
10259
10282
|
if (!textsPositions[yPosition]) {
|
|
10260
10283
|
textsPositions[yPosition] = [];
|
|
10261
10284
|
}
|
|
10262
|
-
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10263
10285
|
for (const otherPosition of textsPositions[yPosition]) {
|
|
10264
10286
|
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
10265
|
-
xPosition =
|
|
10287
|
+
xPosition =
|
|
10288
|
+
value < 0 ? otherPosition - textWidth - PADDING : otherPosition + textWidth + PADDING;
|
|
10266
10289
|
}
|
|
10267
10290
|
}
|
|
10268
10291
|
textsPositions[yPosition].push(xPosition);
|
|
@@ -10284,10 +10307,22 @@ function drawPieChartValues(chart, options, ctx) {
|
|
|
10284
10307
|
const midAngle = (startAngle + endAngle) / 2;
|
|
10285
10308
|
const midRadius = (innerRadius + outerRadius) / 2;
|
|
10286
10309
|
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
10287
|
-
const y = bar.y + midRadius * Math.sin(midAngle)
|
|
10310
|
+
const y = bar.y + midRadius * Math.sin(midAngle);
|
|
10311
|
+
const displayValue = options.callback(value, dataset, i);
|
|
10312
|
+
const textHeight = 12; // ChartJS default
|
|
10313
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
|
|
10314
|
+
const radius = outerRadius - innerRadius;
|
|
10315
|
+
// Check if the text fits in the slice. Not perfect, but good enough heuristic.
|
|
10316
|
+
if (textWidth >= radius || radius < textHeight) {
|
|
10317
|
+
continue;
|
|
10318
|
+
}
|
|
10319
|
+
const sliceAngle = endAngle - startAngle;
|
|
10320
|
+
const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
|
|
10321
|
+
if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
|
|
10322
|
+
continue;
|
|
10323
|
+
}
|
|
10288
10324
|
ctx.fillStyle = chartFontColor(options.background);
|
|
10289
10325
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
10290
|
-
const displayValue = options.callback(value, dataset, i);
|
|
10291
10326
|
drawTextWithBackground(displayValue, x, y, ctx);
|
|
10292
10327
|
}
|
|
10293
10328
|
}
|
|
@@ -26193,7 +26228,7 @@ class XlsxBaseExtractor {
|
|
|
26193
26228
|
*/
|
|
26194
26229
|
handleMissingValue(parentElement, missingElementName, optionalArgs) {
|
|
26195
26230
|
if (optionalArgs?.required) {
|
|
26196
|
-
if (optionalArgs?.default) {
|
|
26231
|
+
if (optionalArgs?.default !== undefined) {
|
|
26197
26232
|
this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
|
|
26198
26233
|
}
|
|
26199
26234
|
else {
|
|
@@ -30066,7 +30101,9 @@ function getPyramidChartShowValues(definition, args) {
|
|
|
30066
30101
|
background: definition.background,
|
|
30067
30102
|
callback: (value, dataset) => {
|
|
30068
30103
|
value = Math.abs(Number(value));
|
|
30069
|
-
return
|
|
30104
|
+
return value === 0
|
|
30105
|
+
? ""
|
|
30106
|
+
: formatChartDatasetValue(axisFormats, locale)(value, dataset.xAxisID || "x");
|
|
30070
30107
|
},
|
|
30071
30108
|
};
|
|
30072
30109
|
}
|
|
@@ -33215,19 +33252,26 @@ class FilterMenu extends owl.Component {
|
|
|
33215
33252
|
.filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
|
|
33216
33253
|
.map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
|
|
33217
33254
|
const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
|
|
33218
|
-
const
|
|
33219
|
-
const
|
|
33220
|
-
|
|
33221
|
-
const
|
|
33222
|
-
|
|
33223
|
-
|
|
33224
|
-
|
|
33225
|
-
|
|
33226
|
-
|
|
33227
|
-
|
|
33228
|
-
|
|
33229
|
-
|
|
33230
|
-
|
|
33255
|
+
const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
|
|
33256
|
+
const set = new Set();
|
|
33257
|
+
const values = [];
|
|
33258
|
+
const addValue = (value) => {
|
|
33259
|
+
const normalizedValue = toLowerCase(value);
|
|
33260
|
+
if (!set.has(normalizedValue)) {
|
|
33261
|
+
values.push({
|
|
33262
|
+
string: value || "",
|
|
33263
|
+
checked: !normalizedFilteredValues.has(normalizedValue),
|
|
33264
|
+
normalizedValue,
|
|
33265
|
+
});
|
|
33266
|
+
set.add(normalizedValue);
|
|
33267
|
+
}
|
|
33268
|
+
};
|
|
33269
|
+
cellValues.forEach(addValue);
|
|
33270
|
+
filterValues.forEach(addValue);
|
|
33271
|
+
return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
|
|
33272
|
+
numeric: true,
|
|
33273
|
+
sensitivity: "base",
|
|
33274
|
+
}));
|
|
33231
33275
|
}
|
|
33232
33276
|
checkValue(value) {
|
|
33233
33277
|
this.state.selectedValue = value.string;
|
|
@@ -34559,6 +34603,10 @@ const REMOVE_ROWS_ACTION = (env) => {
|
|
|
34559
34603
|
});
|
|
34560
34604
|
};
|
|
34561
34605
|
const CAN_REMOVE_COLUMNS_ROWS = (dimension, env) => {
|
|
34606
|
+
if ((dimension === "COL" && env.model.getters.getActiveRows().size > 0) ||
|
|
34607
|
+
(dimension === "ROW" && env.model.getters.getActiveCols().size > 0)) {
|
|
34608
|
+
return false;
|
|
34609
|
+
}
|
|
34562
34610
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34563
34611
|
const selectedElements = env.model.getters.getElementsFromSelection(dimension);
|
|
34564
34612
|
const includesAllVisibleHeaders = env.model.getters.checkElementsIncludeAllVisibleHeaders(sheetId, dimension, selectedElements);
|
|
@@ -37538,11 +37586,11 @@ class OTRegistry extends Registry {
|
|
|
37538
37586
|
* transformation function given
|
|
37539
37587
|
*/
|
|
37540
37588
|
addTransformation(executed, toTransforms, fn) {
|
|
37541
|
-
|
|
37542
|
-
|
|
37543
|
-
|
|
37544
|
-
|
|
37545
|
-
this.content[
|
|
37589
|
+
if (!this.content[executed]) {
|
|
37590
|
+
this.content[executed] = new Map();
|
|
37591
|
+
}
|
|
37592
|
+
for (const toTransform of toTransforms) {
|
|
37593
|
+
this.content[executed].set(toTransform, fn);
|
|
37546
37594
|
}
|
|
37547
37595
|
return this;
|
|
37548
37596
|
}
|
|
@@ -37551,7 +37599,7 @@ class OTRegistry extends Registry {
|
|
|
37551
37599
|
* that the executed command happened.
|
|
37552
37600
|
*/
|
|
37553
37601
|
getTransformation(toTransform, executed) {
|
|
37554
|
-
return this.content[
|
|
37602
|
+
return this.content[executed] && this.content[executed].get(toTransform);
|
|
37555
37603
|
}
|
|
37556
37604
|
}
|
|
37557
37605
|
const otRegistry = new OTRegistry();
|
|
@@ -58095,7 +58143,9 @@ class TablePlugin extends CorePlugin {
|
|
|
58095
58143
|
const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
|
|
58096
58144
|
const union = this.getters.getRangesUnion(ranges);
|
|
58097
58145
|
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
|
|
58098
|
-
|
|
58146
|
+
if (mergesInTarget.length) {
|
|
58147
|
+
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
58148
|
+
}
|
|
58099
58149
|
const id = `${nextTableId++}`;
|
|
58100
58150
|
const config = cmd.config || DEFAULT_TABLE_CONFIG;
|
|
58101
58151
|
const newTable = cmd.tableType === "dynamic"
|
|
@@ -58206,14 +58256,16 @@ class TablePlugin extends CorePlugin {
|
|
|
58206
58256
|
const zoneToCheckIfEmpty = direction === "down"
|
|
58207
58257
|
? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
|
|
58208
58258
|
: { ...zone, right: zone.right + 1, left: zone.right + 1 };
|
|
58209
|
-
for (
|
|
58210
|
-
|
|
58211
|
-
|
|
58212
|
-
|
|
58213
|
-
|
|
58214
|
-
|
|
58215
|
-
|
|
58216
|
-
|
|
58259
|
+
for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
|
|
58260
|
+
for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
|
|
58261
|
+
const cellPosition = { sheetId, col, row };
|
|
58262
|
+
// Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
|
|
58263
|
+
const cellContent = this.getters.getCell(cellPosition)?.content;
|
|
58264
|
+
if (cellContent ||
|
|
58265
|
+
this.getters.isInMerge(cellPosition) ||
|
|
58266
|
+
this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
|
|
58267
|
+
return "none";
|
|
58268
|
+
}
|
|
58217
58269
|
}
|
|
58218
58270
|
}
|
|
58219
58271
|
return direction;
|
|
@@ -64242,10 +64294,20 @@ function transform(toTransform, executed) {
|
|
|
64242
64294
|
*/
|
|
64243
64295
|
function transformAll(toTransform, executed) {
|
|
64244
64296
|
let transformedCommands = [...toTransform];
|
|
64297
|
+
const possibleTransformations = new Set(otRegistry.getKeys());
|
|
64245
64298
|
for (const executedCommand of executed) {
|
|
64246
|
-
|
|
64247
|
-
|
|
64248
|
-
|
|
64299
|
+
// If the executed command is not in the registry, we skip it
|
|
64300
|
+
// because we know there won't be any transformation impacting the
|
|
64301
|
+
// commands to transform.
|
|
64302
|
+
if (possibleTransformations.has(executedCommand.type)) {
|
|
64303
|
+
transformedCommands = transformedCommands.reduce((acc, cmd) => {
|
|
64304
|
+
const transformed = transform(cmd, executedCommand);
|
|
64305
|
+
if (transformed) {
|
|
64306
|
+
acc.push(transformed);
|
|
64307
|
+
}
|
|
64308
|
+
return acc;
|
|
64309
|
+
}, []);
|
|
64310
|
+
}
|
|
64249
64311
|
}
|
|
64250
64312
|
return transformedCommands;
|
|
64251
64313
|
}
|
|
@@ -65940,7 +66002,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
65940
66002
|
}
|
|
65941
66003
|
const position = this.getters.getCellPosition(cell.id);
|
|
65942
66004
|
const colSize = this.getters.getColSize(sheetId, position.col);
|
|
65943
|
-
if (cell.isFormula) {
|
|
66005
|
+
if (cell.isFormula || this.getters.getArrayFormulaSpreadingOn(position)) {
|
|
65944
66006
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
65945
66007
|
const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
|
|
65946
66008
|
if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
|
|
@@ -67579,9 +67641,10 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
67579
67641
|
const filteredZone = filter.filteredRange?.zone;
|
|
67580
67642
|
if (!filteredValues || !filteredZone)
|
|
67581
67643
|
continue;
|
|
67644
|
+
const filteredValuesSet = new Set(filteredValues);
|
|
67582
67645
|
for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
|
|
67583
67646
|
const value = this.getCellValueAsString(sheetId, filter.col, row);
|
|
67584
|
-
if (
|
|
67647
|
+
if (filteredValuesSet.has(value)) {
|
|
67585
67648
|
hiddenRows.add(row);
|
|
67586
67649
|
}
|
|
67587
67650
|
}
|
|
@@ -76511,6 +76574,6 @@ exports.tokenColors = tokenColors;
|
|
|
76511
76574
|
exports.tokenize = tokenize;
|
|
76512
76575
|
|
|
76513
76576
|
|
|
76514
|
-
__info__.version = "18.1.
|
|
76515
|
-
__info__.date = "2025-06-
|
|
76516
|
-
__info__.hash = "
|
|
76577
|
+
__info__.version = "18.1.26";
|
|
76578
|
+
__info__.date = "2025-06-19T18:21:37.648Z";
|
|
76579
|
+
__info__.hash = "06479d4";
|