@odoo/o-spreadsheet 18.2.11 → 18.2.12

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.2.11
6
- * @date 2025-05-12T05:25:59.138Z
7
- * @hash eb87dca
5
+ * @version 18.2.12
6
+ * @date 2025-05-13T17:52:23.989Z
7
+ * @hash ba2ba9b
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -3357,7 +3357,7 @@ function isDateAfter(date, dateAfter) {
3357
3357
  */
3358
3358
  const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
3359
3359
  decimalSeparator = escapeRegExp(decimalSeparator);
3360
- return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
3360
+ return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e(\\+|-)?\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
3361
3361
  });
3362
3362
  const getNumberRegex = memoize(function getNumberRegex(locale) {
3363
3363
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
@@ -6299,6 +6299,13 @@ function getDuplicateSheetName(nameToDuplicate, existingNames) {
6299
6299
  }
6300
6300
  return name;
6301
6301
  }
6302
+ function isSheetNameEqual(name1, name2) {
6303
+ if (name1 === undefined || name2 === undefined) {
6304
+ return false;
6305
+ }
6306
+ return (getUnquotedSheetName(name1.trim().toUpperCase()) ===
6307
+ getUnquotedSheetName(name2.trim().toUpperCase()));
6308
+ }
6302
6309
 
6303
6310
  function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
6304
6311
  return numberOfLines * (textLineHeight + MIN_CELL_TEXT_MARGIN) - MIN_CELL_TEXT_MARGIN;
@@ -8162,10 +8169,9 @@ const AGGREGATOR_NAMES = {
8162
8169
  avg: _t("Average"),
8163
8170
  sum: _t("Sum"),
8164
8171
  };
8165
- const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
8166
8172
  const AGGREGATORS_BY_FIELD_TYPE = {
8167
- integer: NUMBER_CHAR_AGGREGATORS,
8168
- char: NUMBER_CHAR_AGGREGATORS,
8173
+ integer: ["max", "min", "avg", "sum", "count_distinct", "count"],
8174
+ char: ["count_distinct", "count"],
8169
8175
  boolean: ["count_distinct", "count", "bool_and", "bool_or"],
8170
8176
  datetime: ["max", "min", "count_distinct", "count"],
8171
8177
  };
@@ -9518,7 +9524,10 @@ function proxifyStoreMutation(store, callback) {
9518
9524
  const functionProxy = new Proxy(value, {
9519
9525
  // trap the function call
9520
9526
  apply(target, thisArg, argArray) {
9521
- Reflect.apply(target, thisStore, argArray);
9527
+ const res = Reflect.apply(target, thisStore, argArray);
9528
+ if (res === "noStateChange") {
9529
+ return;
9530
+ }
9522
9531
  callback();
9523
9532
  },
9524
9533
  });
@@ -9540,7 +9549,7 @@ function getDependencyContainer(env) {
9540
9549
  const ModelStore = createAbstractStore("Model");
9541
9550
 
9542
9551
  class RendererStore {
9543
- mutators = ["register", "unRegister"];
9552
+ mutators = ["register", "unRegister", "drawLayer"];
9544
9553
  renderers = {};
9545
9554
  register(renderer) {
9546
9555
  if (!renderer.renderingLayers.length) {
@@ -9560,14 +9569,14 @@ class RendererStore {
9560
9569
  }
9561
9570
  drawLayer(context, layer) {
9562
9571
  const renderers = this.renderers[layer];
9563
- if (!renderers) {
9564
- return;
9565
- }
9566
- for (const renderer of renderers) {
9567
- context.ctx.save();
9568
- renderer.drawLayer(context, layer);
9569
- context.ctx.restore();
9572
+ if (renderers) {
9573
+ for (const renderer of renderers) {
9574
+ context.ctx.save();
9575
+ renderer.drawLayer(context, layer);
9576
+ context.ctx.restore();
9577
+ }
9570
9578
  }
9579
+ return "noStateChange";
9571
9580
  }
9572
9581
  }
9573
9582
 
@@ -9620,16 +9629,17 @@ class ComposerFocusStore extends SpreadsheetStore {
9620
9629
  focusComposer(listener, args) {
9621
9630
  this.activeComposer = listener;
9622
9631
  if (this.getters.isReadonly()) {
9623
- return;
9632
+ return "noStateChange";
9624
9633
  }
9625
9634
  this._focusMode = args.focusMode || "contentFocus";
9626
9635
  if (this._focusMode !== "inactive") {
9627
9636
  this.setComposerContent(args);
9628
9637
  }
9638
+ return;
9629
9639
  }
9630
9640
  focusActiveComposer(args) {
9631
9641
  if (this.getters.isReadonly()) {
9632
- return;
9642
+ return "noStateChange";
9633
9643
  }
9634
9644
  if (!this.activeComposer) {
9635
9645
  throw new Error("No composer is registered");
@@ -9638,6 +9648,7 @@ class ComposerFocusStore extends SpreadsheetStore {
9638
9648
  if (this._focusMode !== "inactive") {
9639
9649
  this.setComposerContent(args);
9640
9650
  }
9651
+ return;
9641
9652
  }
9642
9653
  /**
9643
9654
  * Start the edition or update the content if it's already started.
@@ -10131,7 +10142,7 @@ function getDefinedAxis(definition) {
10131
10142
  }
10132
10143
  function formatChartDatasetValue(axisFormats, locale) {
10133
10144
  return (value, axisId) => {
10134
- const format = axisId ? axisFormats?.[axisId] : undefined;
10145
+ const format = axisFormats?.[axisId];
10135
10146
  return formatTickValue({ format, locale })(value);
10136
10147
  };
10137
10148
  }
@@ -10305,7 +10316,7 @@ function drawPieChartValues(chart, options, ctx) {
10305
10316
  const y = bar.y + midRadius * Math.sin(midAngle) + 7;
10306
10317
  ctx.fillStyle = chartFontColor(options.background);
10307
10318
  ctx.strokeStyle = options.background || "#ffffff";
10308
- const displayValue = options.callback(value);
10319
+ const displayValue = options.callback(value, "y");
10309
10320
  drawTextWithBackground(displayValue, x, y, ctx);
10310
10321
  }
10311
10322
  }
@@ -19204,6 +19215,9 @@ const PIVOT_VALUE = {
19204
19215
  };
19205
19216
  }
19206
19217
  const domain = pivot.parseArgsToPivotDomain(domainArgs);
19218
+ if (this.getters.getActiveSheetId() === this.__originSheetId) {
19219
+ this.getters.getPivotPresenceTracker(pivotId)?.trackValue(_measure, domain);
19220
+ }
19207
19221
  return pivot.getPivotCellValueAndFormat(_measure, domain);
19208
19222
  },
19209
19223
  };
@@ -19235,6 +19249,9 @@ const PIVOT_HEADER = {
19235
19249
  };
19236
19250
  }
19237
19251
  const domain = pivot.parseArgsToPivotDomain(domainArgs);
19252
+ if (this.getters.getActiveSheetId() === this.__originSheetId) {
19253
+ this.getters.getPivotPresenceTracker(_pivotId)?.trackHeader(domain);
19254
+ }
19238
19255
  const lastNode = domain.at(-1);
19239
19256
  if (lastNode?.field === "measure") {
19240
19257
  return pivot.getPivotMeasureValue(toString(lastNode.value), domain);
@@ -19457,6 +19474,9 @@ function isEmpty(data) {
19457
19474
  return data === undefined || data.value === null;
19458
19475
  }
19459
19476
  const getNeutral = { number: 0, string: "", boolean: false };
19477
+ function areAlmostEqual(value1, value2, epsilon = 2e-16) {
19478
+ return Math.abs(value1 - value2) < epsilon;
19479
+ }
19460
19480
  const EQ = {
19461
19481
  description: _t("Equal."),
19462
19482
  args: [
@@ -19478,6 +19498,9 @@ const EQ = {
19478
19498
  if (typeof _value2 === "string") {
19479
19499
  _value2 = _value2.toUpperCase();
19480
19500
  }
19501
+ if (typeof _value1 === "number" && typeof _value2 === "number") {
19502
+ return { value: areAlmostEqual(_value1, _value2) };
19503
+ }
19481
19504
  return { value: _value1 === _value2 };
19482
19505
  },
19483
19506
  };
@@ -19517,6 +19540,9 @@ const GT = {
19517
19540
  ],
19518
19541
  compute: function (value1, value2) {
19519
19542
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19543
+ if (typeof v1 === "number" && typeof v2 === "number") {
19544
+ return !areAlmostEqual(v1, v2) && v1 > v2;
19545
+ }
19520
19546
  return v1 > v2;
19521
19547
  });
19522
19548
  },
@@ -19532,6 +19558,9 @@ const GTE = {
19532
19558
  ],
19533
19559
  compute: function (value1, value2) {
19534
19560
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19561
+ if (typeof v1 === "number" && typeof v2 === "number") {
19562
+ return areAlmostEqual(v1, v2) || v1 > v2;
19563
+ }
19535
19564
  return v1 >= v2;
19536
19565
  });
19537
19566
  },
@@ -21138,7 +21167,7 @@ class AbstractComposerStore extends SpreadsheetStore {
21138
21167
  .find((token) => {
21139
21168
  const { xc, sheetName: sheet } = splitReference(token.value);
21140
21169
  const sheetName = sheet || this.getters.getSheetName(this.sheetId);
21141
- if (this.getters.getSheetName(activeSheetId) !== sheetName) {
21170
+ if (!isSheetNameEqual(this.getters.getSheetName(activeSheetId), sheetName)) {
21142
21171
  return false;
21143
21172
  }
21144
21173
  const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
@@ -24600,7 +24629,7 @@ function getRangeSize(reference, defaultSheetIndex, data) {
24600
24629
  ({ xc, sheetName } = splitReference(reference));
24601
24630
  let rangeSheetIndex;
24602
24631
  if (sheetName) {
24603
- const index = data.sheets.findIndex((sheet) => sheet.name === sheetName);
24632
+ const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
24604
24633
  if (index < 0) {
24605
24634
  throw new Error("Unable to find a sheet with the name " + sheetName);
24606
24635
  }
@@ -24941,7 +24970,7 @@ function convertFormula(formula, data) {
24941
24970
  formula = formula.replace(externalReferenceRegex, (match, externalRefId, sheetName, cellRef) => {
24942
24971
  externalRefId = Number(externalRefId) - 1;
24943
24972
  cellRef = cellRef.replace(/\$/g, "");
24944
- const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => name === sheetName);
24973
+ const sheetIndex = data.externalBooks[externalRefId].sheetNames.findIndex((name) => isSheetNameEqual(name, sheetName));
24945
24974
  if (sheetIndex === -1) {
24946
24975
  return match;
24947
24976
  }
@@ -25592,7 +25621,7 @@ function convertPivotTableConfig(pivotTable) {
25592
25621
  */
25593
25622
  function convertTableFormulaReferences(convertedSheets, xlsxSheets) {
25594
25623
  for (let tableSheet of convertedSheets) {
25595
- const tables = xlsxSheets.find((s) => s.sheetName === tableSheet.name).tables;
25624
+ const tables = xlsxSheets.find((s) => isSheetNameEqual(s.sheetName, tableSheet.name)).tables;
25596
25625
  for (let table of tables) {
25597
25626
  const tabRef = table.name + "[";
25598
25627
  for (let sheet of convertedSheets) {
@@ -32584,12 +32613,20 @@ class HoveredCellStore extends SpreadsheetStore {
32584
32613
  }
32585
32614
  }
32586
32615
  hover(position) {
32616
+ if (position.col === this.col && position.row === this.row) {
32617
+ return "noStateChange";
32618
+ }
32587
32619
  this.col = position.col;
32588
32620
  this.row = position.row;
32621
+ return;
32589
32622
  }
32590
32623
  clear() {
32624
+ if (this.col === undefined && this.row === undefined) {
32625
+ return "noStateChange";
32626
+ }
32591
32627
  this.col = undefined;
32592
32628
  this.row = undefined;
32629
+ return;
32593
32630
  }
32594
32631
  }
32595
32632
 
@@ -32611,7 +32648,11 @@ class CellPopoverStore extends SpreadsheetStore {
32611
32648
  this.persistentPopover = { col, row, sheetId, type };
32612
32649
  }
32613
32650
  close() {
32651
+ if (!this.persistentPopover) {
32652
+ return "noStateChange";
32653
+ }
32614
32654
  this.persistentPopover = undefined;
32655
+ return;
32615
32656
  }
32616
32657
  get persistentCellPopover() {
32617
32658
  return ((this.persistentPopover && { isOpen: true, ...this.persistentPopover }) || { isOpen: false });
@@ -40067,10 +40108,18 @@ class GaugeChartConfigPanel extends Component {
40067
40108
  }
40068
40109
 
40069
40110
  class DOMFocusableElementStore {
40070
- mutators = ["setFocusableElement"];
40111
+ mutators = ["setFocusableElement", "focus"];
40071
40112
  focusableElement = undefined;
40072
40113
  setFocusableElement(element) {
40073
40114
  this.focusableElement = element;
40115
+ return "noStateChange";
40116
+ }
40117
+ focus() {
40118
+ if (this.focusableElement === document.activeElement) {
40119
+ return "noStateChange";
40120
+ }
40121
+ this.focusableElement?.focus();
40122
+ return;
40074
40123
  }
40075
40124
  }
40076
40125
 
@@ -40658,7 +40707,7 @@ class Composer extends Component {
40658
40707
  if (document.activeElement === this.contentHelper.el &&
40659
40708
  this.props.composerStore.editionMode === "inactive" &&
40660
40709
  !this.props.isDefaultFocus) {
40661
- this.DOMFocusableElementStore.focusableElement?.focus();
40710
+ this.DOMFocusableElementStore.focus();
40662
40711
  }
40663
40712
  });
40664
40713
  useEffect(() => {
@@ -46942,7 +46991,12 @@ class SpreadsheetPivot {
46942
46991
  entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
46943
46992
  }
46944
46993
  else {
46945
- entry[field.name] = cell;
46994
+ if (field.type === "char") {
46995
+ entry[field.name] = { ...cell, value: cell.formattedValue || null };
46996
+ }
46997
+ else {
46998
+ entry[field.name] = cell;
46999
+ }
46946
47000
  }
46947
47001
  }
46948
47002
  entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
@@ -52080,10 +52134,6 @@ function useGridDrawing(refName, model, canvasSize) {
52080
52134
  ctx.scale(dpr, dpr);
52081
52135
  for (const layer of OrderedLayers()) {
52082
52136
  model.drawLayer(renderingContext, layer);
52083
- // @ts-ignore 'drawLayer' is not declated as a mutator because:
52084
- // it does not mutate anything. Most importantly it's used
52085
- // during rendering. Invoking a mutator during rendering would
52086
- // trigger another rendering, ultimately resulting in an infinite loop.
52087
52137
  rendererStore.drawLayer(renderingContext, layer);
52088
52138
  }
52089
52139
  }
@@ -52774,7 +52824,7 @@ class Grid extends Component {
52774
52824
  this.cellPopovers = useStore(CellPopoverStore);
52775
52825
  useEffect(() => {
52776
52826
  if (!this.sidePanel.isOpen) {
52777
- this.DOMFocusableElementStore.focusableElement?.focus();
52827
+ this.DOMFocusableElementStore.focus();
52778
52828
  }
52779
52829
  }, () => [this.sidePanel.isOpen]);
52780
52830
  useTouchScroll(this.gridRef, this.moveCanvas.bind(this), () => {
@@ -52984,7 +53034,7 @@ class Grid extends Component {
52984
53034
  focusDefaultElement() {
52985
53035
  if (!this.env.model.getters.getSelectedFigureId() &&
52986
53036
  this.composerFocusStore.activeComposer.editionMode === "inactive") {
52987
- this.DOMFocusableElementStore.focusableElement?.focus();
53037
+ this.DOMFocusableElementStore.focus();
52988
53038
  }
52989
53039
  }
52990
53040
  get gridEl() {
@@ -53329,6 +53379,322 @@ class Grid extends Component {
53329
53379
  }
53330
53380
  }
53331
53381
 
53382
+ css /* scss */ `
53383
+ .o_pivot_html_renderer {
53384
+ width: 100%;
53385
+ border-collapse: collapse;
53386
+
53387
+ &:hover {
53388
+ cursor: pointer;
53389
+ }
53390
+
53391
+ td,
53392
+ th {
53393
+ border: 1px solid #dee2e6;
53394
+ background-color: #fff;
53395
+ padding: 0.3rem;
53396
+ white-space: nowrap;
53397
+
53398
+ &:hover {
53399
+ filter: brightness(0.9);
53400
+ }
53401
+ }
53402
+
53403
+ td {
53404
+ text-align: right;
53405
+ }
53406
+
53407
+ th {
53408
+ background-color: #f5f5f5;
53409
+ font-weight: bold;
53410
+ color: black;
53411
+ }
53412
+
53413
+ .o_missing_value {
53414
+ color: #46646d;
53415
+ background: #e7f2f6;
53416
+ }
53417
+ }
53418
+ `;
53419
+ class PivotHTMLRenderer extends Component {
53420
+ static template = "o_spreadsheet.PivotHTMLRenderer";
53421
+ static components = { Checkbox };
53422
+ static props = {
53423
+ pivotId: String,
53424
+ onCellClicked: Function,
53425
+ };
53426
+ pivot = this.env.model.getters.getPivot(this.props.pivotId);
53427
+ data = {
53428
+ columns: [],
53429
+ rows: [],
53430
+ values: [],
53431
+ };
53432
+ state = useState({
53433
+ showMissingValuesOnly: false,
53434
+ });
53435
+ setup() {
53436
+ const table = this.pivot.getTableStructure();
53437
+ const formulaId = this.env.model.getters.getPivotFormulaId(this.props.pivotId);
53438
+ this.data = {
53439
+ columns: this._buildColHeaders(formulaId, table),
53440
+ rows: this._buildRowHeaders(formulaId, table),
53441
+ values: this._buildValues(formulaId, table),
53442
+ };
53443
+ }
53444
+ get tracker() {
53445
+ return this.env.model.getters.getPivotPresenceTracker(this.props.pivotId);
53446
+ }
53447
+ // ---------------------------------------------------------------------
53448
+ // Missing values building
53449
+ // ---------------------------------------------------------------------
53450
+ /**
53451
+ * Retrieve the data to display in the Pivot Table
53452
+ * In the case when showMissingValuesOnly is false, the returned value
53453
+ * is the complete data
53454
+ * In the case when showMissingValuesOnly is true, the returned value is
53455
+ * the data which contains only missing values in the rows and cols. In
53456
+ * the rows, we also return the parent rows of rows which contains missing
53457
+ * values, to give context to the user.
53458
+ *
53459
+ */
53460
+ getTableData() {
53461
+ if (!this.state.showMissingValuesOnly) {
53462
+ return this.data;
53463
+ }
53464
+ const colIndexes = this.getColumnsIndexes();
53465
+ const rowIndexes = this.getRowsIndexes();
53466
+ const columns = this.buildColumnsMissing(colIndexes);
53467
+ const rows = this.buildRowsMissing(rowIndexes);
53468
+ const values = this.buildValuesMissing(colIndexes, rowIndexes);
53469
+ return { columns, rows, values };
53470
+ }
53471
+ /**
53472
+ * Retrieve the parents of the given row
53473
+ * ex:
53474
+ * Australia
53475
+ * January
53476
+ * February
53477
+ * The parent of "January" is "Australia"
53478
+ */
53479
+ addRecursiveRow(index) {
53480
+ const rows = this.pivot.getTableStructure().rows;
53481
+ const row = [...rows[index].values];
53482
+ if (row.length <= 1) {
53483
+ return [index];
53484
+ }
53485
+ row.pop();
53486
+ const parentRowIndex = rows.findIndex((r) => JSON.stringify(r.values) === JSON.stringify(row));
53487
+ return [index].concat(this.addRecursiveRow(parentRowIndex));
53488
+ }
53489
+ /**
53490
+ * Create the columns to be used, based on the indexes of the columns in
53491
+ * which a missing value is present
53492
+ *
53493
+ */
53494
+ buildColumnsMissing(indexes) {
53495
+ // columnsMap explode the columns in an array of array of the same
53496
+ // size with the index of each column, repeated 'span' times.
53497
+ // ex:
53498
+ // | A | B |
53499
+ // | 1 | 2 | 3 |
53500
+ // => [
53501
+ // [0, 0, 1]
53502
+ // [0, 1, 2]
53503
+ // ]
53504
+ const columnsMap = [];
53505
+ for (const column of this.data.columns) {
53506
+ const columnMap = [];
53507
+ for (const index in column) {
53508
+ for (let i = 0; i < column[index].span; i++) {
53509
+ columnMap.push(parseInt(index, 10));
53510
+ }
53511
+ }
53512
+ columnsMap.push(columnMap);
53513
+ }
53514
+ // Remove the columns that are not present in indexes
53515
+ for (let i = columnsMap[columnsMap.length - 1].length; i >= 0; i--) {
53516
+ if (!indexes.includes(i)) {
53517
+ for (const columnMap of columnsMap) {
53518
+ columnMap.splice(i, 1);
53519
+ }
53520
+ }
53521
+ }
53522
+ // Build the columns
53523
+ const columns = [];
53524
+ for (const mapIndex in columnsMap) {
53525
+ const column = [];
53526
+ let index = undefined;
53527
+ let span = 1;
53528
+ for (let i = 0; i < columnsMap[mapIndex].length; i++) {
53529
+ if (index !== columnsMap[mapIndex][i]) {
53530
+ if (index !== undefined) {
53531
+ column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
53532
+ }
53533
+ index = columnsMap[mapIndex][i];
53534
+ span = 1;
53535
+ }
53536
+ else {
53537
+ span++;
53538
+ }
53539
+ }
53540
+ if (index !== undefined) {
53541
+ column.push(Object.assign({}, this.data.columns[mapIndex][index], { span }));
53542
+ }
53543
+ columns.push(column);
53544
+ }
53545
+ return columns;
53546
+ }
53547
+ /**
53548
+ * Create the rows to be used, based on the indexes of the rows in
53549
+ * which a missing value is present.
53550
+ */
53551
+ buildRowsMissing(indexes) {
53552
+ return indexes.map((index) => this.data.rows[index]);
53553
+ }
53554
+ /**
53555
+ * Create the value to be used, based on the indexes of the columns and
53556
+ * rows in which a missing value is present.
53557
+ */
53558
+ buildValuesMissing(colIndexes, rowIndexes) {
53559
+ const values = colIndexes.map(() => []);
53560
+ for (const row of rowIndexes) {
53561
+ for (const col in colIndexes) {
53562
+ values[col].push(this.data.values[colIndexes[col]][row]);
53563
+ }
53564
+ }
53565
+ return values;
53566
+ }
53567
+ getColumnsIndexes() {
53568
+ const indexes = new Set();
53569
+ for (let i = 0; i < this.data.columns.length; i++) {
53570
+ const exploded = [];
53571
+ for (let y = 0; y < this.data.columns[i].length; y++) {
53572
+ for (let x = 0; x < this.data.columns[i][y].span; x++) {
53573
+ exploded.push(this.data.columns[i][y]);
53574
+ }
53575
+ }
53576
+ for (let y = 0; y < exploded.length; y++) {
53577
+ if (exploded[y].isMissing) {
53578
+ indexes.add(y);
53579
+ }
53580
+ }
53581
+ }
53582
+ for (let i = 0; i < this.data.columns[this.data.columns.length - 1].length; i++) {
53583
+ const values = this.data.values[i];
53584
+ if (values.find((x) => x.isMissing)) {
53585
+ indexes.add(i);
53586
+ }
53587
+ }
53588
+ return Array.from(indexes).sort((a, b) => a - b);
53589
+ }
53590
+ getRowsIndexes() {
53591
+ const rowIndexes = new Set();
53592
+ for (let i = 0; i < this.data.rows.length; i++) {
53593
+ if (this.data.rows[i].isMissing) {
53594
+ rowIndexes.add(i);
53595
+ }
53596
+ for (const col of this.data.values) {
53597
+ if (col[i].isMissing) {
53598
+ this.addRecursiveRow(i).forEach((x) => rowIndexes.add(x));
53599
+ }
53600
+ }
53601
+ }
53602
+ return Array.from(rowIndexes).sort((a, b) => a - b);
53603
+ }
53604
+ // ---------------------------------------------------------------------
53605
+ // Data table creation
53606
+ // ---------------------------------------------------------------------
53607
+ _buildColHeaders(id, table) {
53608
+ const headers = [];
53609
+ for (const row of table.columns) {
53610
+ const current = [];
53611
+ for (const cell of row) {
53612
+ const args = [];
53613
+ for (let i = 0; i < cell.fields.length; i++) {
53614
+ args.push({ value: cell.fields[i] }, { value: cell.values[i] });
53615
+ }
53616
+ const domain = this.pivot.parseArgsToPivotDomain(args);
53617
+ const locale = this.env.model.getters.getLocale();
53618
+ if (domain.at(-1)?.field === "measure") {
53619
+ const { value, format } = this.pivot.getPivotMeasureValue(toString(domain.at(-1).value), domain);
53620
+ current.push({
53621
+ formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
53622
+ value: formatValue(value, { format, locale }),
53623
+ span: cell.width,
53624
+ isMissing: !this.tracker?.isHeaderPresent(domain),
53625
+ });
53626
+ }
53627
+ else {
53628
+ const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
53629
+ current.push({
53630
+ formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
53631
+ value: formatValue(value, { format, locale }),
53632
+ span: cell.width,
53633
+ isMissing: !this.tracker?.isHeaderPresent(domain),
53634
+ });
53635
+ }
53636
+ }
53637
+ headers.push(current);
53638
+ }
53639
+ const last = headers[headers.length - 1];
53640
+ headers[headers.length - 1] = last.map((cell) => {
53641
+ if (!cell.isMissing) {
53642
+ cell.style = "color: #756f6f;";
53643
+ }
53644
+ return cell;
53645
+ });
53646
+ return headers;
53647
+ }
53648
+ _buildRowHeaders(id, table) {
53649
+ const headers = [];
53650
+ for (const row of table.rows) {
53651
+ const args = [];
53652
+ for (let i = 0; i < row.fields.length; i++) {
53653
+ args.push({ value: row.fields[i] }, { value: row.values[i] });
53654
+ }
53655
+ const domain = this.pivot.parseArgsToPivotDomain(args);
53656
+ const { value, format } = this.pivot.getPivotHeaderValueAndFormat(domain);
53657
+ const locale = this.env.model.getters.getLocale();
53658
+ const cell = {
53659
+ formula: `=PIVOT.HEADER(${generatePivotArgs(id, domain).join(",")})`,
53660
+ value: formatValue(value, { format, locale }),
53661
+ isMissing: !this.tracker?.isHeaderPresent(domain),
53662
+ };
53663
+ if (row.indent > 1) {
53664
+ cell.style = `padding-left: ${row.indent - 1 * 10}px`;
53665
+ }
53666
+ headers.push(cell);
53667
+ }
53668
+ return headers;
53669
+ }
53670
+ _buildValues(id, table) {
53671
+ const values = [];
53672
+ for (const col of table.columns.at(-1) || []) {
53673
+ const current = [];
53674
+ const measure = toString(col.values[col.values.length - 1]);
53675
+ for (const row of table.rows) {
53676
+ const args = [];
53677
+ for (let i = 0; i < row.fields.length; i++) {
53678
+ args.push({ value: row.fields[i] }, { value: row.values[i] });
53679
+ }
53680
+ for (let i = 0; i < col.fields.length - 1; i++) {
53681
+ args.push({ value: col.fields[i] }, { value: col.values[i] });
53682
+ }
53683
+ const domain = this.pivot.parseArgsToPivotDomain(args);
53684
+ const { value, format } = this.pivot.getPivotCellValueAndFormat(measure, domain);
53685
+ const locale = this.env.model.getters.getLocale();
53686
+ current.push({
53687
+ formula: `=PIVOT.VALUE(${generatePivotArgs(id, domain, measure).join(",")})`,
53688
+ value: formatValue(value, { format, locale }),
53689
+ isMissing: !this.tracker?.isValuePresent(measure, domain),
53690
+ });
53691
+ }
53692
+ values.push(current);
53693
+ }
53694
+ return values;
53695
+ }
53696
+ }
53697
+
53332
53698
  /**
53333
53699
  * BasePlugin
53334
53700
  *
@@ -56788,7 +57154,7 @@ class RangeAdapter {
56788
57154
  if (range.sheetId === cmd.sheetId) {
56789
57155
  return { changeType: "CHANGE", range };
56790
57156
  }
56791
- if (cmd.name && range.invalidSheetName === cmd.name) {
57157
+ if (isSheetNameEqual(range.invalidSheetName, cmd.name)) {
56792
57158
  const invalidSheetName = undefined;
56793
57159
  const sheetId = cmd.sheetId;
56794
57160
  const newRange = range.clone({ sheetId, invalidSheetName });
@@ -57405,7 +57771,7 @@ class SheetPlugin extends CorePlugin {
57405
57771
  if (name) {
57406
57772
  const unquotedName = getUnquotedSheetName(name);
57407
57773
  for (const key in this.sheetIdsMapName) {
57408
- if (key.toUpperCase() === unquotedName.toUpperCase()) {
57774
+ if (isSheetNameEqual(key, unquotedName)) {
57409
57775
  return this.sheetIdsMapName[key];
57410
57776
  }
57411
57777
  }
@@ -57653,7 +58019,7 @@ class SheetPlugin extends CorePlugin {
57653
58019
  }
57654
58020
  const { orderedSheetIds, sheets } = this;
57655
58021
  const name = cmd.name && cmd.name.trim().toLowerCase();
57656
- if (orderedSheetIds.find((id) => sheets[id]?.name.toLowerCase() === name && id !== cmd.sheetId)) {
58022
+ if (orderedSheetIds.find((id) => isSheetNameEqual(sheets[id]?.name, name) && id !== cmd.sheetId)) {
57657
58023
  return "DuplicatedSheetName" /* CommandResult.DuplicatedSheetName */;
57658
58024
  }
57659
58025
  if (FORBIDDEN_SHEETNAME_CHARS_IN_EXCEL_REGEX.test(name)) {
@@ -66546,6 +66912,55 @@ class HistoryPlugin extends UIPlugin {
66546
66912
  }
66547
66913
  }
66548
66914
 
66915
+ class PivotPresenceTracker {
66916
+ trackedValues = new Set();
66917
+ domainToArray(domain) {
66918
+ return domain.flatMap((node) => [node.field, toString(node.value)]);
66919
+ }
66920
+ isValuePresent(measure, domain) {
66921
+ const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
66922
+ return this.trackedValues.has(key);
66923
+ }
66924
+ isHeaderPresent(domain) {
66925
+ const key = JSON.stringify({ domain: this.domainToArray(domain) });
66926
+ return this.trackedValues.has(key);
66927
+ }
66928
+ trackValue(measure, domain) {
66929
+ const key = JSON.stringify({ measure, domain: this.domainToArray(domain) });
66930
+ this.trackedValues.add(key);
66931
+ }
66932
+ trackHeader(domain) {
66933
+ const key = JSON.stringify({ domain: this.domainToArray(domain) });
66934
+ this.trackedValues.add(key);
66935
+ }
66936
+ }
66937
+
66938
+ class PivotPresencePlugin extends UIPlugin {
66939
+ static getters = ["getPivotPresenceTracker"];
66940
+ trackPresencePivotId;
66941
+ tracker;
66942
+ handle(cmd) {
66943
+ switch (cmd.type) {
66944
+ case "PIVOT_START_PRESENCE_TRACKING":
66945
+ this.tracker = new PivotPresenceTracker();
66946
+ this.trackPresencePivotId = cmd.pivotId;
66947
+ break;
66948
+ case "PIVOT_STOP_PRESENCE_TRACKING":
66949
+ this.trackPresencePivotId = undefined;
66950
+ break;
66951
+ }
66952
+ }
66953
+ getPivotPresenceTracker(pivotId) {
66954
+ if (this.trackPresencePivotId !== pivotId) {
66955
+ return undefined;
66956
+ }
66957
+ if (!this.tracker) {
66958
+ throw new Error("Tracker not initialized");
66959
+ }
66960
+ return this.tracker;
66961
+ }
66962
+ }
66963
+
66549
66964
  class SplitToColumnsPlugin extends UIPlugin {
66550
66965
  static getters = ["getAutomaticSeparator"];
66551
66966
  allowDispatch(cmd) {
@@ -69296,6 +69711,7 @@ const featurePluginRegistry = new Registry()
69296
69711
  .add("automatic_sum", AutomaticSumPlugin)
69297
69712
  .add("format", FormatPlugin)
69298
69713
  .add("insert_pivot", InsertPivotPlugin)
69714
+ .add("pivot_presence", PivotPresencePlugin)
69299
69715
  .add("split_to_columns", SplitToColumnsPlugin)
69300
69716
  .add("collaborative", CollaborativePlugin)
69301
69717
  .add("history", HistoryPlugin)
@@ -69676,11 +70092,11 @@ class BottomBarSheet extends Component {
69676
70092
  if (ev.key === "Enter") {
69677
70093
  ev.preventDefault();
69678
70094
  this.stopEdition();
69679
- this.DOMFocusableElementStore.focusableElement?.focus();
70095
+ this.DOMFocusableElementStore.focus();
69680
70096
  }
69681
70097
  if (ev.key === "Escape") {
69682
70098
  this.cancelEdition();
69683
- this.DOMFocusableElementStore.focusableElement?.focus();
70099
+ this.DOMFocusableElementStore.focus();
69684
70100
  }
69685
70101
  }
69686
70102
  onMouseEventSheetName(ev) {
@@ -76291,6 +76707,7 @@ const components = {
76291
76707
  PivotDimensionOrder,
76292
76708
  PivotDimension,
76293
76709
  PivotLayoutConfigurator,
76710
+ PivotHTMLRenderer,
76294
76711
  PivotDeferUpdate,
76295
76712
  PivotTitleSection,
76296
76713
  CogWheelMenu,
@@ -76340,6 +76757,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
76340
76757
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, 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, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
76341
76758
 
76342
76759
 
76343
- __info__.version = "18.2.11";
76344
- __info__.date = "2025-05-12T05:25:59.138Z";
76345
- __info__.hash = "eb87dca";
76760
+ __info__.version = "18.2.12";
76761
+ __info__.date = "2025-05-13T17:52:23.989Z";
76762
+ __info__.hash = "ba2ba9b";