@odoo/o-spreadsheet 18.0.37 → 18.0.39

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.37
6
- * @date 2025-07-11T11:11:13.394Z
7
- * @hash bc6f00d
5
+ * @version 18.0.39
6
+ * @date 2025-07-30T11:19:58.267Z
7
+ * @hash 997e25a
8
8
  */
9
9
 
10
10
  'use strict';
@@ -17377,6 +17377,7 @@ const autoCompleteProviders = new Registry();
17377
17377
 
17378
17378
  autoCompleteProviders.add("dataValidation", {
17379
17379
  displayAllOnInitialContent: true,
17380
+ canBeToggled: false,
17380
17381
  getProposals(tokenAtCursor, content) {
17381
17382
  if (content.startsWith("=")) {
17382
17383
  return [];
@@ -17384,31 +17385,40 @@ autoCompleteProviders.add("dataValidation", {
17384
17385
  if (!this.composer.currentEditedCell) {
17385
17386
  return [];
17386
17387
  }
17387
- const position = this.composer.currentEditedCell;
17388
- const rule = this.getters.getValidationRuleForCell(position);
17389
- if (!rule ||
17390
- (rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange")) {
17391
- return [];
17392
- }
17393
- let values;
17394
- if (rule.criterion.type === "isValueInList") {
17395
- values = rule.criterion.values;
17396
- }
17397
- else {
17398
- const range = this.getters.getRangeFromSheetXC(position.sheetId, rule.criterion.values[0]);
17399
- values = Array.from(new Set(this.getters
17400
- .getRangeValues(range)
17401
- .filter(isNotNull)
17402
- .map((value) => value.toString())
17403
- .filter((val) => val !== "")));
17404
- }
17405
- return values.map((value) => ({ text: value }));
17388
+ return getProposedValues(this.getters, this.composer.currentEditedCell).map((value) => ({
17389
+ text: value.value?.toString() || "",
17390
+ htmlContent: [{ value: value.label }],
17391
+ fuzzySearchKey: value.label,
17392
+ }));
17406
17393
  },
17407
17394
  selectProposal(tokenAtCursor, value) {
17408
17395
  this.composer.setCurrentContent(value);
17409
17396
  this.composer.stopEdition();
17410
17397
  },
17411
17398
  });
17399
+ function getProposedValues(getters, position) {
17400
+ const rule = getters.getValidationRuleForCell(position);
17401
+ if (!rule ||
17402
+ (rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange")) {
17403
+ return [];
17404
+ }
17405
+ let values = [];
17406
+ if (rule.criterion.type === "isValueInList") {
17407
+ values = rule.criterion.values.map((value) => ({ label: value, value }));
17408
+ }
17409
+ else {
17410
+ const labelsSet = new Set();
17411
+ const range = getters.getRangeFromSheetXC(position.sheetId, rule.criterion.values[0]);
17412
+ for (const p of positions(range.zone)) {
17413
+ const cell = getters.getEvaluatedCell({ ...p, sheetId: range.sheetId });
17414
+ if (cell.formattedValue && !labelsSet.has(cell.formattedValue)) {
17415
+ labelsSet.add(cell.formattedValue);
17416
+ values.push({ label: cell.formattedValue, value: cell.value });
17417
+ }
17418
+ }
17419
+ }
17420
+ return values;
17421
+ }
17412
17422
 
17413
17423
  function getHtmlContentFromPattern(pattern, value, highlightColor, className) {
17414
17424
  const pendingHtmlContent = [];
@@ -25032,11 +25042,17 @@ const COLUMN = {
25032
25042
  if (isEvaluationError(cellReference?.value)) {
25033
25043
  return cellReference;
25034
25044
  }
25035
- const column = cellReference === undefined
25036
- ? this.__originCellPosition?.col
25037
- : toZone(cellReference.value).left;
25038
- assert(() => column !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
25039
- return column + 1;
25045
+ if (cellReference === undefined) {
25046
+ assert(() => this.__originCellPosition?.col !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
25047
+ return this.__originCellPosition.col + 1;
25048
+ }
25049
+ const zone = this.getters.getRangeFromSheetXC(this.getters.getActiveSheetId(), cellReference.value).zone;
25050
+ if (zone.left === zone.right) {
25051
+ return zone.left + 1;
25052
+ }
25053
+ return generateMatrix(zone.right - zone.left + 1, 1, (col, row) => ({
25054
+ value: zone.left + col + 1,
25055
+ }));
25040
25056
  },
25041
25057
  isExported: true,
25042
25058
  };
@@ -25255,11 +25271,17 @@ const ROW = {
25255
25271
  if (isEvaluationError(cellReference?.value)) {
25256
25272
  return cellReference;
25257
25273
  }
25258
- const row = cellReference === undefined
25259
- ? this.__originCellPosition?.row
25260
- : toZone(cellReference.value).top;
25261
- assert(() => row !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
25262
- return row + 1;
25274
+ if (cellReference === undefined) {
25275
+ assert(() => this.__originCellPosition?.row !== undefined, "In this context, the function [[FUNCTION_NAME]] needs to have a cell or range in parameter.");
25276
+ return this.__originCellPosition.row + 1;
25277
+ }
25278
+ const zone = this.getters.getRangeFromSheetXC(this.getters.getActiveSheetId(), cellReference.value).zone;
25279
+ if (zone.top === zone.bottom) {
25280
+ return zone.top + 1;
25281
+ }
25282
+ return generateMatrix(1, zone.bottom - zone.top + 1, (col, row) => ({
25283
+ value: zone.top + row + 1,
25284
+ }));
25263
25285
  },
25264
25286
  isExported: true,
25265
25287
  };
@@ -27915,9 +27937,13 @@ class Composer extends owl.Component {
27915
27937
  }
27916
27938
  }
27917
27939
  closeAssistant() {
27940
+ if (!this.canBeToggled)
27941
+ return;
27918
27942
  this.assistant.forcedClosed = true;
27919
27943
  }
27920
27944
  openAssistant() {
27945
+ if (!this.canBeToggled)
27946
+ return;
27921
27947
  this.assistant.forcedClosed = false;
27922
27948
  }
27923
27949
  onWheel(event) {
@@ -27927,6 +27953,9 @@ class Composer extends owl.Component {
27927
27953
  event.stopPropagation();
27928
27954
  }
27929
27955
  }
27956
+ get canBeToggled() {
27957
+ return this.autoCompleteState.provider?.canBeToggled ?? true;
27958
+ }
27930
27959
  // ---------------------------------------------------------------------------
27931
27960
  // Private
27932
27961
  // ---------------------------------------------------------------------------
@@ -28109,7 +28138,7 @@ class Composer extends owl.Component {
28109
28138
  }
28110
28139
  }
28111
28140
  autoComplete(value) {
28112
- if (!value || this.assistant.forcedClosed) {
28141
+ if (!value || (this.assistant.forcedClosed && this.canBeToggled)) {
28113
28142
  return;
28114
28143
  }
28115
28144
  this.autoCompleteState.provider?.selectProposal(value);
@@ -39681,6 +39710,7 @@ class AbstractComposerStore extends SpreadsheetStore {
39681
39710
  proposals,
39682
39711
  selectProposal: provider.selectProposal,
39683
39712
  autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
39713
+ canBeToggled: provider.canBeToggled,
39684
39714
  };
39685
39715
  }
39686
39716
  if (exactMatch && this._currentContent !== this.initialContent) {
@@ -39703,6 +39733,7 @@ class AbstractComposerStore extends SpreadsheetStore {
39703
39733
  proposals,
39704
39734
  selectProposal: provider.selectProposal,
39705
39735
  autoSelectFirstProposal: provider.autoSelectFirstProposal ?? false,
39736
+ canBeToggled: provider.canBeToggled,
39706
39737
  };
39707
39738
  }
39708
39739
  }
@@ -44742,9 +44773,15 @@ class SpreadsheetPivot {
44742
44773
  return domain.reduce((current, acc) => this.filterDataEntriesFromDomainNode(current, acc), dataEntries);
44743
44774
  }
44744
44775
  filterDataEntriesFromDomainNode(dataEntries, domain) {
44745
- const { field, value } = domain;
44776
+ const { field, value, type } = domain;
44746
44777
  const { nameWithGranularity } = this.getDimension(field);
44747
- return dataEntries.filter((entry) => entry[nameWithGranularity]?.value === value);
44778
+ return dataEntries.filter((entry) => {
44779
+ const cellValue = entry[nameWithGranularity]?.value;
44780
+ if (type === "char") {
44781
+ return String(cellValue) === String(value);
44782
+ }
44783
+ return cellValue === value;
44784
+ });
44748
44785
  }
44749
44786
  getDimension(nameWithGranularity) {
44750
44787
  return this.definition.getDimension(nameWithGranularity);
@@ -47219,6 +47256,11 @@ class GridComposer extends owl.Component {
47219
47256
  rect = this.defaultRect;
47220
47257
  isEditing = false;
47221
47258
  isCellReferenceVisible = false;
47259
+ currentEditedCell = {
47260
+ col: 0,
47261
+ row: 0,
47262
+ sheetId: this.env.model.getters.getActiveSheetId(),
47263
+ };
47222
47264
  composerStore;
47223
47265
  composerFocusStore;
47224
47266
  composerInterface;
@@ -47248,7 +47290,7 @@ class GridComposer extends owl.Component {
47248
47290
  return this.isCellReferenceVisible;
47249
47291
  }
47250
47292
  get cellReference() {
47251
- const { col, row, sheetId } = this.composerStore.currentEditedCell;
47293
+ const { col, row, sheetId } = this.currentEditedCell;
47252
47294
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
47253
47295
  return getFullReference(prefixSheet ? this.env.model.getters.getSheetName(sheetId) : undefined, toXC(col, row));
47254
47296
  }
@@ -47341,12 +47383,17 @@ class GridComposer extends owl.Component {
47341
47383
  if (!isEditing && this.composerFocusStore.activeComposer !== this.composerInterface) {
47342
47384
  this.composerFocusStore.focusComposer(this.composerInterface, { focusMode: "inactive" });
47343
47385
  }
47386
+ let shouldRecomputeRect = isEditing && !deepEquals(this.currentEditedCell, this.composerStore.currentEditedCell);
47344
47387
  if (this.isEditing !== isEditing) {
47345
47388
  this.isEditing = isEditing;
47346
47389
  if (!isEditing) {
47347
47390
  this.rect = this.defaultRect;
47348
47391
  return;
47349
47392
  }
47393
+ this.currentEditedCell = this.composerStore.currentEditedCell;
47394
+ shouldRecomputeRect = true;
47395
+ }
47396
+ if (shouldRecomputeRect) {
47350
47397
  const position = this.env.model.getters.getActivePosition();
47351
47398
  const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
47352
47399
  this.rect = this.env.model.getters.getVisibleRect(zone);
@@ -60413,6 +60460,23 @@ class HeaderSizeUIPlugin extends UIPlugin {
60413
60460
  static getters = ["getRowSize", "getHeaderSize"];
60414
60461
  tallestCellInRow = {};
60415
60462
  ctx = document.createElement("canvas").getContext("2d");
60463
+ beforeHandle(cmd) {
60464
+ switch (cmd.type) {
60465
+ // Ensure rows are updated before "UPDATE_CELL" is dispatched from cell plugin.
60466
+ // "UPDATE_CELL" uses the Sheet core plugin to access row data.
60467
+ // If "ADD_COLUMNS_ROWS" has not been processed yet by header_sizes_ui,
60468
+ // size updates may apply to incorrect (pre-insert) rows.
60469
+ case "ADD_COLUMNS_ROWS":
60470
+ if (cmd.dimension === "COL") {
60471
+ return;
60472
+ }
60473
+ const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
60474
+ const newCells = Array(cmd.quantity).fill(undefined);
60475
+ const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
60476
+ this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
60477
+ break;
60478
+ }
60479
+ }
60416
60480
  handle(cmd) {
60417
60481
  switch (cmd.type) {
60418
60482
  case "START":
@@ -60442,16 +60506,6 @@ class HeaderSizeUIPlugin extends UIPlugin {
60442
60506
  this.history.update("tallestCellInRow", cmd.sheetId, tallestCells);
60443
60507
  break;
60444
60508
  }
60445
- case "ADD_COLUMNS_ROWS": {
60446
- if (cmd.dimension === "COL") {
60447
- return;
60448
- }
60449
- const addIndex = getAddHeaderStartIndex(cmd.position, cmd.base);
60450
- const newCells = Array(cmd.quantity).fill(undefined);
60451
- const newTallestCells = insertItemsAtIndex(this.tallestCellInRow[cmd.sheetId], newCells, addIndex);
60452
- this.history.update("tallestCellInRow", cmd.sheetId, newTallestCells);
60453
- break;
60454
- }
60455
60509
  case "RESIZE_COLUMNS_ROWS":
60456
60510
  {
60457
60511
  const sheetId = cmd.sheetId;
@@ -66140,6 +66194,14 @@ class GridSelectionPlugin extends UIPlugin {
66140
66194
  const isBasedBefore = cmd.base < start;
66141
66195
  const deltaCol = isBasedBefore && isCol ? thickness : 0;
66142
66196
  const deltaRow = isBasedBefore && !isCol ? thickness : 0;
66197
+ const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
66198
+ const originalSize = Object.fromEntries(toRemove.map((element) => {
66199
+ const size = isCol
66200
+ ? this.getters.getColSize(cmd.sheetId, element)
66201
+ : this.getters.getUserRowSize(cmd.sheetId, element);
66202
+ const isDefaultCol = isCol && size === DEFAULT_CELL_WIDTH;
66203
+ return [element, isDefaultCol || size === undefined ? null : size];
66204
+ }));
66143
66205
  const target = [
66144
66206
  {
66145
66207
  left: isCol ? start + deltaCol : 0,
@@ -66170,14 +66232,12 @@ class GridSelectionPlugin extends UIPlugin {
66170
66232
  const col = selection.left;
66171
66233
  const row = selection.top;
66172
66234
  this.setSelectionMixin({ zone: selection, cell: { col, row } }, [selection]);
66173
- const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
66174
66235
  let currentIndex = isBasedBefore ? cmd.base : cmd.base + 1;
66175
66236
  for (const element of toRemove) {
66176
- const size = this.getters.getHeaderSize(cmd.sheetId, cmd.dimension, element);
66177
66237
  this.dispatch("RESIZE_COLUMNS_ROWS", {
66178
66238
  dimension: cmd.dimension,
66179
66239
  sheetId: cmd.sheetId,
66180
- size,
66240
+ size: originalSize[element],
66181
66241
  elements: [currentIndex],
66182
66242
  });
66183
66243
  currentIndex += 1;
@@ -67889,14 +67949,12 @@ class BottomBarSheet extends owl.Component {
67889
67949
  this.editionState = "initializing";
67890
67950
  }
67891
67951
  stopEdition() {
67892
- const input = this.sheetNameRef.el;
67893
- if (!this.state.isEditing || !input)
67952
+ if (!this.state.isEditing || !this.sheetNameRef.el)
67894
67953
  return;
67895
67954
  this.state.isEditing = false;
67896
67955
  this.editionState = "initializing";
67897
- input.blur();
67956
+ this.sheetNameRef.el.blur();
67898
67957
  const inputValue = this.getInputContent() || "";
67899
- input.innerText = inputValue;
67900
67958
  interactiveRenameSheet(this.env, this.props.sheetId, inputValue, () => this.startEdition());
67901
67959
  }
67902
67960
  cancelEdition() {
@@ -74591,6 +74649,6 @@ exports.tokenColors = tokenColors;
74591
74649
  exports.tokenize = tokenize;
74592
74650
 
74593
74651
 
74594
- __info__.version = "18.0.37";
74595
- __info__.date = "2025-07-11T11:11:13.394Z";
74596
- __info__.hash = "bc6f00d";
74652
+ __info__.version = "18.0.39";
74653
+ __info__.date = "2025-07-30T11:19:58.267Z";
74654
+ __info__.hash = "997e25a";
@@ -4750,6 +4750,7 @@ declare class HeaderSizeUIPlugin extends UIPlugin<HeaderSizeState> implements He
4750
4750
  static getters: readonly ["getRowSize", "getHeaderSize"];
4751
4751
  readonly tallestCellInRow: Immutable<Record<UID, Array<CellWithSize | undefined>>>;
4752
4752
  private ctx;
4753
+ beforeHandle(cmd: Command): void;
4753
4754
  handle(cmd: Command): void;
4754
4755
  getRowSize(sheetId: UID, row: HeaderIndex): Pixel;
4755
4756
  getHeaderSize(sheetId: UID, dimension: Dimension, index: HeaderIndex): Pixel;
@@ -8193,6 +8194,7 @@ declare class Composer extends Component<CellComposerProps, SpreadsheetChildEnv>
8193
8194
  closeAssistant(): void;
8194
8195
  openAssistant(): void;
8195
8196
  onWheel(event: WheelEvent): void;
8197
+ get canBeToggled(): boolean;
8196
8198
  private processContent;
8197
8199
  /**
8198
8200
  * Get the HTML content corresponding to the current composer token, divided by lines.
@@ -8234,6 +8236,7 @@ interface AutoCompleteProvider {
8234
8236
  proposals: AutoCompleteProposal[];
8235
8237
  selectProposal(text: string): void;
8236
8238
  autoSelectFirstProposal: boolean;
8239
+ canBeToggled?: boolean;
8237
8240
  }
8238
8241
  interface ComposerStoreInterface {
8239
8242
  currentEditedCell?: CellPosition;
@@ -8253,6 +8256,7 @@ interface ComposerStoreInterface {
8253
8256
  interface AutoCompleteProviderDefinition {
8254
8257
  sequence?: number;
8255
8258
  autoSelectFirstProposal?: boolean;
8259
+ canBeToggled?: boolean;
8256
8260
  displayAllOnInitialContent?: boolean;
8257
8261
  maxDisplayedProposals?: number;
8258
8262
  getProposals(this: {
@@ -8560,6 +8564,7 @@ declare class GridComposer extends Component<Props$H, SpreadsheetChildEnv> {
8560
8564
  private rect;
8561
8565
  private isEditing;
8562
8566
  private isCellReferenceVisible;
8567
+ private currentEditedCell;
8563
8568
  private composerStore;
8564
8569
  composerFocusStore: Store<ComposerFocusStore>;
8565
8570
  private composerInterface;