@odoo/o-spreadsheet 17.3.7 → 17.3.8

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.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.3.7
7
- * @date 2024-07-02T10:38:52.530Z
8
- * @hash c570df3
6
+ * @version 17.3.8
7
+ * @date 2024-07-08T05:43:16.647Z
8
+ * @hash e1e7bae
9
9
  */
10
10
 
11
11
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -1830,7 +1830,7 @@ const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSepa
1830
1830
  });
1831
1831
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1832
1832
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1833
- const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
1833
+ const thousandsSeparator = escapeRegExp(locale.thousandsSeparator || "");
1834
1834
  const pIntegerAndDecimals = `(\\d+(${thousandsSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1835
1835
  const pOnlyDecimals = `(${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1836
1836
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -1857,7 +1857,7 @@ function isNumber(value, locale) {
1857
1857
  return getNumberRegex(locale).test(value.trim());
1858
1858
  }
1859
1859
  const getInvaluableSymbolsRegexp = memoize(function getInvaluableSymbolsRegexp(locale) {
1860
- return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator)}]`, "g");
1860
+ return new RegExp(`[\$€${escapeRegExp(locale.thousandsSeparator || "")}]`, "g");
1861
1861
  });
1862
1862
  /**
1863
1863
  * Convert a string into a number. It assumes that the string actually represents
@@ -5894,19 +5894,22 @@ class TokenizingChars {
5894
5894
  }
5895
5895
 
5896
5896
  function isValidLocale(locale) {
5897
- if (!(locale &&
5898
- typeof locale === "object" &&
5899
- typeof locale.name === "string" &&
5900
- typeof locale.code === "string" &&
5901
- typeof locale.thousandsSeparator === "string" &&
5902
- typeof locale.decimalSeparator === "string" &&
5903
- typeof locale.dateFormat === "string" &&
5904
- typeof locale.timeFormat === "string" &&
5905
- typeof locale.formulaArgSeparator === "string")) {
5897
+ if (!locale ||
5898
+ typeof locale !== "object" ||
5899
+ !(!locale.thousandsSeparator || typeof locale.thousandsSeparator === "string")) {
5906
5900
  return false;
5907
5901
  }
5908
- if (!Object.values(locale).every((v) => v)) {
5909
- return false;
5902
+ for (const property of [
5903
+ "code",
5904
+ "name",
5905
+ "decimalSeparator",
5906
+ "dateFormat",
5907
+ "timeFormat",
5908
+ "formulaArgSeparator",
5909
+ ]) {
5910
+ if (!locale[property] || typeof locale[property] !== "string") {
5911
+ return false;
5912
+ }
5910
5913
  }
5911
5914
  if (locale.formulaArgSeparator === locale.decimalSeparator) {
5912
5915
  return false;
@@ -6004,7 +6007,10 @@ function canonicalizeNumberLiteral(content, locale) {
6004
6007
  if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
6005
6008
  return content;
6006
6009
  }
6007
- return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
6010
+ if (locale.thousandsSeparator) {
6011
+ content = content.replaceAll(locale.thousandsSeparator, "");
6012
+ }
6013
+ return content.replace(locale.decimalSeparator, ".");
6008
6014
  }
6009
6015
  /**
6010
6016
  * Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
@@ -6993,6 +6999,146 @@ function transformRangeData(range, executed) {
6993
6999
  return undefined;
6994
7000
  }
6995
7001
 
7002
+ var State;
7003
+ (function (State) {
7004
+ /**
7005
+ * Initial state.
7006
+ * Expecting any reference for the left part of a range
7007
+ * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
7008
+ */
7009
+ State[State["LeftRef"] = 0] = "LeftRef";
7010
+ /**
7011
+ * Expecting any reference for the right part of a range
7012
+ * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
7013
+ */
7014
+ State[State["RightRef"] = 1] = "RightRef";
7015
+ /**
7016
+ * Expecting the separator without any constraint on the right part
7017
+ */
7018
+ State[State["Separator"] = 2] = "Separator";
7019
+ /**
7020
+ * Expecting the separator for a full column range
7021
+ */
7022
+ State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
7023
+ /**
7024
+ * Expecting the separator for a full row range
7025
+ */
7026
+ State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
7027
+ /**
7028
+ * Expecting the right part of a full column range
7029
+ * e.g. "1", "A1"
7030
+ */
7031
+ State[State["RightColumnRef"] = 5] = "RightColumnRef";
7032
+ /**
7033
+ * Expecting the right part of a full row range
7034
+ * e.g. "A", "A1"
7035
+ */
7036
+ State[State["RightRowRef"] = 6] = "RightRowRef";
7037
+ /**
7038
+ * Final state. A range has been matched
7039
+ */
7040
+ State[State["Found"] = 7] = "Found";
7041
+ })(State || (State = {}));
7042
+ const goTo = (state, guard = () => true) => [
7043
+ {
7044
+ goTo: state,
7045
+ guard,
7046
+ },
7047
+ ];
7048
+ const goToMulti = (state, guard = () => true) => ({
7049
+ goTo: state,
7050
+ guard,
7051
+ });
7052
+ const machine = {
7053
+ [State.LeftRef]: {
7054
+ REFERENCE: goTo(State.Separator),
7055
+ NUMBER: goTo(State.FullRowSeparator),
7056
+ SYMBOL: [
7057
+ goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
7058
+ goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
7059
+ ],
7060
+ },
7061
+ [State.FullColumnSeparator]: {
7062
+ SPACE: goTo(State.FullColumnSeparator),
7063
+ OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
7064
+ },
7065
+ [State.FullRowSeparator]: {
7066
+ SPACE: goTo(State.FullRowSeparator),
7067
+ OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
7068
+ },
7069
+ [State.Separator]: {
7070
+ SPACE: goTo(State.Separator),
7071
+ OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
7072
+ },
7073
+ [State.RightRef]: {
7074
+ SPACE: goTo(State.RightRef),
7075
+ NUMBER: goTo(State.Found),
7076
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7077
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
7078
+ },
7079
+ [State.RightColumnRef]: {
7080
+ SPACE: goTo(State.RightColumnRef),
7081
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
7082
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7083
+ },
7084
+ [State.RightRowRef]: {
7085
+ SPACE: goTo(State.RightRowRef),
7086
+ NUMBER: goTo(State.Found),
7087
+ REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7088
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
7089
+ },
7090
+ [State.Found]: {},
7091
+ };
7092
+ /**
7093
+ * Check if the list of tokens starts with a sequence of tokens representing
7094
+ * a range.
7095
+ * If a range is found, the sequence is removed from the list and is returned
7096
+ * as a single token.
7097
+ */
7098
+ function matchReference(tokens) {
7099
+ let head = 0;
7100
+ let transitions = machine[State.LeftRef];
7101
+ let matchedTokens = "";
7102
+ while (transitions !== undefined) {
7103
+ const token = tokens[head++];
7104
+ if (!token) {
7105
+ return null;
7106
+ }
7107
+ const transition = transitions[token.type]?.find((transition) => transition.guard(token));
7108
+ const nextState = transition ? transition.goTo : undefined;
7109
+ switch (nextState) {
7110
+ case undefined:
7111
+ return null;
7112
+ case State.Found:
7113
+ matchedTokens += token.value;
7114
+ tokens.splice(0, head);
7115
+ return {
7116
+ type: "REFERENCE",
7117
+ value: matchedTokens,
7118
+ };
7119
+ default:
7120
+ transitions = machine[nextState];
7121
+ matchedTokens += token.value;
7122
+ break;
7123
+ }
7124
+ }
7125
+ return null;
7126
+ }
7127
+ /**
7128
+ * Take the result of the tokenizer and transform it to be usable in the
7129
+ * manipulations of range
7130
+ *
7131
+ * @param formula
7132
+ */
7133
+ function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
7134
+ const tokens = tokenize(formula, locale);
7135
+ const result = [];
7136
+ while (tokens.length) {
7137
+ result.push(matchReference(tokens) || tokens.shift());
7138
+ }
7139
+ return result;
7140
+ }
7141
+
6996
7142
  const functionRegex = /[a-zA-Z0-9\_]+(\.[a-zA-Z0-9\_]+)*/;
6997
7143
  const UNARY_OPERATORS_PREFIX = ["-", "+"];
6998
7144
  const UNARY_OPERATORS_POSTFIX = ["%"];
@@ -7141,7 +7287,7 @@ function parseExpression(tokens, parent_priority = 0) {
7141
7287
  * Parse an expression (as a string) into an AST.
7142
7288
  */
7143
7289
  function parse(str) {
7144
- return parseTokens(tokenize(str));
7290
+ return parseTokens(rangeTokenize(str));
7145
7291
  }
7146
7292
  function parseTokens(tokens) {
7147
7293
  tokens = tokens.filter((x) => x.type !== "SPACE");
@@ -7277,146 +7423,6 @@ function rightOperandToFormula(operationAST) {
7277
7423
  return needParenthesis ? `(${astToFormula(rightOperation)})` : astToFormula(rightOperation);
7278
7424
  }
7279
7425
 
7280
- var State;
7281
- (function (State) {
7282
- /**
7283
- * Initial state.
7284
- * Expecting any reference for the left part of a range
7285
- * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
7286
- */
7287
- State[State["LeftRef"] = 0] = "LeftRef";
7288
- /**
7289
- * Expecting any reference for the right part of a range
7290
- * e.g. "A1", "1", "A", "Sheet1!A1", "Sheet1!A"
7291
- */
7292
- State[State["RightRef"] = 1] = "RightRef";
7293
- /**
7294
- * Expecting the separator without any constraint on the right part
7295
- */
7296
- State[State["Separator"] = 2] = "Separator";
7297
- /**
7298
- * Expecting the separator for a full column range
7299
- */
7300
- State[State["FullColumnSeparator"] = 3] = "FullColumnSeparator";
7301
- /**
7302
- * Expecting the separator for a full row range
7303
- */
7304
- State[State["FullRowSeparator"] = 4] = "FullRowSeparator";
7305
- /**
7306
- * Expecting the right part of a full column range
7307
- * e.g. "1", "A1"
7308
- */
7309
- State[State["RightColumnRef"] = 5] = "RightColumnRef";
7310
- /**
7311
- * Expecting the right part of a full row range
7312
- * e.g. "A", "A1"
7313
- */
7314
- State[State["RightRowRef"] = 6] = "RightRowRef";
7315
- /**
7316
- * Final state. A range has been matched
7317
- */
7318
- State[State["Found"] = 7] = "Found";
7319
- })(State || (State = {}));
7320
- const goTo = (state, guard = () => true) => [
7321
- {
7322
- goTo: state,
7323
- guard,
7324
- },
7325
- ];
7326
- const goToMulti = (state, guard = () => true) => ({
7327
- goTo: state,
7328
- guard,
7329
- });
7330
- const machine = {
7331
- [State.LeftRef]: {
7332
- REFERENCE: goTo(State.Separator),
7333
- NUMBER: goTo(State.FullRowSeparator),
7334
- SYMBOL: [
7335
- goToMulti(State.FullColumnSeparator, (token) => isColReference(token.value)),
7336
- goToMulti(State.FullRowSeparator, (token) => isRowReference(token.value)),
7337
- ],
7338
- },
7339
- [State.FullColumnSeparator]: {
7340
- SPACE: goTo(State.FullColumnSeparator),
7341
- OPERATOR: goTo(State.RightColumnRef, (token) => token.value === ":"),
7342
- },
7343
- [State.FullRowSeparator]: {
7344
- SPACE: goTo(State.FullRowSeparator),
7345
- OPERATOR: goTo(State.RightRowRef, (token) => token.value === ":"),
7346
- },
7347
- [State.Separator]: {
7348
- SPACE: goTo(State.Separator),
7349
- OPERATOR: goTo(State.RightRef, (token) => token.value === ":"),
7350
- },
7351
- [State.RightRef]: {
7352
- SPACE: goTo(State.RightRef),
7353
- NUMBER: goTo(State.Found),
7354
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7355
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
7356
- },
7357
- [State.RightColumnRef]: {
7358
- SPACE: goTo(State.RightColumnRef),
7359
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
7360
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7361
- },
7362
- [State.RightRowRef]: {
7363
- SPACE: goTo(State.RightRowRef),
7364
- NUMBER: goTo(State.Found),
7365
- REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
7366
- SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
7367
- },
7368
- [State.Found]: {},
7369
- };
7370
- /**
7371
- * Check if the list of tokens starts with a sequence of tokens representing
7372
- * a range.
7373
- * If a range is found, the sequence is removed from the list and is returned
7374
- * as a single token.
7375
- */
7376
- function matchReference(tokens) {
7377
- let head = 0;
7378
- let transitions = machine[State.LeftRef];
7379
- let matchedTokens = "";
7380
- while (transitions !== undefined) {
7381
- const token = tokens[head++];
7382
- if (!token) {
7383
- return null;
7384
- }
7385
- const transition = transitions[token.type]?.find((transition) => transition.guard(token));
7386
- const nextState = transition ? transition.goTo : undefined;
7387
- switch (nextState) {
7388
- case undefined:
7389
- return null;
7390
- case State.Found:
7391
- matchedTokens += token.value;
7392
- tokens.splice(0, head);
7393
- return {
7394
- type: "REFERENCE",
7395
- value: matchedTokens,
7396
- };
7397
- default:
7398
- transitions = machine[nextState];
7399
- matchedTokens += token.value;
7400
- break;
7401
- }
7402
- }
7403
- return null;
7404
- }
7405
- /**
7406
- * Take the result of the tokenizer and transform it to be usable in the
7407
- * manipulations of range
7408
- *
7409
- * @param formula
7410
- */
7411
- function rangeTokenize(formula, locale = DEFAULT_LOCALE) {
7412
- const tokens = tokenize(formula, locale);
7413
- const result = [];
7414
- while (tokens.length) {
7415
- result.push(matchReference(tokens) || tokens.shift());
7416
- }
7417
- return result;
7418
- }
7419
-
7420
7426
  /**
7421
7427
  * Add the following information on tokens:
7422
7428
  * - length
@@ -23925,10 +23931,6 @@ function createLineOrScatterChartRuntime(chart, getters) {
23925
23931
  const colors = new ColorGenerator();
23926
23932
  const definition = chart.getDefinition();
23927
23933
  for (let [index, { label, data }] of dataSetsValues.entries()) {
23928
- if (["linear", "time"].includes(axisType)) {
23929
- // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
23930
- data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
23931
- }
23932
23934
  const color = colors.next();
23933
23935
  let backgroundRGBA = colorToRGBA(color);
23934
23936
  if (stacked) {
@@ -23944,6 +23946,10 @@ function createLineOrScatterChartRuntime(chart, getters) {
23944
23946
  return value;
23945
23947
  });
23946
23948
  }
23949
+ if (["linear", "time"].includes(axisType)) {
23950
+ // Replace empty string labels by undefined to make sure chartJS doesn't decide that "" is the same as 0
23951
+ data = data.map((y, index) => ({ x: labels[index] || undefined, y }));
23952
+ }
23947
23953
  const backgroundColor = rgbaToHex(backgroundRGBA);
23948
23954
  const dataset = {
23949
23955
  label,
@@ -36261,7 +36267,13 @@ class SettingsPanel extends Component {
36261
36267
  }
36262
36268
  async loadLocales() {
36263
36269
  this.loadedLocales = (await this.env.loadLocales())
36264
- .filter(isValidLocale)
36270
+ .filter((locale) => {
36271
+ const isValid = isValidLocale(locale);
36272
+ if (!isValid) {
36273
+ console.warn(`Invalid locale: ${locale["code"]} ${locale}`);
36274
+ }
36275
+ return isValid;
36276
+ })
36265
36277
  .sort((a, b) => a.name.localeCompare(b.name));
36266
36278
  }
36267
36279
  get numberFormatPreview() {
@@ -41413,6 +41425,7 @@ class Grid extends Component {
41413
41425
  return;
41414
41426
  }
41415
41427
  if (clipboardData.types.indexOf(ClipboardMIMEType.PlainText) > -1) {
41428
+ ev.preventDefault();
41416
41429
  const content = clipboardData.getData(ClipboardMIMEType.PlainText);
41417
41430
  const target = this.env.model.getters.getSelectedZones();
41418
41431
  const clipboardString = this.env.model.getters.getClipboardTextContent();
@@ -46203,6 +46216,21 @@ class BordersPlugin extends CorePlugin {
46203
46216
  return [];
46204
46217
  return Object.keys(sheetBorders).map((index) => parseInt(index, 10));
46205
46218
  }
46219
+ /**
46220
+ * Get all the rows which contains at least a border
46221
+ */
46222
+ getRowsWithBorders(sheetId) {
46223
+ const sheetBorders = this.borders[sheetId]?.filter(isDefined);
46224
+ if (!sheetBorders)
46225
+ return [];
46226
+ const rowsWithBorders = new Set();
46227
+ for (const rowBorders of sheetBorders) {
46228
+ for (const rowBorder in rowBorders) {
46229
+ rowsWithBorders.add(parseInt(rowBorder, 10));
46230
+ }
46231
+ }
46232
+ return Array.from(rowsWithBorders);
46233
+ }
46206
46234
  /**
46207
46235
  * Get the range of all the rows in the sheet
46208
46236
  */
@@ -46252,7 +46280,7 @@ class BordersPlugin extends CorePlugin {
46252
46280
  destructive: false,
46253
46281
  });
46254
46282
  }
46255
- this.getRowsRange(sheetId)
46283
+ this.getRowsWithBorders(sheetId)
46256
46284
  .filter((row) => row >= start)
46257
46285
  .sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
46258
46286
  .forEach((row) => {
@@ -67001,6 +67029,6 @@ const constants = {
67001
67029
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
67002
67030
 
67003
67031
 
67004
- __info__.version = "17.3.7";
67005
- __info__.date = "2024-07-02T10:38:52.530Z";
67006
- __info__.hash = "c570df3";
67032
+ __info__.version = "17.3.8";
67033
+ __info__.date = "2024-07-08T05:43:16.647Z";
67034
+ __info__.hash = "e1e7bae";