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