@odoo/o-spreadsheet 19.1.2 → 19.1.3

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 19.1.2
6
- * @date 2026-01-07T16:21:36.757Z
7
- * @hash febc3e9
5
+ * @version 19.1.3
6
+ * @date 2026-01-14T10:02:32.431Z
7
+ * @hash 52a3e52
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -179,6 +179,7 @@
179
179
  textColor: "",
180
180
  rotation: 0,
181
181
  };
182
+ const ROTATION_EPSILON = 0.001;
182
183
  const DEFAULT_VERTICAL_ALIGN = DEFAULT_STYLE.verticalAlign;
183
184
  const DEFAULT_WRAPPING_MODE = DEFAULT_STYLE.wrapping;
184
185
  // Fonts
@@ -15492,9 +15493,10 @@
15492
15493
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
15493
15494
  }
15494
15495
  }
15495
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
15496
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
15496
15497
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
15497
15498
  const dependencies = [];
15499
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
15498
15500
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
15499
15501
  const { sheetId, zone } = coreDefinition.dataSet;
15500
15502
  const xc = zoneToXc(zone);
@@ -15511,8 +15513,7 @@
15511
15513
  }
15512
15514
  for (const measure of forMeasures) {
15513
15515
  if (measure.computedBy) {
15514
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
15515
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
15516
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
15516
15517
  }
15517
15518
  }
15518
15519
  const originPosition = evalContext.__originCellPosition;
@@ -16009,7 +16010,7 @@
16009
16010
  assertDomainLength(domainArgs);
16010
16011
  const pivot = this.getters.getPivot(pivotId);
16011
16012
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
16012
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
16013
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
16013
16014
  pivot.init({ reload: pivot.needsReevaluation });
16014
16015
  const error = pivot.assertIsValid({ throwOnError: false });
16015
16016
  if (error) {
@@ -16042,8 +16043,7 @@
16042
16043
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
16043
16044
  assertDomainLength(domainArgs);
16044
16045
  const pivot = this.getters.getPivot(_pivotId);
16045
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
16046
- addPivotDependencies(this, coreDefinition, []);
16046
+ addPivotDependencies(this, _pivotId, []);
16047
16047
  pivot.init({ reload: pivot.needsReevaluation });
16048
16048
  const error = pivot.assertIsValid({ throwOnError: false });
16049
16049
  if (error) {
@@ -16095,7 +16095,7 @@
16095
16095
  if (pivotStyle.numberOfColumns < 0) {
16096
16096
  return new EvaluationError(_t("The number of columns must be positive."));
16097
16097
  }
16098
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
16098
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
16099
16099
  pivot.init({ reload: pivot.needsReevaluation });
16100
16100
  const error = pivot.assertIsValid({ throwOnError: false });
16101
16101
  if (error) {
@@ -20554,7 +20554,7 @@ stores.inject(MyMetaStore, storeInstance);
20554
20554
  let { x, y } = rect; // top-left when align=left and top-right when align=right, top-center when align=center
20555
20555
  const cos = Math.cos(-style.rotation);
20556
20556
  const sin = Math.sin(-style.rotation);
20557
- const width = rect.textWidth - MIN_CELL_TEXT_MARGIN;
20557
+ const width = rect.textWidth - 2 * MIN_CELL_TEXT_MARGIN;
20558
20558
  const height = rect.textHeight;
20559
20559
  const center = style.align === "center";
20560
20560
  const rotateTowardCellCenter = (style.align === "left") === sin < 0;
@@ -20588,6 +20588,13 @@ stores.inject(MyMetaStore, storeInstance);
20588
20588
  else {
20589
20589
  if (center) {
20590
20590
  x -= sh / 2;
20591
+ y -= height / 2;
20592
+ if (rotateTowardCellCenter) {
20593
+ y += sh;
20594
+ }
20595
+ else {
20596
+ y -= sh;
20597
+ }
20591
20598
  }
20592
20599
  else if (rotateTowardCellCenter) {
20593
20600
  x -= sh;
@@ -34400,6 +34407,328 @@ stores.inject(MyMetaStore, storeInstance);
34400
34407
  */
34401
34408
  const DEFAULT_SYSTEM_COLOR = "FF000000";
34402
34409
 
34410
+ // -------------------------------------
34411
+ // CF HELPERS
34412
+ // -------------------------------------
34413
+ /**
34414
+ * Convert the conditional formatting o-spreadsheet operator to
34415
+ * the corresponding excel operator.
34416
+ * */
34417
+ function convertOperator(operator) {
34418
+ switch (operator) {
34419
+ case "isNotEmpty":
34420
+ return "notContainsBlanks";
34421
+ case "isEmpty":
34422
+ return "containsBlanks";
34423
+ case "notContainsText":
34424
+ return "notContainsBlanks";
34425
+ case "containsText":
34426
+ return "containsText";
34427
+ case "beginsWithText":
34428
+ return "beginsWith";
34429
+ case "endsWithText":
34430
+ return "endsWith";
34431
+ case "isGreaterThan":
34432
+ return "greaterThan";
34433
+ case "isGreaterOrEqualTo":
34434
+ return "greaterThanOrEqual";
34435
+ case "isLessThan":
34436
+ return "lessThan";
34437
+ case "isLessOrEqualTo":
34438
+ return "lessThanOrEqual";
34439
+ case "isBetween":
34440
+ return "between";
34441
+ case "isNotBetween":
34442
+ return "notBetween";
34443
+ case "isEqual":
34444
+ return "equal";
34445
+ case "isNotEqual":
34446
+ return "notEqual";
34447
+ case "customFormula":
34448
+ return "";
34449
+ case "dateIs":
34450
+ return "";
34451
+ case "dateIsBefore":
34452
+ return "lessThan";
34453
+ case "dateIsAfter":
34454
+ return "greaterThan";
34455
+ case "dateIsOnOrAfter":
34456
+ return "greaterThanOrEqual";
34457
+ case "dateIsOnOrBefore":
34458
+ return "lessThanOrEqual";
34459
+ }
34460
+ }
34461
+ // -------------------------------------
34462
+ // WORKSHEET HELPERS
34463
+ // -------------------------------------
34464
+ function getCellType(value) {
34465
+ switch (typeof value) {
34466
+ case "boolean":
34467
+ return "b";
34468
+ case "string":
34469
+ return "str";
34470
+ case "number":
34471
+ return "n";
34472
+ default:
34473
+ return undefined;
34474
+ }
34475
+ }
34476
+ function convertHeightToExcel(height) {
34477
+ return Math.round(HEIGHT_FACTOR * height * 100) / 100;
34478
+ }
34479
+ function convertWidthToExcel(width) {
34480
+ return Math.round(WIDTH_FACTOR * width * 100) / 100;
34481
+ }
34482
+ function convertHeightFromExcel(height) {
34483
+ if (!height)
34484
+ return height;
34485
+ return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
34486
+ }
34487
+ function convertWidthFromExcel(width) {
34488
+ if (!width)
34489
+ return width;
34490
+ return Math.round((width / WIDTH_FACTOR) * 100) / 100;
34491
+ }
34492
+ function extractStyle(data, content, styleId, formatId, borderId) {
34493
+ const style = styleId ? data.styles[styleId] : {};
34494
+ const format = formatId ? data.formats[formatId] : undefined;
34495
+ const styles = {
34496
+ font: {
34497
+ size: style?.fontSize || DEFAULT_FONT_SIZE,
34498
+ color: { rgb: style?.textColor ? style.textColor : "000000" },
34499
+ family: 2,
34500
+ name: "Arial",
34501
+ },
34502
+ fill: style?.fillColor
34503
+ ? {
34504
+ fgColor: { rgb: style.fillColor },
34505
+ }
34506
+ : { reservedAttribute: "none" },
34507
+ numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
34508
+ border: borderId || 0,
34509
+ alignment: {
34510
+ horizontal: style.align,
34511
+ vertical: style.verticalAlign
34512
+ ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
34513
+ : undefined,
34514
+ wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
34515
+ textRotation: style.rotation ? rotationToXLSX(style.rotation) : undefined,
34516
+ },
34517
+ };
34518
+ styles.font["strike"] = !!style?.strikethrough || undefined;
34519
+ styles.font["underline"] = !!style?.underline || undefined;
34520
+ styles.font["bold"] = !!style?.bold || undefined;
34521
+ styles.font["italic"] = !!style?.italic || undefined;
34522
+ return styles;
34523
+ }
34524
+ function rotationToXLSX(rad) {
34525
+ let deg = Math.round((-rad / Math.PI) * 180) % 180;
34526
+ if (deg > 90) {
34527
+ deg -= 180;
34528
+ }
34529
+ else if (deg < -90) {
34530
+ deg += 180;
34531
+ }
34532
+ if (deg >= 0) {
34533
+ return deg;
34534
+ }
34535
+ else {
34536
+ return 90 - deg;
34537
+ }
34538
+ }
34539
+ function rotationFromXLSX(deg) {
34540
+ if (deg <= 90) {
34541
+ return -(deg / 180) * Math.PI;
34542
+ }
34543
+ else {
34544
+ return (-(90 - deg) / 180) * Math.PI;
34545
+ }
34546
+ }
34547
+ function normalizeStyle(construct, styles) {
34548
+ // Normalize this
34549
+ const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
34550
+ const style = {
34551
+ fontId: pushElement(styles.font, construct.fonts),
34552
+ fillId: pushElement(styles.fill, construct.fills),
34553
+ borderId: styles.border,
34554
+ numFmtId,
34555
+ alignment: {
34556
+ vertical: styles.alignment.vertical,
34557
+ horizontal: styles.alignment.horizontal,
34558
+ wrapText: styles.alignment.wrapText,
34559
+ textRotation: styles.alignment.textRotation,
34560
+ },
34561
+ };
34562
+ return pushElement(style, construct.styles);
34563
+ }
34564
+ function convertFormat(format, numFmtStructure) {
34565
+ if (!format) {
34566
+ return 0;
34567
+ }
34568
+ let formatId = XLSX_FORMAT_MAP[format.format];
34569
+ if (!formatId) {
34570
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
34571
+ }
34572
+ return formatId;
34573
+ }
34574
+ /**
34575
+ * Add a relation to the given file and return its id.
34576
+ */
34577
+ function addRelsToFile(relsFiles, path, rel) {
34578
+ const relsFile = relsFiles.find((file) => file.path === path);
34579
+ // the id is a one-based int casted as string
34580
+ let id;
34581
+ if (!relsFile) {
34582
+ id = "rId1";
34583
+ relsFiles.push({ path, rels: [{ ...rel, id }] });
34584
+ }
34585
+ else {
34586
+ id = `rId${(relsFile.rels.length + 1).toString()}`;
34587
+ relsFile.rels.push({
34588
+ ...rel,
34589
+ id,
34590
+ });
34591
+ }
34592
+ return id;
34593
+ }
34594
+ const globalReverseLookup = new WeakMap();
34595
+ function pushElement(property, propertyList) {
34596
+ let reverseLookup = globalReverseLookup.get(propertyList);
34597
+ if (!reverseLookup) {
34598
+ reverseLookup = new Map();
34599
+ for (let i = 0; i < propertyList.length; i++) {
34600
+ const canonical = getCanonicalRepresentation(propertyList[i]);
34601
+ reverseLookup.set(canonical, i);
34602
+ }
34603
+ globalReverseLookup.set(propertyList, reverseLookup);
34604
+ }
34605
+ const canonical = getCanonicalRepresentation(property);
34606
+ if (reverseLookup.has(canonical)) {
34607
+ return reverseLookup.get(canonical);
34608
+ }
34609
+ const maxId = propertyList.length;
34610
+ propertyList.push(property);
34611
+ reverseLookup.set(canonical, maxId);
34612
+ return maxId;
34613
+ }
34614
+ /**
34615
+ * Convert a chart o-spreadsheet id to a xlsx id which
34616
+ * are unsigned integers (starting from 1).
34617
+ */
34618
+ function convertChartId(chartId, construct) {
34619
+ const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
34620
+ if (xlsxId === -1) {
34621
+ construct.chartIds.push(chartId);
34622
+ return construct.chartIds.length;
34623
+ }
34624
+ return xlsxId + 1;
34625
+ }
34626
+ const imageIds = [];
34627
+ /**
34628
+ * Convert a image o-spreadsheet id to a xlsx id which
34629
+ * are unsigned integers (starting from 1).
34630
+ */
34631
+ function convertImageId(imageId) {
34632
+ const xlsxId = imageIds.findIndex((id) => id === imageId);
34633
+ if (xlsxId === -1) {
34634
+ imageIds.push(imageId);
34635
+ return imageIds.length;
34636
+ }
34637
+ return xlsxId + 1;
34638
+ }
34639
+ /**
34640
+ * Convert a value expressed in dot to EMU.
34641
+ * EMU = English Metrical Unit
34642
+ * There are 914400 EMU per inch.
34643
+ *
34644
+ * /!\ A value expressed in EMU cannot be fractional.
34645
+ * See https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vml-units#other-units-of-measurement
34646
+ */
34647
+ function convertDotValueToEMU(value) {
34648
+ const DPI = 96;
34649
+ return Math.round((value * 914400) / DPI);
34650
+ }
34651
+ function getRangeSize(reference, defaultSheetIndex, data) {
34652
+ let xc = reference;
34653
+ let sheetName = undefined;
34654
+ ({ xc, sheetName } = splitReference(reference));
34655
+ let rangeSheetIndex;
34656
+ if (sheetName) {
34657
+ const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
34658
+ if (index < 0) {
34659
+ throw new Error("Unable to find a sheet with the name " + sheetName);
34660
+ }
34661
+ rangeSheetIndex = index;
34662
+ }
34663
+ else {
34664
+ rangeSheetIndex = Number(defaultSheetIndex);
34665
+ }
34666
+ const zone = toUnboundedZone(xc);
34667
+ if (zone.right === undefined) {
34668
+ zone.right = data.sheets[rangeSheetIndex].colNumber;
34669
+ }
34670
+ if (zone.bottom === undefined) {
34671
+ zone.bottom = data.sheets[rangeSheetIndex].rowNumber;
34672
+ }
34673
+ return (zone.right - zone.left + 1) * (zone.bottom - zone.top + 1);
34674
+ }
34675
+ function convertEMUToDotValue(value) {
34676
+ const DPI = 96;
34677
+ return Math.round((value * DPI) / 914400);
34678
+ }
34679
+ /**
34680
+ * Get the position of the start of a column in Excel (in px).
34681
+ */
34682
+ function getColPosition(colIndex, sheetData) {
34683
+ let position = 0;
34684
+ for (let i = 0; i < colIndex; i++) {
34685
+ const colAtIndex = sheetData.cols.find((col) => i >= col.min && i <= col.max);
34686
+ if (colAtIndex?.width) {
34687
+ position += colAtIndex.width;
34688
+ }
34689
+ else if (sheetData.sheetFormat?.defaultColWidth) {
34690
+ position += sheetData.sheetFormat.defaultColWidth;
34691
+ }
34692
+ else {
34693
+ position += EXCEL_DEFAULT_COL_WIDTH;
34694
+ }
34695
+ }
34696
+ return position / WIDTH_FACTOR;
34697
+ }
34698
+ /**
34699
+ * Get the position of the start of a row in Excel (in px).
34700
+ */
34701
+ function getRowPosition(rowIndex, sheetData) {
34702
+ let position = 0;
34703
+ for (let i = 0; i < rowIndex; i++) {
34704
+ const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
34705
+ if (rowAtIndex?.height) {
34706
+ position += rowAtIndex.height;
34707
+ }
34708
+ else if (sheetData.sheetFormat?.defaultRowHeight) {
34709
+ position += sheetData.sheetFormat.defaultRowHeight;
34710
+ }
34711
+ else {
34712
+ position += EXCEL_DEFAULT_ROW_HEIGHT;
34713
+ }
34714
+ }
34715
+ return position / HEIGHT_FACTOR;
34716
+ }
34717
+ /**
34718
+ * Convert the o-spreadsheet data validation decimal
34719
+ * criterion type to the corresponding excel operator.
34720
+ */
34721
+ function convertDecimalCriterionTypeToExcelOperator(operator) {
34722
+ return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
34723
+ }
34724
+ /**
34725
+ * Convert the o-spreadsheet data validation date
34726
+ * criterion type to the corresponding excel operator.
34727
+ */
34728
+ function convertDateCriterionTypeToExcelOperator(operator) {
34729
+ return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
34730
+ }
34731
+
34403
34732
  const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
34404
34733
  /**
34405
34734
  * Convert excel format to o_spreadsheet format
@@ -34499,6 +34828,9 @@ stores.inject(MyMetaStore, storeInstance);
34499
34828
  align: styleStruct.alignment?.horizontal
34500
34829
  ? H_ALIGNMENT_CONVERSION_MAP[styleStruct.alignment.horizontal]
34501
34830
  : undefined,
34831
+ rotation: styleStruct.alignment?.textRotation
34832
+ ? rotationFromXLSX(styleStruct.alignment.textRotation)
34833
+ : undefined,
34502
34834
  // In xlsx fills, bgColor is the color of the fill, and fgColor is the color of the pattern above the background, except in solid fills
34503
34835
  fillColor: styleStruct.fillStyle?.patternType === "solid"
34504
34836
  ? convertColor(styleStruct.fillStyle?.fgColor)
@@ -34798,303 +35130,6 @@ stores.inject(MyMetaStore, storeInstance);
34798
35130
  }
34799
35131
  }
34800
35132
 
34801
- // -------------------------------------
34802
- // CF HELPERS
34803
- // -------------------------------------
34804
- /**
34805
- * Convert the conditional formatting o-spreadsheet operator to
34806
- * the corresponding excel operator.
34807
- * */
34808
- function convertOperator(operator) {
34809
- switch (operator) {
34810
- case "isNotEmpty":
34811
- return "notContainsBlanks";
34812
- case "isEmpty":
34813
- return "containsBlanks";
34814
- case "notContainsText":
34815
- return "notContainsBlanks";
34816
- case "containsText":
34817
- return "containsText";
34818
- case "beginsWithText":
34819
- return "beginsWith";
34820
- case "endsWithText":
34821
- return "endsWith";
34822
- case "isGreaterThan":
34823
- return "greaterThan";
34824
- case "isGreaterOrEqualTo":
34825
- return "greaterThanOrEqual";
34826
- case "isLessThan":
34827
- return "lessThan";
34828
- case "isLessOrEqualTo":
34829
- return "lessThanOrEqual";
34830
- case "isBetween":
34831
- return "between";
34832
- case "isNotBetween":
34833
- return "notBetween";
34834
- case "isEqual":
34835
- return "equal";
34836
- case "isNotEqual":
34837
- return "notEqual";
34838
- case "customFormula":
34839
- return "";
34840
- case "dateIs":
34841
- return "";
34842
- case "dateIsBefore":
34843
- return "lessThan";
34844
- case "dateIsAfter":
34845
- return "greaterThan";
34846
- case "dateIsOnOrAfter":
34847
- return "greaterThanOrEqual";
34848
- case "dateIsOnOrBefore":
34849
- return "lessThanOrEqual";
34850
- }
34851
- }
34852
- // -------------------------------------
34853
- // WORKSHEET HELPERS
34854
- // -------------------------------------
34855
- function getCellType(value) {
34856
- switch (typeof value) {
34857
- case "boolean":
34858
- return "b";
34859
- case "string":
34860
- return "str";
34861
- case "number":
34862
- return "n";
34863
- default:
34864
- return undefined;
34865
- }
34866
- }
34867
- function convertHeightToExcel(height) {
34868
- return Math.round(HEIGHT_FACTOR * height * 100) / 100;
34869
- }
34870
- function convertWidthToExcel(width) {
34871
- return Math.round(WIDTH_FACTOR * width * 100) / 100;
34872
- }
34873
- function convertHeightFromExcel(height) {
34874
- if (!height)
34875
- return height;
34876
- return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
34877
- }
34878
- function convertWidthFromExcel(width) {
34879
- if (!width)
34880
- return width;
34881
- return Math.round((width / WIDTH_FACTOR) * 100) / 100;
34882
- }
34883
- function extractStyle(data, content, styleId, formatId, borderId) {
34884
- const style = styleId ? data.styles[styleId] : {};
34885
- const format = formatId ? data.formats[formatId] : undefined;
34886
- const styles = {
34887
- font: {
34888
- size: style?.fontSize || DEFAULT_FONT_SIZE,
34889
- color: { rgb: style?.textColor ? style.textColor : "000000" },
34890
- family: 2,
34891
- name: "Arial",
34892
- },
34893
- fill: style?.fillColor
34894
- ? {
34895
- fgColor: { rgb: style.fillColor },
34896
- }
34897
- : { reservedAttribute: "none" },
34898
- numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
34899
- border: borderId || 0,
34900
- alignment: {
34901
- horizontal: style.align,
34902
- vertical: style.verticalAlign
34903
- ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
34904
- : undefined,
34905
- wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
34906
- },
34907
- };
34908
- styles.font["strike"] = !!style?.strikethrough || undefined;
34909
- styles.font["underline"] = !!style?.underline || undefined;
34910
- styles.font["bold"] = !!style?.bold || undefined;
34911
- styles.font["italic"] = !!style?.italic || undefined;
34912
- return styles;
34913
- }
34914
- function normalizeStyle(construct, styles) {
34915
- // Normalize this
34916
- const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
34917
- const style = {
34918
- fontId: pushElement(styles.font, construct.fonts),
34919
- fillId: pushElement(styles.fill, construct.fills),
34920
- borderId: styles.border,
34921
- numFmtId,
34922
- alignment: {
34923
- vertical: styles.alignment.vertical,
34924
- horizontal: styles.alignment.horizontal,
34925
- wrapText: styles.alignment.wrapText,
34926
- },
34927
- };
34928
- return pushElement(style, construct.styles);
34929
- }
34930
- function convertFormat(format, numFmtStructure) {
34931
- if (!format) {
34932
- return 0;
34933
- }
34934
- let formatId = XLSX_FORMAT_MAP[format.format];
34935
- if (!formatId) {
34936
- formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
34937
- }
34938
- return formatId;
34939
- }
34940
- /**
34941
- * Add a relation to the given file and return its id.
34942
- */
34943
- function addRelsToFile(relsFiles, path, rel) {
34944
- const relsFile = relsFiles.find((file) => file.path === path);
34945
- // the id is a one-based int casted as string
34946
- let id;
34947
- if (!relsFile) {
34948
- id = "rId1";
34949
- relsFiles.push({ path, rels: [{ ...rel, id }] });
34950
- }
34951
- else {
34952
- id = `rId${(relsFile.rels.length + 1).toString()}`;
34953
- relsFile.rels.push({
34954
- ...rel,
34955
- id,
34956
- });
34957
- }
34958
- return id;
34959
- }
34960
- const globalReverseLookup = new WeakMap();
34961
- function pushElement(property, propertyList) {
34962
- let reverseLookup = globalReverseLookup.get(propertyList);
34963
- if (!reverseLookup) {
34964
- reverseLookup = new Map();
34965
- for (let i = 0; i < propertyList.length; i++) {
34966
- const canonical = getCanonicalRepresentation(propertyList[i]);
34967
- reverseLookup.set(canonical, i);
34968
- }
34969
- globalReverseLookup.set(propertyList, reverseLookup);
34970
- }
34971
- const canonical = getCanonicalRepresentation(property);
34972
- if (reverseLookup.has(canonical)) {
34973
- return reverseLookup.get(canonical);
34974
- }
34975
- const maxId = propertyList.length;
34976
- propertyList.push(property);
34977
- reverseLookup.set(canonical, maxId);
34978
- return maxId;
34979
- }
34980
- /**
34981
- * Convert a chart o-spreadsheet id to a xlsx id which
34982
- * are unsigned integers (starting from 1).
34983
- */
34984
- function convertChartId(chartId, construct) {
34985
- const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
34986
- if (xlsxId === -1) {
34987
- construct.chartIds.push(chartId);
34988
- return construct.chartIds.length;
34989
- }
34990
- return xlsxId + 1;
34991
- }
34992
- const imageIds = [];
34993
- /**
34994
- * Convert a image o-spreadsheet id to a xlsx id which
34995
- * are unsigned integers (starting from 1).
34996
- */
34997
- function convertImageId(imageId) {
34998
- const xlsxId = imageIds.findIndex((id) => id === imageId);
34999
- if (xlsxId === -1) {
35000
- imageIds.push(imageId);
35001
- return imageIds.length;
35002
- }
35003
- return xlsxId + 1;
35004
- }
35005
- /**
35006
- * Convert a value expressed in dot to EMU.
35007
- * EMU = English Metrical Unit
35008
- * There are 914400 EMU per inch.
35009
- *
35010
- * /!\ A value expressed in EMU cannot be fractional.
35011
- * See https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vml-units#other-units-of-measurement
35012
- */
35013
- function convertDotValueToEMU(value) {
35014
- const DPI = 96;
35015
- return Math.round((value * 914400) / DPI);
35016
- }
35017
- function getRangeSize(reference, defaultSheetIndex, data) {
35018
- let xc = reference;
35019
- let sheetName = undefined;
35020
- ({ xc, sheetName } = splitReference(reference));
35021
- let rangeSheetIndex;
35022
- if (sheetName) {
35023
- const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
35024
- if (index < 0) {
35025
- throw new Error("Unable to find a sheet with the name " + sheetName);
35026
- }
35027
- rangeSheetIndex = index;
35028
- }
35029
- else {
35030
- rangeSheetIndex = Number(defaultSheetIndex);
35031
- }
35032
- const zone = toUnboundedZone(xc);
35033
- if (zone.right === undefined) {
35034
- zone.right = data.sheets[rangeSheetIndex].colNumber;
35035
- }
35036
- if (zone.bottom === undefined) {
35037
- zone.bottom = data.sheets[rangeSheetIndex].rowNumber;
35038
- }
35039
- return (zone.right - zone.left + 1) * (zone.bottom - zone.top + 1);
35040
- }
35041
- function convertEMUToDotValue(value) {
35042
- const DPI = 96;
35043
- return Math.round((value * DPI) / 914400);
35044
- }
35045
- /**
35046
- * Get the position of the start of a column in Excel (in px).
35047
- */
35048
- function getColPosition(colIndex, sheetData) {
35049
- let position = 0;
35050
- for (let i = 0; i < colIndex; i++) {
35051
- const colAtIndex = sheetData.cols.find((col) => i >= col.min && i <= col.max);
35052
- if (colAtIndex?.width) {
35053
- position += colAtIndex.width;
35054
- }
35055
- else if (sheetData.sheetFormat?.defaultColWidth) {
35056
- position += sheetData.sheetFormat.defaultColWidth;
35057
- }
35058
- else {
35059
- position += EXCEL_DEFAULT_COL_WIDTH;
35060
- }
35061
- }
35062
- return position / WIDTH_FACTOR;
35063
- }
35064
- /**
35065
- * Get the position of the start of a row in Excel (in px).
35066
- */
35067
- function getRowPosition(rowIndex, sheetData) {
35068
- let position = 0;
35069
- for (let i = 0; i < rowIndex; i++) {
35070
- const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
35071
- if (rowAtIndex?.height) {
35072
- position += rowAtIndex.height;
35073
- }
35074
- else if (sheetData.sheetFormat?.defaultRowHeight) {
35075
- position += sheetData.sheetFormat.defaultRowHeight;
35076
- }
35077
- else {
35078
- position += EXCEL_DEFAULT_ROW_HEIGHT;
35079
- }
35080
- }
35081
- return position / HEIGHT_FACTOR;
35082
- }
35083
- /**
35084
- * Convert the o-spreadsheet data validation decimal
35085
- * criterion type to the corresponding excel operator.
35086
- */
35087
- function convertDecimalCriterionTypeToExcelOperator(operator) {
35088
- return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
35089
- }
35090
- /**
35091
- * Convert the o-spreadsheet data validation date
35092
- * criterion type to the corresponding excel operator.
35093
- */
35094
- function convertDateCriterionTypeToExcelOperator(operator) {
35095
- return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
35096
- }
35097
-
35098
35133
  function convertFigures(sheetData) {
35099
35134
  let id = 1;
35100
35135
  return sheetData.figures
@@ -44675,6 +44710,7 @@ stores.inject(MyMetaStore, storeInstance);
44675
44710
  "getMeasureCompiledFormula",
44676
44711
  "getPivotName",
44677
44712
  "isExistingPivot",
44713
+ "getMeasureFullDependencies",
44678
44714
  ];
44679
44715
  nextFormulaId = 1;
44680
44716
  pivots = {};
@@ -44760,7 +44796,7 @@ stores.inject(MyMetaStore, storeInstance);
44760
44796
  }
44761
44797
  case "UPDATE_PIVOT": {
44762
44798
  this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
44763
- this.compileCalculatedMeasures(cmd.pivot.measures);
44799
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
44764
44800
  break;
44765
44801
  }
44766
44802
  }
@@ -44778,9 +44814,14 @@ stores.inject(MyMetaStore, storeInstance);
44778
44814
  this.history.update("pivots", pivotId, "definition", newDefinition);
44779
44815
  }
44780
44816
  }
44781
- for (const sheetId in this.compiledMeasureFormulas) {
44782
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
44783
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
44817
+ for (const pivotId in this.compiledMeasureFormulas) {
44818
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
44819
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
44820
+ if (!measure || !measure.computedBy) {
44821
+ continue;
44822
+ }
44823
+ const sheetId = measure.computedBy.sheetId;
44824
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
44784
44825
  const newDependencies = [];
44785
44826
  for (const range of compiledFormula.dependencies) {
44786
44827
  const change = applyChange(range);
@@ -44792,8 +44833,9 @@ stores.inject(MyMetaStore, storeInstance);
44792
44833
  }
44793
44834
  }
44794
44835
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
44795
- if (newFormulaString !== formulaString) {
44796
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
44836
+ const oldFormulaString = measure.computedBy.formula;
44837
+ if (newFormulaString !== oldFormulaString) {
44838
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
44797
44839
  }
44798
44840
  }
44799
44841
  }
@@ -44831,30 +44873,59 @@ stores.inject(MyMetaStore, storeInstance);
44831
44873
  isExistingPivot(pivotId) {
44832
44874
  return pivotId in this.pivots;
44833
44875
  }
44834
- getMeasureCompiledFormula(measure) {
44876
+ getMeasureCompiledFormula(pivotId, measure) {
44877
+ if (!measure.computedBy) {
44878
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
44879
+ }
44880
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
44881
+ }
44882
+ getMeasureFullDependencies(pivotId, measure) {
44835
44883
  if (!measure.computedBy) {
44836
44884
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
44837
44885
  }
44838
- const sheetId = measure.computedBy.sheetId;
44839
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
44886
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
44840
44887
  }
44841
44888
  // -------------------------------------------------------------------------
44842
44889
  // Private
44843
44890
  // -------------------------------------------------------------------------
44844
44891
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
44845
44892
  this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
44846
- this.compileCalculatedMeasures(pivot.measures);
44893
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
44847
44894
  this.history.update("formulaIds", formulaId, pivotId);
44848
44895
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
44849
44896
  }
44850
- compileCalculatedMeasures(measures) {
44897
+ compileCalculatedMeasures(pivotId, measures) {
44851
44898
  for (const measure of measures) {
44852
44899
  if (measure.computedBy) {
44853
- const sheetId = measure.computedBy.sheetId;
44854
44900
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
44855
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
44901
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
44902
+ }
44903
+ }
44904
+ for (const measure of measures) {
44905
+ if (measure.computedBy) {
44906
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
44907
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
44908
+ }
44909
+ }
44910
+ }
44911
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
44912
+ const rangeDependencies = [];
44913
+ const definition = this.getPivotCoreDefinition(pivotId);
44914
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
44915
+ exploredMeasures.add(measure.id);
44916
+ for (const token of formula.tokens) {
44917
+ if (token.type !== "SYMBOL") {
44918
+ continue;
44919
+ }
44920
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
44921
+ measure.id !== measureCandidate.id);
44922
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
44923
+ continue;
44856
44924
  }
44925
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
44857
44926
  }
44927
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
44928
+ return rangeDependencies;
44858
44929
  }
44859
44930
  insertPivot(position, formulaId, table) {
44860
44931
  this.resizeSheet(position.sheetId, position, table);
@@ -44914,21 +44985,17 @@ stores.inject(MyMetaStore, storeInstance);
44914
44985
  dependencies: rangeDependencies,
44915
44986
  };
44916
44987
  }
44917
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
44918
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
44919
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
44920
- for (const pivotId in this.pivots) {
44921
- const pivot = this.pivots[pivotId];
44922
- if (!pivot) {
44923
- continue;
44924
- }
44925
- for (const measure of pivot.definition.measures) {
44926
- if (measure.computedBy?.formula === formulaString) {
44927
- const measureIndex = pivot.definition.measures.indexOf(measure);
44928
- this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
44929
- }
44930
- }
44988
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
44989
+ const pivot = this.pivots[pivotId];
44990
+ if (!pivot) {
44991
+ return;
44931
44992
  }
44993
+ const measureIndex = pivot.definition.measures.indexOf(measure);
44994
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
44995
+ formula: newFormulaString,
44996
+ sheetId: measure.computedBy.sheetId,
44997
+ });
44998
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
44932
44999
  }
44933
45000
  checkSortedColumnInMeasures(definition) {
44934
45001
  const measures = definition.measures.map((measure) => measure.id);
@@ -45989,7 +46056,7 @@ stores.inject(MyMetaStore, storeInstance);
45989
46056
  case "UPDATE_CELL":
45990
46057
  if (cmd.style !== undefined) {
45991
46058
  if (cmd.style !== null) {
45992
- this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style);
46059
+ this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style, { force: true });
45993
46060
  }
45994
46061
  else {
45995
46062
  this.clearStyle(cmd.sheetId, [positionToZone(cmd)]);
@@ -46057,16 +46124,22 @@ stores.inject(MyMetaStore, storeInstance);
46057
46124
  }
46058
46125
  }
46059
46126
  styleIsDefault(style) {
46060
- return deepEquals(this.removeDefaultStyleValues(style), {});
46127
+ for (const key in style) {
46128
+ if (DEFAULT_STYLE_NO_ALIGN[key] !== style[key]) {
46129
+ return false;
46130
+ }
46131
+ }
46132
+ return true;
46061
46133
  }
46062
46134
  removeDefaultStyleValues(style) {
46063
46135
  const cleanedStyle = { ...style };
46064
- for (const property in DEFAULT_STYLE_NO_ALIGN) {
46065
- if (cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
46136
+ for (const property in style) {
46137
+ if (cleanedStyle[property] === undefined ||
46138
+ cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
46066
46139
  delete cleanedStyle[property];
46067
46140
  }
46068
46141
  }
46069
- return cleanedStyle;
46142
+ return Object.keys(cleanedStyle).length > 0 ? cleanedStyle : undefined;
46070
46143
  }
46071
46144
  onMerge(sheetId, zone) {
46072
46145
  this.setStyle(sheetId, zone, this.getCellStyle({ sheetId, col: zone.left, row: zone.top }), {
@@ -46102,13 +46175,13 @@ stores.inject(MyMetaStore, storeInstance);
46102
46175
  }
46103
46176
  editingZone = recomputeZones(editingZone, [inter]);
46104
46177
  }
46178
+ style = this.removeDefaultStyleValues(style);
46105
46179
  if (style) {
46106
- const newStyle = this.removeDefaultStyleValues(style);
46107
46180
  styles.push(...editingZone.map((zone) => {
46108
- return { zone, style: newStyle };
46181
+ return { zone, style };
46109
46182
  }));
46110
46183
  }
46111
- this.history.update("styles", sheetId, styles.filter((zoneStyle) => !this.styleIsDefault(zoneStyle.style)));
46184
+ this.history.update("styles", sheetId, styles);
46112
46185
  }
46113
46186
  clearStyle(sheetId, zones) {
46114
46187
  this.setStyles(sheetId, zones, undefined, { force: true });
@@ -52037,14 +52110,16 @@ stores.inject(MyMetaStore, storeInstance);
52037
52110
  function withPivotPresentationLayer (PivotClass) {
52038
52111
  class PivotPresentationLayer extends PivotClass {
52039
52112
  getters;
52113
+ pivotId;
52040
52114
  cache = {};
52041
52115
  rankAsc = {};
52042
52116
  rankDesc = {};
52043
52117
  runningTotal = {};
52044
52118
  runningTotalInPercent = {};
52045
- constructor(custom, params) {
52119
+ constructor(pivotId, custom, params) {
52046
52120
  super(custom, params);
52047
52121
  this.getters = params.getters;
52122
+ this.pivotId = pivotId;
52048
52123
  }
52049
52124
  markAsDirtyForEvaluation() {
52050
52125
  this.cache = {};
@@ -52094,7 +52169,7 @@ stores.inject(MyMetaStore, storeInstance);
52094
52169
  return handleError(error, measure.aggregator.toUpperCase());
52095
52170
  }
52096
52171
  }
52097
- const formula = this.getters.getMeasureCompiledFormula(measure);
52172
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
52098
52173
  const getSymbolValue = (symbolName) => {
52099
52174
  const { columns, rows } = this.definition;
52100
52175
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -52841,7 +52916,7 @@ stores.inject(MyMetaStore, storeInstance);
52841
52916
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
52842
52917
  if (!(pivotId in this.pivots)) {
52843
52918
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
52844
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
52919
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
52845
52920
  }
52846
52921
  else if (recreate) {
52847
52922
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -61939,6 +62014,9 @@ stores.inject(MyMetaStore, storeInstance);
61939
62014
  if (style.alignment && style.alignment.wrapText) {
61940
62015
  alignAttrs.push(["wrapText", "1"]);
61941
62016
  }
62017
+ if (style.alignment && style.alignment.textRotation) {
62018
+ alignAttrs.push(["textRotation", style.alignment.textRotation]);
62019
+ }
61942
62020
  if (alignAttrs.length > 0) {
61943
62021
  attributes.push(["applyAlignment", "1"]); // for Libre Office
61944
62022
  styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}><alignment ${formatAttributes(alignAttrs)} /></xf> `);
@@ -72239,7 +72317,7 @@ stores.inject(MyMetaStore, storeInstance);
72239
72317
  }
72240
72318
  captureSelection(zone, col, row) {
72241
72319
  this.model.selection.capture(this, {
72242
- cell: { col: col ?? zone.left, row: row ?? zone.right },
72320
+ cell: { col: col ?? zone.left, row: row ?? zone.top },
72243
72321
  zone,
72244
72322
  }, {
72245
72323
  handleEvent: this.handleEvent.bind(this),
@@ -77962,35 +78040,46 @@ stores.inject(MyMetaStore, storeInstance);
77962
78040
  name: _t("Rotation"),
77963
78041
  icon: (env) => getRotationIcon(env),
77964
78042
  };
78043
+ function setRotation(env, rotation) {
78044
+ rotation = Math.trunc(rotation / ROTATION_EPSILON) * ROTATION_EPSILON;
78045
+ setStyle(env, { rotation });
78046
+ }
78047
+ function currentRotationEqual(env, rotation) {
78048
+ const current = env.model.getters.getCurrentStyle().rotation;
78049
+ if (current === undefined) {
78050
+ return rotation === 0;
78051
+ }
78052
+ return Math.abs(current - rotation) < ROTATION_EPSILON;
78053
+ }
77965
78054
  const formatNoRotation = {
77966
78055
  name: _t("No rotation"),
77967
78056
  execute: (env) => setStyle(env, { rotation: 0 }),
77968
78057
  icon: "o-spreadsheet-Icon.ROTATION-0",
77969
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === 0,
78058
+ isActive: (env) => currentRotationEqual(env, 0),
77970
78059
  };
77971
78060
  const formatRotation45 = {
77972
78061
  name: _t("45° rotation"),
77973
- execute: (env) => setStyle(env, { rotation: Math.PI / 4 }),
78062
+ execute: (env) => setRotation(env, Math.PI / 4),
77974
78063
  icon: "o-spreadsheet-Icon.ROTATION-45",
77975
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === Math.PI / 4,
78064
+ isActive: (env) => currentRotationEqual(env, Math.PI / 4),
77976
78065
  };
77977
78066
  const formatRotation90 = {
77978
78067
  name: _t("90° rotation"),
77979
- execute: (env) => setStyle(env, { rotation: Math.PI / 2 }),
78068
+ execute: (env) => setRotation(env, Math.PI / 2),
77980
78069
  icon: "o-spreadsheet-Icon.ROTATION-90",
77981
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === Math.PI / 2,
78070
+ isActive: (env) => currentRotationEqual(env, Math.PI / 2),
77982
78071
  };
77983
78072
  const formatRotation270 = {
77984
78073
  name: _t("-90° rotation"),
77985
- execute: (env) => setStyle(env, { rotation: -Math.PI / 2 }),
78074
+ execute: (env) => setRotation(env, -Math.PI / 2),
77986
78075
  icon: "o-spreadsheet-Icon.ROTATION-270",
77987
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === -Math.PI / 2,
78076
+ isActive: (env) => currentRotationEqual(env, -Math.PI / 2),
77988
78077
  };
77989
78078
  const formatRotation315 = {
77990
78079
  name: _t("-45° rotation"),
77991
- execute: (env) => setStyle(env, { rotation: -Math.PI / 4 }),
78080
+ execute: (env) => setRotation(env, -Math.PI / 4),
77992
78081
  icon: "o-spreadsheet-Icon.ROTATION-315",
77993
- isActive: (env) => env.model.getters.getCurrentStyle().rotation === -Math.PI / 4,
78082
+ isActive: (env) => currentRotationEqual(env, -Math.PI / 4),
77994
78083
  };
77995
78084
  const formatStrikethrough = {
77996
78085
  name: _t("Strikethrough"),
@@ -78156,10 +78245,6 @@ stores.inject(MyMetaStore, storeInstance);
78156
78245
  }
78157
78246
  return DEFAULT_WRAPPING_MODE;
78158
78247
  }
78159
- function getRotation(env) {
78160
- const style = env.model.getters.getCurrentStyle();
78161
- return style.rotation ?? 0;
78162
- }
78163
78248
  function getHorizontalAlignmentIcon(env) {
78164
78249
  const horizontalAlign = getHorizontalAlign(env);
78165
78250
  switch (horizontalAlign) {
@@ -78194,19 +78279,19 @@ stores.inject(MyMetaStore, storeInstance);
78194
78279
  }
78195
78280
  }
78196
78281
  function getRotationIcon(env) {
78197
- const rotation = getRotation(env);
78198
- switch (rotation) {
78199
- case Math.PI / 2:
78200
- return "o-spreadsheet-Icon.ROTATION-90";
78201
- case -Math.PI / 2:
78202
- return "o-spreadsheet-Icon.ROTATION-270";
78203
- case Math.PI / 4:
78204
- return "o-spreadsheet-Icon.ROTATION-45";
78205
- case -Math.PI / 4:
78206
- return "o-spreadsheet-Icon.ROTATION-315";
78207
- default:
78208
- return "o-spreadsheet-Icon.ROTATION-0";
78282
+ if (currentRotationEqual(env, Math.PI / 2)) {
78283
+ return "o-spreadsheet-Icon.ROTATION-90";
78284
+ }
78285
+ else if (currentRotationEqual(env, -Math.PI / 2)) {
78286
+ return "o-spreadsheet-Icon.ROTATION-270";
78287
+ }
78288
+ else if (currentRotationEqual(env, Math.PI / 4)) {
78289
+ return "o-spreadsheet-Icon.ROTATION-45";
78209
78290
  }
78291
+ else if (currentRotationEqual(env, -Math.PI / 4)) {
78292
+ return "o-spreadsheet-Icon.ROTATION-315";
78293
+ }
78294
+ return "o-spreadsheet-Icon.ROTATION-0";
78210
78295
  }
78211
78296
 
78212
78297
  const colMenuRegistry = new MenuItemRegistry();
@@ -86418,6 +86503,12 @@ stores.inject(MyMetaStore, storeInstance);
86418
86503
  case "ACTIVATE_SHEET":
86419
86504
  this.isSearchDirty = true;
86420
86505
  this.shouldFinalizeUpdateSelection = true;
86506
+ if (this.searchOptions.specificRange) {
86507
+ this.searchOptions.specificRange = {
86508
+ ...this.searchOptions.specificRange,
86509
+ sheetId: this.getters.getActiveSheetId(),
86510
+ };
86511
+ }
86421
86512
  break;
86422
86513
  case "REPLACE_SEARCH":
86423
86514
  for (const match of cmd.matches) {
@@ -86804,9 +86895,20 @@ stores.inject(MyMetaStore, storeInstance);
86804
86895
  const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
86805
86896
  this.store.updateSearchOptions({ specificRange });
86806
86897
  }
86898
+ get specificRange() {
86899
+ const range = this.store.searchOptions.specificRange;
86900
+ return range ? this.env.model.getters.getRangeString(range, "forceSheetReference") : "";
86901
+ }
86807
86902
  get pendingSearch() {
86808
86903
  return this.updateSearchContent.isDebouncePending();
86809
86904
  }
86905
+ get selectionInputKey() {
86906
+ // Selections input are made to work with objects linked to a sheet id. They store the active sheet id at their creation,
86907
+ // and have specific behaviour linked to it (eg. go back to the initial sheet after confirmation).
86908
+ // We don't want all those behaviors here, so we force the recreation of the component when the active sheet changes.
86909
+ // The only drawback is that the input loses focus when changing sheet.
86910
+ return this.env.model.getters.getActiveSheetId();
86911
+ }
86810
86912
  }
86811
86913
 
86812
86914
  /**
@@ -97985,9 +98087,9 @@ stores.inject(MyMetaStore, storeInstance);
97985
98087
  exports.tokenize = tokenize;
97986
98088
 
97987
98089
 
97988
- __info__.version = "19.1.2";
97989
- __info__.date = "2026-01-07T16:21:36.757Z";
97990
- __info__.hash = "febc3e9";
98090
+ __info__.version = "19.1.3";
98091
+ __info__.date = "2026-01-14T10:02:32.431Z";
98092
+ __info__.hash = "52a3e52";
97991
98093
 
97992
98094
 
97993
98095
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);