@odoo/o-spreadsheet 18.1.29 → 18.1.31

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.29
6
- * @date 2025-07-11T11:11:55.442Z
7
- * @hash 3456a93
5
+ * @version 18.1.31
6
+ * @date 2025-08-04T06:52:11.010Z
7
+ * @hash 4f581fb
8
8
  */
9
9
 
10
10
  'use strict';
@@ -10479,6 +10479,7 @@ class ChartJsComponent extends owl.Component {
10479
10479
  }
10480
10480
  setup() {
10481
10481
  owl.onMounted(() => {
10482
+ registerChartJSExtensions();
10482
10483
  const runtime = this.chartRuntime;
10483
10484
  this.currentRuntime = runtime;
10484
10485
  // Note: chartJS modify the runtime in place, so it's important to give it a copy
@@ -11136,6 +11137,7 @@ const autoCompleteProviders = new Registry();
11136
11137
 
11137
11138
  autoCompleteProviders.add("dataValidation", {
11138
11139
  displayAllOnInitialContent: true,
11140
+ canBeToggled: false,
11139
11141
  getProposals(tokenAtCursor, content) {
11140
11142
  if (content.startsWith("=")) {
11141
11143
  return [];
@@ -11143,31 +11145,40 @@ autoCompleteProviders.add("dataValidation", {
11143
11145
  if (!this.composer.currentEditedCell) {
11144
11146
  return [];
11145
11147
  }
11146
- const position = this.composer.currentEditedCell;
11147
- const rule = this.getters.getValidationRuleForCell(position);
11148
- if (!rule ||
11149
- (rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange")) {
11150
- return [];
11151
- }
11152
- let values;
11153
- if (rule.criterion.type === "isValueInList") {
11154
- values = rule.criterion.values;
11155
- }
11156
- else {
11157
- const range = this.getters.getRangeFromSheetXC(position.sheetId, rule.criterion.values[0]);
11158
- values = Array.from(new Set(this.getters
11159
- .getRangeValues(range)
11160
- .filter(isNotNull)
11161
- .map((value) => value.toString())
11162
- .filter((val) => val !== "")));
11163
- }
11164
- return values.map((value) => ({ text: value }));
11148
+ return getProposedValues(this.getters, this.composer.currentEditedCell).map((value) => ({
11149
+ text: value.value?.toString() || "",
11150
+ htmlContent: [{ value: value.label }],
11151
+ fuzzySearchKey: value.label,
11152
+ }));
11165
11153
  },
11166
11154
  selectProposal(tokenAtCursor, value) {
11167
11155
  this.composer.setCurrentContent(value);
11168
11156
  this.composer.stopEdition();
11169
11157
  },
11170
11158
  });
11159
+ function getProposedValues(getters, position) {
11160
+ const rule = getters.getValidationRuleForCell(position);
11161
+ if (!rule ||
11162
+ (rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange")) {
11163
+ return [];
11164
+ }
11165
+ let values = [];
11166
+ if (rule.criterion.type === "isValueInList") {
11167
+ values = rule.criterion.values.map((value) => ({ label: value, value }));
11168
+ }
11169
+ else {
11170
+ const labelsSet = new Set();
11171
+ const range = getters.getRangeFromSheetXC(position.sheetId, rule.criterion.values[0]);
11172
+ for (const p of positions(range.zone)) {
11173
+ const cell = getters.getEvaluatedCell({ ...p, sheetId: range.sheetId });
11174
+ if (cell.formattedValue && !labelsSet.has(cell.formattedValue)) {
11175
+ labelsSet.add(cell.formattedValue);
11176
+ values.push({ label: cell.formattedValue, value: cell.value });
11177
+ }
11178
+ }
11179
+ }
11180
+ return values;
11181
+ }
11171
11182
 
11172
11183
  function getHtmlContentFromPattern(pattern, value, highlightColor, className) {
11173
11184
  const pendingHtmlContent = [];
@@ -18938,11 +18949,17 @@ const COLUMN = {
18938
18949
  if (isEvaluationError(cellReference?.value)) {
18939
18950
  return cellReference;
18940
18951
  }
18941
- const column = cellReference === undefined
18942
- ? this.__originCellPosition?.col
18943
- : toZone(cellReference.value).left;
18944
- assert(() => column !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
18945
- return column + 1;
18952
+ if (cellReference === undefined) {
18953
+ assert(() => this.__originCellPosition?.col !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
18954
+ return this.__originCellPosition.col + 1;
18955
+ }
18956
+ const zone = this.getters.getRangeFromSheetXC(this.getters.getActiveSheetId(), cellReference.value).zone;
18957
+ if (zone.left === zone.right) {
18958
+ return zone.left + 1;
18959
+ }
18960
+ return generateMatrix(zone.right - zone.left + 1, 1, (col, row) => ({
18961
+ value: zone.left + col + 1,
18962
+ }));
18946
18963
  },
18947
18964
  isExported: true,
18948
18965
  };
@@ -19161,11 +19178,17 @@ const ROW = {
19161
19178
  if (isEvaluationError(cellReference?.value)) {
19162
19179
  return cellReference;
19163
19180
  }
19164
- const row = cellReference === undefined
19165
- ? this.__originCellPosition?.row
19166
- : toZone(cellReference.value).top;
19167
- assert(() => row !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
19168
- return row + 1;
19181
+ if (cellReference === undefined) {
19182
+ assert(() => this.__originCellPosition?.row !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
19183
+ return this.__originCellPosition.row + 1;
19184
+ }
19185
+ const zone = this.getters.getRangeFromSheetXC(this.getters.getActiveSheetId(), cellReference.value).zone;
19186
+ if (zone.top === zone.bottom) {
19187
+ return zone.top + 1;
19188
+ }
19189
+ return generateMatrix(1, zone.bottom - zone.top + 1, (col, row) => ({
19190
+ value: zone.top + row + 1,
19191
+ }));
19169
19192
  },
19170
19193
  isExported: true,
19171
19194
  };
@@ -21441,6 +21464,7 @@ class AbstractComposerStore extends SpreadsheetStore {
21441
21464
  proposals,
21442
21465
  selectProposal: provider.selectProposal,
21443
21466
  autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
21467
+ canBeToggled: provider.canBeToggled,
21444
21468
  };
21445
21469
  }
21446
21470
  if (exactMatch && this._currentContent !== this.initialContent) {
@@ -21463,6 +21487,7 @@ class AbstractComposerStore extends SpreadsheetStore {
21463
21487
  proposals,
21464
21488
  selectProposal: provider.selectProposal,
21465
21489
  autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
21490
+ canBeToggled: provider.canBeToggled,
21466
21491
  };
21467
21492
  }
21468
21493
  }
@@ -41501,9 +41526,13 @@ class Composer extends owl.Component {
41501
41526
  }
41502
41527
  }
41503
41528
  closeAssistant() {
41529
+ if (!this.canBeToggled)
41530
+ return;
41504
41531
  this.assistant.forcedClosed = true;
41505
41532
  }
41506
41533
  openAssistant() {
41534
+ if (!this.canBeToggled)
41535
+ return;
41507
41536
  this.assistant.forcedClosed = false;
41508
41537
  }
41509
41538
  onWheel(event) {
@@ -41513,6 +41542,9 @@ class Composer extends owl.Component {
41513
41542
  event.stopPropagation();
41514
41543
  }
41515
41544
  }
41545
+ get canBeToggled() {
41546
+ return this.autoCompleteState.provider?.canBeToggled ?? true;
41547
+ }
41516
41548
  // ---------------------------------------------------------------------------
41517
41549
  // Private
41518
41550
  // ---------------------------------------------------------------------------
@@ -41648,7 +41680,7 @@ class Composer extends owl.Component {
41648
41680
  }
41649
41681
  }
41650
41682
  autoComplete(value) {
41651
- if (!value || this.assistant.forcedClosed) {
41683
+ if (!value || (this.assistant.forcedClosed && this.canBeToggled)) {
41652
41684
  return;
41653
41685
  }
41654
41686
  this.autoCompleteState.provider?.selectProposal(value);
@@ -42445,7 +42477,8 @@ class ConditionalFormattingEditor extends owl.Component {
42445
42477
  static props = {
42446
42478
  editedCf: Object,
42447
42479
  onCancel: Function,
42448
- onSave: Function,
42480
+ onExit: Function,
42481
+ isNewCf: Boolean,
42449
42482
  };
42450
42483
  static components = {
42451
42484
  SelectionInput,
@@ -42464,6 +42497,7 @@ class ConditionalFormattingEditor extends owl.Component {
42464
42497
  getTextDecoration = getTextDecoration;
42465
42498
  colorNumberString = colorNumberString;
42466
42499
  state;
42500
+ hasEditedCf = this.props.isNewCf;
42467
42501
  setup() {
42468
42502
  this.state = owl.useState({
42469
42503
  errors: [],
@@ -42521,6 +42555,9 @@ class ConditionalFormattingEditor extends owl.Component {
42521
42555
  ranges: ranges.map((xc) => this.env.model.getters.getRangeDataFromXc(sheetId, xc)),
42522
42556
  sheetId,
42523
42557
  });
42558
+ if (result.isSuccessful) {
42559
+ this.hasEditedCf = true;
42560
+ }
42524
42561
  const reasons = result.reasons.filter((r) => r !== "NoChanges" /* CommandResult.NoChanges */);
42525
42562
  if (!newCf.suppressErrors) {
42526
42563
  this.state.errors = reasons;
@@ -42542,7 +42579,15 @@ class ConditionalFormattingEditor extends owl.Component {
42542
42579
  onSave() {
42543
42580
  const result = this.updateConditionalFormat({});
42544
42581
  if (result.length === 0) {
42545
- this.props.onSave();
42582
+ this.props.onExit();
42583
+ }
42584
+ }
42585
+ onCancel() {
42586
+ if (this.hasEditedCf) {
42587
+ this.props.onCancel();
42588
+ }
42589
+ else {
42590
+ this.props.onExit();
42546
42591
  }
42547
42592
  }
42548
42593
  getDefaultRules() {
@@ -46893,9 +46938,15 @@ class SpreadsheetPivot {
46893
46938
  return domain.reduce((current, acc) => this.filterDataEntriesFromDomainNode(current, acc), dataEntries);
46894
46939
  }
46895
46940
  filterDataEntriesFromDomainNode(dataEntries, domain) {
46896
- const { field, value } = domain;
46941
+ const { field, value, type } = domain;
46897
46942
  const { nameWithGranularity } = this.getDimension(field);
46898
- return dataEntries.filter((entry) => entry[nameWithGranularity]?.value === value);
46943
+ return dataEntries.filter((entry) => {
46944
+ const cellValue = entry[nameWithGranularity]?.value;
46945
+ if (type === "char") {
46946
+ return String(cellValue) === String(value);
46947
+ }
46948
+ return cellValue === value;
46949
+ });
46899
46950
  }
46900
46951
  getDimension(nameWithGranularity) {
46901
46952
  return this.definition.getDimension(nameWithGranularity);
@@ -49395,6 +49446,11 @@ class GridComposer extends owl.Component {
49395
49446
  rect = this.defaultRect;
49396
49447
  isEditing = false;
49397
49448
  isCellReferenceVisible = false;
49449
+ currentEditedCell = {
49450
+ col: 0,
49451
+ row: 0,
49452
+ sheetId: this.env.model.getters.getActiveSheetId(),
49453
+ };
49398
49454
  composerStore;
49399
49455
  composerFocusStore;
49400
49456
  composerInterface;
@@ -49424,7 +49480,7 @@ class GridComposer extends owl.Component {
49424
49480
  return this.isCellReferenceVisible;
49425
49481
  }
49426
49482
  get cellReference() {
49427
- const { col, row, sheetId } = this.composerStore.currentEditedCell;
49483
+ const { col, row, sheetId } = this.currentEditedCell;
49428
49484
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
49429
49485
  return getFullReference(prefixSheet ? this.env.model.getters.getSheetName(sheetId) : undefined, toXC(col, row));
49430
49486
  }
@@ -49516,12 +49572,17 @@ class GridComposer extends owl.Component {
49516
49572
  if (!isEditing && this.composerFocusStore.activeComposer !== this.composerInterface) {
49517
49573
  this.composerFocusStore.focusComposer(this.composerInterface, { focusMode: "inactive" });
49518
49574
  }
49575
+ let shouldRecomputeRect = isEditing && !deepEquals(this.currentEditedCell, this.composerStore.currentEditedCell);
49519
49576
  if (this.isEditing !== isEditing) {
49520
49577
  this.isEditing = isEditing;
49521
49578
  if (!isEditing) {
49522
49579
  this.rect = this.defaultRect;
49523
49580
  return;
49524
49581
  }
49582
+ this.currentEditedCell = this.composerStore.currentEditedCell;
49583
+ shouldRecomputeRect = true;
49584
+ }
49585
+ if (shouldRecomputeRect) {
49525
49586
  const position = this.env.model.getters.getActivePosition();
49526
49587
  const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
49527
49588
  this.rect = this.env.model.getters.getVisibleRect(zone);
@@ -62489,6 +62550,23 @@ class HeaderSizeUIPlugin extends UIPlugin {
62489
62550
  static getters = ["getRowSize", "getHeaderSize"];
62490
62551
  tallestCellInRow = {};
62491
62552
  ctx = document.createElement("canvas").getContext("2d");
62553
+ beforeHandle(cmd) {
62554
+ switch (cmd.type) {
62555
+ // Ensure rows are updated before "UPDATE_CELL" is dispatched from cell plugin.
62556
+ // "UPDATE_CELL" uses the Sheet core plugin to access row data.
62557
+ // If "ADD_COLUMNS_ROWS" has not been processed yet by header_sizes_ui,
62558
+ // size updates may apply to incorrect (pre-insert) rows.
62559
+ case "ADD_COLUMNS_ROWS":
62560
+ if (cmd.dimension === "COL") {
62561
+ return;
62562
+ }
62563
+ const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
62564
+ const newCells = Array(cmd.quantity).fill(undefined);
62565
+ const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
62566
+ this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
62567
+ break;
62568
+ }
62569
+ }
62492
62570
  handle(cmd) {
62493
62571
  switch (cmd.type) {
62494
62572
  case "START":
@@ -62518,16 +62596,6 @@ class HeaderSizeUIPlugin extends UIPlugin {
62518
62596
  this.history.update("tallestCellInRow", cmd.sheetId, tallestCells);
62519
62597
  break;
62520
62598
  }
62521
- case "ADD_COLUMNS_ROWS": {
62522
- if (cmd.dimension === "COL") {
62523
- return;
62524
- }
62525
- const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
62526
- const newCells = Array(cmd.quantity).fill(undefined);
62527
- const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
62528
- this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
62529
- break;
62530
- }
62531
62599
  case "RESIZE_COLUMNS_ROWS":
62532
62600
  {
62533
62601
  const sheetId = cmd.sheetId;
@@ -68268,6 +68336,14 @@ class GridSelectionPlugin extends UIPlugin {
68268
68336
  const isBasedBefore = cmd.base < start;
68269
68337
  const deltaCol = isBasedBefore && isCol ? thickness : 0;
68270
68338
  const deltaRow = isBasedBefore && !isCol ? thickness : 0;
68339
+ const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
68340
+ const originalSize = Object.fromEntries(toRemove.map((element) => {
68341
+ const size = isCol
68342
+ ? this.getters.getColSize(cmd.sheetId, element)
68343
+ : this.getters.getUserRowSize(cmd.sheetId, element);
68344
+ const isDefaultCol = isCol && size === DEFAULT_CELL_WIDTH;
68345
+ return [element, isDefaultCol ? undefined : size];
68346
+ }));
68271
68347
  const target = [
68272
68348
  {
68273
68349
  left: isCol ? start + deltaCol : 0,
@@ -68298,13 +68374,12 @@ class GridSelectionPlugin extends UIPlugin {
68298
68374
  const col = selection.left;
68299
68375
  const row = selection.top;
68300
68376
  this.setSelectionMixin({ zone: selection, cell: { col, row } }, [selection]);
68301
- const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
68302
68377
  let currentIndex = isBasedBefore ? cmd.base : cmd.base + 1;
68303
68378
  const resizingGroups = {};
68304
68379
  for (const element of toRemove) {
68305
- const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
68380
+ const size = originalSize[element];
68306
68381
  const currentSize = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, currentIndex);
68307
- if (size != currentSize) {
68382
+ if (size && size != currentSize) {
68308
68383
  resizingGroups[size] ??= [];
68309
68384
  resizingGroups[size].push(currentIndex);
68310
68385
  currentIndex += 1;
@@ -70023,14 +70098,12 @@ class BottomBarSheet extends owl.Component {
70023
70098
  this.editionState = "initializing";
70024
70099
  }
70025
70100
  stopEdition() {
70026
- const input = this.sheetNameRef.el;
70027
- if (!this.state.isEditing || !input)
70101
+ if (!this.state.isEditing || !this.sheetNameRef.el)
70028
70102
  return;
70029
70103
  this.state.isEditing = false;
70030
70104
  this.editionState = "initializing";
70031
- input.blur();
70105
+ this.sheetNameRef.el.blur();
70032
70106
  const inputValue = this.getInputContent() || "";
70033
- input.innerText = inputValue;
70034
70107
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
70035
70108
  }
70036
70109
  cancelEdition() {
@@ -72195,7 +72268,6 @@ class Spreadsheet extends owl.Component {
72195
72268
  this.checkViewportSize();
72196
72269
  stores.on("store-updated", this, render);
72197
72270
  resizeObserver.observe(this.spreadsheetRef.el);
72198
- registerChartJSExtensions();
72199
72271
  });
72200
72272
  owl.onWillUnmount(() => {
72201
72273
  this.unbindModelEvents();
@@ -76706,6 +76778,6 @@ exports.tokenColors = tokenColors;
76706
76778
  exports.tokenize = tokenize;
76707
76779
 
76708
76780
 
76709
- __info__.version = "18.1.29";
76710
- __info__.date = "2025-07-11T11:11:55.442Z";
76711
- __info__.hash = "3456a93";
76781
+ __info__.version = "18.1.31";
76782
+ __info__.date = "2025-08-04T06:52:11.010Z";
76783
+ __info__.hash = "4f581fb";
@@ -5278,6 +5278,7 @@ declare class HeaderSizeUIPlugin extends UIPlugin<HeaderSizeState> implements He
5278
5278
  static getters: readonly ["getRowSize", "getHeaderSize"];
5279
5279
  readonly tallestCellInRow: Immutable<Record<UID, Array<CellWithSize | undefined>>>;
5280
5280
  private ctx;
5281
+ beforeHandle(cmd: Command): void;
5281
5282
  handle(cmd: Command): void;
5282
5283
  getRowSize(sheetId: UID, row: HeaderIndex): Pixel;
5283
5284
  getHeaderSize(sheetId: UID, dimension: Dimension, index: HeaderIndex): Pixel;
@@ -8476,6 +8477,7 @@ declare class Composer extends Component<CellComposerProps, SpreadsheetChildEnv>
8476
8477
  closeAssistant(): void;
8477
8478
  openAssistant(): void;
8478
8479
  onWheel(event: WheelEvent): void;
8480
+ get canBeToggled(): boolean;
8479
8481
  private processContent;
8480
8482
  /**
8481
8483
  * Get the HTML content corresponding to the current composer token, divided by lines.
@@ -8517,6 +8519,7 @@ interface AutoCompleteProvider {
8517
8519
  proposals: AutoCompleteProposal[];
8518
8520
  selectProposal(text: string): void;
8519
8521
  autoSelectFirstProposal: boolean;
8522
+ canBeToggled?: boolean;
8520
8523
  }
8521
8524
  interface ComposerStoreInterface {
8522
8525
  currentEditedCell?: CellPosition;
@@ -8536,6 +8539,7 @@ interface ComposerStoreInterface {
8536
8539
  interface AutoCompleteProviderDefinition {
8537
8540
  sequence?: number;
8538
8541
  autoSelectFirstProposal?: boolean;
8542
+ canBeToggled?: boolean;
8539
8543
  displayAllOnInitialContent?: boolean;
8540
8544
  maxDisplayedProposals?: number;
8541
8545
  getProposals(this: {
@@ -8843,6 +8847,7 @@ declare class GridComposer extends Component<Props$J, SpreadsheetChildEnv> {
8843
8847
  private rect;
8844
8848
  private isEditing;
8845
8849
  private isCellReferenceVisible;
8850
+ private currentEditedCell;
8846
8851
  private composerStore;
8847
8852
  composerFocusStore: Store<ComposerFocusStore>;
8848
8853
  private composerInterface;