@odoo/o-spreadsheet 16.2.9 → 16.2.11

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.
@@ -109,7 +109,7 @@ const SELECTION_BORDER_COLOR = "#3266ca";
109
109
  const HEADER_BORDER_COLOR = "#C0C0C0";
110
110
  const CELL_BORDER_COLOR = "#E2E3E3";
111
111
  const BACKGROUND_CHART_COLOR = "#FFFFFF";
112
- const MENU_ITEM_DISABLED_COLOR = "#CACACA";
112
+ const DISABLED_TEXT_COLOR = "#CACACA";
113
113
  const DEFAULT_COLOR_SCALE_MIDPOINT_COLOR = 0xb6d7a8;
114
114
  const LINK_COLOR = "#01666b";
115
115
  const FILTERS_COLOR = "#188038";
@@ -711,12 +711,20 @@ function getDefaultCellHeight(cell) {
711
711
  return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
712
712
  }
713
713
  function computeTextWidth(context, text, style) {
714
- context.save();
715
- context.font = computeTextFont(style);
716
- const textWidth = context.measureText(text).width;
717
- context.restore();
718
- return textWidth;
714
+ const font = computeTextFont(style);
715
+ if (!textWidthCache[font]) {
716
+ textWidthCache[font] = {};
717
+ }
718
+ if (textWidthCache[font][text] === undefined) {
719
+ context.save();
720
+ context.font = font;
721
+ const textWidth = context.measureText(text).width;
722
+ context.restore();
723
+ textWidthCache[font][text] = textWidth;
724
+ }
725
+ return textWidthCache[font][text];
719
726
  }
727
+ const textWidthCache = {};
720
728
  function fontSizeInPixels(fontSize) {
721
729
  return Math.round((fontSize * 96) / 72);
722
730
  }
@@ -4096,7 +4104,6 @@ const readonlyAllowedCommands = new Set([
4096
4104
  "SET_VIEWPORT_OFFSET",
4097
4105
  "SELECT_SEARCH_NEXT_MATCH",
4098
4106
  "SELECT_SEARCH_PREVIOUS_MATCH",
4099
- "REFRESH_SEARCH",
4100
4107
  "UPDATE_SEARCH",
4101
4108
  "CLEAR_SEARCH",
4102
4109
  "EVALUATE_CELLS",
@@ -5415,7 +5422,7 @@ css /* scss */ `
5415
5422
  }
5416
5423
  }
5417
5424
  &.disabled {
5418
- color: ${MENU_ITEM_DISABLED_COLOR};
5425
+ color: ${DISABLED_TEXT_COLOR};
5419
5426
  cursor: not-allowed;
5420
5427
  }
5421
5428
  }
@@ -18677,11 +18684,16 @@ class FindAndReplacePanel extends owl.Component {
18677
18684
  }
18678
18685
  setup() {
18679
18686
  this.showFormulaState = this.env.model.getters.shouldShowFormulas();
18687
+ this.debouncedUpdateSearch = debounce(this.updateSearch.bind(this), 200);
18680
18688
  owl.onMounted(() => this.focusInput());
18681
18689
  owl.onWillUnmount(() => {
18682
18690
  this.env.model.dispatch("CLEAR_SEARCH");
18683
18691
  this.env.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.showFormulaState });
18684
18692
  });
18693
+ owl.useEffect(() => {
18694
+ this.state.searchOptions.searchFormulas = this.env.model.getters.shouldShowFormulas();
18695
+ this.searchFormulas();
18696
+ }, () => [this.env.model.getters.shouldShowFormulas()]);
18685
18697
  }
18686
18698
  onInput(ev) {
18687
18699
  this.state.toSearch = ev.target.value;
@@ -18701,10 +18713,6 @@ class FindAndReplacePanel extends owl.Component {
18701
18713
  this.replace();
18702
18714
  }
18703
18715
  }
18704
- onFocusSidePanel() {
18705
- this.state.searchOptions.searchFormulas = this.env.model.getters.shouldShowFormulas();
18706
- this.env.model.dispatch("REFRESH_SEARCH");
18707
- }
18708
18716
  searchFormulas() {
18709
18717
  this.env.model.dispatch("SET_FORMULA_VISIBILITY", {
18710
18718
  show: this.state.searchOptions.searchFormulas,
@@ -18723,13 +18731,6 @@ class FindAndReplacePanel extends owl.Component {
18723
18731
  searchOptions: this.state.searchOptions,
18724
18732
  });
18725
18733
  }
18726
- debouncedUpdateSearch() {
18727
- clearTimeout(this.debounceTimeoutId);
18728
- this.debounceTimeoutId = setTimeout(() => {
18729
- this.updateSearch();
18730
- this.debounceTimeoutId = undefined;
18731
- }, 400);
18732
- }
18733
18734
  replace() {
18734
18735
  this.env.model.dispatch("REPLACE_SEARCH", {
18735
18736
  replaceWith: this.state.replaceWith,
@@ -29131,7 +29132,14 @@ class FiltersPlugin extends CorePlugin {
29131
29132
  this.history.update("tables", filterTables);
29132
29133
  break;
29133
29134
  case "DUPLICATE_SHEET":
29134
- this.history.update("tables", cmd.sheetIdTo, deepCopy(this.tables[cmd.sheetId]));
29135
+ const tables = {};
29136
+ for (const filterTable of Object.values(this.tables[cmd.sheetId] || {})) {
29137
+ if (filterTable) {
29138
+ const newFilterTable = deepCopy(filterTable);
29139
+ tables[newFilterTable.id] = newFilterTable;
29140
+ }
29141
+ }
29142
+ this.history.update("tables", cmd.sheetIdTo, tables);
29135
29143
  break;
29136
29144
  case "ADD_COLUMNS_ROWS":
29137
29145
  this.onAddColumnsRows(cmd);
@@ -32708,6 +32716,7 @@ class FilterEvaluationPlugin extends UIPlugin {
32708
32716
  }
32709
32717
  exportForExcel(data) {
32710
32718
  for (const sheetData of data.sheets) {
32719
+ const sheetId = sheetData.id;
32711
32720
  for (const tableData of sheetData.filterTables) {
32712
32721
  const tableZone = toZone(tableData.range);
32713
32722
  const filters = [];
@@ -32723,20 +32732,20 @@ class FilterEvaluationPlugin extends UIPlugin {
32723
32732
  if (!filter)
32724
32733
  continue;
32725
32734
  const valuesInFilterZone = filter.filteredZone
32726
- ? positions(filter.filteredZone)
32727
- .map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId: sheetData.id, col, row }))
32728
- .filter((cell) => cell.type !== CellValueType.empty)
32729
- .map((cell) => cell.formattedValue)
32735
+ ? positions(filter.filteredZone).map((position) => this.getters.getEvaluatedCell({ sheetId, ...position }).formattedValue)
32730
32736
  : [];
32731
- // In xlsx, filtered values = values that are displayed, not values that are hidden
32732
- const xlsxFilteredValues = valuesInFilterZone.filter((val) => !filteredValues.includes(val));
32733
- filters.push({ colId: i, filteredValues: [...new Set(xlsxFilteredValues)] });
32734
- // In xlsx, filter header should ALWAYS be a string and should be unique
32735
- const headerPosition = {
32736
- col: filter.col,
32737
- row: filter.zoneWithHeaders.top,
32738
- sheetId: sheetData.id,
32739
- };
32737
+ if (filteredValues.length) {
32738
+ const xlsxDisplayedValues = valuesInFilterZone
32739
+ .filter((val) => val)
32740
+ .filter((val) => !filteredValues.includes(val));
32741
+ filters.push({
32742
+ colId: i,
32743
+ displayedValues: [...new Set(xlsxDisplayedValues)],
32744
+ displayBlanks: !filteredValues.includes("") && valuesInFilterZone.some((val) => !val),
32745
+ });
32746
+ }
32747
+ // In xlsx, filter header should ALWAYS be a string and should be unique in the table
32748
+ const headerPosition = { col: filter.col, row: filter.zoneWithHeaders.top, sheetId };
32740
32749
  const headerString = this.getters.getEvaluatedCell(headerPosition).formattedValue;
32741
32750
  const headerName = this.getUniqueColNameForExcel(i, headerString, headerNames);
32742
32751
  headerNames.push(headerName);
@@ -34473,6 +34482,7 @@ class FindAndReplacePlugin extends UIPlugin {
34473
34482
  searchFormulas: false,
34474
34483
  };
34475
34484
  this.toSearch = "";
34485
+ this.isSearchDirty = false;
34476
34486
  }
34477
34487
  // ---------------------------------------------------------------------------
34478
34488
  // Command Handling
@@ -34501,14 +34511,21 @@ class FindAndReplacePlugin extends UIPlugin {
34501
34511
  case "REDO":
34502
34512
  case "REMOVE_COLUMNS_ROWS":
34503
34513
  case "ADD_COLUMNS_ROWS":
34504
- this.clearSearch();
34514
+ case "EVALUATE_CELLS":
34515
+ case "UPDATE_CELL":
34516
+ this.isSearchDirty = true;
34505
34517
  break;
34506
34518
  case "ACTIVATE_SHEET":
34507
- case "REFRESH_SEARCH":
34508
34519
  this.refreshSearch();
34509
34520
  break;
34510
34521
  }
34511
34522
  }
34523
+ finalize() {
34524
+ if (this.isSearchDirty) {
34525
+ this.refreshSearch();
34526
+ this.isSearchDirty = false;
34527
+ }
34528
+ }
34512
34529
  // ---------------------------------------------------------------------------
34513
34530
  // Getters
34514
34531
  // ---------------------------------------------------------------------------
@@ -34564,6 +34581,11 @@ class FindAndReplacePlugin extends UIPlugin {
34564
34581
  if (this.toSearch) {
34565
34582
  for (const cell of Object.values(cells)) {
34566
34583
  const { col, row } = this.getters.getCellPosition(cell.id);
34584
+ const isColHidden = this.getters.isColHidden(sheetId, col);
34585
+ const isRowHidden = this.getters.isRowHidden(sheetId, row);
34586
+ if (isColHidden || isRowHidden) {
34587
+ continue;
34588
+ }
34567
34589
  if (cell &&
34568
34590
  this.currentSearchRegex &&
34569
34591
  this.currentSearchRegex.test(this.getSearchableString({ sheetId, col, row }))) {
@@ -35765,15 +35787,15 @@ SelectionInputPlugin.getters = [];
35765
35787
  * This plugin handles this internal state.
35766
35788
  */
35767
35789
  class SelectionInputsManagerPlugin extends UIPlugin {
35790
+ get currentInput() {
35791
+ return this.focusedInputId ? this.inputs[this.focusedInputId] : null;
35792
+ }
35768
35793
  constructor(config) {
35769
35794
  super(config);
35770
35795
  this.config = config;
35771
35796
  this.inputs = {};
35772
35797
  this.focusedInputId = null;
35773
35798
  }
35774
- get currentInput() {
35775
- return this.focusedInputId ? this.inputs[this.focusedInputId] : null;
35776
- }
35777
35799
  // ---------------------------------------------------------------------------
35778
35800
  // Command Handling
35779
35801
  // ---------------------------------------------------------------------------
@@ -37002,10 +37024,8 @@ class SortPlugin extends UIPlugin {
37002
37024
  }
37003
37025
  updateCellCommands.push(newCellValues);
37004
37026
  }
37005
- for (const cmd of updateCellCommands) {
37006
- this.dispatch("UPDATE_CELL", cmd);
37007
- }
37008
37027
  }
37028
+ updateCellCommands.forEach((cmdPayload) => this.dispatch("UPDATE_CELL", cmdPayload));
37009
37029
  }
37010
37030
  /**
37011
37031
  * Return the distances between main merge cells in the zone.
@@ -40704,6 +40724,11 @@ css /* scss */ `
40704
40724
  .o-sidePanelButton:enabled {
40705
40725
  cursor: pointer;
40706
40726
  }
40727
+
40728
+ .o-sidePanelButton:disabled {
40729
+ color: ${DISABLED_TEXT_COLOR};
40730
+ }
40731
+
40707
40732
  .o-sidePanelButton:last-child {
40708
40733
  margin-right: 0px;
40709
40734
  }
@@ -40849,11 +40874,9 @@ TopBarComposer.props = {
40849
40874
  onComposerContentFocused: Function,
40850
40875
  };
40851
40876
 
40852
- // -----------------------------------------------------------------------------
40853
- // TopBar
40854
- // -----------------------------------------------------------------------------
40855
40877
  css /* scss */ `
40856
40878
  .o-font-size-editor {
40879
+ height: calc(100% - 4px);
40857
40880
  input.o-font-size {
40858
40881
  height: 20px;
40859
40882
  width: 23px;
@@ -40931,6 +40954,7 @@ FontSizeEditor.components = {};
40931
40954
  FontSizeEditor.props = {
40932
40955
  onToggle: Function,
40933
40956
  dropdownStyle: String,
40957
+ class: String,
40934
40958
  };
40935
40959
 
40936
40960
  const FORMATS = [
@@ -44374,15 +44398,10 @@ function addAutoFilter(table) {
44374
44398
  `;
44375
44399
  }
44376
44400
  function addFilterColumns(table) {
44377
- const tableZone = toZone(table.range);
44378
44401
  const columns = [];
44379
- for (const i of range(0, zoneToDimension(tableZone).numberOfCols)) {
44380
- const filter = table.filters[i];
44381
- if (!filter || !filter.filteredValues.length) {
44382
- continue;
44383
- }
44402
+ for (const filter of table.filters) {
44384
44403
  const colXml = escapeXml /*xml*/ `
44385
- <filterColumn ${formatAttributes([["colId", i]])}>
44404
+ <filterColumn ${formatAttributes([["colId", filter.colId]])}>
44386
44405
  ${addFilter(filter)}
44387
44406
  </filterColumn>
44388
44407
  `;
@@ -44391,9 +44410,10 @@ function addFilterColumns(table) {
44391
44410
  return columns;
44392
44411
  }
44393
44412
  function addFilter(filter) {
44394
- const filterValues = filter.filteredValues.map((val) => escapeXml /*xml*/ `<filter ${formatAttributes([["val", val]])}/>`);
44413
+ const filterValues = filter.displayedValues.map((val) => escapeXml /*xml*/ `<filter ${formatAttributes([["val", val]])}/>`);
44414
+ const filterAttributes = filter.displayBlanks ? [["blank", 1]] : [];
44395
44415
  return escapeXml /*xml*/ `
44396
- <filters>
44416
+ <filters ${formatAttributes(filterAttributes)}>
44397
44417
  ${joinXmlNodes(filterValues)}
44398
44418
  </filters>
44399
44419
  `;
@@ -45368,6 +45388,6 @@ exports.setTranslationMethod = setTranslationMethod;
45368
45388
  exports.tokenize = tokenize;
45369
45389
 
45370
45390
 
45371
- __info__.version = '16.2.9';
45372
- __info__.date = '2023-06-12T13:49:57.216Z';
45373
- __info__.hash = '37e2719';
45391
+ __info__.version = '16.2.11';
45392
+ __info__.date = '2023-07-26T12:09:59.264Z';
45393
+ __info__.hash = '0d46dde';