@odoo/o-spreadsheet 18.1.24 → 18.1.25

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.
@@ -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.24
6
- * @date 2025-06-06T09:31:57.011Z
7
- * @hash 0e386b2
5
+ * @version 18.1.25
6
+ * @date 2025-06-12T09:49:08.707Z
7
+ * @hash a232524
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) ? literalCell.content : literalCell.parsedValue;
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);
@@ -10284,10 +10286,22 @@ function drawPieChartValues(chart, options, ctx) {
10284
10286
  const midAngle = (startAngle + endAngle) / 2;
10285
10287
  const midRadius = (innerRadius + outerRadius) / 2;
10286
10288
  const x = bar.x + midRadius * Math.cos(midAngle);
10287
- const y = bar.y + midRadius * Math.sin(midAngle) + 7;
10289
+ const y = bar.y + midRadius * Math.sin(midAngle);
10290
+ const displayValue = options.callback(value, dataset, i);
10291
+ const textHeight = 12; // ChartJS default
10292
+ const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
10293
+ const radius = outerRadius - innerRadius;
10294
+ // Check if the text fits in the slice. Not perfect, but good enough heuristic.
10295
+ if (textWidth >= radius || radius < textHeight) {
10296
+ continue;
10297
+ }
10298
+ const sliceAngle = endAngle - startAngle;
10299
+ const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
10300
+ if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
10301
+ continue;
10302
+ }
10288
10303
  ctx.fillStyle = chartFontColor(options.background);
10289
10304
  ctx.strokeStyle = options.background || "#ffffff";
10290
- const displayValue = options.callback(value, dataset, i);
10291
10305
  drawTextWithBackground(displayValue, x, y, ctx);
10292
10306
  }
10293
10307
  }
@@ -26193,7 +26207,7 @@ class XlsxBaseExtractor {
26193
26207
  */
26194
26208
  handleMissingValue(parentElement, missingElementName, optionalArgs) {
26195
26209
  if (optionalArgs?.required) {
26196
- if (optionalArgs?.default) {
26210
+ if (optionalArgs?.default !== undefined) {
26197
26211
  this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
26198
26212
  }
26199
26213
  else {
@@ -33215,19 +33229,26 @@ class FilterMenu extends owl.Component {
33215
33229
  .filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
33216
33230
  .map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
33217
33231
  const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
33218
- const strValues = [...cellValues, ...filterValues];
33219
- const normalizedFilteredValues = filterValues.map(toLowerCase);
33220
- // Set with lowercase values to avoid duplicates
33221
- const normalizedValues = [...new Set(strValues.map(toLowerCase))];
33222
- const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
33223
- return sortedValues.map((normalizedValue) => {
33224
- const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
33225
- -1;
33226
- return {
33227
- checked,
33228
- string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
33229
- };
33230
- });
33232
+ const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
33233
+ const set = new Set();
33234
+ const values = [];
33235
+ const addValue = (value) => {
33236
+ const normalizedValue = toLowerCase(value);
33237
+ if (!set.has(normalizedValue)) {
33238
+ values.push({
33239
+ string: value || "",
33240
+ checked: !normalizedFilteredValues.has(normalizedValue),
33241
+ normalizedValue,
33242
+ });
33243
+ set.add(normalizedValue);
33244
+ }
33245
+ };
33246
+ cellValues.forEach(addValue);
33247
+ filterValues.forEach(addValue);
33248
+ return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
33249
+ numeric: true,
33250
+ sensitivity: "base",
33251
+ }));
33231
33252
  }
33232
33253
  checkValue(value) {
33233
33254
  this.state.selectedValue = value.string;
@@ -58095,7 +58116,9 @@ class TablePlugin extends CorePlugin {
58095
58116
  const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
58096
58117
  const union = this.getters.getRangesUnion(ranges);
58097
58118
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
58098
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
58119
+ if (mergesInTarget.length) {
58120
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
58121
+ }
58099
58122
  const id = `${nextTableId++}`;
58100
58123
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
58101
58124
  const newTable = cmd.tableType === "dynamic"
@@ -58206,14 +58229,16 @@ class TablePlugin extends CorePlugin {
58206
58229
  const zoneToCheckIfEmpty = direction === "down"
58207
58230
  ? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
58208
58231
  : { ...zone, right: zone.right + 1, left: zone.right + 1 };
58209
- for (const position of positions(zoneToCheckIfEmpty)) {
58210
- const cellPosition = { sheetId, ...position };
58211
- // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
58212
- const cellContent = this.getters.getCell(cellPosition)?.content;
58213
- if (cellContent ||
58214
- this.getters.isInMerge(cellPosition) ||
58215
- this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
58216
- return "none";
58232
+ for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
58233
+ for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
58234
+ const cellPosition = { sheetId, col, row };
58235
+ // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
58236
+ const cellContent = this.getters.getCell(cellPosition)?.content;
58237
+ if (cellContent ||
58238
+ this.getters.isInMerge(cellPosition) ||
58239
+ this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
58240
+ return "none";
58241
+ }
58217
58242
  }
58218
58243
  }
58219
58244
  return direction;
@@ -67579,9 +67604,10 @@ class FilterEvaluationPlugin extends UIPlugin {
67579
67604
  const filteredZone = filter.filteredRange?.zone;
67580
67605
  if (!filteredValues || !filteredZone)
67581
67606
  continue;
67607
+ const filteredValuesSet = new Set(filteredValues);
67582
67608
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
67583
67609
  const value = this.getCellValueAsString(sheetId, filter.col, row);
67584
- if (filteredValues.includes(value)) {
67610
+ if (filteredValuesSet.has(value)) {
67585
67611
  hiddenRows.add(row);
67586
67612
  }
67587
67613
  }
@@ -76511,6 +76537,6 @@ exports.tokenColors = tokenColors;
76511
76537
  exports.tokenize = tokenize;
76512
76538
 
76513
76539
 
76514
- __info__.version = "18.1.24";
76515
- __info__.date = "2025-06-06T09:31:57.011Z";
76516
- __info__.hash = "0e386b2";
76540
+ __info__.version = "18.1.25";
76541
+ __info__.date = "2025-06-12T09:49:08.707Z";
76542
+ __info__.hash = "a232524";
@@ -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.24
6
- * @date 2025-06-06T09:31:57.011Z
7
- * @hash 0e386b2
5
+ * @version 18.1.25
6
+ * @date 2025-06-12T09:49:08.707Z
7
+ * @hash a232524
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) ? literalCell.content : literalCell.parsedValue;
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);
@@ -10282,10 +10284,22 @@ function drawPieChartValues(chart, options, ctx) {
10282
10284
  const midAngle = (startAngle + endAngle) / 2;
10283
10285
  const midRadius = (innerRadius + outerRadius) / 2;
10284
10286
  const x = bar.x + midRadius * Math.cos(midAngle);
10285
- const y = bar.y + midRadius * Math.sin(midAngle) + 7;
10287
+ const y = bar.y + midRadius * Math.sin(midAngle);
10288
+ const displayValue = options.callback(value, dataset, i);
10289
+ const textHeight = 12; // ChartJS default
10290
+ const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
10291
+ const radius = outerRadius - innerRadius;
10292
+ // Check if the text fits in the slice. Not perfect, but good enough heuristic.
10293
+ if (textWidth >= radius || radius < textHeight) {
10294
+ continue;
10295
+ }
10296
+ const sliceAngle = endAngle - startAngle;
10297
+ const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
10298
+ if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
10299
+ continue;
10300
+ }
10286
10301
  ctx.fillStyle = chartFontColor(options.background);
10287
10302
  ctx.strokeStyle = options.background || "#ffffff";
10288
- const displayValue = options.callback(value, dataset, i);
10289
10303
  drawTextWithBackground(displayValue, x, y, ctx);
10290
10304
  }
10291
10305
  }
@@ -26191,7 +26205,7 @@ class XlsxBaseExtractor {
26191
26205
  */
26192
26206
  handleMissingValue(parentElement, missingElementName, optionalArgs) {
26193
26207
  if (optionalArgs?.required) {
26194
- if (optionalArgs?.default) {
26208
+ if (optionalArgs?.default !== undefined) {
26195
26209
  this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
26196
26210
  }
26197
26211
  else {
@@ -33213,19 +33227,26 @@ class FilterMenu extends Component {
33213
33227
  .filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
33214
33228
  .map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
33215
33229
  const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
33216
- const strValues = [...cellValues, ...filterValues];
33217
- const normalizedFilteredValues = filterValues.map(toLowerCase);
33218
- // Set with lowercase values to avoid duplicates
33219
- const normalizedValues = [...new Set(strValues.map(toLowerCase))];
33220
- const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
33221
- return sortedValues.map((normalizedValue) => {
33222
- const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
33223
- -1;
33224
- return {
33225
- checked,
33226
- string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
33227
- };
33228
- });
33230
+ const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
33231
+ const set = new Set();
33232
+ const values = [];
33233
+ const addValue = (value) => {
33234
+ const normalizedValue = toLowerCase(value);
33235
+ if (!set.has(normalizedValue)) {
33236
+ values.push({
33237
+ string: value || "",
33238
+ checked: !normalizedFilteredValues.has(normalizedValue),
33239
+ normalizedValue,
33240
+ });
33241
+ set.add(normalizedValue);
33242
+ }
33243
+ };
33244
+ cellValues.forEach(addValue);
33245
+ filterValues.forEach(addValue);
33246
+ return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
33247
+ numeric: true,
33248
+ sensitivity: "base",
33249
+ }));
33229
33250
  }
33230
33251
  checkValue(value) {
33231
33252
  this.state.selectedValue = value.string;
@@ -58093,7 +58114,9 @@ class TablePlugin extends CorePlugin {
58093
58114
  const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
58094
58115
  const union = this.getters.getRangesUnion(ranges);
58095
58116
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
58096
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
58117
+ if (mergesInTarget.length) {
58118
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
58119
+ }
58097
58120
  const id = `${nextTableId++}`;
58098
58121
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
58099
58122
  const newTable = cmd.tableType === "dynamic"
@@ -58204,14 +58227,16 @@ class TablePlugin extends CorePlugin {
58204
58227
  const zoneToCheckIfEmpty = direction === "down"
58205
58228
  ? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
58206
58229
  : { ...zone, right: zone.right + 1, left: zone.right + 1 };
58207
- for (const position of positions(zoneToCheckIfEmpty)) {
58208
- const cellPosition = { sheetId, ...position };
58209
- // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
58210
- const cellContent = this.getters.getCell(cellPosition)?.content;
58211
- if (cellContent ||
58212
- this.getters.isInMerge(cellPosition) ||
58213
- this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
58214
- return "none";
58230
+ for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
58231
+ for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
58232
+ const cellPosition = { sheetId, col, row };
58233
+ // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
58234
+ const cellContent = this.getters.getCell(cellPosition)?.content;
58235
+ if (cellContent ||
58236
+ this.getters.isInMerge(cellPosition) ||
58237
+ this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
58238
+ return "none";
58239
+ }
58215
58240
  }
58216
58241
  }
58217
58242
  return direction;
@@ -67577,9 +67602,10 @@ class FilterEvaluationPlugin extends UIPlugin {
67577
67602
  const filteredZone = filter.filteredRange?.zone;
67578
67603
  if (!filteredValues || !filteredZone)
67579
67604
  continue;
67605
+ const filteredValuesSet = new Set(filteredValues);
67580
67606
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
67581
67607
  const value = this.getCellValueAsString(sheetId, filter.col, row);
67582
- if (filteredValues.includes(value)) {
67608
+ if (filteredValuesSet.has(value)) {
67583
67609
  hiddenRows.add(row);
67584
67610
  }
67585
67611
  }
@@ -76465,6 +76491,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
76465
76491
  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
76492
 
76467
76493
 
76468
- __info__.version = "18.1.24";
76469
- __info__.date = "2025-06-06T09:31:57.011Z";
76470
- __info__.hash = "0e386b2";
76494
+ __info__.version = "18.1.25";
76495
+ __info__.date = "2025-06-12T09:49:08.707Z";
76496
+ __info__.hash = "a232524";
@@ -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.24
6
- * @date 2025-06-06T09:31:57.011Z
7
- * @hash 0e386b2
5
+ * @version 18.1.25
6
+ * @date 2025-06-12T09:49:08.707Z
7
+ * @hash a232524
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -5846,7 +5846,9 @@
5846
5846
  }
5847
5847
 
5848
5848
  function evaluateLiteral(literalCell, localeFormat) {
5849
- const value = isTextFormat(localeFormat.format) ? literalCell.content : literalCell.parsedValue;
5849
+ const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
5850
+ ? literalCell.content
5851
+ : literalCell.parsedValue;
5850
5852
  const functionResult = { value, format: localeFormat.format };
5851
5853
  return createEvaluatedCell(functionResult, localeFormat.locale);
5852
5854
  }
@@ -5895,6 +5897,9 @@
5895
5897
  if (isEvaluationError(value)) {
5896
5898
  return errorCell(value, message);
5897
5899
  }
5900
+ if (value === null) {
5901
+ return emptyCell(format);
5902
+ }
5898
5903
  if (isTextFormat(format)) {
5899
5904
  // TO DO:
5900
5905
  // with the next line, the value of the cell is transformed depending on the format.
@@ -5902,9 +5907,6 @@
5902
5907
  // to interpret the value as a number.
5903
5908
  return textCell(toString(value), format, formattedValue);
5904
5909
  }
5905
- if (value === null) {
5906
- return emptyCell(format);
5907
- }
5908
5910
  if (typeof value === "number") {
5909
5911
  if (isDateTimeFormat(format || "")) {
5910
5912
  return dateTimeCell(value, format, formattedValue);
@@ -10283,10 +10285,22 @@ stores.inject(MyMetaStore, storeInstance);
10283
10285
  const midAngle = (startAngle + endAngle) / 2;
10284
10286
  const midRadius = (innerRadius + outerRadius) / 2;
10285
10287
  const x = bar.x + midRadius * Math.cos(midAngle);
10286
- const y = bar.y + midRadius * Math.sin(midAngle) + 7;
10288
+ const y = bar.y + midRadius * Math.sin(midAngle);
10289
+ const displayValue = options.callback(value, dataset, i);
10290
+ const textHeight = 12; // ChartJS default
10291
+ const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
10292
+ const radius = outerRadius - innerRadius;
10293
+ // Check if the text fits in the slice. Not perfect, but good enough heuristic.
10294
+ if (textWidth >= radius || radius < textHeight) {
10295
+ continue;
10296
+ }
10297
+ const sliceAngle = endAngle - startAngle;
10298
+ const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
10299
+ if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
10300
+ continue;
10301
+ }
10287
10302
  ctx.fillStyle = chartFontColor(options.background);
10288
10303
  ctx.strokeStyle = options.background || "#ffffff";
10289
- const displayValue = options.callback(value, dataset, i);
10290
10304
  drawTextWithBackground(displayValue, x, y, ctx);
10291
10305
  }
10292
10306
  }
@@ -26192,7 +26206,7 @@ stores.inject(MyMetaStore, storeInstance);
26192
26206
  */
26193
26207
  handleMissingValue(parentElement, missingElementName, optionalArgs) {
26194
26208
  if (optionalArgs?.required) {
26195
- if (optionalArgs?.default) {
26209
+ if (optionalArgs?.default !== undefined) {
26196
26210
  this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
26197
26211
  }
26198
26212
  else {
@@ -33214,19 +33228,26 @@ stores.inject(MyMetaStore, storeInstance);
33214
33228
  .filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
33215
33229
  .map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
33216
33230
  const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
33217
- const strValues = [...cellValues, ...filterValues];
33218
- const normalizedFilteredValues = filterValues.map(toLowerCase);
33219
- // Set with lowercase values to avoid duplicates
33220
- const normalizedValues = [...new Set(strValues.map(toLowerCase))];
33221
- const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
33222
- return sortedValues.map((normalizedValue) => {
33223
- const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
33224
- -1;
33225
- return {
33226
- checked,
33227
- string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
33228
- };
33229
- });
33231
+ const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
33232
+ const set = new Set();
33233
+ const values = [];
33234
+ const addValue = (value) => {
33235
+ const normalizedValue = toLowerCase(value);
33236
+ if (!set.has(normalizedValue)) {
33237
+ values.push({
33238
+ string: value || "",
33239
+ checked: !normalizedFilteredValues.has(normalizedValue),
33240
+ normalizedValue,
33241
+ });
33242
+ set.add(normalizedValue);
33243
+ }
33244
+ };
33245
+ cellValues.forEach(addValue);
33246
+ filterValues.forEach(addValue);
33247
+ return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
33248
+ numeric: true,
33249
+ sensitivity: "base",
33250
+ }));
33230
33251
  }
33231
33252
  checkValue(value) {
33232
33253
  this.state.selectedValue = value.string;
@@ -58094,7 +58115,9 @@ stores.inject(MyMetaStore, storeInstance);
58094
58115
  const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
58095
58116
  const union = this.getters.getRangesUnion(ranges);
58096
58117
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
58097
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
58118
+ if (mergesInTarget.length) {
58119
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
58120
+ }
58098
58121
  const id = `${nextTableId++}`;
58099
58122
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
58100
58123
  const newTable = cmd.tableType === "dynamic"
@@ -58205,14 +58228,16 @@ stores.inject(MyMetaStore, storeInstance);
58205
58228
  const zoneToCheckIfEmpty = direction === "down"
58206
58229
  ? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
58207
58230
  : { ...zone, right: zone.right + 1, left: zone.right + 1 };
58208
- for (const position of positions(zoneToCheckIfEmpty)) {
58209
- const cellPosition = { sheetId, ...position };
58210
- // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
58211
- const cellContent = this.getters.getCell(cellPosition)?.content;
58212
- if (cellContent ||
58213
- this.getters.isInMerge(cellPosition) ||
58214
- this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
58215
- return "none";
58231
+ for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
58232
+ for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
58233
+ const cellPosition = { sheetId, col, row };
58234
+ // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
58235
+ const cellContent = this.getters.getCell(cellPosition)?.content;
58236
+ if (cellContent ||
58237
+ this.getters.isInMerge(cellPosition) ||
58238
+ this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
58239
+ return "none";
58240
+ }
58216
58241
  }
58217
58242
  }
58218
58243
  return direction;
@@ -67578,9 +67603,10 @@ stores.inject(MyMetaStore, storeInstance);
67578
67603
  const filteredZone = filter.filteredRange?.zone;
67579
67604
  if (!filteredValues || !filteredZone)
67580
67605
  continue;
67606
+ const filteredValuesSet = new Set(filteredValues);
67581
67607
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
67582
67608
  const value = this.getCellValueAsString(sheetId, filter.col, row);
67583
- if (filteredValues.includes(value)) {
67609
+ if (filteredValuesSet.has(value)) {
67584
67610
  hiddenRows.add(row);
67585
67611
  }
67586
67612
  }
@@ -76510,9 +76536,9 @@ stores.inject(MyMetaStore, storeInstance);
76510
76536
  exports.tokenize = tokenize;
76511
76537
 
76512
76538
 
76513
- __info__.version = "18.1.24";
76514
- __info__.date = "2025-06-06T09:31:57.011Z";
76515
- __info__.hash = "0e386b2";
76539
+ __info__.version = "18.1.25";
76540
+ __info__.date = "2025-06-12T09:49:08.707Z";
76541
+ __info__.hash = "a232524";
76516
76542
 
76517
76543
 
76518
76544
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);