@odoo/o-spreadsheet 19.0.0 → 19.0.3

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 19.0.0
6
- * @date 2025-09-11T07:18:49.704Z
7
- * @hash 0ac0e86
5
+ * @version 19.0.3
6
+ * @date 2025-09-19T07:26:41.356Z
7
+ * @hash 84f3b74
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, useExternalListener, onWillUpdateProps, onWillStart, onWillPatch, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -888,6 +888,7 @@ const tokenColors = {
888
888
  ARG_SEPARATOR: functionColor,
889
889
  ORPHAN_RIGHT_PAREN: "#ff0000",
890
890
  };
891
+ const DRAG_THRESHOLD = 5; // in pixels, to avoid unwanted drag when clicking
891
892
 
892
893
  //------------------------------------------------------------------------------
893
894
  // Miscellaneous
@@ -1366,8 +1367,19 @@ function memoize(func) {
1366
1367
  },
1367
1368
  }[funcName];
1368
1369
  }
1370
+ /**
1371
+ * Removes the specified indexes from the array.
1372
+ * Sparse (empty) elements are transformed to undefined (unless their index is explicitly removed).
1373
+ */
1369
1374
  function removeIndexesFromArray(array, indexes) {
1370
- return array.filter((_, index) => !indexes.includes(index));
1375
+ const toRemove = new Set(indexes);
1376
+ const newArray = [];
1377
+ for (let i = 0; i < array.length; i++) {
1378
+ if (!toRemove.has(i)) {
1379
+ newArray.push(array[i]);
1380
+ }
1381
+ }
1382
+ return newArray;
1371
1383
  }
1372
1384
  function insertItemsAtIndex(array, items, index) {
1373
1385
  const newArray = [...array];
@@ -16082,8 +16094,9 @@ function interactiveSort(env, sheetId, anchor, zone, sortDirection, sortOptions)
16082
16094
  }
16083
16095
 
16084
16096
  function sortMatrix(matrix, locale, ...criteria) {
16085
- for (const [i, value] of criteria.entries()) {
16086
- assert(value !== undefined, _t("Value for parameter %d is missing, while the function [[FUNCTION_NAME]] expect a number or a range.", i + 1));
16097
+ for (let i = 0; i < criteria.length; i++) {
16098
+ const param = i % 2 === 0 ? "sort_column" : "is_ascending";
16099
+ assert(criteria[i] !== undefined, _t("Value for parameter %s is missing in [[FUNCTION_NAME]].", param));
16087
16100
  }
16088
16101
  const sortingOrders = [];
16089
16102
  const sortColumns = [];
@@ -24537,18 +24550,15 @@ function createScorecardChartRuntime(chart, getters) {
24537
24550
  return {
24538
24551
  title: {
24539
24552
  ...chart.title,
24540
- // chart titles are extracted from .json files and they are translated at runtime here
24541
- text: chart.title.text ? _t(chart.title.text) : "",
24553
+ text: chart.title.text ? getters.dynamicTranslate(chart.title.text) : "",
24542
24554
  },
24543
24555
  keyValue: formattedKeyValue,
24544
- keyDescr: chart.keyDescr?.text
24545
- ? _t(chart.keyDescr.text) // descriptions are extracted from .json files and they are translated at runtime here
24546
- : "",
24556
+ keyDescr: chart.keyDescr?.text ? getters.dynamicTranslate(chart.keyDescr.text) : "",
24547
24557
  baselineDisplay,
24548
24558
  baselineArrow: getBaselineArrowDirection(baselineCell, keyValueCell, chart.baselineMode),
24549
24559
  baselineColor: getBaselineColor(baselineCell, chart.baselineMode, keyValueCell, chart.baselineColorUp, chart.baselineColorDown),
24550
24560
  baselineDescr: chart.baselineMode !== "progress" && chart.baselineDescr?.text
24551
- ? _t(chart.baselineDescr.text) // descriptions are extracted from .json files and they are translated at runtime here
24561
+ ? getters.dynamicTranslate(chart.baselineDescr.text)
24552
24562
  : "",
24553
24563
  fontColor,
24554
24564
  background,
@@ -24848,9 +24858,8 @@ class ScorecardChart extends Component {
24848
24858
  return this.env.model.getters.getChartRuntime(this.props.chartId);
24849
24859
  }
24850
24860
  get title() {
24851
- const title = this.env.model.getters.getChartDefinition(this.props.chartId).title.text ?? "";
24852
- // chart titles are extracted from .json files and they are translated at runtime here
24853
- return _t(title);
24861
+ const title = this.env.model.getters.getChartDefinition(this.props.chartId).title.text;
24862
+ return title ? this.env.model.getters.dynamicTranslate(title) : "";
24854
24863
  }
24855
24864
  setup() {
24856
24865
  useEffect(this.createChart.bind(this), () => {
@@ -27023,12 +27032,12 @@ function getDatasetAxisId(definition, dataset) {
27023
27032
  return axisId || "y";
27024
27033
  }
27025
27034
 
27026
- function getChartTitle(definition) {
27035
+ function getChartTitle(definition, getters) {
27027
27036
  const chartTitle = definition.title;
27028
27037
  const fontColor = chartMutedFontColor(definition.background);
27029
27038
  return {
27030
27039
  display: !!chartTitle.text,
27031
- text: _t(chartTitle.text),
27040
+ text: chartTitle.text ? getters.dynamicTranslate(chartTitle.text) : "",
27032
27041
  color: chartTitle?.color ?? fontColor,
27033
27042
  align: chartTitle.align === "center" ? "center" : chartTitle.align === "right" ? "end" : "start",
27034
27043
  font: {
@@ -27596,7 +27605,7 @@ function createBarChartRuntime(chart, getters) {
27596
27605
  layout: getChartLayout(definition, chartData),
27597
27606
  scales: getBarChartScales(definition, chartData),
27598
27607
  plugins: {
27599
- title: getChartTitle(definition),
27608
+ title: getChartTitle(definition, getters),
27600
27609
  legend: getBarChartLegend(definition),
27601
27610
  tooltip: getBarChartTooltip(definition, chartData),
27602
27611
  chartShowValuesPlugin: getChartShowValues(definition, chartData),
@@ -28827,7 +28836,7 @@ function createComboChartRuntime(chart, getters) {
28827
28836
  layout: getChartLayout(definition, chartData),
28828
28837
  scales: getBarChartScales(definition, chartData),
28829
28838
  plugins: {
28830
- title: getChartTitle(definition),
28839
+ title: getChartTitle(definition, getters),
28831
28840
  legend: getComboChartLegend(definition),
28832
28841
  tooltip: getBarChartTooltip(definition, chartData),
28833
28842
  chartShowValuesPlugin: getChartShowValues(definition, chartData),
@@ -28973,7 +28982,7 @@ function createFunnelChartRuntime(chart, getters) {
28973
28982
  layout: getChartLayout(definition, chartData),
28974
28983
  scales: getFunnelChartScales(definition, chartData),
28975
28984
  plugins: {
28976
- title: getChartTitle(definition),
28985
+ title: getChartTitle(definition, getters),
28977
28986
  legend: { display: false },
28978
28987
  tooltip: getFunnelChartTooltip(definition, chartData),
28979
28988
  chartShowValuesPlugin: getChartShowValues(definition, chartData),
@@ -29210,8 +29219,7 @@ function createGaugeChartRuntime(chart, getters) {
29210
29219
  background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
29211
29220
  title: {
29212
29221
  ...chart.title,
29213
- // chart titles are extracted from .json files and they are translated at runtime here
29214
- text: _t(chart.title.text ?? ""),
29222
+ text: chart.title.text ? getters.dynamicTranslate(chart.title.text) : "",
29215
29223
  },
29216
29224
  minValue: {
29217
29225
  value: minValue,
@@ -29395,7 +29403,7 @@ function createGeoChartRuntime(chart, getters) {
29395
29403
  layout: getChartLayout(definition, chartData),
29396
29404
  scales: getGeoChartScales(definition, chartData),
29397
29405
  plugins: {
29398
- title: getChartTitle(definition),
29406
+ title: getChartTitle(definition, getters),
29399
29407
  tooltip: getGeoChartTooltip(definition, chartData),
29400
29408
  legend: { display: false },
29401
29409
  },
@@ -29560,7 +29568,7 @@ function createLineChartRuntime(chart, getters) {
29560
29568
  layout: getChartLayout(definition, chartData),
29561
29569
  scales: getLineChartScales(definition, chartData),
29562
29570
  plugins: {
29563
- title: getChartTitle(definition),
29571
+ title: getChartTitle(definition, getters),
29564
29572
  legend: getLineChartLegend(definition),
29565
29573
  tooltip: getLineChartTooltip(definition, chartData),
29566
29574
  chartShowValuesPlugin: getChartShowValues(definition, chartData),
@@ -29697,7 +29705,7 @@ function createPieChartRuntime(chart, getters) {
29697
29705
  : undefined,
29698
29706
  layout: getChartLayout(definition, chartData),
29699
29707
  plugins: {
29700
- title: getChartTitle(definition),
29708
+ title: getChartTitle(definition, getters),
29701
29709
  legend: getPieChartLegend(definition, chartData),
29702
29710
  tooltip: getPieChartTooltip(definition, chartData),
29703
29711
  chartShowValuesPlugin: getChartShowValues(definition, chartData),
@@ -29851,7 +29859,7 @@ function createPyramidChartRuntime(chart, getters) {
29851
29859
  layout: getChartLayout(definition, chartData),
29852
29860
  scales: getPyramidChartScales(definition, chartData),
29853
29861
  plugins: {
29854
- title: getChartTitle(definition),
29862
+ title: getChartTitle(definition, getters),
29855
29863
  legend: getBarChartLegend(definition),
29856
29864
  tooltip: getPyramidChartTooltip(definition, chartData),
29857
29865
  chartShowValuesPlugin: getPyramidChartShowValues(definition, chartData),
@@ -30000,7 +30008,7 @@ function createRadarChartRuntime(chart, getters) {
30000
30008
  layout: getChartLayout(definition, chartData),
30001
30009
  scales: getRadarChartScales(definition, chartData),
30002
30010
  plugins: {
30003
- title: getChartTitle(definition),
30011
+ title: getChartTitle(definition, getters),
30004
30012
  legend: getRadarChartLegend(definition),
30005
30013
  tooltip: getRadarChartTooltip(definition, chartData),
30006
30014
  chartShowValuesPlugin: getChartShowValues(definition, chartData),
@@ -30155,7 +30163,7 @@ function createScatterChartRuntime(chart, getters) {
30155
30163
  layout: getChartLayout(definition, chartData),
30156
30164
  scales: getScatterChartScales(definition, chartData),
30157
30165
  plugins: {
30158
- title: getChartTitle(definition),
30166
+ title: getChartTitle(definition, getters),
30159
30167
  legend: getScatterChartLegend(definition),
30160
30168
  tooltip: getLineChartTooltip(definition, chartData),
30161
30169
  chartShowValuesPlugin: getChartShowValues(definition, chartData),
@@ -30294,7 +30302,7 @@ function createSunburstChartRuntime(chart, getters) {
30294
30302
  ...CHART_COMMON_OPTIONS,
30295
30303
  layout: getChartLayout(definition, chartData),
30296
30304
  plugins: {
30297
- title: getChartTitle(definition),
30305
+ title: getChartTitle(definition, getters),
30298
30306
  legend: getSunburstChartLegend(definition),
30299
30307
  tooltip: getSunburstChartTooltip(definition, chartData),
30300
30308
  sunburstLabelsPlugin: getSunburstShowValues(definition, chartData),
@@ -30444,7 +30452,7 @@ function createTreeMapChartRuntime(chart, getters) {
30444
30452
  ...CHART_COMMON_OPTIONS,
30445
30453
  layout: getChartLayout(definition, chartData),
30446
30454
  plugins: {
30447
- title: getChartTitle(definition),
30455
+ title: getChartTitle(definition, getters),
30448
30456
  legend: { display: false },
30449
30457
  tooltip: getTreeMapChartTooltip(definition, chartData),
30450
30458
  },
@@ -30607,7 +30615,7 @@ function createWaterfallChartRuntime(chart, getters) {
30607
30615
  layout: getChartLayout(definition, chartData),
30608
30616
  scales: getWaterfallChartScales(definition, chartData),
30609
30617
  plugins: {
30610
- title: getChartTitle(definition),
30618
+ title: getChartTitle(definition, getters),
30611
30619
  legend: getWaterfallChartLegend(definition),
30612
30620
  tooltip: getWaterfallChartTooltip(definition, chartData),
30613
30621
  chartShowValuesPlugin: getWaterfallChartShowValues(definition, chartData),
@@ -32383,7 +32391,11 @@ class CarouselFigure extends Component {
32383
32391
  onFigureDeleted: Function,
32384
32392
  editFigureStyle: { type: Function, optional: true },
32385
32393
  };
32386
- static components = { ChartDashboardMenu };
32394
+ static components = { ChartDashboardMenu, MenuPopover };
32395
+ carouselTabsRef = useRef("carouselTabs");
32396
+ carouselTabsDropdownRef = useRef("carouselTabsDropdown");
32397
+ menuState = useState({ isOpen: false, anchorRect: null, menuItems: [] });
32398
+ hiddenItems = [];
32387
32399
  animationStore;
32388
32400
  setup() {
32389
32401
  this.animationStore = useStore(ChartAnimationStore);
@@ -32394,6 +32406,7 @@ class CarouselFigure extends Component {
32394
32406
  else {
32395
32407
  this.props.editFigureStyle?.({ "pointer-events": "auto" });
32396
32408
  }
32409
+ this.updateTabsVisibility();
32397
32410
  });
32398
32411
  }
32399
32412
  get carousel() {
@@ -32453,6 +32466,49 @@ class CarouselFigure extends Component {
32453
32466
  const style = { ...DEFAULT_CAROUSEL_TITLE_STYLE, ...this.carousel.title };
32454
32467
  return cssPropertiesToCss(cellTextStyleToCss(chartStyleToCellStyle(style)));
32455
32468
  }
32469
+ updateTabsVisibility() {
32470
+ const tabsContainerEl = this.carouselTabsRef.el;
32471
+ const dropDownEl = this.carouselTabsDropdownRef.el;
32472
+ if (!tabsContainerEl || !dropDownEl) {
32473
+ return;
32474
+ }
32475
+ this.hiddenItems = [];
32476
+ const containerRect = getBoundingRectAsPOJO(tabsContainerEl);
32477
+ const tabs = Array.from(tabsContainerEl.children);
32478
+ for (const tab of tabs) {
32479
+ tab.style.display = "block";
32480
+ }
32481
+ const tabWidths = tabs.map((tab) => getBoundingRectAsPOJO(tab).width);
32482
+ let currentWidth = 0;
32483
+ for (let i = 0; i < tabs.length; i++) {
32484
+ const shouldBeHidden = currentWidth + tabWidths[i] > containerRect.width;
32485
+ currentWidth += tabWidths[i];
32486
+ if (shouldBeHidden) {
32487
+ tabs[i].style.display = "none";
32488
+ this.hiddenItems.push(this.carousel.items[i]);
32489
+ }
32490
+ }
32491
+ dropDownEl.style.display = this.hiddenItems.length ? "block" : "none";
32492
+ }
32493
+ get menuId() {
32494
+ return "carousel-tabs-menu-";
32495
+ }
32496
+ toggleMenu(ev) {
32497
+ if (ev.closedMenuId === this.menuId) {
32498
+ this.menuState.isOpen = false;
32499
+ return;
32500
+ }
32501
+ const rect = getRefBoundingRect(this.carouselTabsDropdownRef);
32502
+ const menuItems = this.hiddenItems.map((item) => ({
32503
+ name: this.getItemTitle(item),
32504
+ execute: () => this.onCarouselTabClick(item),
32505
+ isActive: () => this.isItemSelected(item),
32506
+ isReadonlyAllowed: true,
32507
+ }));
32508
+ this.menuState.isOpen = true;
32509
+ this.menuState.anchorRect = rect;
32510
+ this.menuState.menuItems = createActions(menuItems);
32511
+ }
32456
32512
  }
32457
32513
 
32458
32514
  class ChartFigure extends Component {
@@ -39326,6 +39382,14 @@ function getCaretDownSvg(color) {
39326
39382
  paths: [{ fillColor: color.textColor || TEXT_BODY_MUTED, path: "M120 195 h270 l-135 130" }],
39327
39383
  };
39328
39384
  }
39385
+ function getCaretUpSvg(color) {
39386
+ return {
39387
+ name: "CARET_UP",
39388
+ width: 512,
39389
+ height: 512,
39390
+ paths: [{ fillColor: color.textColor || TEXT_BODY_MUTED, path: "M120 325 h270 l-135 -130" }],
39391
+ };
39392
+ }
39329
39393
  function getHoveredCaretDownSvg(color) {
39330
39394
  return {
39331
39395
  name: "CARET_DOWN",
@@ -50432,9 +50496,16 @@ class FiguresContainer extends Component {
50432
50496
  maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
50433
50497
  maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
50434
50498
  };
50499
+ let hasStartedDnd = false;
50435
50500
  const onMouseMove = (ev) => {
50436
50501
  const getters = this.env.model.getters;
50437
50502
  const currentMousePosition = { x: ev.clientX, y: ev.clientY };
50503
+ const offsetX = Math.abs(currentMousePosition.x - initialMousePosition.x);
50504
+ const offsetY = Math.abs(currentMousePosition.y - initialMousePosition.y);
50505
+ if (!hasStartedDnd && offsetX < DRAG_THRESHOLD && offsetY < DRAG_THRESHOLD) {
50506
+ return; // add a small threshold to avoid dnd when just clicking
50507
+ }
50508
+ hasStartedDnd = true;
50438
50509
  const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFigure, maxDimensions, initialScrollPosition, getters.getActiveSheetScrollInfo());
50439
50510
  const otherFigures = this.getOtherFigures(initialFigure.id);
50440
50511
  const overlappingCarousel = this.getCarouselOverlappingChart(draggedFigure, otherFigures);
@@ -55634,7 +55705,7 @@ class ScorecardChartDesignPanel extends Component {
55634
55705
  return SCORECARD_CHART_TITLE_FONT_SIZE;
55635
55706
  }
55636
55707
  translate(term) {
55637
- return _t(term);
55708
+ return this.env.model.getters.dynamicTranslate(term);
55638
55709
  }
55639
55710
  setColor(color, colorPickerId) {
55640
55711
  switch (colorPickerId) {
@@ -57186,7 +57257,7 @@ class CustomCurrencyPanel extends Component {
57186
57257
  });
57187
57258
  }
57188
57259
  const emptyCurrency = {
57189
- name: _t(CustomCurrencyTerms.Custom),
57260
+ name: CustomCurrencyTerms.Custom,
57190
57261
  code: "",
57191
57262
  symbol: "",
57192
57263
  decimalPlaces: 2,
@@ -58846,12 +58917,13 @@ class PivotLayoutConfigurator extends Component {
58846
58917
  addCalculatedMeasure() {
58847
58918
  const { measures } = this.props.definition;
58848
58919
  const measureName = this.env.model.getters.generateNewCalculatedMeasureName(measures);
58920
+ const aggregator = "sum";
58849
58921
  this.props.onDimensionsUpdated({
58850
58922
  measures: measures.concat([
58851
58923
  {
58852
- id: this.getMeasureId(measureName),
58924
+ id: this.getMeasureId(measureName, aggregator),
58853
58925
  fieldName: measureName,
58854
- aggregator: "sum",
58926
+ aggregator,
58855
58927
  computedBy: {
58856
58928
  sheetId: this.env.model.getters.getActiveSheetId(),
58857
58929
  formula: "=0",
@@ -61443,14 +61515,16 @@ class ClickableCellSortIcon extends Component {
61443
61515
  "background-color": this.getBackgroundColor(cellStyle),
61444
61516
  });
61445
61517
  }
61446
- get icon() {
61447
- switch (this.props.sortDirection) {
61448
- case "asc":
61449
- return "fa-sort-asc";
61450
- case "desc":
61451
- return "fa-sort-desc";
61518
+ get verticalJustifyClass() {
61519
+ const cellStyle = this.env.model.getters.getCellComputedStyle(this.props.position);
61520
+ switch (cellStyle.verticalAlign) {
61521
+ case "top":
61522
+ return "justify-content-start";
61523
+ case "middle":
61524
+ return "justify-content-center";
61525
+ case "bottom":
61452
61526
  default:
61453
- return "fa-sort";
61527
+ return "justify-content-end";
61454
61528
  }
61455
61529
  }
61456
61530
  getBackgroundColor(cellStyle) {
@@ -70651,6 +70725,30 @@ function togglePivotCollapse(position, env) {
70651
70725
  pivot: { ...definition, collapsedDomains: newDomains },
70652
70726
  });
70653
70727
  }
70728
+ iconsOnCellRegistry.add("pivot_dashboard_sorting", (getters, position) => {
70729
+ if (!getters.isDashboard()) {
70730
+ return undefined;
70731
+ }
70732
+ const pivotCell = getters.getPivotCellFromPosition(position);
70733
+ if (pivotCell.type !== "MEASURE_HEADER") {
70734
+ return undefined;
70735
+ }
70736
+ const sortDirection = getters.getPivotCellSortDirection(position);
70737
+ if (sortDirection !== "asc" && sortDirection !== "desc") {
70738
+ return undefined;
70739
+ }
70740
+ const cellStyle = getters.getCellComputedStyle(position);
70741
+ return {
70742
+ type: `pivot_dashboard_sorting_${sortDirection}`,
70743
+ priority: 5,
70744
+ horizontalAlign: "right",
70745
+ size: GRID_ICON_EDGE_LENGTH,
70746
+ margin: GRID_ICON_MARGIN,
70747
+ svg: sortDirection === "asc" ? getCaretUpSvg(cellStyle) : getCaretDownSvg(cellStyle),
70748
+ position,
70749
+ onClick: undefined, // click is managed by ClickableCellSortIcon
70750
+ };
70751
+ });
70654
70752
 
70655
70753
  class CellIconPlugin extends CoreViewPlugin {
70656
70754
  static getters = ["doesCellHaveGridIcon", "getCellIcons", "getCellIconRect"];
@@ -71130,7 +71228,7 @@ function withPivotPresentationLayer (PivotClass) {
71130
71228
  return { value: 0 };
71131
71229
  }
71132
71230
  const { columns, rows } = super.definition;
71133
- if (columns.length + rows.length !== domain.length) {
71231
+ if (measure.aggregator && columns.length + rows.length !== domain.length) {
71134
71232
  const values = this.getValuesToAggregate(measure, domain);
71135
71233
  const aggregator = AGGREGATORS_FN[measure.aggregator];
71136
71234
  if (!aggregator) {
@@ -71149,11 +71247,17 @@ function withPivotPresentationLayer (PivotClass) {
71149
71247
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
71150
71248
  const { colDomain } = domainToColRowDomain(this, domain);
71151
71249
  const symbolIndex = colDomain.findIndex((node) => node.field === symbolName);
71250
+ if (symbolIndex === -1) {
71251
+ return new NotAvailableError();
71252
+ }
71152
71253
  return this.getPivotHeaderValueAndFormat(colDomain.slice(0, symbolIndex + 1));
71153
71254
  }
71154
71255
  if (rows.find((row) => row.nameWithGranularity === symbolName)) {
71155
71256
  const { rowDomain } = domainToColRowDomain(this, domain);
71156
71257
  const symbolIndex = rowDomain.findIndex((row) => row.field === symbolName);
71258
+ if (symbolIndex === -1) {
71259
+ return new NotAvailableError();
71260
+ }
71157
71261
  return this.getPivotHeaderValueAndFormat(rowDomain.slice(0, symbolIndex + 1));
71158
71262
  }
71159
71263
  return this.getPivotCellValueAndFormat(symbolName, domain);
@@ -75547,6 +75651,21 @@ class DataValidationInsertionPlugin extends UIPlugin {
75547
75651
  }
75548
75652
  }
75549
75653
 
75654
+ /**
75655
+ * This plugin provides dynamic translation getter. In o-spreadsheet, it has
75656
+ * no implementation, but this plugin can be replaced by another one to provide
75657
+ * a real implementation.
75658
+ *
75659
+ * For example, in Odoo, the plugin is replaced by a plugin that used the
75660
+ * module namespace to dynamically translate terms.
75661
+ */
75662
+ class DynamicTranslate extends UIPlugin {
75663
+ static getters = ["dynamicTranslate"];
75664
+ dynamicTranslate(term) {
75665
+ return term;
75666
+ }
75667
+ }
75668
+
75550
75669
  const genericRepeatsTransforms = [
75551
75670
  repeatSheetDependantCommand,
75552
75671
  repeatTargetDependantCommand,
@@ -77517,13 +77636,10 @@ class GridSelectionPlugin extends UIPlugin {
77517
77636
  const deltaCol = isBasedBefore && isCol ? thickness : 0;
77518
77637
  const deltaRow = isBasedBefore && !isCol ? thickness : 0;
77519
77638
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
77520
- const originalSize = Object.fromEntries(toRemove.map((element) => {
77521
- const size = isCol
77522
- ? this.getters.getColSize(cmd.sheetId, element)
77523
- : this.getters.getUserRowSize(cmd.sheetId, element);
77524
- const isDefaultCol = isCol && size === DEFAULT_CELL_WIDTH;
77525
- return [element, isDefaultCol ? undefined : size];
77526
- }));
77639
+ const originalSize = {};
77640
+ for (const element of toRemove) {
77641
+ originalSize[element] = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
77642
+ }
77527
77643
  const target = [
77528
77644
  {
77529
77645
  left: isCol ? start + deltaCol : 0,
@@ -77567,11 +77683,11 @@ class GridSelectionPlugin extends UIPlugin {
77567
77683
  for (const element of toRemove) {
77568
77684
  const size = originalSize[element];
77569
77685
  const currentSize = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, currentIndex);
77570
- if (size && size !== currentSize) {
77686
+ if (size !== currentSize) {
77571
77687
  resizingGroups[size] ??= [];
77572
77688
  resizingGroups[size].push(currentIndex);
77573
- currentIndex += 1;
77574
77689
  }
77690
+ currentIndex += 1;
77575
77691
  }
77576
77692
  for (const size in resizingGroups) {
77577
77693
  this.dispatch("RESIZE_COLUMNS_ROWS", {
@@ -79178,6 +79294,7 @@ const featurePluginRegistry = new Registry()
79178
79294
  .add("table_ui_resize", TableResizeUI)
79179
79295
  .add("datavalidation_insert", DataValidationInsertionPlugin)
79180
79296
  .add("checkbox_toggle", CheckboxTogglePlugin)
79297
+ .add("dynamic_translate", DynamicTranslate)
79181
79298
  .add("geo_features", GeoFeaturePlugin);
79182
79299
  // Plugins which have a state, but which should not be shared in collaborative
79183
79300
  const statefulUIPluginRegistry = new Registry()
@@ -88357,9 +88474,9 @@ const constants = {
88357
88474
  };
88358
88475
  const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
88359
88476
 
88360
- export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, LocalTransportService, 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, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
88477
+ export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
88361
88478
 
88362
88479
 
88363
- __info__.version = "19.0.0";
88364
- __info__.date = "2025-09-11T07:18:49.704Z";
88365
- __info__.hash = "0ac0e86";
88480
+ __info__.version = "19.0.3";
88481
+ __info__.date = "2025-09-19T07:26:41.356Z";
88482
+ __info__.hash = "84f3b74";