@odoo/o-spreadsheet 17.0.54 → 17.0.56

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 17.0.54
6
- * @date 2025-03-19T08:14:16.001Z
7
- * @hash 945b375
5
+ * @version 17.0.56
6
+ * @date 2025-04-04T08:36:58.258Z
7
+ * @hash c484787
8
8
  */
9
9
 
10
10
  'use strict';
@@ -712,8 +712,7 @@ function removeFalsyAttributes(obj) {
712
712
  *
713
713
  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
714
714
  */
715
- const whiteSpaceSpecialCharacters = [
716
- " ",
715
+ const specialWhiteSpaceSpecialCharacters = [
717
716
  "\t",
718
717
  "\f",
719
718
  "\v",
@@ -728,7 +727,7 @@ const whiteSpaceSpecialCharacters = [
728
727
  String.fromCharCode(parseInt("3000", 16)),
729
728
  String.fromCharCode(parseInt("feff", 16)),
730
729
  ];
731
- const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|"), "g");
730
+ const specialWhiteSpaceRegexp = new RegExp(specialWhiteSpaceSpecialCharacters.join("|"), "g");
732
731
  const newLineRegexp = /(\r\n|\r)/g;
733
732
  /**
734
733
  * Replace all different newlines characters by \n
@@ -949,7 +948,10 @@ function rgbaStringToHex(color) {
949
948
  }
950
949
  else if (stringVals.length === 4) {
951
950
  const alpha = parseFloat(stringVals.pop() || "1");
952
- alphaHex = Math.round((alpha || 1) * 255);
951
+ if (isNaN(alpha)) {
952
+ throw new Error("invalid alpha value");
953
+ }
954
+ alphaHex = Math.round(alpha * 255);
953
955
  }
954
956
  const vals = stringVals.map((val) => parseInt(val, 10));
955
957
  if (alphaHex !== 255) {
@@ -7530,8 +7532,12 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
7530
7532
  str = replaceNewLines(str);
7531
7533
  const chars = new TokenizingChars(str);
7532
7534
  const result = [];
7535
+ const tokenizeSpace = specialWhiteSpaceRegexp.test(str)
7536
+ ? tokenizeSpecialCharacterSpace
7537
+ : tokenizeSimpleSpace;
7533
7538
  while (!chars.isOver()) {
7534
- let token = tokenizeSpace(chars) ||
7539
+ let token = tokenizeNewLine(chars) ||
7540
+ tokenizeSpace(chars) ||
7535
7541
  tokenizeArgsSeparator(chars, locale) ||
7536
7542
  tokenizeParenthesis(chars) ||
7537
7543
  tokenizeOperator(chars) ||
@@ -7665,17 +7671,19 @@ function tokenizeSymbol(chars) {
7665
7671
  }
7666
7672
  return null;
7667
7673
  }
7668
- function tokenizeSpace(chars) {
7669
- let length = 0;
7670
- while (chars.current === NEWLINE) {
7671
- length++;
7672
- chars.shift();
7674
+ function tokenizeSpecialCharacterSpace(chars) {
7675
+ let spaces = "";
7676
+ while (chars.current === " " || (chars.current && chars.current.match(specialWhiteSpaceRegexp))) {
7677
+ spaces += chars.shift();
7673
7678
  }
7674
- if (length) {
7675
- return { type: "SPACE", value: NEWLINE.repeat(length) };
7679
+ if (spaces) {
7680
+ return { type: "SPACE", value: spaces };
7676
7681
  }
7682
+ return null;
7683
+ }
7684
+ function tokenizeSimpleSpace(chars) {
7677
7685
  let spaces = "";
7678
- while (chars.current && chars.current.match(whiteSpaceRegexp)) {
7686
+ while (chars.current === " ") {
7679
7687
  spaces += chars.shift();
7680
7688
  }
7681
7689
  if (spaces) {
@@ -7683,6 +7691,17 @@ function tokenizeSpace(chars) {
7683
7691
  }
7684
7692
  return null;
7685
7693
  }
7694
+ function tokenizeNewLine(chars) {
7695
+ let length = 0;
7696
+ while (chars.current === NEWLINE) {
7697
+ length++;
7698
+ chars.shift();
7699
+ }
7700
+ if (length) {
7701
+ return { type: "SPACE", value: NEWLINE.repeat(length) };
7702
+ }
7703
+ return null;
7704
+ }
7686
7705
  function tokenizeInvalidRange(chars) {
7687
7706
  if (chars.currentStartsWith(INCORRECT_RANGE_STRING)) {
7688
7707
  chars.advanceBy(INCORRECT_RANGE_STRING.length);
@@ -8570,7 +8589,8 @@ function getChartLabelValues(getters, dataSets, labelRange) {
8570
8589
  }
8571
8590
  }
8572
8591
  else if (dataSets.length === 1) {
8573
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
8592
+ const dataLength = getData(getters, dataSets[0]).length;
8593
+ for (let i = 0; i < dataLength; i++) {
8574
8594
  labels.formattedValues.push("");
8575
8595
  labels.values.push("");
8576
8596
  }
@@ -30371,9 +30391,9 @@ const XLSX_CHART_TYPES = [
30371
30391
  /** In XLSX color format (no #) */
30372
30392
  const AUTO_COLOR = "000000";
30373
30393
  const XLSX_ICONSET_MAP = {
30374
- arrow: "3Arrows",
30394
+ arrows: "3Arrows",
30375
30395
  smiley: "3Symbols",
30376
- dot: "3TrafficLights1",
30396
+ dots: "3TrafficLights1",
30377
30397
  };
30378
30398
  const NAMESPACE = {
30379
30399
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -30789,6 +30809,7 @@ const ICON_SET_CONVERSION_MAP = {
30789
30809
  };
30790
30810
  /** Map between legend position in XLSX file and human readable position */
30791
30811
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
30812
+ none: "none",
30792
30813
  b: "bottom",
30793
30814
  t: "top",
30794
30815
  l: "left",
@@ -33021,7 +33042,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
33021
33042
  ? "right"
33022
33043
  : "left",
33023
33044
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
33024
- default: "b",
33045
+ default: "none",
33025
33046
  }).asString()],
33026
33047
  stacked: barChartGrouping === "stacked",
33027
33048
  fontColor: "000000",
@@ -53482,7 +53503,9 @@ css /* scss */ `
53482
53503
  margin-top: -1px;
53483
53504
  border: 1px solid;
53484
53505
 
53485
- .o-composer:empty:not(:focus):not(.active)::before {
53506
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
53507
+ .o-composer:empty:not(:focus):not(.active)::before,
53508
+ &.o-topbar-composer-readonly .o-composer:empty::before {
53486
53509
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
53487
53510
  position: relative;
53488
53511
  top: 20%;
@@ -56483,10 +56506,14 @@ function addIconSetRule(cf, rule) {
56483
56506
  continue;
56484
56507
  }
56485
56508
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
56509
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
56510
+ if (isIconSetReversed(rule.icons)) {
56511
+ iconSetAttrs.push(["reverse", "1"]);
56512
+ }
56486
56513
  conditionalFormats.push(escapeXml /*xml*/ `
56487
56514
  <conditionalFormatting sqref="${range}">
56488
56515
  <cfRule ${formatAttributes(ruleAttributes)}>
56489
- <iconSet iconSet="${getIconSet(rule.icons)}">
56516
+ <iconSet ${formatAttributes(iconSetAttrs)}>
56490
56517
  ${joinXmlNodes(cfValueObjectNodes)}
56491
56518
  </iconSet>
56492
56519
  </cfRule>
@@ -56504,9 +56531,21 @@ function commonCfAttributes(cf) {
56504
56531
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
56505
56532
  ];
56506
56533
  }
56534
+ function isIconSetReversed(iconSet) {
56535
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
56536
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
56537
+ }
56507
56538
  function getIconSet(iconSet) {
56508
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
56509
- "dots"];
56539
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
56540
+ }
56541
+ /**
56542
+ * Partial detection based on "upper" point only.
56543
+ * We support any arbitrary icon in the set, while excel doesn't allow
56544
+ * mixing icons from different types.
56545
+ */
56546
+ function detectIconsType(iconSet) {
56547
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
56548
+ return type;
56510
56549
  }
56511
56550
  function thresholdAttributes(threshold, position) {
56512
56551
  const type = getExcelThresholdType(threshold.type, position);
@@ -58082,6 +58121,6 @@ exports.setTranslationMethod = setTranslationMethod;
58082
58121
  exports.tokenize = tokenize;
58083
58122
 
58084
58123
 
58085
- __info__.version = "17.0.54";
58086
- __info__.date = "2025-03-19T08:14:16.001Z";
58087
- __info__.hash = "945b375";
58124
+ __info__.version = "17.0.56";
58125
+ __info__.date = "2025-04-04T08:36:58.258Z";
58126
+ __info__.hash = "c484787";
@@ -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 17.0.54
6
- * @date 2025-03-19T08:14:16.001Z
7
- * @hash 945b375
5
+ * @version 17.0.56
6
+ * @date 2025-04-04T08:36:58.258Z
7
+ * @hash c484787
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillUnmount, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -710,8 +710,7 @@ function removeFalsyAttributes(obj) {
710
710
  *
711
711
  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
712
712
  */
713
- const whiteSpaceSpecialCharacters = [
714
- " ",
713
+ const specialWhiteSpaceSpecialCharacters = [
715
714
  "\t",
716
715
  "\f",
717
716
  "\v",
@@ -726,7 +725,7 @@ const whiteSpaceSpecialCharacters = [
726
725
  String.fromCharCode(parseInt("3000", 16)),
727
726
  String.fromCharCode(parseInt("feff", 16)),
728
727
  ];
729
- const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|"), "g");
728
+ const specialWhiteSpaceRegexp = new RegExp(specialWhiteSpaceSpecialCharacters.join("|"), "g");
730
729
  const newLineRegexp = /(\r\n|\r)/g;
731
730
  /**
732
731
  * Replace all different newlines characters by \n
@@ -947,7 +946,10 @@ function rgbaStringToHex(color) {
947
946
  }
948
947
  else if (stringVals.length === 4) {
949
948
  const alpha = parseFloat(stringVals.pop() || "1");
950
- alphaHex = Math.round((alpha || 1) * 255);
949
+ if (isNaN(alpha)) {
950
+ throw new Error("invalid alpha value");
951
+ }
952
+ alphaHex = Math.round(alpha * 255);
951
953
  }
952
954
  const vals = stringVals.map((val) => parseInt(val, 10));
953
955
  if (alphaHex !== 255) {
@@ -7528,8 +7530,12 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
7528
7530
  str = replaceNewLines(str);
7529
7531
  const chars = new TokenizingChars(str);
7530
7532
  const result = [];
7533
+ const tokenizeSpace = specialWhiteSpaceRegexp.test(str)
7534
+ ? tokenizeSpecialCharacterSpace
7535
+ : tokenizeSimpleSpace;
7531
7536
  while (!chars.isOver()) {
7532
- let token = tokenizeSpace(chars) ||
7537
+ let token = tokenizeNewLine(chars) ||
7538
+ tokenizeSpace(chars) ||
7533
7539
  tokenizeArgsSeparator(chars, locale) ||
7534
7540
  tokenizeParenthesis(chars) ||
7535
7541
  tokenizeOperator(chars) ||
@@ -7663,17 +7669,19 @@ function tokenizeSymbol(chars) {
7663
7669
  }
7664
7670
  return null;
7665
7671
  }
7666
- function tokenizeSpace(chars) {
7667
- let length = 0;
7668
- while (chars.current === NEWLINE) {
7669
- length++;
7670
- chars.shift();
7672
+ function tokenizeSpecialCharacterSpace(chars) {
7673
+ let spaces = "";
7674
+ while (chars.current === " " || (chars.current && chars.current.match(specialWhiteSpaceRegexp))) {
7675
+ spaces += chars.shift();
7671
7676
  }
7672
- if (length) {
7673
- return { type: "SPACE", value: NEWLINE.repeat(length) };
7677
+ if (spaces) {
7678
+ return { type: "SPACE", value: spaces };
7674
7679
  }
7680
+ return null;
7681
+ }
7682
+ function tokenizeSimpleSpace(chars) {
7675
7683
  let spaces = "";
7676
- while (chars.current && chars.current.match(whiteSpaceRegexp)) {
7684
+ while (chars.current === " ") {
7677
7685
  spaces += chars.shift();
7678
7686
  }
7679
7687
  if (spaces) {
@@ -7681,6 +7689,17 @@ function tokenizeSpace(chars) {
7681
7689
  }
7682
7690
  return null;
7683
7691
  }
7692
+ function tokenizeNewLine(chars) {
7693
+ let length = 0;
7694
+ while (chars.current === NEWLINE) {
7695
+ length++;
7696
+ chars.shift();
7697
+ }
7698
+ if (length) {
7699
+ return { type: "SPACE", value: NEWLINE.repeat(length) };
7700
+ }
7701
+ return null;
7702
+ }
7684
7703
  function tokenizeInvalidRange(chars) {
7685
7704
  if (chars.currentStartsWith(INCORRECT_RANGE_STRING)) {
7686
7705
  chars.advanceBy(INCORRECT_RANGE_STRING.length);
@@ -8568,7 +8587,8 @@ function getChartLabelValues(getters, dataSets, labelRange) {
8568
8587
  }
8569
8588
  }
8570
8589
  else if (dataSets.length === 1) {
8571
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
8590
+ const dataLength = getData(getters, dataSets[0]).length;
8591
+ for (let i = 0; i < dataLength; i++) {
8572
8592
  labels.formattedValues.push("");
8573
8593
  labels.values.push("");
8574
8594
  }
@@ -30369,9 +30389,9 @@ const XLSX_CHART_TYPES = [
30369
30389
  /** In XLSX color format (no #) */
30370
30390
  const AUTO_COLOR = "000000";
30371
30391
  const XLSX_ICONSET_MAP = {
30372
- arrow: "3Arrows",
30392
+ arrows: "3Arrows",
30373
30393
  smiley: "3Symbols",
30374
- dot: "3TrafficLights1",
30394
+ dots: "3TrafficLights1",
30375
30395
  };
30376
30396
  const NAMESPACE = {
30377
30397
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -30787,6 +30807,7 @@ const ICON_SET_CONVERSION_MAP = {
30787
30807
  };
30788
30808
  /** Map between legend position in XLSX file and human readable position */
30789
30809
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
30810
+ none: "none",
30790
30811
  b: "bottom",
30791
30812
  t: "top",
30792
30813
  l: "left",
@@ -33019,7 +33040,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
33019
33040
  ? "right"
33020
33041
  : "left",
33021
33042
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
33022
- default: "b",
33043
+ default: "none",
33023
33044
  }).asString()],
33024
33045
  stacked: barChartGrouping === "stacked",
33025
33046
  fontColor: "000000",
@@ -53480,7 +53501,9 @@ css /* scss */ `
53480
53501
  margin-top: -1px;
53481
53502
  border: 1px solid;
53482
53503
 
53483
- .o-composer:empty:not(:focus):not(.active)::before {
53504
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
53505
+ .o-composer:empty:not(:focus):not(.active)::before,
53506
+ &.o-topbar-composer-readonly .o-composer:empty::before {
53484
53507
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
53485
53508
  position: relative;
53486
53509
  top: 20%;
@@ -56481,10 +56504,14 @@ function addIconSetRule(cf, rule) {
56481
56504
  continue;
56482
56505
  }
56483
56506
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
56507
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
56508
+ if (isIconSetReversed(rule.icons)) {
56509
+ iconSetAttrs.push(["reverse", "1"]);
56510
+ }
56484
56511
  conditionalFormats.push(escapeXml /*xml*/ `
56485
56512
  <conditionalFormatting sqref="${range}">
56486
56513
  <cfRule ${formatAttributes(ruleAttributes)}>
56487
- <iconSet iconSet="${getIconSet(rule.icons)}">
56514
+ <iconSet ${formatAttributes(iconSetAttrs)}>
56488
56515
  ${joinXmlNodes(cfValueObjectNodes)}
56489
56516
  </iconSet>
56490
56517
  </cfRule>
@@ -56502,9 +56529,21 @@ function commonCfAttributes(cf) {
56502
56529
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
56503
56530
  ];
56504
56531
  }
56532
+ function isIconSetReversed(iconSet) {
56533
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
56534
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
56535
+ }
56505
56536
  function getIconSet(iconSet) {
56506
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
56507
- "dots"];
56537
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
56538
+ }
56539
+ /**
56540
+ * Partial detection based on "upper" point only.
56541
+ * We support any arbitrary icon in the set, while excel doesn't allow
56542
+ * mixing icons from different types.
56543
+ */
56544
+ function detectIconsType(iconSet) {
56545
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
56546
+ return type;
56508
56547
  }
56509
56548
  function thresholdAttributes(threshold, position) {
56510
56549
  const type = getExcelThresholdType(threshold.type, position);
@@ -58045,6 +58084,6 @@ const constants = {
58045
58084
  export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
58046
58085
 
58047
58086
 
58048
- __info__.version = "17.0.54";
58049
- __info__.date = "2025-03-19T08:14:16.001Z";
58050
- __info__.hash = "945b375";
58087
+ __info__.version = "17.0.56";
58088
+ __info__.date = "2025-04-04T08:36:58.258Z";
58089
+ __info__.hash = "c484787";
@@ -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 17.0.54
6
- * @date 2025-03-19T08:14:16.001Z
7
- * @hash 945b375
5
+ * @version 17.0.56
6
+ * @date 2025-04-04T08:36:58.258Z
7
+ * @hash c484787
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -711,8 +711,7 @@
711
711
  *
712
712
  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
713
713
  */
714
- const whiteSpaceSpecialCharacters = [
715
- " ",
714
+ const specialWhiteSpaceSpecialCharacters = [
716
715
  "\t",
717
716
  "\f",
718
717
  "\v",
@@ -727,7 +726,7 @@
727
726
  String.fromCharCode(parseInt("3000", 16)),
728
727
  String.fromCharCode(parseInt("feff", 16)),
729
728
  ];
730
- const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|"), "g");
729
+ const specialWhiteSpaceRegexp = new RegExp(specialWhiteSpaceSpecialCharacters.join("|"), "g");
731
730
  const newLineRegexp = /(\r\n|\r)/g;
732
731
  /**
733
732
  * Replace all different newlines characters by \n
@@ -948,7 +947,10 @@
948
947
  }
949
948
  else if (stringVals.length === 4) {
950
949
  const alpha = parseFloat(stringVals.pop() || "1");
951
- alphaHex = Math.round((alpha || 1) * 255);
950
+ if (isNaN(alpha)) {
951
+ throw new Error("invalid alpha value");
952
+ }
953
+ alphaHex = Math.round(alpha * 255);
952
954
  }
953
955
  const vals = stringVals.map((val) => parseInt(val, 10));
954
956
  if (alphaHex !== 255) {
@@ -7529,8 +7531,12 @@
7529
7531
  str = replaceNewLines(str);
7530
7532
  const chars = new TokenizingChars(str);
7531
7533
  const result = [];
7534
+ const tokenizeSpace = specialWhiteSpaceRegexp.test(str)
7535
+ ? tokenizeSpecialCharacterSpace
7536
+ : tokenizeSimpleSpace;
7532
7537
  while (!chars.isOver()) {
7533
- let token = tokenizeSpace(chars) ||
7538
+ let token = tokenizeNewLine(chars) ||
7539
+ tokenizeSpace(chars) ||
7534
7540
  tokenizeArgsSeparator(chars, locale) ||
7535
7541
  tokenizeParenthesis(chars) ||
7536
7542
  tokenizeOperator(chars) ||
@@ -7664,17 +7670,19 @@
7664
7670
  }
7665
7671
  return null;
7666
7672
  }
7667
- function tokenizeSpace(chars) {
7668
- let length = 0;
7669
- while (chars.current === NEWLINE) {
7670
- length++;
7671
- chars.shift();
7673
+ function tokenizeSpecialCharacterSpace(chars) {
7674
+ let spaces = "";
7675
+ while (chars.current === " " || (chars.current && chars.current.match(specialWhiteSpaceRegexp))) {
7676
+ spaces += chars.shift();
7672
7677
  }
7673
- if (length) {
7674
- return { type: "SPACE", value: NEWLINE.repeat(length) };
7678
+ if (spaces) {
7679
+ return { type: "SPACE", value: spaces };
7675
7680
  }
7681
+ return null;
7682
+ }
7683
+ function tokenizeSimpleSpace(chars) {
7676
7684
  let spaces = "";
7677
- while (chars.current && chars.current.match(whiteSpaceRegexp)) {
7685
+ while (chars.current === " ") {
7678
7686
  spaces += chars.shift();
7679
7687
  }
7680
7688
  if (spaces) {
@@ -7682,6 +7690,17 @@
7682
7690
  }
7683
7691
  return null;
7684
7692
  }
7693
+ function tokenizeNewLine(chars) {
7694
+ let length = 0;
7695
+ while (chars.current === NEWLINE) {
7696
+ length++;
7697
+ chars.shift();
7698
+ }
7699
+ if (length) {
7700
+ return { type: "SPACE", value: NEWLINE.repeat(length) };
7701
+ }
7702
+ return null;
7703
+ }
7685
7704
  function tokenizeInvalidRange(chars) {
7686
7705
  if (chars.currentStartsWith(INCORRECT_RANGE_STRING)) {
7687
7706
  chars.advanceBy(INCORRECT_RANGE_STRING.length);
@@ -8569,7 +8588,8 @@
8569
8588
  }
8570
8589
  }
8571
8590
  else if (dataSets.length === 1) {
8572
- for (let i = 0; i < getData(getters, dataSets[0]).length; i++) {
8591
+ const dataLength = getData(getters, dataSets[0]).length;
8592
+ for (let i = 0; i < dataLength; i++) {
8573
8593
  labels.formattedValues.push("");
8574
8594
  labels.values.push("");
8575
8595
  }
@@ -30370,9 +30390,9 @@
30370
30390
  /** In XLSX color format (no #) */
30371
30391
  const AUTO_COLOR = "000000";
30372
30392
  const XLSX_ICONSET_MAP = {
30373
- arrow: "3Arrows",
30393
+ arrows: "3Arrows",
30374
30394
  smiley: "3Symbols",
30375
- dot: "3TrafficLights1",
30395
+ dots: "3TrafficLights1",
30376
30396
  };
30377
30397
  const NAMESPACE = {
30378
30398
  styleSheet: "http://schemas.openxmlformats.org/spreadsheetml/2006/main",
@@ -30788,6 +30808,7 @@
30788
30808
  };
30789
30809
  /** Map between legend position in XLSX file and human readable position */
30790
30810
  const DRAWING_LEGEND_POSITION_CONVERSION_MAP = {
30811
+ none: "none",
30791
30812
  b: "bottom",
30792
30813
  t: "top",
30793
30814
  l: "left",
@@ -33020,7 +33041,7 @@
33020
33041
  ? "right"
33021
33042
  : "left",
33022
33043
  legendPosition: DRAWING_LEGEND_POSITION_CONVERSION_MAP[this.extractChildAttr(rootChartElement, "c:legendPos", "val", {
33023
- default: "b",
33044
+ default: "none",
33024
33045
  }).asString()],
33025
33046
  stacked: barChartGrouping === "stacked",
33026
33047
  fontColor: "000000",
@@ -53481,7 +53502,9 @@
53481
53502
  margin-top: -1px;
53482
53503
  border: 1px solid;
53483
53504
 
53484
- .o-composer:empty:not(:focus):not(.active)::before {
53505
+ /* In readonly we always show the fx icon if the composer is empty, not matter the focus */
53506
+ .o-composer:empty:not(:focus):not(.active)::before,
53507
+ &.o-topbar-composer-readonly .o-composer:empty::before {
53485
53508
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
53486
53509
  position: relative;
53487
53510
  top: 20%;
@@ -56482,10 +56505,14 @@
56482
56505
  continue;
56483
56506
  }
56484
56507
  const cfValueObjectNodes = cfValueObject.map((attrs) => escapeXml /*xml*/ `<cfvo ${formatAttributes(attrs)} />`);
56508
+ const iconSetAttrs = [["iconSet", getIconSet(rule.icons)]];
56509
+ if (isIconSetReversed(rule.icons)) {
56510
+ iconSetAttrs.push(["reverse", "1"]);
56511
+ }
56485
56512
  conditionalFormats.push(escapeXml /*xml*/ `
56486
56513
  <conditionalFormatting sqref="${range}">
56487
56514
  <cfRule ${formatAttributes(ruleAttributes)}>
56488
- <iconSet iconSet="${getIconSet(rule.icons)}">
56515
+ <iconSet ${formatAttributes(iconSetAttrs)}>
56489
56516
  ${joinXmlNodes(cfValueObjectNodes)}
56490
56517
  </iconSet>
56491
56518
  </cfRule>
@@ -56503,9 +56530,21 @@
56503
56530
  ["stopIfTrue", cf.stopIfTrue ? 1 : 0],
56504
56531
  ];
56505
56532
  }
56533
+ function isIconSetReversed(iconSet) {
56534
+ const defaultIconSet = ICON_SETS[detectIconsType(iconSet)];
56535
+ return iconSet.upper === defaultIconSet.bad && iconSet.lower === defaultIconSet.good;
56536
+ }
56506
56537
  function getIconSet(iconSet) {
56507
- return XLSX_ICONSET_MAP[Object.keys(XLSX_ICONSET_MAP).find((key) => iconSet.upper.toLowerCase().startsWith(key)) ||
56508
- "dots"];
56538
+ return XLSX_ICONSET_MAP[detectIconsType(iconSet)];
56539
+ }
56540
+ /**
56541
+ * Partial detection based on "upper" point only.
56542
+ * We support any arbitrary icon in the set, while excel doesn't allow
56543
+ * mixing icons from different types.
56544
+ */
56545
+ function detectIconsType(iconSet) {
56546
+ const type = Object.keys(ICON_SETS).find((type) => Object.values(ICON_SETS[type]).includes(iconSet.upper)) || "dots";
56547
+ return type;
56509
56548
  }
56510
56549
  function thresholdAttributes(threshold, position) {
56511
56550
  const type = getExcelThresholdType(threshold.type, position);
@@ -58081,9 +58120,9 @@
58081
58120
  exports.tokenize = tokenize;
58082
58121
 
58083
58122
 
58084
- __info__.version = "17.0.54";
58085
- __info__.date = "2025-03-19T08:14:16.001Z";
58086
- __info__.hash = "945b375";
58123
+ __info__.version = "17.0.56";
58124
+ __info__.date = "2025-04-04T08:36:58.258Z";
58125
+ __info__.hash = "c484787";
58087
58126
 
58088
58127
 
58089
58128
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);