@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
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -5845,7 +5845,9 @@ function isTextFormat(format) {
|
|
|
5845
5845
|
}
|
|
5846
5846
|
|
|
5847
5847
|
function evaluateLiteral(literalCell, localeFormat) {
|
|
5848
|
-
const value = isTextFormat(localeFormat.format)
|
|
5848
|
+
const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
|
|
5849
|
+
? literalCell.content
|
|
5850
|
+
: literalCell.parsedValue;
|
|
5849
5851
|
const functionResult = { value, format: localeFormat.format };
|
|
5850
5852
|
return createEvaluatedCell(functionResult, localeFormat.locale);
|
|
5851
5853
|
}
|
|
@@ -5894,6 +5896,9 @@ function _createEvaluatedCell(functionResult, locale, cell) {
|
|
|
5894
5896
|
if (isEvaluationError(value)) {
|
|
5895
5897
|
return errorCell(value, message);
|
|
5896
5898
|
}
|
|
5899
|
+
if (value === null) {
|
|
5900
|
+
return emptyCell(format);
|
|
5901
|
+
}
|
|
5897
5902
|
if (isTextFormat(format)) {
|
|
5898
5903
|
// TO DO:
|
|
5899
5904
|
// with the next line, the value of the cell is transformed depending on the format.
|
|
@@ -5901,9 +5906,6 @@ function _createEvaluatedCell(functionResult, locale, cell) {
|
|
|
5901
5906
|
// to interpret the value as a number.
|
|
5902
5907
|
return textCell(toString(value), format, formattedValue);
|
|
5903
5908
|
}
|
|
5904
|
-
if (value === null) {
|
|
5905
|
-
return emptyCell(format);
|
|
5906
|
-
}
|
|
5907
5909
|
if (typeof value === "number") {
|
|
5908
5910
|
if (isDateTimeFormat(format || "")) {
|
|
5909
5911
|
return dateTimeCell(value, format, formattedValue);
|
|
@@ -10200,6 +10202,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10200
10202
|
if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
|
|
10201
10203
|
continue;
|
|
10202
10204
|
}
|
|
10205
|
+
const yAxisScale = chart.scales[dataset.yAxisID];
|
|
10203
10206
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10204
10207
|
const parsedValue = dataset._parsed[i];
|
|
10205
10208
|
const value = Number(chart.config.type === "radar" ? parsedValue.r : parsedValue.y);
|
|
@@ -10210,10 +10213,18 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10210
10213
|
const xPosition = point.x;
|
|
10211
10214
|
let yPosition = 0;
|
|
10212
10215
|
if (chart.config.type === "line" || chart.config.type === "radar") {
|
|
10213
|
-
yPosition = point.y - 10;
|
|
10216
|
+
yPosition = value < 0 ? point.y + 10 : point.y - 10;
|
|
10214
10217
|
}
|
|
10215
10218
|
else {
|
|
10216
|
-
|
|
10219
|
+
const yZeroLine = yAxisScale.getPixelForValue(0);
|
|
10220
|
+
const distanceFromAxisOrigin = Math.abs(yZeroLine - point.y);
|
|
10221
|
+
const textHeight = 12; // ChartJS default text height
|
|
10222
|
+
if (distanceFromAxisOrigin < textHeight) {
|
|
10223
|
+
yPosition = value < 0 ? yZeroLine + textHeight / 2 : yZeroLine - textHeight / 2;
|
|
10224
|
+
}
|
|
10225
|
+
else {
|
|
10226
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
10227
|
+
}
|
|
10217
10228
|
}
|
|
10218
10229
|
yPosition = Math.min(yPosition, yMax);
|
|
10219
10230
|
yPosition = Math.max(yPosition, yMin);
|
|
@@ -10223,7 +10234,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10223
10234
|
}
|
|
10224
10235
|
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
10225
10236
|
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
10226
|
-
yPosition = otherPosition - 13;
|
|
10237
|
+
yPosition = value < 0 ? otherPosition + 13 : otherPosition - 13;
|
|
10227
10238
|
}
|
|
10228
10239
|
}
|
|
10229
10240
|
textsPositions[xPosition].push(yPosition);
|
|
@@ -10242,6 +10253,8 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10242
10253
|
if (isTrendLineAxis(dataset.xAxisID)) {
|
|
10243
10254
|
return; // ignore trend lines
|
|
10244
10255
|
}
|
|
10256
|
+
const xAxisScale = chart.scales[dataset.xAxisID];
|
|
10257
|
+
const xZeroLine = xAxisScale.getPixelForValue(0);
|
|
10245
10258
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10246
10259
|
const value = Number(dataset._parsed[i].x);
|
|
10247
10260
|
if (isNaN(value)) {
|
|
@@ -10250,17 +10263,27 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10250
10263
|
const displayValue = options.callback(value, dataset, i);
|
|
10251
10264
|
const point = dataset.data[i];
|
|
10252
10265
|
const yPosition = point.y;
|
|
10253
|
-
|
|
10254
|
-
|
|
10255
|
-
|
|
10266
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10267
|
+
const distanceFromAxisOrigin = Math.abs(point.x - xZeroLine);
|
|
10268
|
+
const PADDING = 3;
|
|
10269
|
+
let xPosition;
|
|
10270
|
+
if (distanceFromAxisOrigin < textWidth) {
|
|
10271
|
+
xPosition =
|
|
10272
|
+
value < 0 ? xZeroLine - textWidth / 2 - PADDING : xZeroLine + textWidth / 2 + PADDING;
|
|
10273
|
+
}
|
|
10274
|
+
else {
|
|
10275
|
+
xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
10276
|
+
xPosition = Math.min(xPosition, xMax);
|
|
10277
|
+
xPosition = Math.max(xPosition, xMin);
|
|
10278
|
+
}
|
|
10256
10279
|
// Avoid overlapping texts with same Y
|
|
10257
10280
|
if (!textsPositions[yPosition]) {
|
|
10258
10281
|
textsPositions[yPosition] = [];
|
|
10259
10282
|
}
|
|
10260
|
-
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10261
10283
|
for (const otherPosition of textsPositions[yPosition]) {
|
|
10262
10284
|
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
10263
|
-
xPosition =
|
|
10285
|
+
xPosition =
|
|
10286
|
+
value < 0 ? otherPosition - textWidth - PADDING : otherPosition + textWidth + PADDING;
|
|
10264
10287
|
}
|
|
10265
10288
|
}
|
|
10266
10289
|
textsPositions[yPosition].push(xPosition);
|
|
@@ -10282,10 +10305,22 @@ function drawPieChartValues(chart, options, ctx) {
|
|
|
10282
10305
|
const midAngle = (startAngle + endAngle) / 2;
|
|
10283
10306
|
const midRadius = (innerRadius + outerRadius) / 2;
|
|
10284
10307
|
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
10285
|
-
const y = bar.y + midRadius * Math.sin(midAngle)
|
|
10308
|
+
const y = bar.y + midRadius * Math.sin(midAngle);
|
|
10309
|
+
const displayValue = options.callback(value, dataset, i);
|
|
10310
|
+
const textHeight = 12; // ChartJS default
|
|
10311
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
|
|
10312
|
+
const radius = outerRadius - innerRadius;
|
|
10313
|
+
// Check if the text fits in the slice. Not perfect, but good enough heuristic.
|
|
10314
|
+
if (textWidth >= radius || radius < textHeight) {
|
|
10315
|
+
continue;
|
|
10316
|
+
}
|
|
10317
|
+
const sliceAngle = endAngle - startAngle;
|
|
10318
|
+
const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
|
|
10319
|
+
if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
|
|
10320
|
+
continue;
|
|
10321
|
+
}
|
|
10286
10322
|
ctx.fillStyle = chartFontColor(options.background);
|
|
10287
10323
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
10288
|
-
const displayValue = options.callback(value, dataset, i);
|
|
10289
10324
|
drawTextWithBackground(displayValue, x, y, ctx);
|
|
10290
10325
|
}
|
|
10291
10326
|
}
|
|
@@ -26191,7 +26226,7 @@ class XlsxBaseExtractor {
|
|
|
26191
26226
|
*/
|
|
26192
26227
|
handleMissingValue(parentElement, missingElementName, optionalArgs) {
|
|
26193
26228
|
if (optionalArgs?.required) {
|
|
26194
|
-
if (optionalArgs?.default) {
|
|
26229
|
+
if (optionalArgs?.default !== undefined) {
|
|
26195
26230
|
this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
|
|
26196
26231
|
}
|
|
26197
26232
|
else {
|
|
@@ -30064,7 +30099,9 @@ function getPyramidChartShowValues(definition, args) {
|
|
|
30064
30099
|
background: definition.background,
|
|
30065
30100
|
callback: (value, dataset) => {
|
|
30066
30101
|
value = Math.abs(Number(value));
|
|
30067
|
-
return
|
|
30102
|
+
return value === 0
|
|
30103
|
+
? ""
|
|
30104
|
+
: formatChartDatasetValue(axisFormats, locale)(value, dataset.xAxisID || "x");
|
|
30068
30105
|
},
|
|
30069
30106
|
};
|
|
30070
30107
|
}
|
|
@@ -33213,19 +33250,26 @@ class FilterMenu extends Component {
|
|
|
33213
33250
|
.filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
|
|
33214
33251
|
.map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
|
|
33215
33252
|
const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
|
|
33216
|
-
const
|
|
33217
|
-
const
|
|
33218
|
-
|
|
33219
|
-
const
|
|
33220
|
-
|
|
33221
|
-
|
|
33222
|
-
|
|
33223
|
-
|
|
33224
|
-
|
|
33225
|
-
|
|
33226
|
-
|
|
33227
|
-
|
|
33228
|
-
|
|
33253
|
+
const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
|
|
33254
|
+
const set = new Set();
|
|
33255
|
+
const values = [];
|
|
33256
|
+
const addValue = (value) => {
|
|
33257
|
+
const normalizedValue = toLowerCase(value);
|
|
33258
|
+
if (!set.has(normalizedValue)) {
|
|
33259
|
+
values.push({
|
|
33260
|
+
string: value || "",
|
|
33261
|
+
checked: !normalizedFilteredValues.has(normalizedValue),
|
|
33262
|
+
normalizedValue,
|
|
33263
|
+
});
|
|
33264
|
+
set.add(normalizedValue);
|
|
33265
|
+
}
|
|
33266
|
+
};
|
|
33267
|
+
cellValues.forEach(addValue);
|
|
33268
|
+
filterValues.forEach(addValue);
|
|
33269
|
+
return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
|
|
33270
|
+
numeric: true,
|
|
33271
|
+
sensitivity: "base",
|
|
33272
|
+
}));
|
|
33229
33273
|
}
|
|
33230
33274
|
checkValue(value) {
|
|
33231
33275
|
this.state.selectedValue = value.string;
|
|
@@ -34557,6 +34601,10 @@ const REMOVE_ROWS_ACTION = (env) => {
|
|
|
34557
34601
|
});
|
|
34558
34602
|
};
|
|
34559
34603
|
const CAN_REMOVE_COLUMNS_ROWS = (dimension, env) => {
|
|
34604
|
+
if ((dimension === "COL" && env.model.getters.getActiveRows().size > 0) ||
|
|
34605
|
+
(dimension === "ROW" && env.model.getters.getActiveCols().size > 0)) {
|
|
34606
|
+
return false;
|
|
34607
|
+
}
|
|
34560
34608
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34561
34609
|
const selectedElements = env.model.getters.getElementsFromSelection(dimension);
|
|
34562
34610
|
const includesAllVisibleHeaders = env.model.getters.checkElementsIncludeAllVisibleHeaders(sheetId, dimension, selectedElements);
|
|
@@ -37536,11 +37584,11 @@ class OTRegistry extends Registry {
|
|
|
37536
37584
|
* transformation function given
|
|
37537
37585
|
*/
|
|
37538
37586
|
addTransformation(executed, toTransforms, fn) {
|
|
37539
|
-
|
|
37540
|
-
|
|
37541
|
-
|
|
37542
|
-
|
|
37543
|
-
this.content[
|
|
37587
|
+
if (!this.content[executed]) {
|
|
37588
|
+
this.content[executed] = new Map();
|
|
37589
|
+
}
|
|
37590
|
+
for (const toTransform of toTransforms) {
|
|
37591
|
+
this.content[executed].set(toTransform, fn);
|
|
37544
37592
|
}
|
|
37545
37593
|
return this;
|
|
37546
37594
|
}
|
|
@@ -37549,7 +37597,7 @@ class OTRegistry extends Registry {
|
|
|
37549
37597
|
* that the executed command happened.
|
|
37550
37598
|
*/
|
|
37551
37599
|
getTransformation(toTransform, executed) {
|
|
37552
|
-
return this.content[
|
|
37600
|
+
return this.content[executed] && this.content[executed].get(toTransform);
|
|
37553
37601
|
}
|
|
37554
37602
|
}
|
|
37555
37603
|
const otRegistry = new OTRegistry();
|
|
@@ -58093,7 +58141,9 @@ class TablePlugin extends CorePlugin {
|
|
|
58093
58141
|
const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
|
|
58094
58142
|
const union = this.getters.getRangesUnion(ranges);
|
|
58095
58143
|
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
|
|
58096
|
-
|
|
58144
|
+
if (mergesInTarget.length) {
|
|
58145
|
+
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
58146
|
+
}
|
|
58097
58147
|
const id = `${nextTableId++}`;
|
|
58098
58148
|
const config = cmd.config || DEFAULT_TABLE_CONFIG;
|
|
58099
58149
|
const newTable = cmd.tableType === "dynamic"
|
|
@@ -58204,14 +58254,16 @@ class TablePlugin extends CorePlugin {
|
|
|
58204
58254
|
const zoneToCheckIfEmpty = direction === "down"
|
|
58205
58255
|
? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
|
|
58206
58256
|
: { ...zone, right: zone.right + 1, left: zone.right + 1 };
|
|
58207
|
-
for (
|
|
58208
|
-
|
|
58209
|
-
|
|
58210
|
-
|
|
58211
|
-
|
|
58212
|
-
|
|
58213
|
-
|
|
58214
|
-
|
|
58257
|
+
for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
|
|
58258
|
+
for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
|
|
58259
|
+
const cellPosition = { sheetId, col, row };
|
|
58260
|
+
// Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
|
|
58261
|
+
const cellContent = this.getters.getCell(cellPosition)?.content;
|
|
58262
|
+
if (cellContent ||
|
|
58263
|
+
this.getters.isInMerge(cellPosition) ||
|
|
58264
|
+
this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
|
|
58265
|
+
return "none";
|
|
58266
|
+
}
|
|
58215
58267
|
}
|
|
58216
58268
|
}
|
|
58217
58269
|
return direction;
|
|
@@ -64240,10 +64292,20 @@ function transform(toTransform, executed) {
|
|
|
64240
64292
|
*/
|
|
64241
64293
|
function transformAll(toTransform, executed) {
|
|
64242
64294
|
let transformedCommands = [...toTransform];
|
|
64295
|
+
const possibleTransformations = new Set(otRegistry.getKeys());
|
|
64243
64296
|
for (const executedCommand of executed) {
|
|
64244
|
-
|
|
64245
|
-
|
|
64246
|
-
|
|
64297
|
+
// If the executed command is not in the registry, we skip it
|
|
64298
|
+
// because we know there won't be any transformation impacting the
|
|
64299
|
+
// commands to transform.
|
|
64300
|
+
if (possibleTransformations.has(executedCommand.type)) {
|
|
64301
|
+
transformedCommands = transformedCommands.reduce((acc, cmd) => {
|
|
64302
|
+
const transformed = transform(cmd, executedCommand);
|
|
64303
|
+
if (transformed) {
|
|
64304
|
+
acc.push(transformed);
|
|
64305
|
+
}
|
|
64306
|
+
return acc;
|
|
64307
|
+
}, []);
|
|
64308
|
+
}
|
|
64247
64309
|
}
|
|
64248
64310
|
return transformedCommands;
|
|
64249
64311
|
}
|
|
@@ -65938,7 +66000,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
65938
66000
|
}
|
|
65939
66001
|
const position = this.getters.getCellPosition(cell.id);
|
|
65940
66002
|
const colSize = this.getters.getColSize(sheetId, position.col);
|
|
65941
|
-
if (cell.isFormula) {
|
|
66003
|
+
if (cell.isFormula || this.getters.getArrayFormulaSpreadingOn(position)) {
|
|
65942
66004
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
65943
66005
|
const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
|
|
65944
66006
|
if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
|
|
@@ -67577,9 +67639,10 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
67577
67639
|
const filteredZone = filter.filteredRange?.zone;
|
|
67578
67640
|
if (!filteredValues || !filteredZone)
|
|
67579
67641
|
continue;
|
|
67642
|
+
const filteredValuesSet = new Set(filteredValues);
|
|
67580
67643
|
for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
|
|
67581
67644
|
const value = this.getCellValueAsString(sheetId, filter.col, row);
|
|
67582
|
-
if (
|
|
67645
|
+
if (filteredValuesSet.has(value)) {
|
|
67583
67646
|
hiddenRows.add(row);
|
|
67584
67647
|
}
|
|
67585
67648
|
}
|
|
@@ -76465,6 +76528,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
|
|
|
76465
76528
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
76466
76529
|
|
|
76467
76530
|
|
|
76468
|
-
__info__.version = "18.1.
|
|
76469
|
-
__info__.date = "2025-06-
|
|
76470
|
-
__info__.hash = "
|
|
76531
|
+
__info__.version = "18.1.26";
|
|
76532
|
+
__info__.date = "2025-06-19T18:21:37.648Z";
|
|
76533
|
+
__info__.hash = "06479d4";
|