@odoo/o-spreadsheet 18.2.0-alpha.0 → 18.2.0-alpha.2

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.0-alpha.0
6
- * @date 2024-12-26T08:02:39.123Z
7
- * @hash 0f45915
5
+ * @version 18.2.0-alpha.2
6
+ * @date 2025-01-15T08:06:32.137Z
7
+ * @hash 4f96c47
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -356,6 +356,7 @@
356
356
  ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
357
357
  ComponentsImportance[ComponentsImportance["FigureAnchor"] = 1000] = "FigureAnchor";
358
358
  ComponentsImportance[ComponentsImportance["FigureSnapLine"] = 1001] = "FigureSnapLine";
359
+ ComponentsImportance[ComponentsImportance["FigureTooltip"] = 1002] = "FigureTooltip";
359
360
  })(ComponentsImportance || (ComponentsImportance = {}));
360
361
  let DEFAULT_SHEETVIEW_SIZE = 0;
361
362
  function getDefaultSheetViewSize() {
@@ -975,6 +976,16 @@
975
976
  }
976
977
  return result;
977
978
  }
979
+ function getUniqueText(text, texts, options = {}) {
980
+ const compute = options.compute ?? ((text, i) => `${text} (${i})`);
981
+ const computeFirstOne = options.computeFirstOne ?? false;
982
+ let i = options.start ?? 1;
983
+ let newText = computeFirstOne ? compute(text, i) : text;
984
+ while (texts.includes(newText)) {
985
+ newText = compute(text, i++);
986
+ }
987
+ return newText;
988
+ }
978
989
 
979
990
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
980
991
  const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
@@ -3710,6 +3721,7 @@
3710
3721
  CommandResult["SheetIsHidden"] = "SheetIsHidden";
3711
3722
  CommandResult["InvalidTableResize"] = "InvalidTableResize";
3712
3723
  CommandResult["PivotIdNotFound"] = "PivotIdNotFound";
3724
+ CommandResult["PivotInError"] = "PivotInError";
3713
3725
  CommandResult["EmptyName"] = "EmptyName";
3714
3726
  CommandResult["ValueCellIsInvalidFormula"] = "ValueCellIsInvalidFormula";
3715
3727
  CommandResult["InvalidDefinition"] = "InvalidDefinition";
@@ -6027,10 +6039,10 @@
6027
6039
  }
6028
6040
  }
6029
6041
  /**
6030
- * Copy a range. If the range is on the sheetIdFrom, the range will target
6042
+ * Duplicate a range. If the range is on the sheetIdFrom, the range will target
6031
6043
  * sheetIdTo.
6032
6044
  */
6033
- function copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
6045
+ function duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, range) {
6034
6046
  const sheetId = range.sheetId === sheetIdFrom ? sheetIdTo : range.sheetId;
6035
6047
  return range.clone({ sheetId });
6036
6048
  }
@@ -7478,18 +7490,18 @@
7478
7490
  });
7479
7491
  return newY.length === newX.length ? newY : transposeMatrix(newY);
7480
7492
  }
7481
- function getMovingAverageValues(dataset, windowSize = DEFAULT_WINDOW_SIZE) {
7493
+ function getMovingAverageValues(dataset, labels, windowSize = DEFAULT_WINDOW_SIZE) {
7482
7494
  const values = [];
7483
7495
  // Fill the starting values with null until we have a full window
7484
7496
  for (let i = 0; i < windowSize - 1; i++) {
7485
- values.push(null);
7497
+ values.push({ x: labels[i], y: NaN });
7486
7498
  }
7487
7499
  for (let i = 0; i <= dataset.length - windowSize; i++) {
7488
7500
  let sum = 0;
7489
7501
  for (let j = i; j < i + windowSize; j++) {
7490
7502
  sum += dataset[j];
7491
7503
  }
7492
- values.push(sum / windowSize);
7504
+ values.push({ x: labels[i + windowSize - 1], y: sum / windowSize });
7493
7505
  }
7494
7506
  return values;
7495
7507
  }
@@ -9463,6 +9475,150 @@ stores.inject(MyMetaStore, storeInstance);
9463
9475
  }
9464
9476
  }
9465
9477
 
9478
+ /**
9479
+ * This file is largely inspired by owl 1.
9480
+ * `css` tag has been removed from owl 2 without workaround to manage css.
9481
+ * So, the solution was to import the behavior of owl 1 directly in our
9482
+ * codebase, with one difference: the css is added to the sheet as soon as the
9483
+ * css tag is executed. In owl 1, the css was added as soon as a Component was
9484
+ * created for the first time.
9485
+ */
9486
+ const STYLESHEETS = {};
9487
+ let nextId = 0;
9488
+ /**
9489
+ * CSS tag helper for defining inline stylesheets. With this, one can simply define
9490
+ * an inline stylesheet with just the following code:
9491
+ * ```js
9492
+ * css`.component-a { color: red; }`;
9493
+ * ```
9494
+ */
9495
+ function css(strings, ...args) {
9496
+ const name = `__sheet__${nextId++}`;
9497
+ const value = String.raw(strings, ...args);
9498
+ registerSheet(name, value);
9499
+ activateSheet(name);
9500
+ return name;
9501
+ }
9502
+ function processSheet(str) {
9503
+ const tokens = str.split(/(\{|\}|;)/).map((s) => s.trim());
9504
+ const selectorStack = [];
9505
+ const parts = [];
9506
+ let rules = [];
9507
+ function generateSelector(stackIndex, parentSelector) {
9508
+ const parts = [];
9509
+ for (const selector of selectorStack[stackIndex]) {
9510
+ let part = (parentSelector && parentSelector + " " + selector) || selector;
9511
+ if (part.includes("&")) {
9512
+ part = selector.replace(/&/g, parentSelector || "");
9513
+ }
9514
+ if (stackIndex < selectorStack.length - 1) {
9515
+ part = generateSelector(stackIndex + 1, part);
9516
+ }
9517
+ parts.push(part);
9518
+ }
9519
+ return parts.join(", ");
9520
+ }
9521
+ function generateRules() {
9522
+ if (rules.length) {
9523
+ parts.push(generateSelector(0) + " {");
9524
+ parts.push(...rules);
9525
+ parts.push("}");
9526
+ rules = [];
9527
+ }
9528
+ }
9529
+ while (tokens.length) {
9530
+ let token = tokens.shift();
9531
+ if (token === "}") {
9532
+ generateRules();
9533
+ selectorStack.pop();
9534
+ }
9535
+ else {
9536
+ if (tokens[0] === "{") {
9537
+ generateRules();
9538
+ selectorStack.push(token.split(/\s*,\s*/));
9539
+ tokens.shift();
9540
+ }
9541
+ if (tokens[0] === ";") {
9542
+ rules.push(" " + token + ";");
9543
+ }
9544
+ }
9545
+ }
9546
+ return parts.join("\n");
9547
+ }
9548
+ function registerSheet(id, css) {
9549
+ const sheet = document.createElement("style");
9550
+ sheet.textContent = processSheet(css);
9551
+ STYLESHEETS[id] = sheet;
9552
+ }
9553
+ function activateSheet(id) {
9554
+ const sheet = STYLESHEETS[id];
9555
+ sheet.setAttribute("component", id);
9556
+ document.head.appendChild(sheet);
9557
+ }
9558
+ function getTextDecoration({ strikethrough, underline, }) {
9559
+ if (!strikethrough && !underline) {
9560
+ return "none";
9561
+ }
9562
+ return `${strikethrough ? "line-through" : ""} ${underline ? "underline" : ""}`;
9563
+ }
9564
+ /**
9565
+ * Convert the cell style to CSS properties.
9566
+ */
9567
+ function cellStyleToCss(style) {
9568
+ const attributes = cellTextStyleToCss(style);
9569
+ if (!style)
9570
+ return attributes;
9571
+ if (style.fillColor) {
9572
+ attributes["background"] = style.fillColor;
9573
+ }
9574
+ return attributes;
9575
+ }
9576
+ /**
9577
+ * Convert the cell text style to CSS properties.
9578
+ */
9579
+ function cellTextStyleToCss(style) {
9580
+ const attributes = {};
9581
+ if (!style)
9582
+ return attributes;
9583
+ if (style.bold) {
9584
+ attributes["font-weight"] = "bold";
9585
+ }
9586
+ if (style.italic) {
9587
+ attributes["font-style"] = "italic";
9588
+ }
9589
+ if (style.strikethrough || style.underline) {
9590
+ let decoration = style.strikethrough ? "line-through" : "";
9591
+ decoration = style.underline ? decoration + " underline" : decoration;
9592
+ attributes["text-decoration"] = decoration;
9593
+ }
9594
+ if (style.textColor) {
9595
+ attributes["color"] = style.textColor;
9596
+ }
9597
+ return attributes;
9598
+ }
9599
+ /**
9600
+ * Transform CSS properties into a CSS string.
9601
+ */
9602
+ function cssPropertiesToCss(attributes) {
9603
+ let styleStr = "";
9604
+ for (const attName in attributes) {
9605
+ if (!attributes[attName]) {
9606
+ continue;
9607
+ }
9608
+ styleStr += `${attName}:${attributes[attName]}; `;
9609
+ }
9610
+ return styleStr;
9611
+ }
9612
+ function getElementMargins(el) {
9613
+ const style = window.getComputedStyle(el);
9614
+ return {
9615
+ top: parseInt(style.marginTop, 10) || 0,
9616
+ bottom: parseInt(style.marginBottom, 10) || 0,
9617
+ left: parseInt(style.marginLeft, 10) || 0,
9618
+ right: parseInt(style.marginRight, 10) || 0,
9619
+ };
9620
+ }
9621
+
9466
9622
  const TREND_LINE_XAXIS_ID = "x1";
9467
9623
  /**
9468
9624
  * This file contains helpers that are common to different charts (mainly
@@ -9515,25 +9671,25 @@ stores.inject(MyMetaStore, storeInstance);
9515
9671
  };
9516
9672
  }
9517
9673
  /**
9518
- * Copy the dataSets given. All the ranges which are on sheetIdFrom will target
9674
+ * Duplicate the dataSets. All ranges on sheetIdFrom are adapted to target
9519
9675
  * sheetIdTo.
9520
9676
  */
9521
- function copyDataSetsWithNewSheetId(sheetIdFrom, sheetIdTo, dataSets) {
9677
+ function duplicateDataSetsInDuplicatedSheet(sheetIdFrom, sheetIdTo, dataSets) {
9522
9678
  return dataSets.map((ds) => {
9523
9679
  return {
9524
- dataRange: copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, ds.dataRange),
9680
+ dataRange: duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, ds.dataRange),
9525
9681
  labelCell: ds.labelCell
9526
- ? copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, ds.labelCell)
9682
+ ? duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, ds.labelCell)
9527
9683
  : undefined,
9528
9684
  };
9529
9685
  });
9530
9686
  }
9531
9687
  /**
9532
- * Copy a range. If the range is on the sheetIdFrom, the range will target
9688
+ * Duplicate a range. If the range is on the sheetIdFrom, the range will target
9533
9689
  * sheetIdTo.
9534
9690
  */
9535
- function copyLabelRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) {
9536
- return range ? copyRangeWithNewSheetId(sheetIdFrom, sheetIdTo, range) : undefined;
9691
+ function duplicateLabelRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, range) {
9692
+ return range ? duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, range) : undefined;
9537
9693
  }
9538
9694
  /**
9539
9695
  * Adapt a single range of a chart
@@ -9786,10 +9942,11 @@ stores.inject(MyMetaStore, storeInstance);
9786
9942
  if (isNaN(value))
9787
9943
  return value;
9788
9944
  const { locale, format } = localeFormat;
9789
- return formatValue(value, {
9945
+ const formattedValue = formatValue(value, {
9790
9946
  locale,
9791
9947
  format: !format && Math.abs(value) >= 1000 ? "#,##" : format,
9792
9948
  });
9949
+ return truncateLabel(formattedValue);
9793
9950
  };
9794
9951
  }
9795
9952
  const CHART_AXIS_CHOICES = [
@@ -9804,6 +9961,15 @@ stores.inject(MyMetaStore, storeInstance);
9804
9961
  }
9805
9962
  return pieColors;
9806
9963
  }
9964
+ function truncateLabel(label) {
9965
+ if (!label) {
9966
+ return "";
9967
+ }
9968
+ if (label.length > MAX_CHAR_LABEL) {
9969
+ return label.substring(0, MAX_CHAR_LABEL) + "…";
9970
+ }
9971
+ return label;
9972
+ }
9807
9973
 
9808
9974
  /** This is a chartJS plugin that will draw the values of each data next to the point/bar/pie slice */
9809
9975
  const chartShowValuesPlugin = {
@@ -9999,6 +10165,18 @@ stores.inject(MyMetaStore, storeInstance);
9999
10165
 
10000
10166
  window.Chart?.register(waterfallLinesPlugin);
10001
10167
  window.Chart?.register(chartShowValuesPlugin);
10168
+ css /* scss */ `
10169
+ .o-spreadsheet {
10170
+ .o-chart-custom-tooltip {
10171
+ font-size: 12px;
10172
+ background-color: #fff;
10173
+ z-index: ${ComponentsImportance.FigureTooltip};
10174
+ table td span {
10175
+ box-sizing: border-box;
10176
+ }
10177
+ }
10178
+ }
10179
+ `;
10002
10180
  class ChartJsComponent extends owl.Component {
10003
10181
  static template = "o-spreadsheet-ChartJsComponent";
10004
10182
  static props = {
@@ -10237,11 +10415,11 @@ stores.inject(MyMetaStore, storeInstance);
10237
10415
  keyValue: keyValueZone ? zoneToXc(keyValueZone) : undefined,
10238
10416
  };
10239
10417
  }
10240
- copyForSheetId(sheetId) {
10241
- const baseline = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.baseline);
10242
- const keyValue = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.keyValue);
10243
- const definition = this.getDefinitionWithSpecificRanges(baseline, keyValue, sheetId);
10244
- return new ScorecardChart(definition, sheetId, this.getters);
10418
+ duplicateInDuplicatedSheet(newSheetId) {
10419
+ const baseline = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.baseline);
10420
+ const keyValue = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.keyValue);
10421
+ const definition = this.getDefinitionWithSpecificRanges(baseline, keyValue, newSheetId);
10422
+ return new ScorecardChart(definition, newSheetId, this.getters);
10245
10423
  }
10246
10424
  copyInSheetId(sheetId) {
10247
10425
  const definition = this.getDefinitionWithSpecificRanges(this.baseline, this.keyValue, sheetId);
@@ -19931,6 +20109,17 @@ stores.inject(MyMetaStore, storeInstance);
19931
20109
  },
19932
20110
  isExported: true,
19933
20111
  };
20112
+ // -----------------------------------------------------------------------------
20113
+ // VALUE
20114
+ // -----------------------------------------------------------------------------
20115
+ const VALUE = {
20116
+ description: _t("Converts a string to a numeric value."),
20117
+ args: [arg("value (number)", _t("the string to be converted"))],
20118
+ compute: function (value) {
20119
+ return toNumber(value, this.locale);
20120
+ },
20121
+ isExported: true,
20122
+ };
19934
20123
 
19935
20124
  var text = /*#__PURE__*/Object.freeze({
19936
20125
  __proto__: null,
@@ -19953,7 +20142,8 @@ stores.inject(MyMetaStore, storeInstance);
19953
20142
  TEXT: TEXT,
19954
20143
  TEXTJOIN: TEXTJOIN,
19955
20144
  TRIM: TRIM,
19956
- UPPER: UPPER
20145
+ UPPER: UPPER,
20146
+ VALUE: VALUE
19957
20147
  });
19958
20148
 
19959
20149
  // -----------------------------------------------------------------------------
@@ -22556,15 +22746,6 @@ stores.inject(MyMetaStore, storeInstance);
22556
22746
  },
22557
22747
  animation: false,
22558
22748
  };
22559
- function truncateLabel(label) {
22560
- if (!label) {
22561
- return "";
22562
- }
22563
- if (label.length > MAX_CHAR_LABEL) {
22564
- return label.substring(0, MAX_CHAR_LABEL) + "…";
22565
- }
22566
- return label;
22567
- }
22568
22749
  function chartToImage(runtime, figure, type) {
22569
22750
  // wrap the canvas in a div with a fixed size because chart.js would
22570
22751
  // fill the whole page otherwise
@@ -22886,150 +23067,6 @@ stores.inject(MyMetaStore, storeInstance);
22886
23067
  */
22887
23068
  const iconsOnCellRegistry = new Registry();
22888
23069
 
22889
- /**
22890
- * This file is largely inspired by owl 1.
22891
- * `css` tag has been removed from owl 2 without workaround to manage css.
22892
- * So, the solution was to import the behavior of owl 1 directly in our
22893
- * codebase, with one difference: the css is added to the sheet as soon as the
22894
- * css tag is executed. In owl 1, the css was added as soon as a Component was
22895
- * created for the first time.
22896
- */
22897
- const STYLESHEETS = {};
22898
- let nextId = 0;
22899
- /**
22900
- * CSS tag helper for defining inline stylesheets. With this, one can simply define
22901
- * an inline stylesheet with just the following code:
22902
- * ```js
22903
- * css`.component-a { color: red; }`;
22904
- * ```
22905
- */
22906
- function css(strings, ...args) {
22907
- const name = `__sheet__${nextId++}`;
22908
- const value = String.raw(strings, ...args);
22909
- registerSheet(name, value);
22910
- activateSheet(name);
22911
- return name;
22912
- }
22913
- function processSheet(str) {
22914
- const tokens = str.split(/(\{|\}|;)/).map((s) => s.trim());
22915
- const selectorStack = [];
22916
- const parts = [];
22917
- let rules = [];
22918
- function generateSelector(stackIndex, parentSelector) {
22919
- const parts = [];
22920
- for (const selector of selectorStack[stackIndex]) {
22921
- let part = (parentSelector && parentSelector + " " + selector) || selector;
22922
- if (part.includes("&")) {
22923
- part = selector.replace(/&/g, parentSelector || "");
22924
- }
22925
- if (stackIndex < selectorStack.length - 1) {
22926
- part = generateSelector(stackIndex + 1, part);
22927
- }
22928
- parts.push(part);
22929
- }
22930
- return parts.join(", ");
22931
- }
22932
- function generateRules() {
22933
- if (rules.length) {
22934
- parts.push(generateSelector(0) + " {");
22935
- parts.push(...rules);
22936
- parts.push("}");
22937
- rules = [];
22938
- }
22939
- }
22940
- while (tokens.length) {
22941
- let token = tokens.shift();
22942
- if (token === "}") {
22943
- generateRules();
22944
- selectorStack.pop();
22945
- }
22946
- else {
22947
- if (tokens[0] === "{") {
22948
- generateRules();
22949
- selectorStack.push(token.split(/\s*,\s*/));
22950
- tokens.shift();
22951
- }
22952
- if (tokens[0] === ";") {
22953
- rules.push(" " + token + ";");
22954
- }
22955
- }
22956
- }
22957
- return parts.join("\n");
22958
- }
22959
- function registerSheet(id, css) {
22960
- const sheet = document.createElement("style");
22961
- sheet.textContent = processSheet(css);
22962
- STYLESHEETS[id] = sheet;
22963
- }
22964
- function activateSheet(id) {
22965
- const sheet = STYLESHEETS[id];
22966
- sheet.setAttribute("component", id);
22967
- document.head.appendChild(sheet);
22968
- }
22969
- function getTextDecoration({ strikethrough, underline, }) {
22970
- if (!strikethrough && !underline) {
22971
- return "none";
22972
- }
22973
- return `${strikethrough ? "line-through" : ""} ${underline ? "underline" : ""}`;
22974
- }
22975
- /**
22976
- * Convert the cell style to CSS properties.
22977
- */
22978
- function cellStyleToCss(style) {
22979
- const attributes = cellTextStyleToCss(style);
22980
- if (!style)
22981
- return attributes;
22982
- if (style.fillColor) {
22983
- attributes["background"] = style.fillColor;
22984
- }
22985
- return attributes;
22986
- }
22987
- /**
22988
- * Convert the cell text style to CSS properties.
22989
- */
22990
- function cellTextStyleToCss(style) {
22991
- const attributes = {};
22992
- if (!style)
22993
- return attributes;
22994
- if (style.bold) {
22995
- attributes["font-weight"] = "bold";
22996
- }
22997
- if (style.italic) {
22998
- attributes["font-style"] = "italic";
22999
- }
23000
- if (style.strikethrough || style.underline) {
23001
- let decoration = style.strikethrough ? "line-through" : "";
23002
- decoration = style.underline ? decoration + " underline" : decoration;
23003
- attributes["text-decoration"] = decoration;
23004
- }
23005
- if (style.textColor) {
23006
- attributes["color"] = style.textColor;
23007
- }
23008
- return attributes;
23009
- }
23010
- /**
23011
- * Transform CSS properties into a CSS string.
23012
- */
23013
- function cssPropertiesToCss(attributes) {
23014
- let styleStr = "";
23015
- for (const attName in attributes) {
23016
- if (!attributes[attName]) {
23017
- continue;
23018
- }
23019
- styleStr += `${attName}:${attributes[attName]}; `;
23020
- }
23021
- return styleStr;
23022
- }
23023
- function getElementMargins(el) {
23024
- const style = window.getComputedStyle(el);
23025
- return {
23026
- top: parseInt(style.marginTop, 10) || 0,
23027
- bottom: parseInt(style.marginBottom, 10) || 0,
23028
- left: parseInt(style.marginLeft, 10) || 0,
23029
- right: parseInt(style.marginRight, 10) || 0,
23030
- };
23031
- }
23032
-
23033
23070
  css /* scss */ `
23034
23071
  .o-spreadsheet {
23035
23072
  .o-icon {
@@ -24141,7 +24178,7 @@ stores.inject(MyMetaStore, storeInstance);
24141
24178
  return width;
24142
24179
  return Math.round((width / WIDTH_FACTOR) * 100) / 100;
24143
24180
  }
24144
- function extractStyle(data, styleId, formatId, borderId) {
24181
+ function extractStyle(data, content, styleId, formatId, borderId) {
24145
24182
  const style = styleId ? data.styles[styleId] : {};
24146
24183
  const format = formatId ? data.formats[formatId] : undefined;
24147
24184
  const styles = {
@@ -24163,7 +24200,7 @@ stores.inject(MyMetaStore, storeInstance);
24163
24200
  vertical: style.verticalAlign
24164
24201
  ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
24165
24202
  : undefined,
24166
- wrapText: style.wrapping === "wrap" || undefined,
24203
+ wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
24167
24204
  },
24168
24205
  };
24169
24206
  styles.font["strike"] = !!style?.strikethrough || undefined;
@@ -24394,7 +24431,7 @@ stores.inject(MyMetaStore, storeInstance);
24394
24431
  return undefined;
24395
24432
  }
24396
24433
  function isChartData(data) {
24397
- return "dataSets" in data;
24434
+ return "dataSets" in data && data.dataSets.length > 0;
24398
24435
  }
24399
24436
  function isImageData(data) {
24400
24437
  return "imageSrc" in data;
@@ -24740,9 +24777,8 @@ stores.inject(MyMetaStore, storeInstance);
24740
24777
  }
24741
24778
  return rows;
24742
24779
  }
24743
- /** Remove newlines (\n) in shared strings, We do not support them */
24744
24780
  function convertSharedStrings(xlsxSharedStrings) {
24745
- return xlsxSharedStrings.map((str) => str.replace(/\n/g, ""));
24781
+ return xlsxSharedStrings.map(replaceNewLines);
24746
24782
  }
24747
24783
  function convertCells(sheet, data, sheetDims, warningManager) {
24748
24784
  const cells = {};
@@ -25830,15 +25866,10 @@ stores.inject(MyMetaStore, storeInstance);
25830
25866
  getSharedStrings() {
25831
25867
  return this.mapOnElements({ parent: this.rootFile.file.xml, query: "si" }, (ssElement) => {
25832
25868
  // Shared string can either be a simple text, or a rich text (text with formatting, possibly in multiple parts)
25833
- if (ssElement.children[0].tagName === "t") {
25834
- return this.extractTextContent(ssElement) || "";
25835
- }
25836
25869
  // We don't support rich text formatting, we'll only extract the text
25837
- else {
25838
- return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
25839
- return this.extractTextContent(textElement) || "";
25840
- }).join("");
25841
- }
25870
+ return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
25871
+ return this.extractTextContent(textElement) || "";
25872
+ }).join("");
25842
25873
  });
25843
25874
  }
25844
25875
  }
@@ -27155,12 +27186,9 @@ stores.inject(MyMetaStore, storeInstance);
27155
27186
  }
27156
27187
  const oldName = sheet.name;
27157
27188
  const escapedName = sanitizeSheetName(oldName, "_");
27158
- let i = 1;
27159
- let newName = escapedName;
27160
- while (namesTaken.includes(newName)) {
27161
- newName = `${escapedName}${i}`;
27162
- i++;
27163
- }
27189
+ const newName = getUniqueText(escapedName, namesTaken, {
27190
+ compute: (name, i) => `${name}${i}`,
27191
+ });
27164
27192
  sheet.name = newName;
27165
27193
  namesTaken.push(newName);
27166
27194
  const replaceName = (str) => {
@@ -27479,6 +27507,13 @@ stores.inject(MyMetaStore, storeInstance);
27479
27507
  }
27480
27508
  return data;
27481
27509
  },
27510
+ })
27511
+ .add("migration_24", {
27512
+ // Empty migration to allow odoo migrate pivot custom sorting.
27513
+ versionFrom: "24",
27514
+ migrate(data) {
27515
+ return data;
27516
+ },
27482
27517
  });
27483
27518
  function fixOverlappingFilters(data) {
27484
27519
  for (let sheet of data.sheets || []) {
@@ -27506,7 +27541,7 @@ stores.inject(MyMetaStore, storeInstance);
27506
27541
  * a breaking change is made in the way the state is handled, and an upgrade
27507
27542
  * function should be defined
27508
27543
  */
27509
- const CURRENT_VERSION = 24;
27544
+ const CURRENT_VERSION = 25;
27510
27545
  const INITIAL_SHEET_ID = "Sheet1";
27511
27546
  /**
27512
27547
  * This function tries to load anything that could look like a valid
@@ -28407,12 +28442,12 @@ stores.inject(MyMetaStore, storeInstance);
28407
28442
  }
28408
28443
  const numberOfStep = 5 * trendLabels.length;
28409
28444
  const step = (xmax - xmin) / numberOfStep;
28410
- const newLabels = range(xmin, xmax + step / 2, step);
28411
- const newValues = interpolateData(config, filteredValues, filteredLabels, newLabels);
28412
- if (!newValues.length) {
28445
+ const trendNewLabels = range(xmin, xmax + step / 2, step);
28446
+ const trendValues = interpolateData(config, filteredValues, filteredLabels, trendNewLabels);
28447
+ if (!trendValues.length) {
28413
28448
  return;
28414
28449
  }
28415
- return newValues;
28450
+ return trendValues;
28416
28451
  }
28417
28452
  function interpolateData(config, values, labels, newLabels) {
28418
28453
  if (values.length < 2 || labels.length < 2 || newLabels.length === 0) {
@@ -28428,13 +28463,16 @@ stores.inject(MyMetaStore, storeInstance);
28428
28463
  case "polynomial": {
28429
28464
  const order = config.order;
28430
28465
  if (!order) {
28431
- return Array.from({ length: newLabels.length }, () => NaN);
28466
+ return newLabels.map((x) => ({ x, y: NaN }));
28432
28467
  }
28433
28468
  if (order === 1) {
28434
- return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0];
28469
+ return predictLinearValues([values], [normalizedLabels], [normalizedNewLabels], true)[0].map((y, i) => ({ x: newLabels[i], y }));
28435
28470
  }
28436
28471
  const coeffs = polynomialRegression(values, normalizedLabels, order, true).flat();
28437
- return normalizedNewLabels.map((v) => evaluatePolynomial(coeffs, v, order));
28472
+ return normalizedNewLabels.map((x, i) => ({
28473
+ x: newLabels[i],
28474
+ y: evaluatePolynomial(coeffs, x, order),
28475
+ }));
28438
28476
  }
28439
28477
  case "exponential": {
28440
28478
  const positiveLogValues = [];
@@ -28446,22 +28484,22 @@ stores.inject(MyMetaStore, storeInstance);
28446
28484
  }
28447
28485
  }
28448
28486
  if (!filteredLabels.length) {
28449
- return Array.from({ length: newLabels.length }, () => NaN);
28487
+ return newLabels.map((x) => ({ x, y: NaN }));
28450
28488
  }
28451
- return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0];
28489
+ return expM(predictLinearValues([positiveLogValues], [filteredLabels], [normalizedNewLabels], true))[0].map((y, i) => ({ x: newLabels[i], y }));
28452
28490
  }
28453
28491
  case "logarithmic": {
28454
- return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0];
28492
+ return predictLinearValues([values], logM([normalizedLabels]), logM([normalizedNewLabels]), true)[0].map((y, i) => ({ x: newLabels[i], y }));
28455
28493
  }
28456
28494
  case "trailingMovingAverage": {
28457
- return getMovingAverageValues(values, config.window);
28495
+ return getMovingAverageValues(values, labels, config.window);
28458
28496
  }
28459
28497
  default:
28460
- return Array.from({ length: newLabels.length }, () => NaN);
28498
+ return newLabels.map((x) => ({ x, y: NaN }));
28461
28499
  }
28462
28500
  }
28463
28501
  catch (e) {
28464
- return Array.from({ length: newLabels.length }, () => NaN);
28502
+ return newLabels.map((x) => ({ x, y: NaN }));
28465
28503
  }
28466
28504
  }
28467
28505
  function getChartAxisType(chart, labelRange, getters) {
@@ -28683,7 +28721,7 @@ stores.inject(MyMetaStore, storeInstance);
28683
28721
  : undefined;
28684
28722
  label =
28685
28723
  cell && labelRange
28686
- ? truncateLabel(cell.formattedValue)
28724
+ ? cell.formattedValue
28687
28725
  : (label = `${ChartTerms.Series} ${parseInt(dsIndex) + 1}`);
28688
28726
  }
28689
28727
  else {
@@ -28697,7 +28735,7 @@ stores.inject(MyMetaStore, storeInstance);
28697
28735
  // then using the classical aggregation method to sum the values.
28698
28736
  data.fill(1);
28699
28737
  }
28700
- else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), getters.getLocale()))) {
28738
+ else if (data.every((cell) => cell === undefined || cell === null || !isNumber(cell.toString(), DEFAULT_LOCALE))) {
28701
28739
  continue;
28702
28740
  }
28703
28741
  datasetValues.push({ data, label });
@@ -28773,7 +28811,7 @@ stores.inject(MyMetaStore, storeInstance);
28773
28811
  }
28774
28812
  return {
28775
28813
  datasets: [dataset],
28776
- labels: labelsWithSubTotals.map(truncateLabel),
28814
+ labels: labelsWithSubTotals,
28777
28815
  };
28778
28816
  }
28779
28817
  function getLineChartDatasets(definition, args) {
@@ -29022,7 +29060,7 @@ stores.inject(MyMetaStore, storeInstance);
29022
29060
  generateLabels: (c) =>
29023
29061
  //@ts-ignore
29024
29062
  c.data.labels.map((label, index) => ({
29025
- text: label,
29063
+ text: truncateLabel(String(label)),
29026
29064
  strokeStyle: colors[index],
29027
29065
  fillStyle: colors[index],
29028
29066
  pointStyle: "rect",
@@ -29091,6 +29129,7 @@ stores.inject(MyMetaStore, storeInstance);
29091
29129
  return legendValues;
29092
29130
  },
29093
29131
  },
29132
+ onClick: () => { }, // Disables click interaction with the waterfall chart legend items
29094
29133
  };
29095
29134
  }
29096
29135
  function getRadarChartLegend(definition, args) {
@@ -29152,7 +29191,7 @@ stores.inject(MyMetaStore, storeInstance);
29152
29191
  generateLabels: (chart) => chart.data.datasets.map((dataset, index) => {
29153
29192
  if (dataset["xAxisID"] === TREND_LINE_XAXIS_ID) {
29154
29193
  return {
29155
- text: dataset.label ?? "",
29194
+ text: truncateLabel(dataset.label),
29156
29195
  fontColor,
29157
29196
  strokeStyle: dataset.borderColor,
29158
29197
  hidden: !chart.isDatasetVisible(index),
@@ -29162,7 +29201,7 @@ stores.inject(MyMetaStore, storeInstance);
29162
29201
  };
29163
29202
  }
29164
29203
  return {
29165
- text: dataset.label ?? "",
29204
+ text: truncateLabel(dataset.label),
29166
29205
  fontColor,
29167
29206
  strokeStyle: dataset.borderColor,
29168
29207
  fillStyle: dataset.backgroundColor,
@@ -29232,14 +29271,19 @@ stores.inject(MyMetaStore, storeInstance);
29232
29271
  /* We add a second x axis here to draw the trend lines, with the labels length being
29233
29272
  * set so that the second axis points match the classical x axis
29234
29273
  */
29235
- const maxLength = Math.max(...trendDatasets.map((trendDataset) => trendDataset?.length || 0));
29236
29274
  scales[TREND_LINE_XAXIS_ID] = {
29237
29275
  ...scales.x,
29238
- type: "category",
29239
- labels: range(0, maxLength).map((x) => x.toString()),
29240
- offset: false,
29241
29276
  display: false,
29242
29277
  };
29278
+ if (axisType === "category" || axisType === "time") {
29279
+ /* We add a second x axis here to draw the trend lines, with the labels length being
29280
+ * set so that the second axis points match the classical x axis
29281
+ */
29282
+ const maxLength = Math.max(...trendDatasets.map((trendDataset) => trendDataset?.length || 0));
29283
+ scales[TREND_LINE_XAXIS_ID]["type"] = "category";
29284
+ scales[TREND_LINE_XAXIS_ID]["labels"] = range(0, maxLength).map((x) => x.toString());
29285
+ scales[TREND_LINE_XAXIS_ID]["offset"] = false;
29286
+ }
29243
29287
  }
29244
29288
  return scales;
29245
29289
  }
@@ -29304,7 +29348,10 @@ stores.inject(MyMetaStore, storeInstance);
29304
29348
  callback: formatTickValue({ format: axisFormats?.r, locale }),
29305
29349
  backdropColor: definition.background || "#FFFFFF",
29306
29350
  },
29307
- pointLabels: { color: chartFontColor(definition.background) },
29351
+ pointLabels: {
29352
+ color: chartFontColor(definition.background),
29353
+ callback: truncateLabel,
29354
+ },
29308
29355
  suggestedMin: minValue < 0 ? minValue - 1 : 0,
29309
29356
  },
29310
29357
  };
@@ -29401,6 +29448,11 @@ stores.inject(MyMetaStore, storeInstance);
29401
29448
  ticks: {
29402
29449
  padding: 5,
29403
29450
  color: fontColor,
29451
+ callback: function (tickValue) {
29452
+ // Category axis callback's internal tick value is the index of the label
29453
+ // https://www.chartjs.org/docs/latest/axes/labelling.html#creating-custom-tick-formats
29454
+ return truncateLabel(this.getLabelForValue(tickValue));
29455
+ },
29404
29456
  },
29405
29457
  grid: {
29406
29458
  display: false,
@@ -29480,8 +29532,70 @@ stores.inject(MyMetaStore, storeInstance);
29480
29532
  };
29481
29533
  }
29482
29534
 
29535
+ /**
29536
+ * Custom tooltip for the charts. Mostly copied from Odoo's custom tooltip, with some slight changes to make it work
29537
+ * with o-spreadsheet chart data and CSS.
29538
+ *
29539
+ * https://github.com/odoo/odoo/blob/18.0/addons/web/static/src/views/graph/graph_renderer.xml
29540
+ */
29541
+ const templates = /* xml */ `
29542
+ <templates>
29543
+ <t t-name="o-spreadsheet-CustomTooltip">
29544
+ <div
29545
+ class="o-chart-custom-tooltip border rounded px-2 py-1 pe-none mw-100 position-absolute text-nowrap shadow opacity-100">
29546
+ <table class="overflow-hidden m-0">
29547
+ <thead>
29548
+ <tr>
29549
+ <th class="o-tooltip-title align-baseline border-0 text-truncate" t-esc="title" t-attf-style="max-width: {{ labelsMaxWidth }}"/>
29550
+ </tr>
29551
+ </thead>
29552
+ <tbody>
29553
+ <tr t-foreach="tooltipItems" t-as="tooltipItem" t-key="tooltipItem_index">
29554
+ <td>
29555
+ <span
29556
+ class="badge ps-2 py-2 rounded-0 align-middle"
29557
+ t-attf-style="background-color: {{ tooltipItem.boxColor }}"
29558
+ > </span>
29559
+ <small
29560
+ t-if="tooltipItem.label"
29561
+ class="o-tooltip-label d-inline-block text-truncate align-middle smaller ms-2"
29562
+ t-esc="tooltipItem.label"
29563
+ t-attf-style="max-width: {{ labelsMaxWidth }}"
29564
+ />
29565
+ </td>
29566
+ <td class="o-tooltip-value ps-2 fw-bolder text-end">
29567
+ <small class="smaller d-inline-block text-truncate align-middle" t-attf-style="max-width: {{ valuesMaxWidth }}">
29568
+ <t t-esc="tooltipItem.value"/>
29569
+ <t t-if="tooltipItem.percentage">
29570
+ (
29571
+ <t t-esc="tooltipItem.percentage"/>
29572
+ %)
29573
+ </t>
29574
+ </small>
29575
+ </td>
29576
+ </tr>
29577
+ </tbody>
29578
+ </table>
29579
+ </div>
29580
+ </t>
29581
+ </templates>
29582
+ `;
29583
+ const app = new owl.App(owl.Component, { templates, translateFn: _t });
29584
+ function renderToString(templateName, context = {}) {
29585
+ return render(templateName, context).innerHTML;
29586
+ }
29587
+ function render(templateName, context = {}) {
29588
+ const templateFn = app.getTemplate(templateName);
29589
+ const bdom = templateFn(context, {});
29590
+ const div = document.createElement("div");
29591
+ owl.blockDom.mount(bdom, div);
29592
+ return div;
29593
+ }
29594
+
29483
29595
  function getBarChartTooltip(definition, args) {
29484
29596
  return {
29597
+ enabled: false,
29598
+ external: customTooltipHandler,
29485
29599
  callbacks: {
29486
29600
  title: function (tooltipItems) {
29487
29601
  return tooltipItems.some((item) => item.dataset.xAxisID !== TREND_LINE_XAXIS_ID)
@@ -29505,11 +29619,17 @@ stores.inject(MyMetaStore, storeInstance);
29505
29619
  function getLineChartTooltip(definition, args) {
29506
29620
  const { axisType, locale, axisFormats } = args;
29507
29621
  const labelFormat = axisFormats?.x;
29508
- const tooltip = { callbacks: {} };
29622
+ const tooltip = {
29623
+ enabled: false,
29624
+ external: customTooltipHandler,
29625
+ callbacks: {},
29626
+ };
29509
29627
  if (axisType === "linear") {
29510
29628
  tooltip.callbacks.label = (tooltipItem) => {
29511
29629
  const dataSetPoint = tooltipItem.parsed.y;
29512
- let label = tooltipItem.parsed.x;
29630
+ let label = tooltipItem.dataset.xAxisID === TREND_LINE_XAXIS_ID
29631
+ ? ""
29632
+ : tooltipItem.parsed.x;
29513
29633
  if (typeof label === "string" && isNumber(label, locale)) {
29514
29634
  label = toNumber(label, locale);
29515
29635
  }
@@ -29542,6 +29662,8 @@ stores.inject(MyMetaStore, storeInstance);
29542
29662
  const { locale, axisFormats } = args;
29543
29663
  const format = axisFormats?.y || axisFormats?.y1;
29544
29664
  return {
29665
+ enabled: false,
29666
+ external: customTooltipHandler,
29545
29667
  callbacks: {
29546
29668
  title: function (tooltipItems) {
29547
29669
  return tooltipItems[0].dataset.label;
@@ -29566,6 +29688,8 @@ stores.inject(MyMetaStore, storeInstance);
29566
29688
  const format = axisFormats?.y || axisFormats?.y1;
29567
29689
  const dataSeriesLabels = dataSetsValues.map((dataSet) => dataSet.label);
29568
29690
  return {
29691
+ enabled: false,
29692
+ external: customTooltipHandler,
29569
29693
  callbacks: {
29570
29694
  label: function (tooltipItem) {
29571
29695
  const [lastValue, currentValue] = tooltipItem.raw;
@@ -29597,6 +29721,8 @@ stores.inject(MyMetaStore, storeInstance);
29597
29721
  function getRadarChartTooltip(definition, args) {
29598
29722
  const { locale, axisFormats } = args;
29599
29723
  return {
29724
+ enabled: false,
29725
+ external: customTooltipHandler,
29600
29726
  callbacks: {
29601
29727
  label: function (tooltipItem) {
29602
29728
  const xLabel = tooltipItem.dataset?.label || tooltipItem.label;
@@ -29635,6 +29761,48 @@ stores.inject(MyMetaStore, storeInstance);
29635
29761
  const percentage = (dataset[dataIndex] / total) * 100;
29636
29762
  return percentage.toFixed(2);
29637
29763
  }
29764
+ function customTooltipHandler({ chart, tooltip }) {
29765
+ chart.canvas.parentNode.querySelector("div.o-chart-custom-tooltip")?.remove();
29766
+ if (tooltip.opacity === 0 || tooltip.dataPoints.length === 0) {
29767
+ return;
29768
+ }
29769
+ const tooltipItems = tooltip.body.map((body, index) => {
29770
+ let [label, value] = body.lines[0].split(":").map((str) => str.trim());
29771
+ if (!value) {
29772
+ value = label;
29773
+ label = "";
29774
+ }
29775
+ const color = tooltip.labelColors[index].backgroundColor;
29776
+ return {
29777
+ label,
29778
+ value,
29779
+ boxColor: typeof color === "string" ? setColorAlpha(color, 1) : color,
29780
+ };
29781
+ });
29782
+ const innerHTML = renderToString("o-spreadsheet-CustomTooltip", {
29783
+ labelsMaxWidth: Math.floor(chart.canvas.clientWidth * 0.5) + "px",
29784
+ valuesMaxWidth: Math.floor(chart.canvas.clientWidth * 0.25) + "px",
29785
+ title: tooltip.title[0],
29786
+ tooltipItems,
29787
+ });
29788
+ const template = Object.assign(document.createElement("template"), { innerHTML });
29789
+ const newTooltipEl = template.content.firstChild;
29790
+ chart.canvas.parentNode?.appendChild(newTooltipEl);
29791
+ Object.assign(newTooltipEl.style, {
29792
+ left: getTooltipLeftPosition(chart, tooltip, newTooltipEl.clientWidth) + "px",
29793
+ top: Math.floor(tooltip.caretY - newTooltipEl.clientHeight / 2) + "px",
29794
+ });
29795
+ }
29796
+ /**
29797
+ * Get the left position for the tooltip, making sure it doesn't go out of the chart area.
29798
+ */
29799
+ function getTooltipLeftPosition(chart, tooltip, tooltipWidth) {
29800
+ const x = tooltip.caretX;
29801
+ if (x + tooltipWidth > chart.chartArea.right) {
29802
+ return Math.max(0, x - tooltipWidth);
29803
+ }
29804
+ return x;
29805
+ }
29638
29806
 
29639
29807
  var CHART_RUNTIME_HELPERS = /*#__PURE__*/Object.freeze({
29640
29808
  __proto__: null,
@@ -29748,11 +29916,11 @@ stores.inject(MyMetaStore, storeInstance);
29748
29916
  : undefined,
29749
29917
  };
29750
29918
  }
29751
- copyForSheetId(sheetId) {
29752
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
29753
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
29754
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
29755
- return new BarChart(definition, sheetId, this.getters);
29919
+ duplicateInDuplicatedSheet(newSheetId) {
29920
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
29921
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
29922
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
29923
+ return new BarChart(definition, newSheetId, this.getters);
29756
29924
  }
29757
29925
  copyInSheetId(sheetId) {
29758
29926
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -29819,7 +29987,7 @@ stores.inject(MyMetaStore, storeInstance);
29819
29987
  const config = {
29820
29988
  type: "bar",
29821
29989
  data: {
29822
- labels: chartData.labels.map(truncateLabel),
29990
+ labels: chartData.labels,
29823
29991
  datasets: getBarChartDatasets(definition, chartData),
29824
29992
  },
29825
29993
  options: {
@@ -29955,11 +30123,11 @@ stores.inject(MyMetaStore, storeInstance);
29955
30123
  showValues: context.showValues,
29956
30124
  };
29957
30125
  }
29958
- copyForSheetId(sheetId) {
29959
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
29960
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
29961
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
29962
- return new ComboChart(definition, sheetId, this.getters);
30126
+ duplicateInDuplicatedSheet(newSheetId) {
30127
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
30128
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
30129
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
30130
+ return new ComboChart(definition, newSheetId, this.getters);
29963
30131
  }
29964
30132
  copyInSheetId(sheetId) {
29965
30133
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -29972,7 +30140,7 @@ stores.inject(MyMetaStore, storeInstance);
29972
30140
  const config = {
29973
30141
  type: "bar",
29974
30142
  data: {
29975
- labels: chartData.labels.map(truncateLabel),
30143
+ labels: chartData.labels,
29976
30144
  datasets: getComboChartDatasets(definition, chartData),
29977
30145
  },
29978
30146
  options: {
@@ -30106,10 +30274,10 @@ stores.inject(MyMetaStore, storeInstance);
30106
30274
  },
30107
30275
  };
30108
30276
  }
30109
- copyForSheetId(sheetId) {
30110
- const dataRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.dataRange);
30111
- const definition = this.getDefinitionWithSpecificRanges(dataRange, sheetId);
30112
- return new GaugeChart(definition, sheetId, this.getters);
30277
+ duplicateInDuplicatedSheet(newSheetId) {
30278
+ const dataRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.dataRange);
30279
+ const definition = this.getDefinitionWithSpecificRanges(dataRange, newSheetId);
30280
+ return new GaugeChart(definition, newSheetId, this.getters);
30113
30281
  }
30114
30282
  copyInSheetId(sheetId) {
30115
30283
  const definition = this.getDefinitionWithSpecificRanges(this.dataRange, sheetId);
@@ -30202,7 +30370,11 @@ stores.inject(MyMetaStore, storeInstance);
30202
30370
  colors.push(chartColors.upperColor);
30203
30371
  return {
30204
30372
  background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
30205
- title: chart.title ?? { text: "" },
30373
+ title: {
30374
+ ...chart.title,
30375
+ // chart titles are extracted from .json files and they are translated at runtime here
30376
+ text: _t(chart.title.text ?? ""),
30377
+ },
30206
30378
  minValue: {
30207
30379
  value: minValue,
30208
30380
  label: formatValue(minValue, { locale, format }),
@@ -30286,11 +30458,11 @@ stores.inject(MyMetaStore, storeInstance);
30286
30458
  : undefined,
30287
30459
  };
30288
30460
  }
30289
- copyForSheetId(sheetId) {
30290
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
30291
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
30292
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
30293
- return new GeoChart(definition, sheetId, this.getters);
30461
+ duplicateInDuplicatedSheet(newSheetId) {
30462
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
30463
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
30464
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
30465
+ return new GeoChart(definition, newSheetId, this.getters);
30294
30466
  }
30295
30467
  copyInSheetId(sheetId) {
30296
30468
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -30483,11 +30655,11 @@ stores.inject(MyMetaStore, storeInstance);
30483
30655
  verticalAxis: getDefinedAxis(definition),
30484
30656
  };
30485
30657
  }
30486
- copyForSheetId(sheetId) {
30487
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
30488
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
30489
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
30490
- return new LineChart(definition, sheetId, this.getters);
30658
+ duplicateInDuplicatedSheet(newSheetId) {
30659
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
30660
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
30661
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
30662
+ return new LineChart(definition, newSheetId, this.getters);
30491
30663
  }
30492
30664
  copyInSheetId(sheetId) {
30493
30665
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -30500,7 +30672,7 @@ stores.inject(MyMetaStore, storeInstance);
30500
30672
  const config = {
30501
30673
  type: "line",
30502
30674
  data: {
30503
- labels: chartData.axisType !== "time" ? chartData.labels.map(truncateLabel) : chartData.labels,
30675
+ labels: chartData.labels,
30504
30676
  datasets: getLineChartDatasets(definition, chartData),
30505
30677
  },
30506
30678
  options: {
@@ -30594,11 +30766,11 @@ stores.inject(MyMetaStore, storeInstance);
30594
30766
  showValues: this.showValues,
30595
30767
  };
30596
30768
  }
30597
- copyForSheetId(sheetId) {
30598
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
30599
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
30600
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
30601
- return new PieChart(definition, sheetId, this.getters);
30769
+ duplicateInDuplicatedSheet(newSheetId) {
30770
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
30771
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
30772
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
30773
+ return new PieChart(definition, newSheetId, this.getters);
30602
30774
  }
30603
30775
  copyInSheetId(sheetId) {
30604
30776
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -30635,7 +30807,7 @@ stores.inject(MyMetaStore, storeInstance);
30635
30807
  const config = {
30636
30808
  type: chart.isDoughnut ? "doughnut" : "pie",
30637
30809
  data: {
30638
- labels: chartData.labels.map(truncateLabel),
30810
+ labels: chartData.labels,
30639
30811
  datasets: getPieChartDatasets(definition, chartData),
30640
30812
  },
30641
30813
  options: {
@@ -30715,11 +30887,11 @@ stores.inject(MyMetaStore, storeInstance);
30715
30887
  : undefined,
30716
30888
  };
30717
30889
  }
30718
- copyForSheetId(sheetId) {
30719
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
30720
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
30721
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
30722
- return new PyramidChart(definition, sheetId, this.getters);
30890
+ duplicateInDuplicatedSheet(newSheetId) {
30891
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
30892
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
30893
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
30894
+ return new PyramidChart(definition, newSheetId, this.getters);
30723
30895
  }
30724
30896
  copyInSheetId(sheetId) {
30725
30897
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -30771,7 +30943,7 @@ stores.inject(MyMetaStore, storeInstance);
30771
30943
  const config = {
30772
30944
  type: "bar",
30773
30945
  data: {
30774
- labels: chartData.labels.map(truncateLabel),
30946
+ labels: chartData.labels,
30775
30947
  datasets: getBarChartDatasets(definition, chartData),
30776
30948
  },
30777
30949
  options: {
@@ -30852,11 +31024,11 @@ stores.inject(MyMetaStore, storeInstance);
30852
31024
  : undefined,
30853
31025
  };
30854
31026
  }
30855
- copyForSheetId(sheetId) {
30856
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
30857
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
30858
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
30859
- return new RadarChart(definition, sheetId, this.getters);
31027
+ duplicateInDuplicatedSheet(newSheetId) {
31028
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
31029
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
31030
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
31031
+ return new RadarChart(definition, newSheetId, this.getters);
30860
31032
  }
30861
31033
  copyInSheetId(sheetId) {
30862
31034
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -30921,7 +31093,7 @@ stores.inject(MyMetaStore, storeInstance);
30921
31093
  const config = {
30922
31094
  type: "radar",
30923
31095
  data: {
30924
- labels: chartData.labels.map(truncateLabel),
31096
+ labels: chartData.labels,
30925
31097
  datasets: getRadarChartDatasets(definition, chartData),
30926
31098
  },
30927
31099
  options: {
@@ -31055,11 +31227,11 @@ stores.inject(MyMetaStore, storeInstance);
31055
31227
  verticalAxis: getDefinedAxis(definition),
31056
31228
  };
31057
31229
  }
31058
- copyForSheetId(sheetId) {
31059
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
31060
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
31061
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
31062
- return new ScatterChart(definition, sheetId, this.getters);
31230
+ duplicateInDuplicatedSheet(newSheetId) {
31231
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
31232
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
31233
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
31234
+ return new ScatterChart(definition, newSheetId, this.getters);
31063
31235
  }
31064
31236
  copyInSheetId(sheetId) {
31065
31237
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -31074,7 +31246,7 @@ stores.inject(MyMetaStore, storeInstance);
31074
31246
  // have less options than the line chart (it only works with linear labels)
31075
31247
  type: "line",
31076
31248
  data: {
31077
- labels: chartData.axisType !== "time" ? chartData.labels.map(truncateLabel) : chartData.labels,
31249
+ labels: chartData.labels,
31078
31250
  datasets: getScatterChartDatasets(definition, chartData),
31079
31251
  },
31080
31252
  options: {
@@ -31172,11 +31344,11 @@ stores.inject(MyMetaStore, storeInstance);
31172
31344
  : undefined,
31173
31345
  };
31174
31346
  }
31175
- copyForSheetId(sheetId) {
31176
- const dataSets = copyDataSetsWithNewSheetId(this.sheetId, sheetId, this.dataSets);
31177
- const labelRange = copyLabelRangeWithNewSheetId(this.sheetId, sheetId, this.labelRange);
31178
- const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, sheetId);
31179
- return new WaterfallChart(definition, sheetId, this.getters);
31347
+ duplicateInDuplicatedSheet(newSheetId) {
31348
+ const dataSets = duplicateDataSetsInDuplicatedSheet(this.sheetId, newSheetId, this.dataSets);
31349
+ const labelRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.labelRange);
31350
+ const definition = this.getDefinitionWithSpecificDataSets(dataSets, labelRange, newSheetId);
31351
+ return new WaterfallChart(definition, newSheetId, this.getters);
31180
31352
  }
31181
31353
  copyInSheetId(sheetId) {
31182
31354
  const definition = this.getDefinitionWithSpecificDataSets(this.dataSets, this.labelRange, sheetId);
@@ -33603,8 +33775,6 @@ stores.inject(MyMetaStore, storeInstance);
33603
33775
  chartToImage: chartToImage,
33604
33776
  checkDataset: checkDataset,
33605
33777
  checkLabelRange: checkLabelRange,
33606
- copyDataSetsWithNewSheetId: copyDataSetsWithNewSheetId,
33607
- copyLabelRangeWithNewSheetId: copyLabelRangeWithNewSheetId,
33608
33778
  createBarChartRuntime: createBarChartRuntime,
33609
33779
  createDataSets: createDataSets,
33610
33780
  createGaugeChartRuntime: createGaugeChartRuntime,
@@ -33613,6 +33783,8 @@ stores.inject(MyMetaStore, storeInstance);
33613
33783
  createScorecardChartRuntime: createScorecardChartRuntime,
33614
33784
  createWaterfallChartRuntime: createWaterfallChartRuntime,
33615
33785
  drawScoreChart: drawScoreChart,
33786
+ duplicateDataSetsInDuplicatedSheet: duplicateDataSetsInDuplicatedSheet,
33787
+ duplicateLabelRangeInDuplicatedSheet: duplicateLabelRangeInDuplicatedSheet,
33616
33788
  formatChartDatasetValue: formatChartDatasetValue,
33617
33789
  formatTickValue: formatTickValue,
33618
33790
  getChartPositionAtCenterOfViewport: getChartPositionAtCenterOfViewport,
@@ -35333,12 +35505,20 @@ stores.inject(MyMetaStore, storeInstance);
35333
35505
  });
35334
35506
  }
35335
35507
  function isAutomaticFormatSelected(env) {
35336
- const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
35337
- return !activeCell || !activeCell.format;
35508
+ const activePosition = env.model.getters.getActivePosition();
35509
+ const pivotCell = env.model.getters.getPivotCellFromPosition(activePosition);
35510
+ if (pivotCell.type === "VALUE") {
35511
+ return !env.model.getters.getEvaluatedCell(activePosition).format;
35512
+ }
35513
+ return !env.model.getters.getCell(activePosition)?.format;
35338
35514
  }
35339
35515
  function isFormatSelected(env, format) {
35340
- const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
35341
- return activeCell?.format === format;
35516
+ const activePosition = env.model.getters.getActivePosition();
35517
+ const pivotCell = env.model.getters.getPivotCellFromPosition(activePosition);
35518
+ if (pivotCell.type === "VALUE") {
35519
+ return env.model.getters.getEvaluatedCell(activePosition).format === format;
35520
+ }
35521
+ return env.model.getters.getCell(activePosition)?.format === format;
35342
35522
  }
35343
35523
  function isFontSizeSelected(env, fontSize) {
35344
35524
  const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
@@ -39677,14 +39857,11 @@ stores.inject(MyMetaStore, storeInstance);
39677
39857
  }
39678
39858
 
39679
39859
  class DOMFocusableElementStore {
39680
- mutators = ["setFocusableElement", "focus"];
39860
+ mutators = ["setFocusableElement"];
39681
39861
  focusableElement = undefined;
39682
39862
  setFocusableElement(element) {
39683
39863
  this.focusableElement = element;
39684
39864
  }
39685
- focus() {
39686
- this.focusableElement?.focus();
39687
- }
39688
39865
  }
39689
39866
 
39690
39867
  css /* scss */ `
@@ -40332,7 +40509,7 @@ stores.inject(MyMetaStore, storeInstance);
40332
40509
  if (document.activeElement === this.contentHelper.el &&
40333
40510
  this.props.composerStore.editionMode === "inactive" &&
40334
40511
  !this.props.isDefaultFocus) {
40335
- this.DOMFocusableElementStore.focus();
40512
+ this.DOMFocusableElementStore.focusableElement?.focus();
40336
40513
  }
40337
40514
  });
40338
40515
  owl.useEffect(() => {
@@ -44313,16 +44490,21 @@ stores.inject(MyMetaStore, storeInstance);
44313
44490
  }
44314
44491
  this.inputRef.el?.blur();
44315
44492
  }
44316
- focusInputAndSelectContent() {
44317
- const inputEl = this.inputRef.el;
44318
- if (!inputEl)
44319
- return;
44320
- // The onFocus event selects all text in the input.
44321
- // The subsequent mouseup event can deselect this text,
44322
- // so t-on-mouseup.prevent.stop is used to prevent this
44323
- // default behavior and preserve the selection.
44324
- inputEl.focus();
44325
- inputEl.select();
44493
+ onMouseDown(ev) {
44494
+ // Stop the event if the input is not focused, we handle everything in onMouseUp
44495
+ if (ev.target !== document.activeElement) {
44496
+ ev.preventDefault();
44497
+ ev.stopPropagation();
44498
+ }
44499
+ }
44500
+ onMouseUp(ev) {
44501
+ const target = ev.target;
44502
+ if (target !== document.activeElement) {
44503
+ target.focus();
44504
+ target.select();
44505
+ ev.preventDefault();
44506
+ ev.stopPropagation();
44507
+ }
44326
44508
  }
44327
44509
  }
44328
44510
 
@@ -44875,7 +45057,16 @@ stores.inject(MyMetaStore, storeInstance);
44875
45057
  newPivotId,
44876
45058
  newSheetId,
44877
45059
  });
44878
- const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
45060
+ let text;
45061
+ if (result.isSuccessful) {
45062
+ text = _t("Pivot duplicated.");
45063
+ }
45064
+ else if (result.isCancelledBecause("PivotInError" /* CommandResult.PivotInError */)) {
45065
+ text = _t("Cannot duplicate a pivot in error.");
45066
+ }
45067
+ else {
45068
+ text = _t("Pivot duplication failed.");
45069
+ }
44879
45070
  const type = result.isSuccessful ? "success" : "danger";
44880
45071
  this.env.notifyUser({
44881
45072
  text,
@@ -46026,12 +46217,10 @@ stores.inject(MyMetaStore, storeInstance);
46026
46217
  * Take cares of double names
46027
46218
  */
46028
46219
  findName(name, fields) {
46029
- let increment = 1;
46030
- const initialName = name;
46031
- while (name in fields) {
46032
- name = `${initialName}${++increment}`;
46033
- }
46034
- return name;
46220
+ return getUniqueText(name, Object.keys(fields), {
46221
+ compute: (name, i) => `${name}${i}`,
46222
+ start: 2,
46223
+ });
46035
46224
  }
46036
46225
  extractDataEntriesFromRange(range) {
46037
46226
  const dataEntries = [];
@@ -46214,7 +46403,9 @@ stores.inject(MyMetaStore, storeInstance);
46214
46403
  pivot: this.draft,
46215
46404
  });
46216
46405
  this.draft = null;
46217
- if (!this.alreadyNotified && !this.isDynamicPivotInViewport()) {
46406
+ if (!this.alreadyNotified &&
46407
+ !this.isDynamicPivotInViewport() &&
46408
+ this.isStaticPivotInViewport()) {
46218
46409
  const formulaId = this.getters.getPivotFormulaId(this.pivotId);
46219
46410
  const pivotExample = `=PIVOT(${formulaId})`;
46220
46411
  this.alreadyNotified = true;
@@ -46271,11 +46462,20 @@ stores.inject(MyMetaStore, storeInstance);
46271
46462
  }
46272
46463
  }
46273
46464
  isDynamicPivotInViewport() {
46274
- const sheetId = this.getters.getActiveSheetId();
46275
- for (const col of this.getters.getSheetViewVisibleCols()) {
46276
- for (const row of this.getters.getSheetViewVisibleRows()) {
46277
- const isDynamicPivot = this.getters.isSpillPivotFormula({ sheetId, col, row });
46278
- if (isDynamicPivot) {
46465
+ for (const position of this.getters.getVisibleCellPositions()) {
46466
+ const isDynamicPivot = this.getters.isSpillPivotFormula(position);
46467
+ if (isDynamicPivot) {
46468
+ return true;
46469
+ }
46470
+ }
46471
+ return false;
46472
+ }
46473
+ isStaticPivotInViewport() {
46474
+ for (const position of this.getters.getVisibleCellPositions()) {
46475
+ const cell = this.getters.getCell(position);
46476
+ if (cell?.isFormula) {
46477
+ const pivotFunction = getFirstPivotFunction(cell.compiledFormula.tokens);
46478
+ if (pivotFunction && pivotFunction.functionName !== "PIVOT") {
46279
46479
  return true;
46280
46480
  }
46281
46481
  }
@@ -51694,7 +51894,7 @@ stores.inject(MyMetaStore, storeInstance);
51694
51894
  this.cellPopovers = useStore(CellPopoverStore);
51695
51895
  owl.useEffect(() => {
51696
51896
  if (!this.sidePanel.isOpen) {
51697
- this.DOMFocusableElementStore.focus();
51897
+ this.DOMFocusableElementStore.focusableElement?.focus();
51698
51898
  }
51699
51899
  }, () => [this.sidePanel.isOpen]);
51700
51900
  }
@@ -51900,7 +52100,7 @@ stores.inject(MyMetaStore, storeInstance);
51900
52100
  focusDefaultElement() {
51901
52101
  if (!this.env.model.getters.getSelectedFigureId() &&
51902
52102
  this.composerFocusStore.activeComposer.editionMode === "inactive") {
51903
- this.DOMFocusableElementStore.focus();
52103
+ this.DOMFocusableElementStore.focusableElement?.focus();
51904
52104
  }
51905
52105
  }
51906
52106
  get gridEl() {
@@ -52259,15 +52459,11 @@ stores.inject(MyMetaStore, storeInstance);
52259
52459
  class BasePlugin {
52260
52460
  static getters = [];
52261
52461
  history;
52262
- dispatch;
52263
- canDispatch;
52264
- constructor(stateObserver, dispatch, canDispatch) {
52462
+ constructor(stateObserver) {
52265
52463
  this.history = Object.assign(Object.create(stateObserver), {
52266
52464
  update: stateObserver.addChange.bind(stateObserver, this),
52267
52465
  selectCell: () => { },
52268
52466
  });
52269
- this.dispatch = dispatch;
52270
- this.canDispatch = canDispatch;
52271
52467
  }
52272
52468
  /**
52273
52469
  * Export for excel should be available for all plugins, even for the UI.
@@ -52345,10 +52541,14 @@ stores.inject(MyMetaStore, storeInstance);
52345
52541
  */
52346
52542
  class CorePlugin extends BasePlugin {
52347
52543
  getters;
52544
+ dispatch;
52545
+ canDispatch;
52348
52546
  constructor({ getters, stateObserver, range, dispatch, canDispatch }) {
52349
- super(stateObserver, dispatch, canDispatch);
52547
+ super(stateObserver);
52350
52548
  range.addRangeProvider(this.adaptRanges.bind(this));
52351
52549
  this.getters = getters;
52550
+ this.dispatch = dispatch;
52551
+ this.canDispatch = canDispatch;
52352
52552
  }
52353
52553
  // ---------------------------------------------------------------------------
52354
52554
  // Import/Export
@@ -52437,10 +52637,34 @@ stores.inject(MyMetaStore, storeInstance);
52437
52637
  const elements = [...cmd.elements].sort((a, b) => b - a);
52438
52638
  for (const group of groupConsecutive(elements)) {
52439
52639
  if (cmd.dimension === "COL") {
52440
- this.shiftBordersHorizontally(cmd.sheetId, group[group.length - 1] + 1, -group.length);
52640
+ if (group[0] >= this.getters.getNumberCols(cmd.sheetId)) {
52641
+ for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
52642
+ this.history.update("borders", cmd.sheetId, group[0] + 1, row, "vertical", undefined);
52643
+ }
52644
+ }
52645
+ if (group[group.length - 1] === 0) {
52646
+ for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
52647
+ this.history.update("borders", cmd.sheetId, 0, row, "vertical", undefined);
52648
+ }
52649
+ }
52650
+ const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
52651
+ this.clearInsideBorders(cmd.sheetId, [zone]);
52652
+ this.shiftBordersHorizontally(cmd.sheetId, group[0] + 1, -group.length);
52441
52653
  }
52442
52654
  else {
52443
- this.shiftBordersVertically(cmd.sheetId, group[group.length - 1] + 1, -group.length);
52655
+ if (group[0] >= this.getters.getNumberRows(cmd.sheetId)) {
52656
+ for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
52657
+ this.history.update("borders", cmd.sheetId, col, group[0] + 1, "horizontal", undefined);
52658
+ }
52659
+ }
52660
+ if (group[group.length - 1] === 0) {
52661
+ for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
52662
+ this.history.update("borders", cmd.sheetId, col, 0, "horizontal", undefined);
52663
+ }
52664
+ }
52665
+ const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
52666
+ this.clearInsideBorders(cmd.sheetId, [zone]);
52667
+ this.shiftBordersVertically(cmd.sheetId, group[0] + 1, -group.length);
52444
52668
  }
52445
52669
  }
52446
52670
  break;
@@ -52747,6 +52971,18 @@ stores.inject(MyMetaStore, storeInstance);
52747
52971
  }
52748
52972
  }
52749
52973
  }
52974
+ /**
52975
+ * Remove the borders inside of a zone
52976
+ */
52977
+ clearInsideBorders(sheetId, zones) {
52978
+ for (let zone of zones) {
52979
+ for (let row = zone.top; row <= zone.bottom; row++) {
52980
+ for (let col = zone.left; col <= zone.right; col++) {
52981
+ this.history.update("borders", sheetId, col, row, undefined);
52982
+ }
52983
+ }
52984
+ }
52985
+ }
52750
52986
  /**
52751
52987
  * Add a border to the existing one to a cell
52752
52988
  */
@@ -53549,7 +53785,7 @@ stores.inject(MyMetaStore, storeInstance);
53549
53785
  if (fig.tag === "chart") {
53550
53786
  const figureIdBase = fig.id.split(FIGURE_ID_SPLITTER).pop();
53551
53787
  const duplicatedFigureId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${figureIdBase}`;
53552
- const chart = this.charts[fig.id]?.copyForSheetId(cmd.sheetIdTo);
53788
+ const chart = this.charts[fig.id]?.duplicateInDuplicatedSheet(cmd.sheetIdTo);
53553
53789
  if (chart) {
53554
53790
  this.dispatch("CREATE_CHART", {
53555
53791
  id: duplicatedFigureId,
@@ -54193,7 +54429,7 @@ stores.inject(MyMetaStore, storeInstance);
54193
54429
  case "DUPLICATE_SHEET": {
54194
54430
  const rules = deepCopy(this.rules[cmd.sheetId]).map((rule) => ({
54195
54431
  ...rule,
54196
- ranges: rule.ranges.map((range) => copyRangeWithNewSheetId(cmd.sheetId, cmd.sheetIdTo, range)),
54432
+ ranges: rule.ranges.map((range) => duplicateRangeInDuplicatedSheet(cmd.sheetId, cmd.sheetIdTo, range)),
54197
54433
  }));
54198
54434
  this.history.update("rules", cmd.sheetIdTo, rules);
54199
54435
  break;
@@ -56242,14 +56478,11 @@ stores.inject(MyMetaStore, storeInstance);
56242
56478
  return dimension === "COL" ? this.getNumberCols(sheetId) : this.getNumberRows(sheetId);
56243
56479
  }
56244
56480
  getNextSheetName(baseName = "Sheet") {
56245
- let i = 1;
56246
56481
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
56247
- let name = `${baseName}${i}`;
56248
- while (names.includes(name)) {
56249
- name = `${baseName}${i}`;
56250
- i++;
56251
- }
56252
- return name;
56482
+ return getUniqueText(baseName, names, {
56483
+ compute: (name, i) => `${name}${i}`,
56484
+ computeFirstOne: true,
56485
+ });
56253
56486
  }
56254
56487
  getSheetSize(sheetId) {
56255
56488
  return {
@@ -56529,15 +56762,9 @@ stores.inject(MyMetaStore, storeInstance);
56529
56762
  this.history.update("sheetIdsMapName", sheetIdsMapName);
56530
56763
  }
56531
56764
  getDuplicateSheetName(sheetName) {
56532
- let i = 1;
56533
56765
  const names = this.orderedSheetIds.map(this.getSheetName.bind(this));
56534
56766
  const baseName = _t("Copy of %s", sheetName);
56535
- let name = baseName.toString();
56536
- while (names.includes(name)) {
56537
- name = `${baseName} (${i})`;
56538
- i++;
56539
- }
56540
- return name;
56767
+ return getUniqueText(baseName.toString(), names);
56541
56768
  }
56542
56769
  deleteSheet(sheet) {
56543
56770
  const name = sheet.name;
@@ -58067,15 +58294,8 @@ stores.inject(MyMetaStore, storeInstance);
58067
58294
  }
58068
58295
  getNewCustomTableStyleName() {
58069
58296
  let name = _t("Custom Table Style");
58070
- const styleNames = new Set(Object.values(this.styles).map((style) => style.displayName));
58071
- if (!styleNames.has(name)) {
58072
- return name;
58073
- }
58074
- let i = 2;
58075
- while (styleNames.has(`${name} ${i}`)) {
58076
- i++;
58077
- }
58078
- return `${name} ${i}`;
58297
+ const styleNames = Object.values(this.styles).map((style) => style.displayName);
58298
+ return getUniqueText(name, styleNames, { compute: (name, i) => `${name} ${i}`, start: 2 });
58079
58299
  }
58080
58300
  isTableStyleEditable(styleId) {
58081
58301
  return !TABLE_PRESETS[styleId];
@@ -58105,24 +58325,15 @@ stores.inject(MyMetaStore, storeInstance);
58105
58325
  }
58106
58326
 
58107
58327
  /**
58108
- * UI plugins handle any transient data required to display a spreadsheet.
58109
- * They can draw on the grid canvas.
58328
+ * Core view plugins handle any data derived from core date (i.e. evaluation).
58329
+ * They cannot impact the model data (i.e. cannot dispatch commands).
58110
58330
  */
58111
- class UIPlugin extends BasePlugin {
58112
- static layers = [];
58331
+ class CoreViewPlugin extends BasePlugin {
58113
58332
  getters;
58114
- ui;
58115
- selection;
58116
- constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
58117
- super(stateObserver, dispatch, canDispatch);
58333
+ constructor({ getters, stateObserver }) {
58334
+ super(stateObserver);
58118
58335
  this.getters = getters;
58119
- this.ui = uiActions;
58120
- this.selection = selection;
58121
58336
  }
58122
- // ---------------------------------------------------------------------------
58123
- // Grid rendering
58124
- // ---------------------------------------------------------------------------
58125
- drawLayer(ctx, layer) { }
58126
58337
  }
58127
58338
 
58128
58339
  /**
@@ -59817,7 +60028,7 @@ stores.inject(MyMetaStore, storeInstance);
59817
60028
  // as necessary in several iterations, where evaluated cells can trigger the evaluation
59818
60029
  // of other cells depending on it, at the next iteration.
59819
60030
  //#endregion
59820
- class EvaluationPlugin extends UIPlugin {
60031
+ class EvaluationPlugin extends CoreViewPlugin {
59821
60032
  static getters = [
59822
60033
  "evaluateFormula",
59823
60034
  "evaluateFormulaResult",
@@ -60084,7 +60295,7 @@ stores.inject(MyMetaStore, storeInstance);
60084
60295
  * This plugins aims to compute and keep to custom colors used in the
60085
60296
  * current spreadsheet
60086
60297
  */
60087
- class CustomColorsPlugin extends UIPlugin {
60298
+ class CustomColorsPlugin extends CoreViewPlugin {
60088
60299
  customColors = {};
60089
60300
  shouldUpdateColors = true;
60090
60301
  static getters = ["getCustomColors"];
@@ -60220,7 +60431,7 @@ stores.inject(MyMetaStore, storeInstance);
60220
60431
  }
60221
60432
  }
60222
60433
 
60223
- class EvaluationChartPlugin extends UIPlugin {
60434
+ class EvaluationChartPlugin extends CoreViewPlugin {
60224
60435
  static getters = ["getChartRuntime", "getStyleOfSingleCellChart"];
60225
60436
  charts = {};
60226
60437
  createRuntimeChart = chartRuntimeFactory(this.getters);
@@ -60324,7 +60535,7 @@ stores.inject(MyMetaStore, storeInstance);
60324
60535
  }
60325
60536
  }
60326
60537
 
60327
- class EvaluationConditionalFormatPlugin extends UIPlugin {
60538
+ class EvaluationConditionalFormatPlugin extends CoreViewPlugin {
60328
60539
  static getters = [
60329
60540
  "getConditionalIcon",
60330
60541
  "getCellConditionalFormatStyle",
@@ -60642,7 +60853,7 @@ stores.inject(MyMetaStore, storeInstance);
60642
60853
  }
60643
60854
 
60644
60855
  const VALID_RESULT = { isValid: true };
60645
- class EvaluationDataValidationPlugin extends UIPlugin {
60856
+ class EvaluationDataValidationPlugin extends CoreViewPlugin {
60646
60857
  static getters = [
60647
60858
  "getDataValidationInvalidCriterionValueMessage",
60648
60859
  "getInvalidDataValidationMessage",
@@ -60773,7 +60984,7 @@ stores.inject(MyMetaStore, storeInstance);
60773
60984
  }
60774
60985
  }
60775
60986
 
60776
- class DynamicTablesPlugin extends UIPlugin {
60987
+ class DynamicTablesPlugin extends CoreViewPlugin {
60777
60988
  static getters = [
60778
60989
  "canCreateDynamicTableOnZones",
60779
60990
  "doesZonesContainFilter",
@@ -60947,7 +61158,7 @@ stores.inject(MyMetaStore, storeInstance);
60947
61158
  }
60948
61159
  }
60949
61160
 
60950
- class HeaderSizeUIPlugin extends UIPlugin {
61161
+ class HeaderSizeUIPlugin extends CoreViewPlugin {
60951
61162
  static getters = ["getRowSize", "getHeaderSize"];
60952
61163
  tallestCellInRow = {};
60953
61164
  ctx = document.createElement("canvas").getContext("2d");
@@ -61653,7 +61864,7 @@ stores.inject(MyMetaStore, storeInstance);
61653
61864
  function isPivotCommand(cmd) {
61654
61865
  return UNDO_REDO_PIVOT_COMMANDS.includes(cmd.type);
61655
61866
  }
61656
- class PivotUIPlugin extends UIPlugin {
61867
+ class PivotUIPlugin extends CoreViewPlugin {
61657
61868
  static getters = [
61658
61869
  "getPivot",
61659
61870
  "getFirstPivotFunction",
@@ -61857,13 +62068,9 @@ stores.inject(MyMetaStore, storeInstance);
61857
62068
  }
61858
62069
  generateNewCalculatedMeasureName(measures) {
61859
62070
  const existingMeasures = measures.map((m) => m.fieldName);
61860
- let i = 1;
61861
- let name = _t("Calculated measure %s", i);
61862
- while (existingMeasures.includes(name)) {
61863
- i++;
61864
- name = _t("Calculated measure %s", i);
61865
- }
61866
- return name;
62071
+ return getUniqueText(_t("Calculated measure 1"), existingMeasures, {
62072
+ compute: (name, i) => _t("Calculated measure %s", i),
62073
+ });
61867
62074
  }
61868
62075
  getPivot(pivotId) {
61869
62076
  if (!this.getters.isExistingPivot(pivotId)) {
@@ -61917,6 +62124,31 @@ stores.inject(MyMetaStore, storeInstance);
61917
62124
  }
61918
62125
  }
61919
62126
 
62127
+ /**
62128
+ * UI plugins handle any transient data required to display a spreadsheet.
62129
+ * They can draw on the grid canvas.
62130
+ */
62131
+ class UIPlugin extends BasePlugin {
62132
+ static layers = [];
62133
+ getters;
62134
+ ui;
62135
+ selection;
62136
+ dispatch;
62137
+ canDispatch;
62138
+ constructor({ getters, stateObserver, dispatch, canDispatch, uiActions, selection, }) {
62139
+ super(stateObserver);
62140
+ this.getters = getters;
62141
+ this.ui = uiActions;
62142
+ this.selection = selection;
62143
+ this.dispatch = dispatch;
62144
+ this.canDispatch = canDispatch;
62145
+ }
62146
+ // ---------------------------------------------------------------------------
62147
+ // Grid rendering
62148
+ // ---------------------------------------------------------------------------
62149
+ drawLayer(ctx, layer) { }
62150
+ }
62151
+
61920
62152
  /**
61921
62153
  * This plugin manage the autofill.
61922
62154
  *
@@ -63943,6 +64175,19 @@ stores.inject(MyMetaStore, storeInstance);
63943
64175
 
63944
64176
  class InsertPivotPlugin extends UIPlugin {
63945
64177
  static getters = [];
64178
+ allowDispatch(cmd) {
64179
+ switch (cmd.type) {
64180
+ case "DUPLICATE_PIVOT_IN_NEW_SHEET":
64181
+ if (!this.getters.isExistingPivot(cmd.pivotId)) {
64182
+ return "PivotIdNotFound" /* CommandResult.PivotIdNotFound */;
64183
+ }
64184
+ if (!this.getters.getPivot(cmd.pivotId).isValid()) {
64185
+ return "PivotInError" /* CommandResult.PivotInError */;
64186
+ }
64187
+ break;
64188
+ }
64189
+ return "Success" /* CommandResult.Success */;
64190
+ }
63946
64191
  handle(cmd) {
63947
64192
  switch (cmd.type) {
63948
64193
  case "INSERT_NEW_PIVOT":
@@ -64016,15 +64261,9 @@ stores.inject(MyMetaStore, storeInstance);
64016
64261
  }
64017
64262
  }
64018
64263
  getPivotDuplicateSheetName(pivotName) {
64019
- let i = 1;
64020
64264
  const names = this.getters.getSheetIds().map((id) => this.getters.getSheetName(id));
64021
64265
  const sanitizedName = sanitizeSheetName(pivotName);
64022
- let name = sanitizedName;
64023
- while (names.includes(name)) {
64024
- name = `${sanitizedName} (${i})`;
64025
- i++;
64026
- }
64027
- return name;
64266
+ return getUniqueText(sanitizedName, names);
64028
64267
  }
64029
64268
  insertPivotWithTable(sheetId, col, row, pivotId, table, mode) {
64030
64269
  const { cols, rows, measures, fieldsType } = table;
@@ -66131,13 +66370,10 @@ stores.inject(MyMetaStore, storeInstance);
66131
66370
  if (!colName) {
66132
66371
  colName = `Column${colIndex}`;
66133
66372
  }
66134
- let currentColName = colName;
66135
- let i = 2;
66136
- while (usedColNames.includes(currentColName)) {
66137
- currentColName = colName + String(i);
66138
- i++;
66139
- }
66140
- return currentColName;
66373
+ return getUniqueText(colName, usedColNames, {
66374
+ compute: (name, i) => colName + String(i),
66375
+ start: 2,
66376
+ });
66141
66377
  }
66142
66378
  }
66143
66379
 
@@ -68179,11 +68415,6 @@ stores.inject(MyMetaStore, storeInstance);
68179
68415
  editionState = "initializing";
68180
68416
  DOMFocusableElementStore;
68181
68417
  setup() {
68182
- owl.onMounted(() => {
68183
- if (this.isSheetActive) {
68184
- this.scrollToSheet();
68185
- }
68186
- });
68187
68418
  owl.onPatched(() => {
68188
68419
  if (this.sheetNameRef.el && this.state.isEditing && this.editionState === "initializing") {
68189
68420
  this.editionState = "editing";
@@ -68192,6 +68423,11 @@ stores.inject(MyMetaStore, storeInstance);
68192
68423
  });
68193
68424
  this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
68194
68425
  owl.useExternalListener(window, "click", () => (this.state.pickerOpened = false));
68426
+ owl.useEffect((sheetId) => {
68427
+ if (this.props.sheetId === sheetId) {
68428
+ this.scrollToSheet();
68429
+ }
68430
+ }, () => [this.env.model.getters.getActiveSheetId()]);
68195
68431
  }
68196
68432
  focusInputAndSelectContent() {
68197
68433
  if (!this.state.isEditing || !this.sheetNameRef.el)
@@ -68203,7 +68439,10 @@ stores.inject(MyMetaStore, storeInstance);
68203
68439
  }
68204
68440
  }
68205
68441
  scrollToSheet() {
68206
- this.sheetDivRef.el?.scrollIntoView?.();
68442
+ this.sheetDivRef.el?.scrollIntoView?.({
68443
+ behavior: "smooth",
68444
+ inline: "nearest",
68445
+ });
68207
68446
  }
68208
68447
  onFocusOut() {
68209
68448
  if (this.state.isEditing && this.editionState !== "initializing") {
@@ -68233,11 +68472,11 @@ stores.inject(MyMetaStore, storeInstance);
68233
68472
  if (ev.key === "Enter") {
68234
68473
  ev.preventDefault();
68235
68474
  this.stopEdition();
68236
- this.DOMFocusableElementStore.focus();
68475
+ this.DOMFocusableElementStore.focusableElement?.focus();
68237
68476
  }
68238
68477
  if (ev.key === "Escape") {
68239
68478
  this.cancelEdition();
68240
- this.DOMFocusableElementStore.focus();
68479
+ this.DOMFocusableElementStore.focusableElement?.focus();
68241
68480
  }
68242
68481
  }
68243
68482
  onMouseEventSheetName(ev) {
@@ -68786,23 +69025,17 @@ stores.inject(MyMetaStore, storeInstance);
68786
69025
  const cells = [];
68787
69026
  const getters = this.getters;
68788
69027
  const sheetId = getters.getActiveSheetId();
68789
- for (const col of getters.getSheetViewVisibleCols()) {
68790
- for (const row of getters.getSheetViewVisibleRows()) {
68791
- const position = { sheetId, col, row };
68792
- if (!getters.isMainCellPosition(position)) {
68793
- continue;
68794
- }
68795
- const action = this.getClickableAction(position);
68796
- if (!action) {
68797
- continue;
68798
- }
68799
- const zone = getters.expandZone(sheetId, positionToZone(position));
68800
- cells.push({
68801
- coordinates: getters.getVisibleRect(zone),
68802
- position,
68803
- action,
68804
- });
69028
+ for (const position of this.getters.getVisibleCellPositions()) {
69029
+ const action = this.getClickableAction(position);
69030
+ if (!action) {
69031
+ continue;
68805
69032
  }
69033
+ const zone = getters.expandZone(sheetId, positionToZone(position));
69034
+ cells.push({
69035
+ coordinates: getters.getVisibleRect(zone),
69036
+ position,
69037
+ action,
69038
+ });
68806
69039
  }
68807
69040
  return cells;
68808
69041
  }
@@ -73613,7 +73846,7 @@ stores.inject(MyMetaStore, storeInstance);
73613
73846
  if (content || styleId || formatId || borderId || value !== undefined) {
73614
73847
  const attributes = [["r", xc]];
73615
73848
  // style
73616
- const id = normalizeStyle(construct, extractStyle(data, styleId, formatId, borderId));
73849
+ const id = normalizeStyle(construct, extractStyle(data, content, styleId, formatId, borderId));
73617
73850
  // don't add style if default
73618
73851
  if (id) {
73619
73852
  attributes.push(["s", id]);
@@ -73967,7 +74200,12 @@ stores.inject(MyMetaStore, storeInstance);
73967
74200
  ["count", strings.length],
73968
74201
  ["uniqueCount", strings.length],
73969
74202
  ];
73970
- const stringNodes = strings.map((string) => escapeXml /*xml*/ `<si><t>${string}</t></si>`);
74203
+ const stringNodes = strings.map((string) => {
74204
+ if (string.trim() !== string) {
74205
+ return escapeXml /*xml*/ `<si><t xml:space="preserve">${string}</t></si>`;
74206
+ }
74207
+ return escapeXml /*xml*/ `<si><t>${string}</t></si>`;
74208
+ });
73971
74209
  const xml = escapeXml /*xml*/ `
73972
74210
  <sst ${formatAttributes(namespaces)}>
73973
74211
  ${joinXmlNodes(stringNodes)}
@@ -74048,14 +74286,13 @@ stores.inject(MyMetaStore, storeInstance);
74048
74286
  */
74049
74287
  function fixLengthySheetNames(data) {
74050
74288
  const nameMapping = {};
74051
- const newNames = new Set();
74289
+ const newNames = [];
74052
74290
  for (const sheet of data.sheets) {
74053
74291
  let newName = sheet.name.slice(0, 31);
74054
- let i = 1;
74055
- while (newNames.has(newName)) {
74056
- newName = newName.slice(0, 31 - String(i).length) + i++;
74057
- }
74058
- newNames.add(newName);
74292
+ newName = getUniqueText(newName, newNames, {
74293
+ compute: (name, i) => name.slice(0, 31 - String(i).length) + i,
74294
+ });
74295
+ newNames.push(newName);
74059
74296
  if (newName !== sheet.name) {
74060
74297
  nameMapping[sheet.name] = newName;
74061
74298
  sheet.name = newName;
@@ -74120,6 +74357,7 @@ stores.inject(MyMetaStore, storeInstance);
74120
74357
  */
74121
74358
  config;
74122
74359
  corePluginConfig;
74360
+ coreViewPluginConfig;
74123
74361
  uiPluginConfig;
74124
74362
  state;
74125
74363
  selection;
@@ -74172,6 +74410,7 @@ stores.inject(MyMetaStore, storeInstance);
74172
74410
  this.coreHandlers.push(this.range);
74173
74411
  this.handlers.push(this.range);
74174
74412
  this.corePluginConfig = this.setupCorePluginConfig();
74413
+ this.coreViewPluginConfig = this.setupCoreViewPluginConfig();
74175
74414
  this.uiPluginConfig = this.setupUiPluginConfig();
74176
74415
  // registering plugins
74177
74416
  for (let Plugin of corePluginRegistry.getAll()) {
@@ -74180,7 +74419,7 @@ stores.inject(MyMetaStore, storeInstance);
74180
74419
  Object.assign(this.getters, this.coreGetters);
74181
74420
  this.session.loadInitialMessages(stateUpdateMessages);
74182
74421
  for (let Plugin of coreViewsPluginRegistry.getAll()) {
74183
- const plugin = this.setupUiPlugin(Plugin);
74422
+ const plugin = this.setupCoreViewPlugin(Plugin);
74184
74423
  this.handlers.push(plugin);
74185
74424
  this.uiHandlers.push(plugin);
74186
74425
  this.coreHandlers.push(plugin);
@@ -74207,7 +74446,7 @@ stores.inject(MyMetaStore, storeInstance);
74207
74446
  // events
74208
74447
  this.setupSessionEvents();
74209
74448
  this.joinSession();
74210
- if (config.snapshotRequested) {
74449
+ if (config.snapshotRequested || (data["[Content_Types].xml"] && !this.getters.isReadonly())) {
74211
74450
  const startSnapshot = performance.now();
74212
74451
  console.debug("Snapshot requested");
74213
74452
  this.session.snapshot(this.exportData());
@@ -74246,6 +74485,19 @@ stores.inject(MyMetaStore, storeInstance);
74246
74485
  }
74247
74486
  return plugin;
74248
74487
  }
74488
+ setupCoreViewPlugin(Plugin) {
74489
+ const plugin = new Plugin(this.coreViewPluginConfig);
74490
+ for (let name of Plugin.getters) {
74491
+ if (!(name in plugin)) {
74492
+ throw new Error(`Invalid getter name: ${name} for plugin ${plugin.constructor}`);
74493
+ }
74494
+ if (name in this.getters) {
74495
+ throw new Error(`Getter "${name}" is already defined.`);
74496
+ }
74497
+ this.getters[name] = plugin[name].bind(plugin);
74498
+ }
74499
+ return plugin;
74500
+ }
74249
74501
  /**
74250
74502
  * Initialize and properly configure a plugin.
74251
74503
  *
@@ -74347,6 +74599,20 @@ stores.inject(MyMetaStore, storeInstance);
74347
74599
  external: this.config.external,
74348
74600
  };
74349
74601
  }
74602
+ setupCoreViewPluginConfig() {
74603
+ return {
74604
+ getters: this.getters,
74605
+ stateObserver: this.state,
74606
+ selection: this.selection,
74607
+ moveClient: this.session.move.bind(this.session),
74608
+ custom: this.config.custom,
74609
+ uiActions: this.config,
74610
+ session: this.session,
74611
+ defaultCurrency: this.config.defaultCurrency,
74612
+ customColors: this.config.customColors || [],
74613
+ external: this.config.external,
74614
+ };
74615
+ }
74350
74616
  setupUiPluginConfig() {
74351
74617
  return {
74352
74618
  getters: this.getters,
@@ -74694,6 +74960,9 @@ stores.inject(MyMetaStore, storeInstance);
74694
74960
  areDomainArgsFieldsValid,
74695
74961
  splitReference,
74696
74962
  sanitizeSheetName,
74963
+ getUniqueText,
74964
+ isNumber,
74965
+ isDateTime,
74697
74966
  };
74698
74967
  const links = {
74699
74968
  isMarkdownLink,
@@ -74790,6 +75059,7 @@ stores.inject(MyMetaStore, storeInstance);
74790
75059
  exports.AbstractFigureClipboardHandler = AbstractFigureClipboardHandler;
74791
75060
  exports.CellErrorType = CellErrorType;
74792
75061
  exports.CorePlugin = CorePlugin;
75062
+ exports.CoreViewPlugin = CoreViewPlugin;
74793
75063
  exports.DispatchResult = DispatchResult;
74794
75064
  exports.EvaluationError = EvaluationError;
74795
75065
  exports.Model = Model;
@@ -74832,9 +75102,9 @@ stores.inject(MyMetaStore, storeInstance);
74832
75102
  exports.tokenize = tokenize;
74833
75103
 
74834
75104
 
74835
- __info__.version = "18.2.0-alpha.0";
74836
- __info__.date = "2024-12-26T08:02:39.123Z";
74837
- __info__.hash = "0f45915";
75105
+ __info__.version = "18.2.0-alpha.2";
75106
+ __info__.date = "2025-01-15T08:06:32.137Z";
75107
+ __info__.hash = "4f96c47";
74838
75108
 
74839
75109
 
74840
75110
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);