@odoo/o-spreadsheet 18.0.32 → 18.0.33

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.0.32
6
- * @date 2025-06-06T09:29:16.581Z
7
- * @hash bef1e2b
5
+ * @version 18.0.33
6
+ * @date 2025-06-12T09:17:53.747Z
7
+ * @hash c1d64fb
8
8
  */
9
9
 
10
10
  'use strict';
@@ -5678,7 +5678,9 @@ function isTextFormat(format) {
5678
5678
  }
5679
5679
 
5680
5680
  function evaluateLiteral(literalCell, localeFormat) {
5681
- const value = isTextFormat(localeFormat.format) ? literalCell.content : literalCell.parsedValue;
5681
+ const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
5682
+ ? literalCell.content
5683
+ : literalCell.parsedValue;
5682
5684
  const functionResult = { value, format: localeFormat.format };
5683
5685
  return createEvaluatedCell(functionResult, localeFormat.locale);
5684
5686
  }
@@ -5727,6 +5729,9 @@ function _createEvaluatedCell(functionResult, locale, cell) {
5727
5729
  if (isEvaluationError(value)) {
5728
5730
  return errorCell(value, message);
5729
5731
  }
5732
+ if (value === null) {
5733
+ return emptyCell(format);
5734
+ }
5730
5735
  if (isTextFormat(format)) {
5731
5736
  // TO DO:
5732
5737
  // with the next line, the value of the cell is transformed depending on the format.
@@ -5734,9 +5739,6 @@ function _createEvaluatedCell(functionResult, locale, cell) {
5734
5739
  // to interpret the value as a number.
5735
5740
  return textCell(toString(value), format, formattedValue);
5736
5741
  }
5737
- if (value === null) {
5738
- return emptyCell(format);
5739
- }
5740
5742
  if (typeof value === "number") {
5741
5743
  if (isDateTimeFormat(format || "")) {
5742
5744
  return dateTimeCell(value, format, formattedValue);
@@ -10172,10 +10174,22 @@ function drawPieChartValues(chart, options, ctx) {
10172
10174
  const midAngle = (startAngle + endAngle) / 2;
10173
10175
  const midRadius = (innerRadius + outerRadius) / 2;
10174
10176
  const x = bar.x + midRadius * Math.cos(midAngle);
10175
- const y = bar.y + midRadius * Math.sin(midAngle) + 7;
10177
+ const y = bar.y + midRadius * Math.sin(midAngle);
10178
+ const displayValue = options.callback(value, dataset, i);
10179
+ const textHeight = 12; // ChartJS default
10180
+ const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
10181
+ const radius = outerRadius - innerRadius;
10182
+ // Check if the text fits in the slice. Not perfect, but good enough heuristic.
10183
+ if (textWidth >= radius || radius < textHeight) {
10184
+ continue;
10185
+ }
10186
+ const sliceAngle = endAngle - startAngle;
10187
+ const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
10188
+ if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
10189
+ continue;
10190
+ }
10176
10191
  ctx.fillStyle = chartFontColor(options.background);
10177
10192
  ctx.strokeStyle = options.background || "#ffffff";
10178
- const displayValue = options.callback(value, dataset, i);
10179
10193
  drawTextWithBackground(displayValue, x, y, ctx);
10180
10194
  }
10181
10195
  }
@@ -13392,7 +13406,7 @@ class XlsxBaseExtractor {
13392
13406
  */
13393
13407
  handleMissingValue(parentElement, missingElementName, optionalArgs) {
13394
13408
  if (optionalArgs?.required) {
13395
- if (optionalArgs?.default) {
13409
+ if (optionalArgs?.default !== undefined) {
13396
13410
  this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
13397
13411
  }
13398
13412
  else {
@@ -32518,19 +32532,26 @@ class FilterMenu extends owl.Component {
32518
32532
  .filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
32519
32533
  .map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
32520
32534
  const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
32521
- const strValues = [...cellValues, ...filterValues];
32522
- const normalizedFilteredValues = filterValues.map(toLowerCase);
32523
- // Set with lowercase values to avoid duplicates
32524
- const normalizedValues = [...new Set(strValues.map(toLowerCase))];
32525
- const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
32526
- return sortedValues.map((normalizedValue) => {
32527
- const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
32528
- -1;
32529
- return {
32530
- checked,
32531
- string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
32532
- };
32533
- });
32535
+ const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
32536
+ const set = new Set();
32537
+ const values = [];
32538
+ const addValue = (value) => {
32539
+ const normalizedValue = toLowerCase(value);
32540
+ if (!set.has(normalizedValue)) {
32541
+ values.push({
32542
+ string: value || "",
32543
+ checked: !normalizedFilteredValues.has(normalizedValue),
32544
+ normalizedValue,
32545
+ });
32546
+ set.add(normalizedValue);
32547
+ }
32548
+ };
32549
+ cellValues.forEach(addValue);
32550
+ filterValues.forEach(addValue);
32551
+ return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
32552
+ numeric: true,
32553
+ sensitivity: "base",
32554
+ }));
32534
32555
  }
32535
32556
  checkValue(value) {
32536
32557
  this.state.selectedValue = value.string;
@@ -56029,7 +56050,9 @@ class TablePlugin extends CorePlugin {
56029
56050
  const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
56030
56051
  const union = this.getters.getRangesUnion(ranges);
56031
56052
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
56032
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
56053
+ if (mergesInTarget.length) {
56054
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
56055
+ }
56033
56056
  const id = this.uuidGenerator.smallUuid();
56034
56057
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
56035
56058
  const newTable = cmd.tableType === "dynamic"
@@ -56140,14 +56163,16 @@ class TablePlugin extends CorePlugin {
56140
56163
  const zoneToCheckIfEmpty = direction === "down"
56141
56164
  ? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
56142
56165
  : { ...zone, right: zone.right + 1, left: zone.right + 1 };
56143
- for (const position of positions(zoneToCheckIfEmpty)) {
56144
- const cellPosition = { sheetId, ...position };
56145
- // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
56146
- const cellContent = this.getters.getCell(cellPosition)?.content;
56147
- if (cellContent ||
56148
- this.getters.isInMerge(cellPosition) ||
56149
- this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
56150
- return "none";
56166
+ for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
56167
+ for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
56168
+ const cellPosition = { sheetId, col, row };
56169
+ // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
56170
+ const cellContent = this.getters.getCell(cellPosition)?.content;
56171
+ if (cellContent ||
56172
+ this.getters.isInMerge(cellPosition) ||
56173
+ this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
56174
+ return "none";
56175
+ }
56151
56176
  }
56152
56177
  }
56153
56178
  return direction;
@@ -65472,9 +65497,10 @@ class FilterEvaluationPlugin extends UIPlugin {
65472
65497
  const filteredZone = filter.filteredRange?.zone;
65473
65498
  if (!filteredValues || !filteredZone)
65474
65499
  continue;
65500
+ const filteredValuesSet = new Set(filteredValues);
65475
65501
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
65476
65502
  const value = this.getCellValueAsString(sheetId, filter.col, row);
65477
- if (filteredValues.includes(value)) {
65503
+ if (filteredValuesSet.has(value)) {
65478
65504
  hiddenRows.add(row);
65479
65505
  }
65480
65506
  }
@@ -74421,6 +74447,6 @@ exports.tokenColors = tokenColors;
74421
74447
  exports.tokenize = tokenize;
74422
74448
 
74423
74449
 
74424
- __info__.version = "18.0.32";
74425
- __info__.date = "2025-06-06T09:29:16.581Z";
74426
- __info__.hash = "bef1e2b";
74450
+ __info__.version = "18.0.33";
74451
+ __info__.date = "2025-06-12T09:17:53.747Z";
74452
+ __info__.hash = "c1d64fb";
@@ -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.0.32
6
- * @date 2025-06-06T09:29:16.581Z
7
- * @hash bef1e2b
5
+ * @version 18.0.33
6
+ * @date 2025-06-12T09:17:53.747Z
7
+ * @hash c1d64fb
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';
@@ -5676,7 +5676,9 @@ function isTextFormat(format) {
5676
5676
  }
5677
5677
 
5678
5678
  function evaluateLiteral(literalCell, localeFormat) {
5679
- const value = isTextFormat(localeFormat.format) ? literalCell.content : literalCell.parsedValue;
5679
+ const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
5680
+ ? literalCell.content
5681
+ : literalCell.parsedValue;
5680
5682
  const functionResult = { value, format: localeFormat.format };
5681
5683
  return createEvaluatedCell(functionResult, localeFormat.locale);
5682
5684
  }
@@ -5725,6 +5727,9 @@ function _createEvaluatedCell(functionResult, locale, cell) {
5725
5727
  if (isEvaluationError(value)) {
5726
5728
  return errorCell(value, message);
5727
5729
  }
5730
+ if (value === null) {
5731
+ return emptyCell(format);
5732
+ }
5728
5733
  if (isTextFormat(format)) {
5729
5734
  // TO DO:
5730
5735
  // with the next line, the value of the cell is transformed depending on the format.
@@ -5732,9 +5737,6 @@ function _createEvaluatedCell(functionResult, locale, cell) {
5732
5737
  // to interpret the value as a number.
5733
5738
  return textCell(toString(value), format, formattedValue);
5734
5739
  }
5735
- if (value === null) {
5736
- return emptyCell(format);
5737
- }
5738
5740
  if (typeof value === "number") {
5739
5741
  if (isDateTimeFormat(format || "")) {
5740
5742
  return dateTimeCell(value, format, formattedValue);
@@ -10170,10 +10172,22 @@ function drawPieChartValues(chart, options, ctx) {
10170
10172
  const midAngle = (startAngle + endAngle) / 2;
10171
10173
  const midRadius = (innerRadius + outerRadius) / 2;
10172
10174
  const x = bar.x + midRadius * Math.cos(midAngle);
10173
- const y = bar.y + midRadius * Math.sin(midAngle) + 7;
10175
+ const y = bar.y + midRadius * Math.sin(midAngle);
10176
+ const displayValue = options.callback(value, dataset, i);
10177
+ const textHeight = 12; // ChartJS default
10178
+ const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
10179
+ const radius = outerRadius - innerRadius;
10180
+ // Check if the text fits in the slice. Not perfect, but good enough heuristic.
10181
+ if (textWidth >= radius || radius < textHeight) {
10182
+ continue;
10183
+ }
10184
+ const sliceAngle = endAngle - startAngle;
10185
+ const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
10186
+ if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
10187
+ continue;
10188
+ }
10174
10189
  ctx.fillStyle = chartFontColor(options.background);
10175
10190
  ctx.strokeStyle = options.background || "#ffffff";
10176
- const displayValue = options.callback(value, dataset, i);
10177
10191
  drawTextWithBackground(displayValue, x, y, ctx);
10178
10192
  }
10179
10193
  }
@@ -13390,7 +13404,7 @@ class XlsxBaseExtractor {
13390
13404
  */
13391
13405
  handleMissingValue(parentElement, missingElementName, optionalArgs) {
13392
13406
  if (optionalArgs?.required) {
13393
- if (optionalArgs?.default) {
13407
+ if (optionalArgs?.default !== undefined) {
13394
13408
  this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
13395
13409
  }
13396
13410
  else {
@@ -32516,19 +32530,26 @@ class FilterMenu extends Component {
32516
32530
  .filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
32517
32531
  .map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
32518
32532
  const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
32519
- const strValues = [...cellValues, ...filterValues];
32520
- const normalizedFilteredValues = filterValues.map(toLowerCase);
32521
- // Set with lowercase values to avoid duplicates
32522
- const normalizedValues = [...new Set(strValues.map(toLowerCase))];
32523
- const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
32524
- return sortedValues.map((normalizedValue) => {
32525
- const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
32526
- -1;
32527
- return {
32528
- checked,
32529
- string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
32530
- };
32531
- });
32533
+ const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
32534
+ const set = new Set();
32535
+ const values = [];
32536
+ const addValue = (value) => {
32537
+ const normalizedValue = toLowerCase(value);
32538
+ if (!set.has(normalizedValue)) {
32539
+ values.push({
32540
+ string: value || "",
32541
+ checked: !normalizedFilteredValues.has(normalizedValue),
32542
+ normalizedValue,
32543
+ });
32544
+ set.add(normalizedValue);
32545
+ }
32546
+ };
32547
+ cellValues.forEach(addValue);
32548
+ filterValues.forEach(addValue);
32549
+ return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
32550
+ numeric: true,
32551
+ sensitivity: "base",
32552
+ }));
32532
32553
  }
32533
32554
  checkValue(value) {
32534
32555
  this.state.selectedValue = value.string;
@@ -56027,7 +56048,9 @@ class TablePlugin extends CorePlugin {
56027
56048
  const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
56028
56049
  const union = this.getters.getRangesUnion(ranges);
56029
56050
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
56030
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
56051
+ if (mergesInTarget.length) {
56052
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
56053
+ }
56031
56054
  const id = this.uuidGenerator.smallUuid();
56032
56055
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
56033
56056
  const newTable = cmd.tableType === "dynamic"
@@ -56138,14 +56161,16 @@ class TablePlugin extends CorePlugin {
56138
56161
  const zoneToCheckIfEmpty = direction === "down"
56139
56162
  ? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
56140
56163
  : { ...zone, right: zone.right + 1, left: zone.right + 1 };
56141
- for (const position of positions(zoneToCheckIfEmpty)) {
56142
- const cellPosition = { sheetId, ...position };
56143
- // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
56144
- const cellContent = this.getters.getCell(cellPosition)?.content;
56145
- if (cellContent ||
56146
- this.getters.isInMerge(cellPosition) ||
56147
- this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
56148
- return "none";
56164
+ for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
56165
+ for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
56166
+ const cellPosition = { sheetId, col, row };
56167
+ // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
56168
+ const cellContent = this.getters.getCell(cellPosition)?.content;
56169
+ if (cellContent ||
56170
+ this.getters.isInMerge(cellPosition) ||
56171
+ this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
56172
+ return "none";
56173
+ }
56149
56174
  }
56150
56175
  }
56151
56176
  return direction;
@@ -65470,9 +65495,10 @@ class FilterEvaluationPlugin extends UIPlugin {
65470
65495
  const filteredZone = filter.filteredRange?.zone;
65471
65496
  if (!filteredValues || !filteredZone)
65472
65497
  continue;
65498
+ const filteredValuesSet = new Set(filteredValues);
65473
65499
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
65474
65500
  const value = this.getCellValueAsString(sheetId, filter.col, row);
65475
- if (filteredValues.includes(value)) {
65501
+ if (filteredValuesSet.has(value)) {
65476
65502
  hiddenRows.add(row);
65477
65503
  }
65478
65504
  }
@@ -74376,6 +74402,6 @@ const constants = {
74376
74402
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, 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 };
74377
74403
 
74378
74404
 
74379
- __info__.version = "18.0.32";
74380
- __info__.date = "2025-06-06T09:29:16.581Z";
74381
- __info__.hash = "bef1e2b";
74405
+ __info__.version = "18.0.33";
74406
+ __info__.date = "2025-06-12T09:17:53.747Z";
74407
+ __info__.hash = "c1d64fb";
@@ -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.0.32
6
- * @date 2025-06-06T09:29:16.581Z
7
- * @hash bef1e2b
5
+ * @version 18.0.33
6
+ * @date 2025-06-12T09:17:53.747Z
7
+ * @hash c1d64fb
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -5677,7 +5677,9 @@
5677
5677
  }
5678
5678
 
5679
5679
  function evaluateLiteral(literalCell, localeFormat) {
5680
- const value = isTextFormat(localeFormat.format) ? literalCell.content : literalCell.parsedValue;
5680
+ const value = isTextFormat(localeFormat.format) && literalCell.parsedValue !== null
5681
+ ? literalCell.content
5682
+ : literalCell.parsedValue;
5681
5683
  const functionResult = { value, format: localeFormat.format };
5682
5684
  return createEvaluatedCell(functionResult, localeFormat.locale);
5683
5685
  }
@@ -5726,6 +5728,9 @@
5726
5728
  if (isEvaluationError(value)) {
5727
5729
  return errorCell(value, message);
5728
5730
  }
5731
+ if (value === null) {
5732
+ return emptyCell(format);
5733
+ }
5729
5734
  if (isTextFormat(format)) {
5730
5735
  // TO DO:
5731
5736
  // with the next line, the value of the cell is transformed depending on the format.
@@ -5733,9 +5738,6 @@
5733
5738
  // to interpret the value as a number.
5734
5739
  return textCell(toString(value), format, formattedValue);
5735
5740
  }
5736
- if (value === null) {
5737
- return emptyCell(format);
5738
- }
5739
5741
  if (typeof value === "number") {
5740
5742
  if (isDateTimeFormat(format || "")) {
5741
5743
  return dateTimeCell(value, format, formattedValue);
@@ -10171,10 +10173,22 @@ stores.inject(MyMetaStore, storeInstance);
10171
10173
  const midAngle = (startAngle + endAngle) / 2;
10172
10174
  const midRadius = (innerRadius + outerRadius) / 2;
10173
10175
  const x = bar.x + midRadius * Math.cos(midAngle);
10174
- const y = bar.y + midRadius * Math.sin(midAngle) + 7;
10176
+ const y = bar.y + midRadius * Math.sin(midAngle);
10177
+ const displayValue = options.callback(value, dataset, i);
10178
+ const textHeight = 12; // ChartJS default
10179
+ const textWidth = computeTextWidth(ctx, displayValue, { fontSize: textHeight }, "px");
10180
+ const radius = outerRadius - innerRadius;
10181
+ // Check if the text fits in the slice. Not perfect, but good enough heuristic.
10182
+ if (textWidth >= radius || radius < textHeight) {
10183
+ continue;
10184
+ }
10185
+ const sliceAngle = endAngle - startAngle;
10186
+ const midWidth = 2 * midRadius * Math.tan(sliceAngle / 2);
10187
+ if (sliceAngle < Math.PI / 2 && (textWidth >= midWidth || midWidth < textHeight)) {
10188
+ continue;
10189
+ }
10175
10190
  ctx.fillStyle = chartFontColor(options.background);
10176
10191
  ctx.strokeStyle = options.background || "#ffffff";
10177
- const displayValue = options.callback(value, dataset, i);
10178
10192
  drawTextWithBackground(displayValue, x, y, ctx);
10179
10193
  }
10180
10194
  }
@@ -13391,7 +13405,7 @@ stores.inject(MyMetaStore, storeInstance);
13391
13405
  */
13392
13406
  handleMissingValue(parentElement, missingElementName, optionalArgs) {
13393
13407
  if (optionalArgs?.required) {
13394
- if (optionalArgs?.default) {
13408
+ if (optionalArgs?.default !== undefined) {
13395
13409
  this.warningManager.addParsingWarning(`Missing required ${missingElementName} in element <${parentElement.tagName}> of ${this.currentFile}, replacing it by the default value ${optionalArgs.default}`);
13396
13410
  }
13397
13411
  else {
@@ -32517,19 +32531,26 @@ stores.inject(MyMetaStore, storeInstance);
32517
32531
  .filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
32518
32532
  .map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
32519
32533
  const filterValues = this.env.model.getters.getFilterHiddenValues({ sheetId, ...position });
32520
- const strValues = [...cellValues, ...filterValues];
32521
- const normalizedFilteredValues = filterValues.map(toLowerCase);
32522
- // Set with lowercase values to avoid duplicates
32523
- const normalizedValues = [...new Set(strValues.map(toLowerCase))];
32524
- const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
32525
- return sortedValues.map((normalizedValue) => {
32526
- const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
32527
- -1;
32528
- return {
32529
- checked,
32530
- string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
32531
- };
32532
- });
32534
+ const normalizedFilteredValues = new Set(filterValues.map(toLowerCase));
32535
+ const set = new Set();
32536
+ const values = [];
32537
+ const addValue = (value) => {
32538
+ const normalizedValue = toLowerCase(value);
32539
+ if (!set.has(normalizedValue)) {
32540
+ values.push({
32541
+ string: value || "",
32542
+ checked: !normalizedFilteredValues.has(normalizedValue),
32543
+ normalizedValue,
32544
+ });
32545
+ set.add(normalizedValue);
32546
+ }
32547
+ };
32548
+ cellValues.forEach(addValue);
32549
+ filterValues.forEach(addValue);
32550
+ return values.sort((val1, val2) => val1.normalizedValue.localeCompare(val2.normalizedValue, undefined, {
32551
+ numeric: true,
32552
+ sensitivity: "base",
32553
+ }));
32533
32554
  }
32534
32555
  checkValue(value) {
32535
32556
  this.state.selectedValue = value.string;
@@ -56028,7 +56049,9 @@ stores.inject(MyMetaStore, storeInstance);
56028
56049
  const ranges = cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData));
56029
56050
  const union = this.getters.getRangesUnion(ranges);
56030
56051
  const mergesInTarget = this.getters.getMergesInZone(cmd.sheetId, union.zone);
56031
- this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
56052
+ if (mergesInTarget.length) {
56053
+ this.dispatch("REMOVE_MERGE", { sheetId: cmd.sheetId, target: mergesInTarget });
56054
+ }
56032
56055
  const id = this.uuidGenerator.smallUuid();
56033
56056
  const config = cmd.config || DEFAULT_TABLE_CONFIG;
56034
56057
  const newTable = cmd.tableType === "dynamic"
@@ -56139,14 +56162,16 @@ stores.inject(MyMetaStore, storeInstance);
56139
56162
  const zoneToCheckIfEmpty = direction === "down"
56140
56163
  ? { ...zone, bottom: zone.bottom + 1, top: zone.bottom + 1 }
56141
56164
  : { ...zone, right: zone.right + 1, left: zone.right + 1 };
56142
- for (const position of positions(zoneToCheckIfEmpty)) {
56143
- const cellPosition = { sheetId, ...position };
56144
- // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
56145
- const cellContent = this.getters.getCell(cellPosition)?.content;
56146
- if (cellContent ||
56147
- this.getters.isInMerge(cellPosition) ||
56148
- this.getTablesOverlappingZones(sheetId, [positionToZone(position)]).length) {
56149
- return "none";
56165
+ for (let row = zoneToCheckIfEmpty.top; row <= zoneToCheckIfEmpty.bottom; row++) {
56166
+ for (let col = zoneToCheckIfEmpty.left; col <= zoneToCheckIfEmpty.right; col++) {
56167
+ const cellPosition = { sheetId, col, row };
56168
+ // Since this plugin is loaded before CellPlugin, the getters still give us the old cell content
56169
+ const cellContent = this.getters.getCell(cellPosition)?.content;
56170
+ if (cellContent ||
56171
+ this.getters.isInMerge(cellPosition) ||
56172
+ this.getTablesOverlappingZones(sheetId, [positionToZone(cellPosition)]).length) {
56173
+ return "none";
56174
+ }
56150
56175
  }
56151
56176
  }
56152
56177
  return direction;
@@ -65471,9 +65496,10 @@ stores.inject(MyMetaStore, storeInstance);
65471
65496
  const filteredZone = filter.filteredRange?.zone;
65472
65497
  if (!filteredValues || !filteredZone)
65473
65498
  continue;
65499
+ const filteredValuesSet = new Set(filteredValues);
65474
65500
  for (let row = filteredZone.top; row <= filteredZone.bottom; row++) {
65475
65501
  const value = this.getCellValueAsString(sheetId, filter.col, row);
65476
- if (filteredValues.includes(value)) {
65502
+ if (filteredValuesSet.has(value)) {
65477
65503
  hiddenRows.add(row);
65478
65504
  }
65479
65505
  }
@@ -74420,9 +74446,9 @@ stores.inject(MyMetaStore, storeInstance);
74420
74446
  exports.tokenize = tokenize;
74421
74447
 
74422
74448
 
74423
- __info__.version = "18.0.32";
74424
- __info__.date = "2025-06-06T09:29:16.581Z";
74425
- __info__.hash = "bef1e2b";
74449
+ __info__.version = "18.0.33";
74450
+ __info__.date = "2025-06-12T09:17:53.747Z";
74451
+ __info__.hash = "c1d64fb";
74426
74452
 
74427
74453
 
74428
74454
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);