@odoo/o-spreadsheet 16.4.0-alpha.6 → 16.4.0-alpha.7

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.
@@ -12592,6 +12592,18 @@ const AND = {
12592
12592
  isExported: true,
12593
12593
  };
12594
12594
  // -----------------------------------------------------------------------------
12595
+ // FALSE
12596
+ // -----------------------------------------------------------------------------
12597
+ const FALSE = {
12598
+ description: _lt("Logical value `false`."),
12599
+ args: [],
12600
+ returns: ["BOOLEAN"],
12601
+ compute: function () {
12602
+ return false;
12603
+ },
12604
+ isExported: true,
12605
+ };
12606
+ // -----------------------------------------------------------------------------
12595
12607
  // IF
12596
12608
  // -----------------------------------------------------------------------------
12597
12609
  const IF = {
@@ -12727,6 +12739,18 @@ const OR = {
12727
12739
  isExported: true,
12728
12740
  };
12729
12741
  // -----------------------------------------------------------------------------
12742
+ // TRUE
12743
+ // -----------------------------------------------------------------------------
12744
+ const TRUE = {
12745
+ description: _lt("Logical value `true`."),
12746
+ args: [],
12747
+ returns: ["BOOLEAN"],
12748
+ compute: function () {
12749
+ return true;
12750
+ },
12751
+ isExported: true,
12752
+ };
12753
+ // -----------------------------------------------------------------------------
12730
12754
  // XOR
12731
12755
  // -----------------------------------------------------------------------------
12732
12756
  const XOR = {
@@ -12753,12 +12777,14 @@ const XOR = {
12753
12777
  var logical = /*#__PURE__*/Object.freeze({
12754
12778
  __proto__: null,
12755
12779
  AND: AND,
12780
+ FALSE: FALSE,
12756
12781
  IF: IF,
12757
12782
  IFERROR: IFERROR,
12758
12783
  IFNA: IFNA,
12759
12784
  IFS: IFS,
12760
12785
  NOT: NOT,
12761
12786
  OR: OR,
12787
+ TRUE: TRUE,
12762
12788
  XOR: XOR
12763
12789
  });
12764
12790
 
@@ -13945,7 +13971,6 @@ function indentCode(code) {
13945
13971
  * is useful for the composer, which needs to be able to work with incomplete
13946
13972
  * formulas.
13947
13973
  */
13948
- const functions$3 = functionRegistry.content;
13949
13974
  const POSTFIX_UNARY_OPERATORS = ["%"];
13950
13975
  const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
13951
13976
  function tokenize(str, locale = DEFAULT_LOCALE) {
@@ -14076,17 +14101,11 @@ function tokenizeSymbol(chars) {
14076
14101
  }
14077
14102
  if (result.length) {
14078
14103
  const value = result;
14079
- const isFunction = value.toUpperCase() in functions$3;
14080
- if (isFunction) {
14081
- return { type: "FUNCTION", value };
14082
- }
14083
14104
  const isReference = rangeReference.test(value);
14084
14105
  if (isReference) {
14085
14106
  return { type: "REFERENCE", value };
14086
14107
  }
14087
- else {
14088
- return { type: "SYMBOL", value };
14089
- }
14108
+ return { type: "SYMBOL", value };
14090
14109
  }
14091
14110
  return null;
14092
14111
  }
@@ -14186,9 +14205,6 @@ function parseOperand(tokens) {
14186
14205
  return { type: "NUMBER", value: parseNumber(current.value, DEFAULT_LOCALE) };
14187
14206
  case "STRING":
14188
14207
  return { type: "STRING", value: removeStringQuotes(current.value) };
14189
- case "FUNCTION":
14190
- const args = parseFunctionArgs(tokens);
14191
- return { type: "FUNCALL", value: current.value, args };
14192
14208
  case "INVALID_REFERENCE":
14193
14209
  throw new InvalidReferenceError();
14194
14210
  case "REFERENCE":
@@ -14205,13 +14221,15 @@ function parseOperand(tokens) {
14205
14221
  value: current.value,
14206
14222
  };
14207
14223
  case "SYMBOL":
14208
- if (["TRUE", "FALSE"].includes(current.value.toUpperCase())) {
14209
- return { type: "BOOLEAN", value: current.value.toUpperCase() === "TRUE" };
14224
+ const value = current.value;
14225
+ const nextToken = tokens[0];
14226
+ if (nextToken?.type === "LEFT_PAREN" && functionRegex.test(current.value)) {
14227
+ const args = parseFunctionArgs(tokens);
14228
+ return { type: "FUNCALL", value: value, args };
14210
14229
  }
14211
- if (current.value) {
14212
- if (functionRegex.test(current.value) && tokens[0]?.type === "LEFT_PAREN") {
14213
- throw new UnknownFunctionError(current.value);
14214
- }
14230
+ const upperCaseValue = value.toUpperCase();
14231
+ if (upperCaseValue === "TRUE" || upperCaseValue === "FALSE") {
14232
+ return { type: "BOOLEAN", value: upperCaseValue === "TRUE" };
14215
14233
  }
14216
14234
  throw new BadExpressionError(_lt("Invalid formula"));
14217
14235
  case "LEFT_PAREN":
@@ -14313,36 +14331,60 @@ function parseTokens(tokens) {
14313
14331
  * to nodes of a specific type.
14314
14332
  * Useful if you want to convert some part of a formula.
14315
14333
  *
14316
- * e.g.
14317
- * ```ts
14334
+ * @example
14318
14335
  * convertAstNodes(ast, "FUNCALL", convertFormulaToExcel)
14319
14336
  *
14320
14337
  * function convertFormulaToExcel(ast: ASTFuncall) {
14321
14338
  * // ...
14322
14339
  * return modifiedAst
14323
14340
  * }
14324
- * ```
14325
14341
  */
14326
14342
  function convertAstNodes(ast, type, fn) {
14327
- if (type === ast.type) {
14328
- ast = fn(ast);
14343
+ return mapAst(ast, (ast) => {
14344
+ if (ast.type === type) {
14345
+ return fn(ast);
14346
+ }
14347
+ return ast;
14348
+ });
14349
+ }
14350
+ function iterateAstNodes(ast) {
14351
+ return Array.from(astIterator(ast));
14352
+ }
14353
+ function* astIterator(ast) {
14354
+ yield ast;
14355
+ switch (ast.type) {
14356
+ case "FUNCALL":
14357
+ for (const arg of ast.args) {
14358
+ yield* astIterator(arg);
14359
+ }
14360
+ break;
14361
+ case "UNARY_OPERATION":
14362
+ yield* astIterator(ast.operand);
14363
+ break;
14364
+ case "BIN_OPERATION":
14365
+ yield* astIterator(ast.left);
14366
+ yield* astIterator(ast.right);
14367
+ break;
14329
14368
  }
14369
+ }
14370
+ function mapAst(ast, fn) {
14371
+ ast = fn(ast);
14330
14372
  switch (ast.type) {
14331
14373
  case "FUNCALL":
14332
14374
  return {
14333
14375
  ...ast,
14334
- args: ast.args.map((child) => convertAstNodes(child, type, fn)),
14376
+ args: ast.args.map((child) => mapAst(child, fn)),
14335
14377
  };
14336
14378
  case "UNARY_OPERATION":
14337
14379
  return {
14338
14380
  ...ast,
14339
- operand: convertAstNodes(ast.operand, type, fn),
14381
+ operand: mapAst(ast.operand, fn),
14340
14382
  };
14341
14383
  case "BIN_OPERATION":
14342
14384
  return {
14343
14385
  ...ast,
14344
- right: convertAstNodes(ast.right, type, fn),
14345
- left: convertAstNodes(ast.left, type, fn),
14386
+ right: mapAst(ast.right, fn),
14387
+ left: mapAst(ast.left, fn),
14346
14388
  };
14347
14389
  default:
14348
14390
  return ast;
@@ -14612,6 +14654,9 @@ function compile(formula) {
14612
14654
  const { args } = ast;
14613
14655
  const functionName = ast.value.toUpperCase();
14614
14656
  const functionDefinition = functions$2[functionName];
14657
+ if (!functionDefinition) {
14658
+ throw new UnknownFunctionError(ast.value);
14659
+ }
14615
14660
  assertEnoughArgs(ast);
14616
14661
  const compiledArgs = [];
14617
14662
  for (let i = 0; i < args.length; i++) {
@@ -14870,7 +14915,7 @@ function mapParentFunction(tokens) {
14870
14915
  functionStarted = "";
14871
14916
  }
14872
14917
  switch (token.type) {
14873
- case "FUNCTION":
14918
+ case "SYMBOL":
14874
14919
  functionStarted = token.value;
14875
14920
  break;
14876
14921
  case "LEFT_PAREN":
@@ -14907,6 +14952,17 @@ function composerTokenize(formula, locale) {
14907
14952
  return mapParentFunction(mapParenthesis(enrichTokens(tokens)));
14908
14953
  }
14909
14954
 
14955
+ const functions$1 = functionRegistry.content;
14956
+ function isExportableToExcel(tokens) {
14957
+ try {
14958
+ const nonExportableFunctions = iterateAstNodes(parseTokens(tokens)).filter((ast) => ast.type === "FUNCALL" && !functions$1[ast.value.toUpperCase()]?.isExported);
14959
+ return nonExportableFunctions.length === 0;
14960
+ }
14961
+ catch (error) {
14962
+ return false;
14963
+ }
14964
+ }
14965
+
14910
14966
  function isValidLocale(locale) {
14911
14967
  if (!(locale &&
14912
14968
  typeof locale === "object" &&
@@ -17479,8 +17535,14 @@ function getImageMenuRegistry(figureId, onFigureDeleted, env) {
17479
17535
  id: "reset_size",
17480
17536
  name: _lt("Reset size"),
17481
17537
  sequence: 4,
17482
- execute: () => {
17483
- const size = env.model.getters.getImageSize(figureId);
17538
+ execute: async () => {
17539
+ const imagePath = env.model.getters.getImagePath(figureId);
17540
+ const size = env.model.getters.getImageSize(figureId) ??
17541
+ (await env.imageProvider?.getImageOriginalSize(imagePath));
17542
+ if (!env.model.getters.getImageSize(figureId)) {
17543
+ const image = env.model.getters.getImage(figureId);
17544
+ image.size = size;
17545
+ }
17484
17546
  const { height, width } = getMaxFigureSize(env.model.getters, size);
17485
17547
  env.model.dispatch("UPDATE_FIGURE", {
17486
17548
  sheetId: env.model.getters.getActiveSheetId(),
@@ -23533,7 +23595,7 @@ FunctionDescriptionProvider.props = {
23533
23595
  argToFocus: Number,
23534
23596
  };
23535
23597
 
23536
- const functions$1 = functionRegistry.content;
23598
+ const functions = functionRegistry.content;
23537
23599
  const ASSISTANT_WIDTH = 300;
23538
23600
  const selectionIndicatorClass = "selector-flag";
23539
23601
  const selectionIndicatorColor = "#a9a9a9";
@@ -23567,10 +23629,6 @@ css /* scss */ `
23567
23629
  padding-right: 3px;
23568
23630
  outline: none;
23569
23631
 
23570
- &.unfocusable {
23571
- pointer-events: none;
23572
- }
23573
-
23574
23632
  p {
23575
23633
  margin-bottom: 0px;
23576
23634
 
@@ -23818,7 +23876,10 @@ class Composer extends Component {
23818
23876
  }
23819
23877
  }
23820
23878
  showAutocomplete(searchTerm) {
23821
- if (!this.env.model.getters.getCurrentContent().startsWith("=")) {
23879
+ const searchTermUpperCase = searchTerm.toUpperCase();
23880
+ if (!this.env.model.getters.getCurrentContent().startsWith("=") ||
23881
+ searchTermUpperCase === "TRUE" ||
23882
+ searchTermUpperCase === "FALSE") {
23822
23883
  return;
23823
23884
  }
23824
23885
  this.autoCompleteState.showProvider = true;
@@ -23936,7 +23997,6 @@ class Composer extends Component {
23936
23997
  switch (token.type) {
23937
23998
  case "OPERATOR":
23938
23999
  case "NUMBER":
23939
- case "FUNCTION":
23940
24000
  case "ARG_SEPARATOR":
23941
24001
  case "STRING":
23942
24002
  result.push({ value: token.value, color: tokenColors[token.type] || "#000" });
@@ -23946,10 +24006,14 @@ class Composer extends Component {
23946
24006
  result.push({ value: token.value, color: this.rangeColor(xc, sheetName) || "#000" });
23947
24007
  break;
23948
24008
  case "SYMBOL":
23949
- let value = token.value;
23950
- if (["TRUE", "FALSE"].includes(value.toUpperCase())) {
24009
+ const value = token.value;
24010
+ const upperCaseValue = value.toUpperCase();
24011
+ if (upperCaseValue === "TRUE" || upperCaseValue === "FALSE") {
23951
24012
  result.push({ value: token.value, color: tokenColors.NUMBER });
23952
24013
  }
24014
+ else if (upperCaseValue in functionRegistry.content) {
24015
+ result.push({ value: token.value, color: tokenColors.FUNCTION });
24016
+ }
23953
24017
  else {
23954
24018
  result.push({ value: token.value, color: "#000" });
23955
24019
  }
@@ -24045,25 +24109,28 @@ class Composer extends Component {
24045
24109
  this.autoCompleteState.showProvider = false;
24046
24110
  this.functionDescriptionState.showDescription = false;
24047
24111
  if (content.startsWith("=")) {
24048
- const tokenAtCursor = this.env.model.getters.getTokenAtCursor();
24049
- if (tokenAtCursor) {
24050
- const { xc } = splitReference(tokenAtCursor.value);
24051
- if (tokenAtCursor.type === "FUNCTION" ||
24052
- (tokenAtCursor.type === "SYMBOL" && !rangeReference.test(xc))) {
24053
- // initialize Autocomplete Dropdown
24054
- this.showAutocomplete(tokenAtCursor.value);
24055
- }
24056
- else if (tokenAtCursor.functionContext && tokenAtCursor.type !== "UNKNOWN") {
24057
- // initialize Formula Assistant
24058
- const tokenContext = tokenAtCursor.functionContext;
24059
- const parentFunction = tokenContext.parent.toUpperCase();
24060
- const description = functions$1[parentFunction];
24061
- const argPosition = tokenContext.argPosition;
24062
- this.functionDescriptionState.functionName = parentFunction;
24063
- this.functionDescriptionState.functionDescription = description;
24064
- this.functionDescriptionState.argToFocus = description.getArgToFocus(argPosition + 1) - 1;
24065
- this.functionDescriptionState.showDescription = true;
24066
- }
24112
+ const token = this.env.model.getters.getTokenAtCursor();
24113
+ if (!token) {
24114
+ return;
24115
+ }
24116
+ if (token.type === "SYMBOL") {
24117
+ // initialize Autocomplete Dropdown
24118
+ this.showAutocomplete(token.value);
24119
+ return;
24120
+ }
24121
+ const tokenContext = token.functionContext;
24122
+ const parentFunction = tokenContext?.parent.toUpperCase();
24123
+ if (tokenContext &&
24124
+ parentFunction &&
24125
+ parentFunction in functions &&
24126
+ token.type !== "UNKNOWN") {
24127
+ // initialize Formula Assistant
24128
+ const description = functions[parentFunction];
24129
+ const argPosition = tokenContext.argPosition;
24130
+ this.functionDescriptionState.functionName = parentFunction;
24131
+ this.functionDescriptionState.functionDescription = description;
24132
+ this.functionDescriptionState.argToFocus = description.getArgToFocus(argPosition + 1) - 1;
24133
+ this.functionDescriptionState.showDescription = true;
24067
24134
  }
24068
24135
  }
24069
24136
  }
@@ -26763,7 +26830,12 @@ const XLSX_RELATION_TYPE = {
26763
26830
  };
26764
26831
  const RELATIONSHIP_NSR = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
26765
26832
  const HEIGHT_FACTOR = 0.75; // 100px => 75 u
26766
- const WIDTH_FACTOR = 0.1317; // 100px => 13.17 u
26833
+ /**
26834
+ * Excel says its default column width is 8.43 characters (64px)
26835
+ * which makes WIDTH_FACTOR = 0.1317, but it doesn't work well
26836
+ * 0.143 is a value from dev's experiments.
26837
+ */
26838
+ const WIDTH_FACTOR = 0.143;
26767
26839
  /** unit : maximum number of characters a column can hold at the standard font size. What. */
26768
26840
  const EXCEL_DEFAULT_COL_WIDTH = 8.43;
26769
26841
  /** unit : points */
@@ -27280,7 +27352,7 @@ const XLSX_INDEXED_COLORS = {
27280
27352
  64: "000000",
27281
27353
  65: "FFFFFF", // system background
27282
27354
  };
27283
- const IMAGE_MIMETYPE_EXTENSION_MAPPING = {
27355
+ const IMAGE_MIMETYPE_TO_EXTENSION_MAPPING = {
27284
27356
  "image/avif": "avif",
27285
27357
  "image/bmp": "bmp",
27286
27358
  "image/gif": "gif",
@@ -27289,6 +27361,17 @@ const IMAGE_MIMETYPE_EXTENSION_MAPPING = {
27289
27361
  "image/png": "png",
27290
27362
  "image/tiff": "tiff",
27291
27363
  "image/webp": "webp",
27364
+ };
27365
+ const IMAGE_EXTENSION_TO_MIMETYPE_MAPPING = {
27366
+ avif: "image/avif",
27367
+ bmp: "image/bmp",
27368
+ gif: "image/gif",
27369
+ ico: "image/vnd.microsoft.icon",
27370
+ jpeg: "image/jpeg",
27371
+ png: "image/png",
27372
+ tiff: "image/tiff",
27373
+ webp: "image/webp",
27374
+ jpg: "image/jpeg",
27292
27375
  };
27293
27376
 
27294
27377
  /**
@@ -28092,20 +28175,35 @@ function convertFigure(figure, id, sheetData) {
28092
28175
  convertEMUToDotValue(figure.anchors[0].rowOffset);
28093
28176
  const y2 = getRowPosition(figure.anchors[1].row, sheetData) +
28094
28177
  convertEMUToDotValue(figure.anchors[1].rowOffset);
28095
- const width = x2 - x1;
28096
- const height = y2 - y1;
28097
- const chartData = convertChartData(figure.data);
28098
- if (!chartData)
28099
- return undefined;
28100
- return {
28101
- id: id,
28102
- x: x1,
28103
- y: y1,
28104
- width: width,
28105
- height: height,
28106
- tag: "chart",
28107
- data: convertChartData(figure.data),
28108
- };
28178
+ const figureData = { id, x: x1, y: y1 };
28179
+ if (isChartData(figure.data)) {
28180
+ return {
28181
+ ...figureData,
28182
+ width: x2 - x1,
28183
+ height: y2 - y1,
28184
+ tag: "chart",
28185
+ data: convertChartData(figure.data),
28186
+ };
28187
+ }
28188
+ else if (isImageData(figure.data)) {
28189
+ return {
28190
+ ...figureData,
28191
+ width: convertEMUToDotValue(figure.data.size.cx),
28192
+ height: convertEMUToDotValue(figure.data.size.cy),
28193
+ tag: "image",
28194
+ data: {
28195
+ path: figure.data.imageSrc,
28196
+ mimetype: figure.data.mimetype,
28197
+ },
28198
+ };
28199
+ }
28200
+ return undefined;
28201
+ }
28202
+ function isChartData(data) {
28203
+ return "dataSets" in data;
28204
+ }
28205
+ function isImageData(data) {
28206
+ return "imageSrc" in data;
28109
28207
  }
28110
28208
  function convertChartData(chartData) {
28111
28209
  const dataSetsHaveTitle = chartData.dataSets[0].label !== undefined;
@@ -28812,9 +28910,13 @@ class XlsxBaseExtractor {
28812
28910
  /**
28813
28911
  * Get the list of all the XLSX files in the XLSX file structure
28814
28912
  */
28815
- getListOfFiles() {
28816
- const files = Object.values(this.xlsxFileStructure).flat().filter(isDefined$1);
28817
- return files;
28913
+ getListOfXMLFiles() {
28914
+ const XMLFiles = Object.entries(this.xlsxFileStructure)
28915
+ .filter(([key]) => key !== "images")
28916
+ .map(([_, value]) => value)
28917
+ .flat()
28918
+ .filter(isDefined$1);
28919
+ return XMLFiles;
28818
28920
  }
28819
28921
  /**
28820
28922
  * Return an array containing the return value of the given function applied to all the XML elements
@@ -28986,20 +29088,31 @@ class XlsxBaseExtractor {
28986
29088
  return color;
28987
29089
  }
28988
29090
  /**
28989
- * Returns the xlsx file targeted by a relationship.
29091
+ * Returns the xml file targeted by a relationship.
28990
29092
  */
28991
29093
  getTargetXmlFile(relationship) {
28992
29094
  if (!relationship)
28993
29095
  throw new Error("Undefined target file");
28994
- let target = relationship.target;
28995
- target = target.replace("../", "");
28996
- target = target.replace("./", "");
29096
+ const target = this.processRelationshipTargetName(relationship.target);
28997
29097
  // Use "endsWith" because targets are relative paths, and we know the files by their absolute path.
28998
- const f = this.getListOfFiles().find((f) => f.file.fileName.endsWith(target));
29098
+ const f = this.getListOfXMLFiles().find((f) => f.file.fileName.endsWith(target));
28999
29099
  if (!f || !f.file)
29000
29100
  throw new Error("Cannot find target file");
29001
29101
  return f;
29002
29102
  }
29103
+ /**
29104
+ * Returns the image parameters targeted by a relationship.
29105
+ */
29106
+ getTargetImageFile(relationship) {
29107
+ if (!relationship)
29108
+ throw new Error("Undefined target file");
29109
+ const target = this.processRelationshipTargetName(relationship.target);
29110
+ // Use "endsWith" because targets are relative paths, and we know the files by their absolute path.
29111
+ const f = this.xlsxFileStructure.images.find((f) => f.fileName.endsWith(target));
29112
+ if (!f)
29113
+ throw new Error("Cannot find target file");
29114
+ return f;
29115
+ }
29003
29116
  /**
29004
29117
  * Wrapper of querySelector, but we'll remove the namespaces from the query if areNamespacesIgnored is true.
29005
29118
  *
@@ -29046,6 +29159,10 @@ class XlsxBaseExtractor {
29046
29159
  return clrScheme[colorId].value;
29047
29160
  }
29048
29161
  }
29162
+ /** Remove signs of relative path. */
29163
+ processRelationshipTargetName(targetName) {
29164
+ return targetName.replace(/\.+\//, "");
29165
+ }
29049
29166
  }
29050
29167
 
29051
29168
  /**
@@ -29275,15 +29392,16 @@ class XlsxFigureExtractor extends XlsxBaseExtractor {
29275
29392
  throw new Error("Only twoCellAnchor are supported for xlsx drawings.");
29276
29393
  }
29277
29394
  const chartElement = this.querySelector(figureElement, "c:chart");
29278
- if (!chartElement) {
29279
- throw new Error("Only chart figures are currently supported.");
29395
+ const imageElement = this.querySelector(figureElement, "a:blip");
29396
+ if (!chartElement && !imageElement) {
29397
+ throw new Error("Only chart and image figures are currently supported.");
29280
29398
  }
29281
29399
  return {
29282
29400
  anchors: [
29283
29401
  this.extractFigureAnchor("xdr:from", figureElement),
29284
29402
  this.extractFigureAnchor("xdr:to", figureElement),
29285
29403
  ],
29286
- data: this.extractChart(chartElement),
29404
+ data: chartElement ? this.extractChart(chartElement) : this.extractImage(figureElement),
29287
29405
  };
29288
29406
  });
29289
29407
  }
@@ -29308,6 +29426,24 @@ class XlsxFigureExtractor extends XlsxBaseExtractor {
29308
29426
  }
29309
29427
  return chartDefinition;
29310
29428
  }
29429
+ extractImage(figureElement) {
29430
+ const imageElement = this.querySelector(figureElement, "a:blip");
29431
+ const imageId = this.extractAttr(imageElement, "r:embed", { required: true }).asString();
29432
+ const image = this.getTargetImageFile(this.relationships[imageId]);
29433
+ if (!image) {
29434
+ throw new Error("Unable to extract image");
29435
+ }
29436
+ const shapePropertyElement = this.querySelector(figureElement, "a:xfrm");
29437
+ const extension = image.fileName.split(".").at(-1);
29438
+ return {
29439
+ imageSrc: image.imageSrc,
29440
+ mimetype: extension ? IMAGE_EXTENSION_TO_MIMETYPE_MAPPING[extension] : undefined,
29441
+ size: {
29442
+ cx: this.extractChildAttr(shapePropertyElement, "a:ext", "cx", { required: true }).asNum(),
29443
+ cy: this.extractChildAttr(shapePropertyElement, "a:ext", "cy", { required: true }).asNum(),
29444
+ },
29445
+ };
29446
+ }
29311
29447
  }
29312
29448
 
29313
29449
  /**
@@ -29877,14 +30013,22 @@ const EXCEL_IMPORT_VERSION = 12;
29877
30013
  class XlsxReader {
29878
30014
  warningManager;
29879
30015
  xmls;
30016
+ images;
29880
30017
  constructor(files) {
29881
30018
  this.warningManager = new XLSXImportWarningManager();
29882
30019
  this.xmls = {};
30020
+ this.images = [];
29883
30021
  for (let key of Object.keys(files)) {
29884
30022
  // Random files can be in xlsx (like a bin file for printer settings)
29885
30023
  if (key.endsWith(".xml") || key.endsWith(".rels")) {
29886
30024
  this.xmls[key] = parseXML(new XMLString(files[key]));
29887
30025
  }
30026
+ else if (key.includes("media/image")) {
30027
+ this.images.push({
30028
+ fileName: key,
30029
+ imageSrc: files[key]["imageSrc"],
30030
+ });
30031
+ }
29888
30032
  }
29889
30033
  }
29890
30034
  convertXlsx() {
@@ -29937,6 +30081,7 @@ class XlsxReader {
29937
30081
  tables: getXLSXFilesOfType(CONTENT_TYPES.table, this.xmls),
29938
30082
  pivots: getXLSXFilesOfType(CONTENT_TYPES.pivot, this.xmls),
29939
30083
  externalLinks: getXLSXFilesOfType(CONTENT_TYPES.externalLink, this.xmls),
30084
+ images: this.images,
29940
30085
  };
29941
30086
  if (!xlsxFileStructure.workbook.rels) {
29942
30087
  throw Error(_lt("Cannot find workbook relations file"));
@@ -33087,7 +33232,7 @@ class ImagePlugin extends CorePlugin {
33087
33232
  handle(cmd) {
33088
33233
  switch (cmd.type) {
33089
33234
  case "CREATE_IMAGE":
33090
- this.addFigure(cmd.figureId, cmd.sheetId, cmd.position, cmd.size);
33235
+ this.addImage(cmd.figureId, cmd.sheetId, cmd.position, cmd.size);
33091
33236
  this.history.update("images", cmd.sheetId, cmd.figureId, cmd.definition);
33092
33237
  this.syncedImages.add(cmd.definition.path);
33093
33238
  break;
@@ -33151,7 +33296,7 @@ class ImagePlugin extends CorePlugin {
33151
33296
  // ---------------------------------------------------------------------------
33152
33297
  // Private
33153
33298
  // ---------------------------------------------------------------------------
33154
- addFigure(id, sheetId, position, size) {
33299
+ addImage(id, sheetId, position, size) {
33155
33300
  const figure = {
33156
33301
  id,
33157
33302
  x: position.x,
@@ -35658,7 +35803,6 @@ class PositionBitsEncoder {
35658
35803
  }
35659
35804
  }
35660
35805
 
35661
- const functions = functionRegistry.content;
35662
35806
  //#region
35663
35807
  // ---------------------------------------------------------------------------
35664
35808
  // INTRODUCTION
@@ -35880,9 +36024,7 @@ class EvaluationPlugin extends UIPlugin {
35880
36024
  let isExported = true;
35881
36025
  const formulaCell = this.getCorrespondingFormulaCell(position);
35882
36026
  if (formulaCell) {
35883
- isExported = formulaCell.compiledFormula.tokens
35884
- .filter((tk) => tk.type === "FUNCTION")
35885
- .every((tk) => functions[tk.value.toUpperCase()].isExported);
36027
+ isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
35886
36028
  isFormula = isExported;
35887
36029
  if (!isExported) {
35888
36030
  newContent = value.toString();
@@ -44288,7 +44430,7 @@ class ImageProvider {
44288
44430
  async requestImage() {
44289
44431
  const file = await this.getImageFromUser();
44290
44432
  const path = await this.fileStore.upload(file);
44291
- const size = await this.getImageSize(path);
44433
+ const size = await this.getImageOriginalSize(path);
44292
44434
  return { path, size, mimetype: file.type };
44293
44435
  }
44294
44436
  getImageFromUser() {
@@ -44307,7 +44449,7 @@ class ImageProvider {
44307
44449
  input.click();
44308
44450
  });
44309
44451
  }
44310
- getImageSize(path) {
44452
+ getImageOriginalSize(path) {
44311
44453
  return new Promise((resolve, reject) => {
44312
44454
  const image = new Image();
44313
44455
  image.src = path;
@@ -45792,6 +45934,10 @@ css /* scss */ `
45792
45934
  top: 20%;
45793
45935
  }
45794
45936
  }
45937
+
45938
+ .user-select-text {
45939
+ user-select: text;
45940
+ }
45795
45941
  `;
45796
45942
  class TopBarComposer extends Component {
45797
45943
  static template = "o-spreadsheet-TopBarComposer";
@@ -48830,6 +48976,8 @@ function createImageDrawing(figure, sheet, imageRelId) {
48830
48976
  ["name", `Image ${imageId}`],
48831
48977
  ["title", "Image"],
48832
48978
  ];
48979
+ const cx = convertDotValueToEMU(figure.width);
48980
+ const cy = convertDotValueToEMU(figure.height);
48833
48981
  return escapeXml /*xml*/ `
48834
48982
  <xdr:twoCellAnchor editAs="oneCell">
48835
48983
  <xdr:from>
@@ -48856,6 +49004,9 @@ function createImageDrawing(figure, sheet, imageRelId) {
48856
49004
  </a:stretch>
48857
49005
  </xdr:blipFill>
48858
49006
  <xdr:spPr>
49007
+ <a:xfrm>
49008
+ <a:ext cx="${cx}" cy="${cy}" />
49009
+ </a:xfrm>
48859
49010
  <a:prstGeom prst="rect">
48860
49011
  <a:avLst/>
48861
49012
  </a:prstGeom>
@@ -49375,7 +49526,7 @@ function createWorksheets(data, construct) {
49375
49526
  const mimeType = image.data.mimetype;
49376
49527
  if (mimeType === undefined)
49377
49528
  continue;
49378
- const extension = IMAGE_MIMETYPE_EXTENSION_MAPPING[mimeType];
49529
+ const extension = IMAGE_MIMETYPE_TO_EXTENSION_MAPPING[mimeType];
49379
49530
  // only support exporting images with mimetypes specified in the mapping
49380
49531
  if (extension === undefined)
49381
49532
  continue;
@@ -49511,7 +49662,7 @@ function createRelsFiles(relsFiles) {
49511
49662
  function createContentTypes(files) {
49512
49663
  const overrideNodes = [];
49513
49664
  // hard-code supported image mimetypes
49514
- const imageDefaultNodes = Object.entries(IMAGE_MIMETYPE_EXTENSION_MAPPING).map(([mimetype, extension]) => createDefaultXMLElement(extension, mimetype));
49665
+ const imageDefaultNodes = Object.entries(IMAGE_MIMETYPE_TO_EXTENSION_MAPPING).map(([mimetype, extension]) => createDefaultXMLElement(extension, mimetype));
49515
49666
  for (const file of files) {
49516
49667
  if ("contentType" in file && file.contentType) {
49517
49668
  overrideNodes.push(createOverride("/" + file.path, CONTENT_TYPES[file.contentType]));
@@ -50117,9 +50268,9 @@ const constants = {
50117
50268
  DEFAULT_LOCALE,
50118
50269
  };
50119
50270
 
50120
- export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
50271
+ export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
50121
50272
 
50122
50273
 
50123
- __info__.version = '16.4.0-alpha.6';
50124
- __info__.date = '2023-06-28T11:40:12.377Z';
50125
- __info__.hash = '7d15d3c';
50274
+ __info__.version = '16.4.0-alpha.7';
50275
+ __info__.date = '2023-07-04T13:46:24.130Z';
50276
+ __info__.hash = 'b04cf78';