@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
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -5854,7 +5854,9 @@ function isTextFormat(format) {
|
|
|
5854
5854
|
}
|
|
5855
5855
|
|
|
5856
5856
|
function evaluateLiteral(literalCell, localeFormat) {
|
|
5857
|
-
const value = isTextFormat(localeFormat.format)
|
|
5857
|
+
const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
|
|
5858
|
+
? literalCell.content
|
|
5859
|
+
: literalCell.parsedValue;
|
|
5858
5860
|
const functionResult = { value, format: localeFormat.format };
|
|
5859
5861
|
return createEvaluatedCell(functionResult, localeFormat.locale);
|
|
5860
5862
|
}
|
|
@@ -5903,6 +5905,9 @@ function _createEvaluatedCell(functionResult, locale, cell) {
|
|
|
5903
5905
|
if (isEvaluationError(value)) {
|
|
5904
5906
|
return errorCell(value, message);
|
|
5905
5907
|
}
|
|
5908
|
+
if (value === null) {
|
|
5909
|
+
return emptyCell(format);
|
|
5910
|
+
}
|
|
5906
5911
|
if (isTextFormat(format)) {
|
|
5907
5912
|
// TO DO:
|
|
5908
5913
|
// with the next line, the value of the cell is transformed depending on the format.
|
|
@@ -5910,9 +5915,6 @@ function _createEvaluatedCell(functionResult, locale, cell) {
|
|
|
5910
5915
|
// to interpret the value as a number.
|
|
5911
5916
|
return textCell(toString(value), format, formattedValue);
|
|
5912
5917
|
}
|
|
5913
|
-
if (value === null) {
|
|
5914
|
-
return emptyCell(format);
|
|
5915
|
-
}
|
|
5916
5918
|
if (typeof value === "number") {
|
|
5917
5919
|
if (isDateTimeFormat(format || "")) {
|
|
5918
5920
|
return dateTimeCell(value, format, formattedValue);
|
|
@@ -10364,6 +10366,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10364
10366
|
if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
|
|
10365
10367
|
continue;
|
|
10366
10368
|
}
|
|
10369
|
+
const yAxisScale = chart.scales[dataset.yAxisID];
|
|
10367
10370
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10368
10371
|
const parsedValue = dataset._parsed[i];
|
|
10369
10372
|
const value = Number(chart.config.type === "radar" ? parsedValue.r : parsedValue.y);
|
|
@@ -10374,10 +10377,18 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10374
10377
|
const xPosition = point.x;
|
|
10375
10378
|
let yPosition = 0;
|
|
10376
10379
|
if (chart.config.type === "line" || chart.config.type === "radar") {
|
|
10377
|
-
yPosition = point.y - 10;
|
|
10380
|
+
yPosition = value < 0 ? point.y + 10 : point.y - 10;
|
|
10378
10381
|
}
|
|
10379
10382
|
else {
|
|
10380
|
-
|
|
10383
|
+
const yZeroLine = yAxisScale.getPixelForValue(0);
|
|
10384
|
+
const distanceFromAxisOrigin = Math.abs(yZeroLine - point.y);
|
|
10385
|
+
const textHeight = 12; // ChartJS default text height
|
|
10386
|
+
if (distanceFromAxisOrigin < textHeight) {
|
|
10387
|
+
yPosition = value < 0 ? yZeroLine + textHeight / 2 : yZeroLine - textHeight / 2;
|
|
10388
|
+
}
|
|
10389
|
+
else {
|
|
10390
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
10391
|
+
}
|
|
10381
10392
|
}
|
|
10382
10393
|
yPosition = Math.min(yPosition, yMax);
|
|
10383
10394
|
yPosition = Math.max(yPosition, yMin);
|
|
@@ -10387,7 +10398,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
10387
10398
|
}
|
|
10388
10399
|
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
10389
10400
|
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
10390
|
-
yPosition = otherPosition - 13;
|
|
10401
|
+
yPosition = value < 0 ? otherPosition + 13 : otherPosition - 13;
|
|
10391
10402
|
}
|
|
10392
10403
|
}
|
|
10393
10404
|
textsPositions[xPosition].push(yPosition);
|
|
@@ -10406,6 +10417,8 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10406
10417
|
if (isTrendLineAxis(dataset.xAxisID)) {
|
|
10407
10418
|
return; // ignore trend lines
|
|
10408
10419
|
}
|
|
10420
|
+
const xAxisScale = chart.scales[dataset.xAxisID];
|
|
10421
|
+
const xZeroLine = xAxisScale.getPixelForValue(0);
|
|
10409
10422
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
10410
10423
|
const value = Number(dataset._parsed[i].x);
|
|
10411
10424
|
if (isNaN(value)) {
|
|
@@ -10414,17 +10427,27 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
10414
10427
|
const displayValue = options.callback(value, dataset, i);
|
|
10415
10428
|
const point = dataset.data[i];
|
|
10416
10429
|
const yPosition = point.y;
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
|
|
10430
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10431
|
+
const distanceFromAxisOrigin = Math.abs(point.x - xZeroLine);
|
|
10432
|
+
const PADDING = 3;
|
|
10433
|
+
let xPosition;
|
|
10434
|
+
if (distanceFromAxisOrigin < textWidth) {
|
|
10435
|
+
xPosition =
|
|
10436
|
+
value < 0 ? xZeroLine - textWidth / 2 - PADDING : xZeroLine + textWidth / 2 + PADDING;
|
|
10437
|
+
}
|
|
10438
|
+
else {
|
|
10439
|
+
xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
10440
|
+
xPosition = Math.min(xPosition, xMax);
|
|
10441
|
+
xPosition = Math.max(xPosition, xMin);
|
|
10442
|
+
}
|
|
10420
10443
|
// Avoid overlapping texts with same Y
|
|
10421
10444
|
if (!textsPositions[yPosition]) {
|
|
10422
10445
|
textsPositions[yPosition] = [];
|
|
10423
10446
|
}
|
|
10424
|
-
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
10425
10447
|
for (const otherPosition of textsPositions[yPosition]) {
|
|
10426
10448
|
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
10427
|
-
xPosition =
|
|
10449
|
+
xPosition =
|
|
10450
|
+
value < 0 ? otherPosition - textWidth - PADDING : otherPosition + textWidth + PADDING;
|
|
10428
10451
|
}
|
|
10429
10452
|
}
|
|
10430
10453
|
textsPositions[yPosition].push(xPosition);
|
|
@@ -10446,10 +10469,22 @@ function drawPieChartValues(chart, options, ctx) {
|
|
|
10446
10469
|
const midAngle = (startAngle + endAngle) / 2;
|
|
10447
10470
|
const midRadius = (innerRadius + outerRadius) / 2;
|
|
10448
10471
|
const x = bar.x + midRadius * Math.cos(midAngle);
|
|
10449
|
-
const y = bar.y + midRadius * Math.sin(midAngle)
|
|
10472
|
+
const y = bar.y + midRadius * Math.sin(midAngle);
|
|
10473
|
+
const displayValue = options.callback(value, dataset, i);
|
|
10474
|
+
const textHeight = 12; // ChartJS default
|
|
10475
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
|
|
10476
|
+
const radius = outerRadius - innerRadius;
|
|
10477
|
+
// Check if the text fits in the slice. Not perfect, but good enough heuristic.
|
|
10478
|
+
if (textWidth >= radius || radius < textHeight) {
|
|
10479
|
+
continue;
|
|
10480
|
+
}
|
|
10481
|
+
const sliceAngle = endAngle - startAngle;
|
|
10482
|
+
const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
|
|
10483
|
+
if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
|
|
10484
|
+
continue;
|
|
10485
|
+
}
|
|
10450
10486
|
ctx.fillStyle = chartFontColor(options.background);
|
|
10451
10487
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
10452
|
-
const displayValue = options.callback(value, dataset, i);
|
|
10453
10488
|
drawTextWithBackground(displayValue, x, y, ctx);
|
|
10454
10489
|
}
|
|
10455
10490
|
}
|
|
@@ -26215,7 +26250,7 @@ class XlsxBaseExtractor {
|
|
|
26215
26250
|
*/
|
|
26216
26251
|
handleMissingValue(parentElement, missingElementName, optionalArgs) {
|
|
26217
26252
|
if (optionalArgs?.required) {
|
|
26218
|
-
if (optionalArgs?.default) {
|
|
26253
|
+
if (optionalArgs?.default !== undefined) {
|
|
26219
26254
|
this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
|
|
26220
26255
|
}
|
|
26221
26256
|
else {
|
|
@@ -30096,7 +30131,9 @@ function getPyramidChartShowValues(definition, args) {
|
|
|
30096
30131
|
background: definition.background,
|
|
30097
30132
|
callback: (value, dataset) => {
|
|
30098
30133
|
value = Math.abs(Number(value));
|
|
30099
|
-
return
|
|
30134
|
+
return value === 0
|
|
30135
|
+
? ""
|
|
30136
|
+
: formatChartDatasetValue(axisFormats, locale)(value, dataset.xAxisID || "x");
|
|
30100
30137
|
},
|
|
30101
30138
|
};
|
|
30102
30139
|
}
|
|
@@ -33412,19 +33449,26 @@ class FilterMenu extends Component {
|
|
|
33412
33449
|
.filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
|
|
33413
33450
|
.map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
|
|
33414
33451
|
const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
|
|
33415
|
-
const
|
|
33416
|
-
const
|
|
33417
|
-
|
|
33418
|
-
const
|
|
33419
|
-
|
|
33420
|
-
|
|
33421
|
-
|
|
33422
|
-
|
|
33423
|
-
|
|
33424
|
-
|
|
33425
|
-
|
|
33426
|
-
|
|
33427
|
-
|
|
33452
|
+
const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
|
|
33453
|
+
const set = new Set();
|
|
33454
|
+
const values = [];
|
|
33455
|
+
const addValue = (value) => {
|
|
33456
|
+
const normalizedValue = toLowerCase(value);
|
|
33457
|
+
if (!set.has(normalizedValue)) {
|
|
33458
|
+
values.push({
|
|
33459
|
+
string: value || "",
|
|
33460
|
+
checked: !normalizedFilteredValues.has(normalizedValue),
|
|
33461
|
+
normalizedValue,
|
|
33462
|
+
});
|
|
33463
|
+
set.add(normalizedValue);
|
|
33464
|
+
}
|
|
33465
|
+
};
|
|
33466
|
+
cellValues.forEach(addValue);
|
|
33467
|
+
filterValues.forEach(addValue);
|
|
33468
|
+
return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
|
|
33469
|
+
numeric: true,
|
|
33470
|
+
sensitivity: "base",
|
|
33471
|
+
}));
|
|
33428
33472
|
}
|
|
33429
33473
|
checkValue(value) {
|
|
33430
33474
|
this.state.selectedValue = value.string;
|
|
@@ -34758,6 +34802,10 @@ const REMOVE_ROWS_ACTION = (env) => {
|
|
|
34758
34802
|
});
|
|
34759
34803
|
};
|
|
34760
34804
|
const CAN_REMOVE_COLUMNS_ROWS = (dimension, env) => {
|
|
34805
|
+
if ((dimension === "COL" && env.model.getters.getActiveRows().size > 0) ||
|
|
34806
|
+
(dimension === "ROW" && env.model.getters.getActiveCols().size > 0)) {
|
|
34807
|
+
return false;
|
|
34808
|
+
}
|
|
34761
34809
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
34762
34810
|
const selectedElements = env.model.getters.getElementsFromSelection(dimension);
|
|
34763
34811
|
const includesAllVisibleHeaders = env.model.getters.checkElementsIncludeAllVisibleHeaders(sheetId, dimension, selectedElements);
|
|
@@ -37737,11 +37785,11 @@ class OTRegistry extends Registry {
|
|
|
37737
37785
|
* transformation function given
|
|
37738
37786
|
*/
|
|
37739
37787
|
addTransformation(executed, toTransforms, fn) {
|
|
37740
|
-
|
|
37741
|
-
|
|
37742
|
-
|
|
37743
|
-
|
|
37744
|
-
this.content[
|
|
37788
|
+
if (!this.content[executed]) {
|
|
37789
|
+
this.content[executed] = new Map();
|
|
37790
|
+
}
|
|
37791
|
+
for (const toTransform of toTransforms) {
|
|
37792
|
+
this.content[executed].set(toTransform, fn);
|
|
37745
37793
|
}
|
|
37746
37794
|
return this;
|
|
37747
37795
|
}
|
|
@@ -37750,7 +37798,7 @@ class OTRegistry extends Registry {
|
|
|
37750
37798
|
* that the executed command happened.
|
|
37751
37799
|
*/
|
|
37752
37800
|
getTransformation(toTransform, executed) {
|
|
37753
|
-
return this.content[
|
|
37801
|
+
return this.content[executed] && this.content[executed].get(toTransform);
|
|
37754
37802
|
}
|
|
37755
37803
|
}
|
|
37756
37804
|
const otRegistry = new OTRegistry();
|
|
@@ -58591,7 +58639,9 @@ class TablePlugin extends CorePlugin {
|
|
|
58591
58639
|
const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
|
|
58592
58640
|
const union = this.getters.getRangesUnion(ranges);
|
|
58593
58641
|
const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
|
|
58594
|
-
|
|
58642
|
+
if (mergesInTarget.length) {
|
|
58643
|
+
this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
|
|
58644
|
+
}
|
|
58595
58645
|
const id = this.consumeNextId();
|
|
58596
58646
|
const config = cmd.config || DEFAULT_TABLE_CONFIG;
|
|
58597
58647
|
const newTable = cmd.tableType === "dynamic"
|
|
@@ -58690,14 +58740,16 @@ class TablePlugin extends CorePlugin {
|
|
|
58690
58740
|
const zoneToCheckIfEmpty = direction === "down"
|
|
58691
58741
|
? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
|
|
58692
58742
|
: { ...zone, right: zone.right + 1, left: zone.right + 1 };
|
|
58693
|
-
for (
|
|
58694
|
-
|
|
58695
|
-
|
|
58696
|
-
|
|
58697
|
-
|
|
58698
|
-
|
|
58699
|
-
|
|
58700
|
-
|
|
58743
|
+
for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
|
|
58744
|
+
for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
|
|
58745
|
+
const cellPosition = { sheetId, col, row };
|
|
58746
|
+
// Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
|
|
58747
|
+
const cellContent = this.getters.getCell(cellPosition)?.content;
|
|
58748
|
+
if (cellContent ||
|
|
58749
|
+
this.getters.isInMerge(cellPosition) ||
|
|
58750
|
+
this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
|
|
58751
|
+
return "none";
|
|
58752
|
+
}
|
|
58701
58753
|
}
|
|
58702
58754
|
}
|
|
58703
58755
|
return direction;
|
|
@@ -64740,10 +64792,20 @@ function transform(toTransform, executed) {
|
|
|
64740
64792
|
*/
|
|
64741
64793
|
function transformAll(toTransform, executed) {
|
|
64742
64794
|
let transformedCommands = [...toTransform];
|
|
64795
|
+
const possibleTransformations = new Set(otRegistry.getKeys());
|
|
64743
64796
|
for (const executedCommand of executed) {
|
|
64744
|
-
|
|
64745
|
-
|
|
64746
|
-
|
|
64797
|
+
// If the executed command is not in the registry, we skip it
|
|
64798
|
+
// because we know there won't be any transformation impacting the
|
|
64799
|
+
// commands to transform.
|
|
64800
|
+
if (possibleTransformations.has(executedCommand.type)) {
|
|
64801
|
+
transformedCommands = transformedCommands.reduce((acc, cmd) => {
|
|
64802
|
+
const transformed = transform(cmd, executedCommand);
|
|
64803
|
+
if (transformed) {
|
|
64804
|
+
acc.push(transformed);
|
|
64805
|
+
}
|
|
64806
|
+
return acc;
|
|
64807
|
+
}, []);
|
|
64808
|
+
}
|
|
64747
64809
|
}
|
|
64748
64810
|
return transformedCommands;
|
|
64749
64811
|
}
|
|
@@ -66432,7 +66494,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
66432
66494
|
}
|
|
66433
66495
|
const position = this.getters.getCellPosition(cell.id);
|
|
66434
66496
|
const colSize = this.getters.getColSize(sheetId, position.col);
|
|
66435
|
-
if (cell.isFormula) {
|
|
66497
|
+
if (cell.isFormula || this.getters.getArrayFormulaSpreadingOn(position)) {
|
|
66436
66498
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
66437
66499
|
const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
|
|
66438
66500
|
if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
|
|
@@ -68071,9 +68133,10 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
68071
68133
|
const filteredZone = filter.filteredRange?.zone;
|
|
68072
68134
|
if (!filteredValues || !filteredZone)
|
|
68073
68135
|
continue;
|
|
68136
|
+
const filteredValuesSet = new Set(filteredValues);
|
|
68074
68137
|
for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
|
|
68075
68138
|
const value = this.getCellValueAsString(sheetId, filter.col, row);
|
|
68076
|
-
if (
|
|
68139
|
+
if (filteredValuesSet.has(value)) {
|
|
68077
68140
|
hiddenRows.add(row);
|
|
68078
68141
|
}
|
|
68079
68142
|
}
|
|
@@ -76942,6 +77005,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
|
|
|
76942
77005
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, 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 };
|
|
76943
77006
|
|
|
76944
77007
|
|
|
76945
|
-
__info__.version = "18.2.
|
|
76946
|
-
__info__.date = "2025-06-
|
|
76947
|
-
__info__.hash = "
|
|
77008
|
+
__info__.version = "18.2.18";
|
|
77009
|
+
__info__.date = "2025-06-19T18:24:41.051Z";
|
|
77010
|
+
__info__.hash = "024c134";
|