@odoo/o-spreadsheet 19.1.0-alpha.10 → 19.1.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 19.1.0-alpha.10
6
- * @date 2025-10-30T12:26:30.196Z
7
- * @hash d0b65e9
5
+ * @version 19.1.0-alpha.11
6
+ * @date 2025-11-03T12:34:28.925Z
7
+ * @hash d9230f3
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -157,6 +157,8 @@
157
157
  const MENU_WIDTH = 250;
158
158
  const MENU_VERTICAL_PADDING = 6;
159
159
  const DESKTOP_MENU_ITEM_HEIGHT = 26;
160
+ // Zoom
161
+ const ZOOM_VALUES = [50, 75, 100, 125, 150, 200];
160
162
  // Style
161
163
  const DEFAULT_STYLE = {
162
164
  align: "left",
@@ -2286,13 +2288,13 @@
2286
2288
  let optionalArg = 0;
2287
2289
  for (const arg of addDescr.args) {
2288
2290
  countArg++;
2289
- if (!arg.optional && !arg.repeating && !arg.default) {
2291
+ if (!arg.optional && !arg.default) {
2290
2292
  minArg++;
2291
2293
  }
2292
2294
  if (arg.repeating) {
2293
2295
  repeatingArg++;
2294
2296
  }
2295
- if (arg.optional || arg.default) {
2297
+ if ((arg.optional || arg.default) && !arg.repeating) {
2296
2298
  optionalArg++;
2297
2299
  }
2298
2300
  }
@@ -2300,7 +2302,7 @@
2300
2302
  descr.minArgRequired = minArg;
2301
2303
  descr.maxArgPossible = repeatingArg ? Infinity : countArg;
2302
2304
  descr.nbrArgRepeating = repeatingArg;
2303
- descr.nbrArgOptional = optionalArg;
2305
+ descr.nbrOptionalNonRepeatingArgs = optionalArg;
2304
2306
  descr.hidden = addDescr.hidden || false;
2305
2307
  descr.name = name;
2306
2308
  return descr;
@@ -2328,9 +2330,9 @@
2328
2330
  * and rows representing the correspondence with the argument index.
2329
2331
  *
2330
2332
  * The tables are built based on the following conventions:
2331
- * - `m`: Mandatory argument
2332
- * - `o`: Optional argument
2333
- * - `r`: Repeating argument
2333
+ * - `m`: Mandatory argument (count as one argument)
2334
+ * - `o`: Optional argument (count as zero or one argument)
2335
+ * - `r`: Repeating argument (count as one or more arguments)
2334
2336
  *
2335
2337
  *
2336
2338
  * Configuration 1: (m, o) like the CEILING function
@@ -2343,39 +2345,39 @@
2343
2345
  *
2344
2346
  * Configuration 2: (m, m, m, r, r) like the SUMIFS function
2345
2347
  *
2346
- * | | 3 | 5 | 7 | 3 + 2n |
2347
- * |---|---|---|------|------------|
2348
- * | m | 0 | 0 | 0 | 0 |
2349
- * | m | 1 | 1 | 1 | 1 |
2350
- * | m | 2 | 2 | 2 | 2 |
2351
- * | r | | 3 | 3, 5 | 3 + 2n |
2352
- * | r | | 4 | 4, 6 | 3 + 2n + 1 |
2348
+ * | | 5 | 7 | 3 + 2n |
2349
+ * |---|---|------|------------|
2350
+ * | m | 0 | 0 | 0 |
2351
+ * | m | 1 | 1 | 1 |
2352
+ * | m | 2 | 2 | 2 |
2353
+ * | r | 3 | 3, 5 | 3 + 2n |
2354
+ * | r | 4 | 4, 6 | 3 + 2n + 1 |
2353
2355
  *
2354
2356
  *
2355
2357
  * Configuration 3: (m, m, m, r, r, o) like the SWITCH function
2356
2358
  *
2357
- * | | 3 | 4 | 5 | 6 | 7 | 8 | 3 + 2n | 3 + 2n + 1 |
2358
- * |---|---|---|---|---|------|------|------------|----------------|
2359
- * | m | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
2360
- * | m | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
2361
- * | m | 2 | 2 | 2 | 2 | 2 | 2 | 2 | 2 |
2362
- * | r | | | 3 | 3 | 3, 5 | 3, 5 | 3 + 2n | 3 + 2n |
2363
- * | r | | | 4 | 4 | 4, 6 | 4, 6 | 3 + 2n + 1 | 3 + 2n + 1 |
2364
- * | o | | 3 | | 5 | | 7 | | 3 + 2N + 2 |
2359
+ * | | 5 | 6 | 7 | 8 | 3 + 2n | 3 + 2n + 1 |
2360
+ * |---|---|---|------|------|------------|----------------|
2361
+ * | m | 0 | 0 | 0 | 0 | 0 | 0 |
2362
+ * | m | 1 | 1 | 1 | 1 | 1 | 1 |
2363
+ * | m | 2 | 2 | 2 | 2 | 2 | 2 |
2364
+ * | r | 3 | 3 | 3, 5 | 3, 5 | 3 + 2n | 3 + 2n |
2365
+ * | r | 4 | 4 | 4, 6 | 4, 6 | 3 + 2n + 1 | 3 + 2n + 1 |
2366
+ * | o | | 5 | | 7 | | 3 + 2N + 2 |
2365
2367
  *
2366
2368
  *
2367
2369
  * Configuration 4: (m, o, m, o, r, r, r, m) a complex case to understand subtleties
2368
2370
  *
2369
- * | | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | ... |
2370
- * |---|---|---|---|---|---|---|------|------|------|-----|
2371
- * | m | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | ... |
2372
- * | o | | 1 | 1 | | 1 | 1 | | 1 | 1 | ... |
2373
- * | m | 1 | 2 | 2 | 1 | 2 | 2 | 1 | 2 | 2 | ... |
2374
- * | o | | | 3 | | | 3 | | | 3 | ... |
2375
- * | r | | | | 2 | 3 | 4 | 2, 5 | 3, 6 | 4, 7 | ... |
2376
- * | r | | | | 3 | 4 | 5 | 3, 6 | 4, 7 | 5, 8 | ... |
2377
- * | r | | | | 4 | 5 | 6 | 4, 7 | 5, 8 | 6, 9 | ... |
2378
- * | m | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | ... |
2371
+ * | | 6 | 7 | 8 | 9 | 10 | 11 | ... |
2372
+ * |---|---|---|---|------|------|------|-----|
2373
+ * | m | 0 | 0 | 0 | 0 | 0 | 0 | ... |
2374
+ * | o | | 1 | 1 | | 1 | 1 | ... |
2375
+ * | m | 1 | 2 | 2 | 1 | 2 | 2 | ... |
2376
+ * | o | | | 3 | | | 3 | ... |
2377
+ * | r | 2 | 3 | 4 | 2, 5 | 3, 6 | 4, 7 | ... |
2378
+ * | r | 3 | 4 | 5 | 3, 6 | 4, 7 | 5, 8 | ... |
2379
+ * | r | 4 | 5 | 6 | 4, 7 | 5, 8 | 6, 9 | ... |
2380
+ * | m | 5 | 6 | 7 | 8 | 9 | 10 | ... |
2379
2381
  *
2380
2382
  */
2381
2383
  function argTargeting(functionDescription, nbrArgSupplied) {
@@ -2394,30 +2396,31 @@
2394
2396
  }
2395
2397
  function _argTargeting(functionDescription, nbrArgSupplied) {
2396
2398
  const valueIndexToArgPosition = {};
2397
- const groupsOfRepeatingValues = functionDescription.nbrArgRepeating
2399
+ const groupsOfOptionalRepeatingValues = functionDescription.nbrArgRepeating
2398
2400
  ? Math.floor((nbrArgSupplied - functionDescription.minArgRequired) / functionDescription.nbrArgRepeating)
2399
2401
  : 0;
2400
- const nbrValueRepeating = functionDescription.nbrArgRepeating * groupsOfRepeatingValues;
2401
- const nbrValueOptional = nbrArgSupplied - functionDescription.minArgRequired - nbrValueRepeating;
2402
+ const nbrValueOptionalRepeating = functionDescription.nbrArgRepeating * groupsOfOptionalRepeatingValues;
2403
+ const nbrValueOptional = nbrArgSupplied - functionDescription.minArgRequired - nbrValueOptionalRepeating;
2402
2404
  let countValueSupplied = 0;
2403
2405
  let countValueOptional = 0;
2404
2406
  for (let i = 0; i < functionDescription.args.length; i++) {
2405
2407
  const arg = functionDescription.args[i];
2406
- if (arg.optional || arg.default) {
2408
+ if ((arg.optional || arg.default) && !arg.repeating) {
2407
2409
  if (countValueOptional < nbrValueOptional) {
2408
- valueIndexToArgPosition[countValueSupplied] = i;
2410
+ valueIndexToArgPosition[countValueSupplied] = { index: i };
2409
2411
  countValueSupplied++;
2410
2412
  }
2411
2413
  countValueOptional++;
2412
2414
  continue;
2413
2415
  }
2414
2416
  if (arg.repeating) {
2417
+ const groupOfMandatoryRepeatingValues = arg.optional ? 0 : 1;
2415
2418
  // As we know all repeating arguments are consecutive,
2416
2419
  // --> we will treat all repeating arguments in one go
2417
2420
  // --> the index i will be incremented by the number of repeating values at the end of the loop
2418
- for (let j = 0; j < groupsOfRepeatingValues; j++) {
2421
+ for (let j = 0; j < groupsOfOptionalRepeatingValues + groupOfMandatoryRepeatingValues; j++) {
2419
2422
  for (let k = 0; k < functionDescription.nbrArgRepeating; k++) {
2420
- valueIndexToArgPosition[countValueSupplied] = i + k;
2423
+ valueIndexToArgPosition[countValueSupplied] = { index: i + k, repeatingGroupIndex: j };
2421
2424
  countValueSupplied++;
2422
2425
  }
2423
2426
  }
@@ -2425,7 +2428,7 @@
2425
2428
  continue;
2426
2429
  }
2427
2430
  // End case: it's a required argument
2428
- valueIndexToArgPosition[countValueSupplied] = i;
2431
+ valueIndexToArgPosition[countValueSupplied] = { index: i };
2429
2432
  countValueSupplied++;
2430
2433
  }
2431
2434
  return (argPosition) => {
@@ -2437,7 +2440,7 @@
2437
2440
  //------------------------------------------------------------------------------
2438
2441
  const META_TYPES = ["META", "RANGE<META>"];
2439
2442
  function validateArguments(descr) {
2440
- if (descr.nbrArgRepeating && descr.nbrArgOptional >= descr.nbrArgRepeating) {
2443
+ if (descr.nbrArgRepeating && descr.nbrOptionalNonRepeatingArgs >= descr.nbrArgRepeating) {
2441
2444
  throw new Error(`Function ${descr.name} has more optional arguments than repeatable ones.`);
2442
2445
  }
2443
2446
  let foundRepeating = false;
@@ -4123,7 +4126,7 @@
4123
4126
  const getArgToFocus = argTargeting(descr, args.length);
4124
4127
  //#region Compute vectorisation limits
4125
4128
  for (let i = 0; i < args.length; i++) {
4126
- const argIndex = getArgToFocus(i) ?? -1;
4129
+ const argIndex = getArgToFocus(i).index ?? -1;
4127
4130
  const argDefinition = descr.args[argIndex];
4128
4131
  const arg = args[i];
4129
4132
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
@@ -4137,7 +4140,7 @@
4137
4140
  for (let i = 0; i < args.length; i++) {
4138
4141
  const arg = args[i];
4139
4142
  const getArgToFocus = argTargeting(descr, args.length);
4140
- const argDefinition = descr.args[getArgToFocus(i) || i];
4143
+ const argDefinition = descr.args[getArgToFocus(i).index ?? i];
4141
4144
  // Early exit if the argument is an error and the function does not accept errors
4142
4145
  // We only check scalar arguments, not matrix arguments for performance reasons.
4143
4146
  // Casting helpers are responsible for handling errors in matrix arguments.
@@ -4405,8 +4408,7 @@
4405
4408
  description: _t$1("Creates a new array from the selected columns in the existing range."),
4406
4409
  args: [
4407
4410
  arg("array (any, range<any>)", _t$1("The array that contains the columns to be returned.")),
4408
- arg("col_num (number, range<number>)", _t$1("The first column index of the columns to be returned.")),
4409
- arg("col_num2 (number, range<number>, repeating)", _t$1("The columns indexes of the columns to be returned.")),
4411
+ arg("col_num (number, range<number>, repeating)", _t$1("The column index of the column to be returned.")),
4410
4412
  ],
4411
4413
  compute: function (array, ...columns) {
4412
4414
  const _array = toMatrix(array);
@@ -4435,8 +4437,7 @@
4435
4437
  description: _t$1("Creates a new array from the selected rows in the existing range."),
4436
4438
  args: [
4437
4439
  arg("array (any, range<any>)", _t$1("The array that contains the rows to be returned.")),
4438
- arg("row_num (number, range<number>)", _t$1("The first row index of the rows to be returned.")),
4439
- arg("row_num2 (number, range<number>, repeating)", _t$1("The rows indexes of the rows to be returned.")),
4440
+ arg("row_num (number, range<number>, repeating)", _t$1("The row index of the row to be returned.")),
4440
4441
  ],
4441
4442
  compute: function (array, ...rows) {
4442
4443
  const _array = toMatrix(array);
@@ -4486,10 +4487,7 @@
4486
4487
  // -----------------------------------------------------------------------------
4487
4488
  const FLATTEN = {
4488
4489
  description: _t$1("Flattens all the values from one or more ranges into a single column."),
4489
- args: [
4490
- arg("range (any, range<any>)", _t$1("The first range to flatten.")),
4491
- arg("range2 (any, range<any>, repeating)", _t$1("Additional ranges to flatten.")),
4492
- ],
4490
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to flatten."))],
4493
4491
  compute: function (...ranges) {
4494
4492
  return [flattenRowFirst(ranges, (val) => (val === undefined ? { value: "" } : val))];
4495
4493
  },
@@ -4547,10 +4545,7 @@
4547
4545
  // -----------------------------------------------------------------------------
4548
4546
  const HSTACK = {
4549
4547
  description: _t$1("Appends ranges horizontally and in sequence to return a larger array."),
4550
- args: [
4551
- arg("range1 (any, range<any>)", _t$1("The first range to be appended.")),
4552
- arg("range2 (any, range<any>, repeating)", _t$1("Additional ranges to add to range1.")),
4553
- ],
4548
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to be appended."))],
4554
4549
  compute: function (...ranges) {
4555
4550
  const nbRows = Math.max(...ranges.map((r) => r?.[0]?.length ?? 0));
4556
4551
  const result = [];
@@ -4636,8 +4631,7 @@
4636
4631
  const SUMPRODUCT = {
4637
4632
  description: _t$1("Calculates the sum of the products of corresponding entries in equal-sized ranges."),
4638
4633
  args: [
4639
- arg("range1 (number, range<number>)", _t$1("The first range whose entries will be multiplied with corresponding entries in the other ranges.")),
4640
- arg("range2 (number, range<number>, repeating)", _t$1("The other range whose entries will be multiplied with corresponding entries in the other ranges.")),
4634
+ arg("range (number, range<number>, repeating)", _t$1("The range whose entries will be multiplied with corresponding entries in the other range.")),
4641
4635
  ],
4642
4636
  compute: function (...args) {
4643
4637
  if (!areSameDimensions(...args)) {
@@ -4823,10 +4817,7 @@
4823
4817
  // -----------------------------------------------------------------------------
4824
4818
  const VSTACK = {
4825
4819
  description: _t$1("Appends ranges vertically and in sequence to return a larger array."),
4826
- args: [
4827
- arg("range1 (any, range<any>)", _t$1("The first range to be appended.")),
4828
- arg("range2 (any, range<any>, repeating)", _t$1("Additional ranges to add to range1.")),
4829
- ],
4820
+ args: [arg("range (any, range<any>, repeating)", _t$1("The range to be appended."))],
4830
4821
  compute: function (...ranges) {
4831
4822
  const nbColumns = Math.max(...ranges.map((range) => toMatrix(range).length));
4832
4823
  const nbRows = ranges.reduce((acc, range) => acc + toMatrix(range)[0].length, 0);
@@ -6393,6 +6384,7 @@
6393
6384
  "COPY",
6394
6385
  "RESIZE_SHEETVIEW",
6395
6386
  "SET_VIEWPORT_OFFSET",
6387
+ "SET_ZOOM",
6396
6388
  "EVALUATE_CELLS",
6397
6389
  "EVALUATE_CHARTS",
6398
6390
  "SET_FORMULA_VISIBILITY",
@@ -7108,8 +7100,7 @@
7108
7100
  const COUNTBLANK = {
7109
7101
  description: _t$1("Number of empty values."),
7110
7102
  args: [
7111
- arg("value1 (any, range)", _t$1("The first value or range in which to count the number of blanks.")),
7112
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges in which to count the number of blanks.")),
7103
+ arg("value (any, range, repeating)", _t$1("Value or range in which to count the number of blanks.")),
7113
7104
  ],
7114
7105
  compute: function (...args) {
7115
7106
  return reduceAny(args, (acc, a) => {
@@ -7151,10 +7142,8 @@
7151
7142
  const COUNTIFS = {
7152
7143
  description: _t$1("Count values depending on multiple criteria."),
7153
7144
  args: [
7154
- arg("criteria_range1 (range)", _t$1("The range to check against criterion1.")),
7155
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1.")),
7156
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
7157
- arg("criterion2 (string, repeating)", _t$1("Additional criteria to check.")),
7145
+ arg("criteria_range (any, range, repeating)", _t$1("Range over which to evaluate criteria.")),
7146
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7158
7147
  ],
7159
7148
  compute: function (...args) {
7160
7149
  let count = 0;
@@ -7170,10 +7159,7 @@
7170
7159
  // -----------------------------------------------------------------------------
7171
7160
  const COUNTUNIQUE = {
7172
7161
  description: _t$1("Counts number of unique values in a range."),
7173
- args: [
7174
- arg("value1 (any, range)", _t$1("The first value or range to consider for uniqueness.")),
7175
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges to consider for uniqueness.")),
7176
- ],
7162
+ args: [arg("value (any, range, repeating)", _t$1("Value or range to consider for uniqueness."))],
7177
7163
  compute: function (...args) {
7178
7164
  return countUnique(args);
7179
7165
  },
@@ -7185,10 +7171,8 @@
7185
7171
  description: _t$1("Counts number of unique values in a range, filtered by a set of criteria."),
7186
7172
  args: [
7187
7173
  arg("range (range)", _t$1("The range of cells from which the number of unique values will be counted.")),
7188
- arg("criteria_range1 (range)", _t$1("The range of cells over which to evaluate criterion1.")),
7189
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1, such that each cell that evaluates to TRUE will be included in the filtered set.")),
7190
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
7191
- arg("criterion2 (string, repeating)", _t$1("The pattern or test to apply to criteria_range2.")),
7174
+ arg("criteria_range (any, range, repeating)", _t$1("Range over which to evaluate criteria.")),
7175
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7192
7176
  ],
7193
7177
  compute: function (range, ...args) {
7194
7178
  const uniqueValues = new Set();
@@ -7544,8 +7528,7 @@
7544
7528
  const PRODUCT = {
7545
7529
  description: _t$1("Result of multiplying a series of numbers together."),
7546
7530
  args: [
7547
- arg("factor1 (number, range<number>)", _t$1("The first number or range to calculate for the product.")),
7548
- arg("factor2 (number, range<number>, repeating)", _t$1("More numbers or ranges to calculate for the product.")),
7531
+ arg("factor (number, range<number>, repeating)", _t$1("Number or range to calculate for the product.")),
7549
7532
  ],
7550
7533
  compute: function (...factors) {
7551
7534
  let count = 0;
@@ -7877,8 +7860,7 @@
7877
7860
  ...subtotalFunctionOptionsIncludeHiddenRows,
7878
7861
  ...subtotalFunctionOptionsExcludeHiddenRows,
7879
7862
  ]),
7880
- arg("ref1 (meta, range<meta>)", _t$1("The range or reference for which you want the subtotal.")),
7881
- arg("ref2 (meta, range<meta>, repeating)", _t$1("Additional ranges or references for which you want the subtotal.")),
7863
+ arg("ref (meta, range<meta>, repeating)", _t$1("Range or reference for which you want the subtotal.")),
7882
7864
  ],
7883
7865
  compute: function (functionCode, ...refs) {
7884
7866
  let code = toInteger(functionCode, this.locale);
@@ -7922,10 +7904,7 @@
7922
7904
  // -----------------------------------------------------------------------------
7923
7905
  const SUM = {
7924
7906
  description: _t$1("Sum of a series of numbers and/or cells."),
7925
- args: [
7926
- arg("value1 (number, range<number>)", _t$1("The first number or range to add together.")),
7927
- arg("value2 (number, range<number>, repeating)", _t$1("Additional numbers or ranges to add to value1.")),
7928
- ],
7907
+ args: [arg("value (number, range<number>, repeating)", _t$1("Number or range to add together."))],
7929
7908
  compute: function (...values) {
7930
7909
  const v1 = values[0];
7931
7910
  return {
@@ -7967,10 +7946,8 @@
7967
7946
  description: _t$1("Sums a range depending on multiple criteria."),
7968
7947
  args: [
7969
7948
  arg("sum_range (range)", _t$1("The range to sum.")),
7970
- arg("criteria_range1 (range)", _t$1("The range to check against criterion1.")),
7971
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1.")),
7972
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges to check.")),
7973
- arg("criterion2 (string, repeating)", _t$1("Additional criteria to check.")),
7949
+ arg("criteria_range (any, range, repeating)", _t$1("Range to check.")),
7950
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
7974
7951
  ],
7975
7952
  compute: function (sumRange, ...criters) {
7976
7953
  let sum = 0;
@@ -8452,8 +8429,7 @@
8452
8429
  const AVEDEV = {
8453
8430
  description: _t$1("Average magnitude of deviations from mean."),
8454
8431
  args: [
8455
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
8456
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
8432
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
8457
8433
  ],
8458
8434
  compute: function (...values) {
8459
8435
  let count = 0;
@@ -8475,8 +8451,7 @@
8475
8451
  const AVERAGE = {
8476
8452
  description: _t$1("Numerical average value in a dataset, ignoring text."),
8477
8453
  args: [
8478
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the average value.")),
8479
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the average value.")),
8454
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the average value.")),
8480
8455
  ],
8481
8456
  compute: function (...values) {
8482
8457
  return {
@@ -8494,10 +8469,8 @@
8494
8469
  const AVERAGE_WEIGHTED = {
8495
8470
  description: _t$1("Weighted average."),
8496
8471
  args: [
8497
- arg("values (number, range<number>)", _t$1("Values to average.")),
8498
- arg("weights (number, range<number>)", _t$1("Weights for each corresponding value.")),
8499
- arg("additional_values (number, range<number>, repeating)", _t$1("Additional values to average.")),
8500
- arg("additional_weights (number, range<number>, repeating)", _t$1("Additional weights.")),
8472
+ arg("values (number, range<number>, repeating)", _t$1("Value to average.")),
8473
+ arg("weights (number, range<number>, repeating)", _t$1("Weight for each corresponding value.")),
8501
8474
  ],
8502
8475
  compute: function (...args) {
8503
8476
  let sum = 0;
@@ -8553,8 +8526,7 @@
8553
8526
  const AVERAGEA = {
8554
8527
  description: _t$1("Numerical average value in a dataset."),
8555
8528
  args: [
8556
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the average value.")),
8557
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the average value.")),
8529
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the average value.")),
8558
8530
  ],
8559
8531
  compute: function (...args) {
8560
8532
  let count = 0;
@@ -8607,10 +8579,8 @@
8607
8579
  description: _t$1("Average of values depending on multiple criteria."),
8608
8580
  args: [
8609
8581
  arg("average_range (range)", _t$1("The range to average.")),
8610
- arg("criteria_range1 (range)", _t$1("The range to check against criterion1.")),
8611
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1.")),
8612
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional criteria_range and criterion to check.")),
8613
- arg("criterion2 (string, repeating)", _t$1("The pattern or test to apply to criteria_range2.")),
8582
+ arg("criteria_range (any, range, repeating)", _t$1("Range to check.")),
8583
+ arg("criterion (string, repeating)", _t$1("Criterion to check.")),
8614
8584
  ],
8615
8585
  compute: function (averageRange, ...args) {
8616
8586
  const _averageRange = toMatrix(averageRange);
@@ -8636,8 +8606,7 @@
8636
8606
  const COUNT = {
8637
8607
  description: _t$1("The number of numeric values in dataset."),
8638
8608
  args: [
8639
- arg("value1 (number, any, range<number>)", _t$1("The first value or range to consider when counting.")),
8640
- arg("value2 (number, any, range<number>, repeating)", _t$1("Additional values or ranges to consider when counting.")),
8609
+ arg("value (number, any, range<number>, repeating)", _t$1("Value or range to consider when counting.")),
8641
8610
  ],
8642
8611
  compute: function (...values) {
8643
8612
  return countNumbers(values, this.locale);
@@ -8649,10 +8618,7 @@
8649
8618
  // -----------------------------------------------------------------------------
8650
8619
  const COUNTA = {
8651
8620
  description: _t$1("The number of values in a dataset."),
8652
- args: [
8653
- arg("value1 (any, range)", _t$1("The first value or range to consider when counting.")),
8654
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges to consider when counting.")),
8655
- ],
8621
+ args: [arg("value (any, range, repeating)", _t$1("Value or range to consider when counting."))],
8656
8622
  compute: function (...values) {
8657
8623
  return countAny(values);
8658
8624
  },
@@ -8885,8 +8851,7 @@
8885
8851
  const MAX = {
8886
8852
  description: _t$1("Maximum value in a numeric dataset."),
8887
8853
  args: [
8888
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the maximum value.")),
8889
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the maximum value.")),
8854
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the maximum value.")),
8890
8855
  ],
8891
8856
  compute: function (...values) {
8892
8857
  return max(values, this.locale);
@@ -8899,8 +8864,7 @@
8899
8864
  const MAXA = {
8900
8865
  description: _t$1("Maximum numeric value in a dataset."),
8901
8866
  args: [
8902
- arg("value1 (any, range)", _t$1("The first value or range to consider when calculating the maximum value.")),
8903
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges to consider when calculating the maximum value.")),
8867
+ arg("value (any, range, repeating)", _t$1("Value or range to consider when calculating the maximum value.")),
8904
8868
  ],
8905
8869
  compute: function (...args) {
8906
8870
  const maxa = reduceNumbersTextAs0(args, (acc, a) => {
@@ -8917,10 +8881,8 @@
8917
8881
  description: _t$1("Returns the maximum value in a range of cells, filtered by a set of criteria."),
8918
8882
  args: [
8919
8883
  arg("range (range)", _t$1("The range of cells from which the maximum will be determined.")),
8920
- arg("criteria_range1 (range)", _t$1("The range of cells over which to evaluate criterion1.")),
8921
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1, such that each cell that evaluates to TRUE will be included in the filtered set.")),
8922
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
8923
- arg("criterion2 (string, repeating)", _t$1("The pattern or test to apply to criteria_range2.")),
8884
+ arg("criteria_range (any, range, repeating)", _t$1("Range to evaluate criteria.")),
8885
+ arg("criterion (string, repeating)", _t$1("Criteria to check.")),
8924
8886
  ],
8925
8887
  compute: function (range, ...args) {
8926
8888
  let result = -Infinity;
@@ -8940,8 +8902,7 @@
8940
8902
  const MEDIAN = {
8941
8903
  description: _t$1("Median value in a numeric dataset."),
8942
8904
  args: [
8943
- arg("value1 (any, range)", _t$1("The first value or range to consider when calculating the median value.")),
8944
- arg("value2 (any, range, repeating)", _t$1("Additional values or ranges to consider when calculating the median value.")),
8905
+ arg("value (any, range, repeating)", _t$1("Value or range to consider when calculating the median value.")),
8945
8906
  ],
8946
8907
  compute: function (...values) {
8947
8908
  const data = [];
@@ -8961,8 +8922,7 @@
8961
8922
  const MIN = {
8962
8923
  description: _t$1("Minimum value in a numeric dataset."),
8963
8924
  args: [
8964
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the minimum value.")),
8965
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the minimum value.")),
8925
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the minimum value.")),
8966
8926
  ],
8967
8927
  compute: function (...values) {
8968
8928
  return min(values, this.locale);
@@ -8975,8 +8935,7 @@
8975
8935
  const MINA = {
8976
8936
  description: _t$1("Minimum numeric value in a dataset."),
8977
8937
  args: [
8978
- arg("value1 (number, range<number>)", _t$1("The first value or range to consider when calculating the minimum value.")),
8979
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to consider when calculating the minimum value.")),
8938
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to consider when calculating the minimum value.")),
8980
8939
  ],
8981
8940
  compute: function (...args) {
8982
8941
  const mina = reduceNumbersTextAs0(args, (acc, a) => {
@@ -8993,10 +8952,8 @@
8993
8952
  description: _t$1("Returns the minimum value in a range of cells, filtered by a set of criteria."),
8994
8953
  args: [
8995
8954
  arg("range (range)", _t$1("The range of cells from which the minimum will be determined.")),
8996
- arg("criteria_range1 (range)", _t$1("The range of cells over which to evaluate criterion1.")),
8997
- arg("criterion1 (string)", _t$1("The pattern or test to apply to criteria_range1, such that each cell that evaluates to TRUE will be included in the filtered set.")),
8998
- arg("criteria_range2 (any, range, repeating)", _t$1("Additional ranges over which to evaluate the additional criteria. The filtered set will be the intersection of the sets produced by each criterion-range pair.")),
8999
- arg("criterion2 (string, repeating)", _t$1("The pattern or test to apply to criteria_range2.")),
8955
+ arg("criteria_range (any, range, repeating)", _t$1("Range to evaluate criteria.")),
8956
+ arg("criterion (string, repeating)", _t$1("Criterion to check.")),
9000
8957
  ],
9001
8958
  compute: function (range, ...args) {
9002
8959
  let result = Infinity;
@@ -9337,8 +9294,7 @@
9337
9294
  const STDEV = {
9338
9295
  description: _t$1("Standard deviation."),
9339
9296
  args: [
9340
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9341
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9297
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9342
9298
  ],
9343
9299
  compute: function (...args) {
9344
9300
  return Math.sqrt(VAR.compute.bind(this)(...args));
@@ -9351,8 +9307,7 @@
9351
9307
  const STDEV_P = {
9352
9308
  description: _t$1("Standard deviation of entire population."),
9353
9309
  args: [
9354
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9355
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9310
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9356
9311
  ],
9357
9312
  compute: function (...args) {
9358
9313
  return Math.sqrt(VAR_P.compute.bind(this)(...args));
@@ -9365,8 +9320,7 @@
9365
9320
  const STDEV_S = {
9366
9321
  description: _t$1("Standard deviation."),
9367
9322
  args: [
9368
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9369
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9323
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9370
9324
  ],
9371
9325
  compute: function (...args) {
9372
9326
  return Math.sqrt(VAR_S.compute.bind(this)(...args));
@@ -9379,8 +9333,7 @@
9379
9333
  const STDEVA = {
9380
9334
  description: _t$1("Standard deviation of sample (text as 0)."),
9381
9335
  args: [
9382
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9383
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9336
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9384
9337
  ],
9385
9338
  compute: function (...args) {
9386
9339
  return Math.sqrt(VARA.compute.bind(this)(...args));
@@ -9393,8 +9346,7 @@
9393
9346
  const STDEVP = {
9394
9347
  description: _t$1("Standard deviation of entire population."),
9395
9348
  args: [
9396
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9397
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9349
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9398
9350
  ],
9399
9351
  compute: function (...args) {
9400
9352
  return Math.sqrt(VARP.compute.bind(this)(...args));
@@ -9407,8 +9359,7 @@
9407
9359
  const STDEVPA = {
9408
9360
  description: _t$1("Standard deviation of entire population (text as 0)."),
9409
9361
  args: [
9410
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9411
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9362
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9412
9363
  ],
9413
9364
  compute: function (...args) {
9414
9365
  return Math.sqrt(VARPA.compute.bind(this)(...args));
@@ -9458,8 +9409,7 @@
9458
9409
  const VAR = {
9459
9410
  description: _t$1("Variance."),
9460
9411
  args: [
9461
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9462
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9412
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9463
9413
  ],
9464
9414
  compute: function (...args) {
9465
9415
  return variance(args, true, false, this.locale);
@@ -9472,8 +9422,7 @@
9472
9422
  const VAR_P = {
9473
9423
  description: _t$1("Variance of entire population."),
9474
9424
  args: [
9475
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9476
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9425
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9477
9426
  ],
9478
9427
  compute: function (...args) {
9479
9428
  return variance(args, false, false, this.locale);
@@ -9486,8 +9435,7 @@
9486
9435
  const VAR_S = {
9487
9436
  description: _t$1("Variance."),
9488
9437
  args: [
9489
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9490
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9438
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9491
9439
  ],
9492
9440
  compute: function (...args) {
9493
9441
  return variance(args, true, false, this.locale);
@@ -9500,8 +9448,7 @@
9500
9448
  const VARA = {
9501
9449
  description: _t$1("Variance of sample (text as 0)."),
9502
9450
  args: [
9503
- arg("value1 (number, range<number>)", _t$1("The first value or range of the sample.")),
9504
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the sample.")),
9451
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the sample.")),
9505
9452
  ],
9506
9453
  compute: function (...args) {
9507
9454
  return variance(args, true, true, this.locale);
@@ -9514,8 +9461,7 @@
9514
9461
  const VARP = {
9515
9462
  description: _t$1("Variance of entire population."),
9516
9463
  args: [
9517
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9518
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9464
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9519
9465
  ],
9520
9466
  compute: function (...args) {
9521
9467
  return variance(args, false, false, this.locale);
@@ -9528,8 +9474,7 @@
9528
9474
  const VARPA = {
9529
9475
  description: _t$1("Variance of entire population (text as 0)."),
9530
9476
  args: [
9531
- arg("value1 (number, range<number>)", _t$1("The first value or range of the population.")),
9532
- arg("value2 (number, range<number>, repeating)", _t$1("Additional values or ranges to include in the population.")),
9477
+ arg("value (number, range<number>, repeating)", _t$1("Value or range to include in the population.")),
9533
9478
  ],
9534
9479
  compute: function (...args) {
9535
9480
  return variance(args, false, true, this.locale);
@@ -11433,8 +11378,7 @@
11433
11378
  // TODO modify args description when vectorization on formulas is available
11434
11379
  args: [
11435
11380
  arg("range (any, range<any>)", _t$1("The data to be filtered.")),
11436
- arg("condition1 (boolean, range<boolean>)", _t$1("A column or row containing true or false values corresponding to the first column or row of range.")),
11437
- arg("condition2 (boolean, range<boolean>, repeating)", _t$1("Additional column or row containing true or false values.")),
11381
+ arg("condition (boolean, range<boolean>, repeating)", _t$1("Column or row containing true or false values corresponding to the range.")),
11438
11382
  ],
11439
11383
  compute: function (range, ...conditions) {
11440
11384
  let _array = toMatrix(range);
@@ -11474,8 +11418,8 @@
11474
11418
  description: _t$1("Sorts the rows of a given array or range by the values in one or more columns."),
11475
11419
  args: [
11476
11420
  arg("range (range)", _t$1("The data to be sorted.")),
11477
- arg("sort_column (any, range<number>, repeating)", _t$1("The index of the column in range or a range outside of range containing the values by which to sort.")),
11478
- arg("is_ascending (boolean, repeating)", _t$1("TRUE or FALSE indicating whether to sort sort_column in ascending order."), [
11421
+ arg("sort_column (any, range<number>, repeating, optional)", _t$1("The index of the column in range or a range outside of range containing the value by which to sort.")),
11422
+ arg("is_ascending (boolean, repeating, optional)", _t$1("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order."), [
11479
11423
  { value: true, label: _t$1("Ascending") },
11480
11424
  { value: false, label: _t$1("Descending") },
11481
11425
  ]),
@@ -11495,8 +11439,8 @@
11495
11439
  arg("range (range)", _t$1("The data to be sorted.")),
11496
11440
  arg("n (number)", _t$1("The number of items to return.")),
11497
11441
  arg("display_ties_mode (number, default=0)", _t$1("A number representing the way to display ties.")),
11498
- arg("sort_column (number, range<number>, repeating)", _t$1("The index of the column in range or a range outside of range containing the values by which to sort.")),
11499
- arg("is_ascending (boolean, repeating)", _t$1("TRUE or FALSE indicating whether to sort sort_column in ascending order."), [
11442
+ arg("sort_column (number, range<number>, repeating, optional)", _t$1("The index of the column in range or a range outside of range containing the value by which to sort.")),
11443
+ arg("is_ascending (boolean, repeating, optional)", _t$1("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order."), [
11500
11444
  { value: true, label: _t$1("Ascending") },
11501
11445
  { value: false, label: _t$1("Descending") },
11502
11446
  ]),
@@ -12764,8 +12708,7 @@
12764
12708
  description: _t$1("The net present value of an investment based on a series of periodic cash flows and a discount rate."),
12765
12709
  args: [
12766
12710
  arg("discount (number)", _t$1("The discount rate of the investment over one period.")),
12767
- arg("cashflow1 (number, range<number>)", _t$1("The first future cash flow.")),
12768
- arg("cashflow2 (number, range<number>, repeating)", _t$1("Additional future cash flows.")),
12711
+ arg("cashflow (number, range<number>, repeating)", _t$1("The future cash flows.")),
12769
12712
  ],
12770
12713
  // to do: replace by dollar format
12771
12714
  compute: function (discount, ...values) {
@@ -14120,8 +14063,7 @@
14120
14063
  const AND = {
14121
14064
  description: _t$1("Logical `and` operator."),
14122
14065
  args: [
14123
- arg("logical_expression1 (boolean, range<boolean>)", _t$1("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
14124
- arg("logical_expression2 (boolean, range<boolean>, repeating)", _t$1("More expressions that represent logical values.")),
14066
+ arg("logical_expression (boolean, range<boolean>, repeating)", _t$1("Expression or reference to a cell containing a logical value (TRUE/FALSE) or an expression that can be coerced to a logical value.")),
14125
14067
  ],
14126
14068
  compute: function (...logicalExpressions) {
14127
14069
  const { result, foundBoolean } = boolAnd(logicalExpressions);
@@ -14204,10 +14146,8 @@
14204
14146
  const IFS = {
14205
14147
  description: _t$1("Returns a value depending on multiple logical expressions."),
14206
14148
  args: [
14207
- arg("condition1 (boolean, range<boolean>)", _t$1("The first condition to be evaluated. This can be a boolean, a number, an array, or a reference to any of those.")),
14208
- arg("value1 (any, range)", _t$1("The returned value if condition1 is TRUE.")),
14209
- arg("condition2 (boolean, any, range, repeating)", _t$1("Additional conditions to be evaluated if the previous ones are FALSE.")),
14210
- arg("value2 (any, range, repeating)", _t$1("Additional values to be returned if their corresponding conditions are TRUE.")),
14149
+ arg("condition (any, range, repeating)", _t$1("The condition to be evaluated. It can be a boolean, a number, an array, or a reference to any of those.")),
14150
+ arg("value (any, range, repeating)", _t$1("The value to be returned if its corresponding condition is TRUE.")),
14211
14151
  ],
14212
14152
  compute: function (...values) {
14213
14153
  if (values.length % 2 !== 0) {
@@ -14246,8 +14186,7 @@
14246
14186
  const OR = {
14247
14187
  description: _t$1("Logical `or` operator."),
14248
14188
  args: [
14249
- arg("logical_expression1 (boolean, range<boolean>)", _t$1("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
14250
- arg("logical_expression2 (boolean, range<boolean>, repeating)", _t$1("More expressions that evaluate to logical values.")),
14189
+ arg("logical_expression (boolean, range<boolean>, repeating)", _t$1("Expression or reference to a cell containing a logical value (TRUE/FALSE) or an expression that can be coerced to a logical value.")),
14251
14190
  ],
14252
14191
  compute: function (...logicalExpressions) {
14253
14192
  const { result, foundBoolean } = boolOr(logicalExpressions);
@@ -14265,10 +14204,8 @@
14265
14204
  description: _t$1("Returns a value by comparing cases to an expression."),
14266
14205
  args: [
14267
14206
  arg("expression (number, boolean, string)", _t$1("The value to be checked.")),
14268
- arg("case1 (number, boolean, string)", _t$1("The first case to be checked against expression.")),
14269
- arg("value1 (any)", _t$1("The corresponding value to be returned if case1 matches expression.")),
14270
- arg("case2 (any, repeating)", _t$1("Additional cases to try if the previous ones don't match expression.")),
14271
- arg("value2 (any, repeating)", _t$1("Additional values to be returned if their corresponding cases match expression.")),
14207
+ arg("case (any, repeating)", _t$1("Case to be checked against expression.")),
14208
+ arg("value (any, repeating)", _t$1("Value to be returned if its corresponding case matches expression.")),
14272
14209
  arg(`default (any, default="empty")`, _t$1("An optional default value to be returned if none of the cases match expression.")),
14273
14210
  ],
14274
14211
  compute: function (expression, ...casesAndValues) {
@@ -14303,8 +14240,7 @@
14303
14240
  const XOR = {
14304
14241
  description: _t$1("Logical `xor` operator."),
14305
14242
  args: [
14306
- arg("logical_expression1 (boolean, range<boolean>)", _t$1("An expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.")),
14307
- arg("logical_expression2 (boolean, range<boolean>, repeating)", _t$1("More expressions that evaluate to logical values.")),
14243
+ arg("logical_expression (boolean, range<boolean>, repeating)", _t$1("Expression or reference to a cell containing a logical value (TRUE/FALSE) or an expression that can be coerced to a logical value.")),
14308
14244
  ],
14309
14245
  compute: function (...logicalExpressions) {
14310
14246
  let foundBoolean = false;
@@ -15817,8 +15753,8 @@
15817
15753
  args: [
15818
15754
  arg("pivot_id (number,string)", _t$1("ID of the pivot.")),
15819
15755
  arg("measure_name (string)", _t$1("Name of the measure.")),
15820
- arg("domain_field_name (string,repeating)", _t$1("Field name.")),
15821
- arg("domain_value (number,string,boolean,repeating)", _t$1("Value.")),
15756
+ arg("domain_field_name (string,repeating,optional)", _t$1("Field name.")),
15757
+ arg("domain_value (number,string,boolean,repeating,optional)", _t$1("Value.")),
15822
15758
  ],
15823
15759
  compute: function (formulaId, measureName, ...domainArgs) {
15824
15760
  const _pivotFormulaId = toString(formulaId);
@@ -15853,8 +15789,8 @@
15853
15789
  description: _t$1("Get the header of a pivot."),
15854
15790
  args: [
15855
15791
  arg("pivot_id (number,string)", _t$1("ID of the pivot.")),
15856
- arg("domain_field_name (string,repeating)", _t$1("Field name.")),
15857
- arg("domain_value (number,string,value,repeating)", _t$1("Value.")),
15792
+ arg("domain_field_name (string,repeating,optional)", _t$1("Field name.")),
15793
+ arg("domain_value (number,string,value,repeating,optional)", _t$1("Value.")),
15858
15794
  ],
15859
15795
  compute: function (pivotId, ...domainArgs) {
15860
15796
  const _pivotFormulaId = toString(pivotId);
@@ -16725,10 +16661,7 @@
16725
16661
  // -----------------------------------------------------------------------------
16726
16662
  const CONCATENATE = {
16727
16663
  description: _t$1("Appends strings to one another."),
16728
- args: [
16729
- arg("string1 (string, range<string>)", _t$1("The initial string.")),
16730
- arg("string2 (string, range<string>, repeating)", _t$1("More strings to append in sequence.")),
16731
- ],
16664
+ args: [arg("string (string, range<string>, repeating)", _t$1("String to append in sequence."))],
16732
16665
  compute: function (...datas) {
16733
16666
  return reduceAny(datas, (acc, a) => acc + toString(a), "");
16734
16667
  },
@@ -16783,8 +16716,7 @@
16783
16716
  description: _t$1("Concatenates elements of arrays with delimiter."),
16784
16717
  args: [
16785
16718
  arg("delimiter (string)", _t$1("The character or string to place between each concatenated value.")),
16786
- arg("value_or_array1 (string, range<string>)", _t$1("The value or values to be appended using delimiter.")),
16787
- arg("value_or_array2 (string, range<string>, repeating)", _t$1("More values to be appended using delimiter.")),
16719
+ arg("value_or_array (string, range<string>, repeating)", _t$1("Value to be appended using delimiter.")),
16788
16720
  ],
16789
16721
  compute: function (delimiter, ...valuesOrArrays) {
16790
16722
  const _delimiter = toString(delimiter);
@@ -17075,13 +17007,12 @@
17075
17007
  const TEXTJOIN = {
17076
17008
  description: _t$1("Combines text from multiple strings and/or arrays."),
17077
17009
  args: [
17078
- arg("delimiter (string)", _t$1(" A string, possible empty, or a reference to a valid string. If empty, the text will be simply concatenated.")),
17010
+ arg("delimiter (string)", _t$1("A string, possible empty, or a reference to a valid string. If empty, the text will be simply concatenated.")),
17079
17011
  arg("ignore_empty (boolean)", _t$1("A boolean; if TRUE, empty cells selected in the text arguments won't be included in the result."), [
17080
17012
  { value: true, label: _t$1("Ignore empty cells") },
17081
17013
  { value: false, label: _t$1("Include empty cells (default)") },
17082
17014
  ]),
17083
- arg("text1 (string, range<string>)", _t$1("Any text item. This could be a string, or an array of strings in a range.")),
17084
- arg("text2 (string, range<string>, repeating)", _t$1("Additional text item(s).")),
17015
+ arg("texts (string, range<string>, repeating)", _t$1("Text item to join.")),
17085
17016
  ],
17086
17017
  compute: function (delimiter, ignoreEmpty = { value: TEXTJOIN_DEFAULT_IGNORE_EMPTY }, ...textsOrArrays) {
17087
17018
  const _delimiter = toString(delimiter);
@@ -22969,6 +22900,66 @@ stores.inject(MyMetaStore, storeInstance);
22969
22900
  }
22970
22901
  }
22971
22902
 
22903
+ /**
22904
+ * Return a POJO containing the original event as well as the client position and the client offset
22905
+ * where the event would target if the spreadsheet was not zoomed
22906
+ * @param ev unzoomed mouse event
22907
+ * @param originalTargetRect The original target bounding rect the resulting ZoomedMouseEvent offset must refer to
22908
+ * @returns a ZoomedMouseEvent
22909
+ */
22910
+ function withZoom(env, ev, originalTargetRect) {
22911
+ const zoomLevel = env.model.getters.getViewportZoomLevel();
22912
+ if (originalTargetRect === undefined) {
22913
+ originalTargetRect = getZoomTargetBoundingRect(ev);
22914
+ }
22915
+ if (!originalTargetRect)
22916
+ return withNoZoom(ev);
22917
+ const baseOffsetX = ev.clientX - originalTargetRect.left;
22918
+ const baseOffsetY = ev.clientY - originalTargetRect.top;
22919
+ const offsetX = baseOffsetX / zoomLevel;
22920
+ const offsetY = baseOffsetY / zoomLevel;
22921
+ return {
22922
+ ev,
22923
+ clientX: ev.clientX - baseOffsetX + offsetX,
22924
+ clientY: ev.clientY - baseOffsetY + offsetY,
22925
+ offsetX,
22926
+ offsetY,
22927
+ };
22928
+ }
22929
+ function withNoZoom(ev) {
22930
+ return {
22931
+ ev,
22932
+ clientX: ev.clientX,
22933
+ clientY: ev.clientY,
22934
+ offsetX: ev.offsetX,
22935
+ offsetY: ev.offsetY,
22936
+ };
22937
+ }
22938
+ /**
22939
+ * Return a Rect with position and size on the zoomed canvas
22940
+ */
22941
+ function getZoomedRect(zoom, rect) {
22942
+ return {
22943
+ height: rect.height * zoom,
22944
+ width: rect.width * zoom,
22945
+ x: rect.x * zoom,
22946
+ y: rect.y * zoom,
22947
+ };
22948
+ }
22949
+ /**
22950
+ * Returns the bounding rect of the closest or self element who is targetable by a ZoomedMouseEvent
22951
+ */
22952
+ function getZoomTargetBoundingRect(ev) {
22953
+ const target = ev.target;
22954
+ if (!target || !("classList" in target) || !(target instanceof Element)) {
22955
+ return null;
22956
+ }
22957
+ const targetEl = target.classList.contains("o-zoomable") ? target : target.closest(".o-zoomable");
22958
+ if (!targetEl)
22959
+ return null;
22960
+ return targetEl.getBoundingClientRect();
22961
+ }
22962
+
22972
22963
  class ScorecardChart extends owl.Component {
22973
22964
  static template = "o-spreadsheet-ScorecardChart";
22974
22965
  static props = {
@@ -22992,7 +22983,8 @@ stores.inject(MyMetaStore, storeInstance);
22992
22983
  }
22993
22984
  createChart() {
22994
22985
  const canvas = this.canvas.el;
22995
- const config = getScorecardConfiguration(canvas.getBoundingClientRect(), this.runtime);
22986
+ const zoom = this.env.model.getters.getViewportZoomLevel();
22987
+ const config = getScorecardConfiguration(getZoomedRect(1 / zoom, canvas.getBoundingClientRect()), this.runtime);
22996
22988
  drawScoreChart(config, canvas);
22997
22989
  }
22998
22990
  }
@@ -23111,8 +23103,7 @@ stores.inject(MyMetaStore, storeInstance);
23111
23103
  function gridOverlayPosition() {
23112
23104
  const spreadsheetElement = document.querySelector(".o-grid-overlay");
23113
23105
  if (spreadsheetElement) {
23114
- const { top, left } = spreadsheetElement.getBoundingClientRect();
23115
- return { top, left };
23106
+ return spreadsheetElement.getBoundingClientRect();
23116
23107
  }
23117
23108
  throw new Error("Can't find spreadsheet position");
23118
23109
  }
@@ -26254,7 +26245,7 @@ stores.inject(MyMetaStore, storeInstance);
26254
26245
  const compiledArgs = [];
26255
26246
  const argToFocus = argTargeting(functionDefinition, args.length);
26256
26247
  for (let i = 0; i < args.length; i++) {
26257
- const argDefinition = functionDefinition.args[argToFocus(i) ?? -1];
26248
+ const argDefinition = functionDefinition.args[argToFocus(i).index ?? -1];
26258
26249
  const currentArg = args[i];
26259
26250
  const argTypes = argDefinition.type || [];
26260
26251
  // detect when an argument need to be evaluated as a meta argument
@@ -26433,12 +26424,15 @@ stores.inject(MyMetaStore, storeInstance);
26433
26424
  }
26434
26425
  if (nbrArgRepeating > 1) {
26435
26426
  const nbrValueRepeating = nbrArgRepeating * Math.floor((nbrArgSupplied - minArgRequired) / nbrArgRepeating);
26436
- const nbrValueRemaining = nbrArgSupplied - minArgRequired - nbrValueRepeating - functionDefinition.nbrArgOptional;
26427
+ const nbrValueRemaining = nbrArgSupplied -
26428
+ minArgRequired -
26429
+ nbrValueRepeating -
26430
+ functionDefinition.nbrOptionalNonRepeatingArgs;
26437
26431
  if (nbrValueRemaining > 0) {
26438
26432
  throw new BadExpressionError(_t$1("Invalid number of arguments for the %(functionName)s function. Repeatable arguments should be supplied in groups of %(nbrArgRepeating)s, with up to %(nbrArgOptional)s optional. Got %(nbrValueRemaining)s too many.", {
26439
26433
  functionName,
26440
26434
  nbrArgRepeating,
26441
- nbrArgOptional: functionDefinition.nbrArgOptional,
26435
+ nbrArgOptional: functionDefinition.nbrOptionalNonRepeatingArgs,
26442
26436
  nbrValueRemaining,
26443
26437
  }));
26444
26438
  }
@@ -44835,8 +44829,24 @@ stores.inject(MyMetaStore, storeInstance);
44835
44829
  case "REFERENCE":
44836
44830
  return ast.value;
44837
44831
  case "FUNCALL":
44838
- const docs = ast.args.map(astToDoc);
44839
- return wrapInParentheses(concat(docs.map((doc, i) => (i < 1 ? doc : concat([", ", line(), doc])))), ast.value);
44832
+ const functionDescription = functionRegistry.get(ast.value.toUpperCase());
44833
+ const getArgToFocus = argTargeting(functionDescription, ast.args.length);
44834
+ const docs = [];
44835
+ let i = 0;
44836
+ while (i < ast.args.length) {
44837
+ const isRepeating = functionDescription.args[getArgToFocus(i).index ?? -1]?.repeating;
44838
+ if (isRepeating) {
44839
+ const repeatingArgSeries = ast.args.slice(i, i + functionDescription.nbrArgRepeating);
44840
+ const docsSeries = repeatingArgSeries.map((arg) => astToDoc(arg));
44841
+ docs.push(group(concat(splitArgsWithCommas(docsSeries))));
44842
+ i += functionDescription.nbrArgRepeating;
44843
+ }
44844
+ else {
44845
+ docs.push(astToDoc(ast.args[i]));
44846
+ i++;
44847
+ }
44848
+ }
44849
+ return wrapInParentheses(concat(splitArgsWithCommas(docs)), ast.value);
44840
44850
  case "UNARY_OPERATION":
44841
44851
  const operandDoc = astToDoc(ast.operand);
44842
44852
  const needParenthesis = ast.postfix
@@ -44862,6 +44872,14 @@ stores.inject(MyMetaStore, storeInstance);
44862
44872
  return "";
44863
44873
  }
44864
44874
  }
44875
+ function splitArgsWithCommas(docs) {
44876
+ const result = docs.length ? [docs[0]] : [];
44877
+ for (let i = 1; i < docs.length; i++) {
44878
+ result.push(", ", line());
44879
+ result.push(docs[i]);
44880
+ }
44881
+ return result;
44882
+ }
44865
44883
  /**
44866
44884
  * Wraps a `Doc` in parentheses (with optional function name).
44867
44885
  */
@@ -46469,6 +46487,7 @@ stores.inject(MyMetaStore, storeInstance);
46469
46487
  isMeasureCandidate: (field) => field.type !== "boolean",
46470
46488
  isGroupable: () => true,
46471
46489
  canHaveCustomGroup: (field) => field.type === "char" && !field.isCustomField,
46490
+ isPivotUnused: () => true,
46472
46491
  });
46473
46492
 
46474
46493
  const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT", "REMOVE_PIVOT"];
@@ -46487,7 +46506,7 @@ stores.inject(MyMetaStore, storeInstance);
46487
46506
  "isSpillPivotFormula",
46488
46507
  ];
46489
46508
  pivots = {};
46490
- unusedPivots;
46509
+ unusedPivotsInFormulas;
46491
46510
  custom;
46492
46511
  constructor(config) {
46493
46512
  super(config);
@@ -46527,12 +46546,12 @@ stores.inject(MyMetaStore, storeInstance);
46527
46546
  }
46528
46547
  case "DELETE_SHEET":
46529
46548
  case "UPDATE_CELL": {
46530
- this.unusedPivots = undefined;
46549
+ this.unusedPivotsInFormulas = undefined;
46531
46550
  break;
46532
46551
  }
46533
46552
  case "UNDO":
46534
46553
  case "REDO": {
46535
- this.unusedPivots = undefined;
46554
+ this.unusedPivotsInFormulas = undefined;
46536
46555
  const pivotCommands = cmd.commands.filter(isPivotCommand);
46537
46556
  for (const cmd of pivotCommands) {
46538
46557
  const pivotId = cmd.pivotId;
@@ -46691,7 +46710,9 @@ stores.inject(MyMetaStore, storeInstance);
46691
46710
  return this.pivots[pivotId];
46692
46711
  }
46693
46712
  isPivotUnused(pivotId) {
46694
- return this._getUnusedPivots().includes(pivotId);
46713
+ const { type } = this.getters.getPivot(pivotId);
46714
+ return (this._getUnusedPivotsInFormulas().includes(pivotId) &&
46715
+ pivotRegistry.get(type).isPivotUnused(this.getters, pivotId));
46695
46716
  }
46696
46717
  getPivotCellSortDirection(position) {
46697
46718
  const pivotId = this.getters.getPivotIdFromPosition(position);
@@ -46727,9 +46748,9 @@ stores.inject(MyMetaStore, storeInstance);
46727
46748
  this.pivots[pivotId].onDefinitionChange(definition);
46728
46749
  }
46729
46750
  }
46730
- _getUnusedPivots() {
46731
- if (this.unusedPivots !== undefined) {
46732
- return this.unusedPivots;
46751
+ _getUnusedPivotsInFormulas() {
46752
+ if (this.unusedPivotsInFormulas !== undefined) {
46753
+ return this.unusedPivotsInFormulas;
46733
46754
  }
46734
46755
  const unusedPivots = new Set(this.getters.getPivotIds());
46735
46756
  for (const sheetId of this.getters.getSheetIds()) {
@@ -46739,14 +46760,14 @@ stores.inject(MyMetaStore, storeInstance);
46739
46760
  if (pivotId) {
46740
46761
  unusedPivots.delete(pivotId);
46741
46762
  if (!unusedPivots.size) {
46742
- this.unusedPivots = [];
46763
+ this.unusedPivotsInFormulas = [];
46743
46764
  return [];
46744
46765
  }
46745
46766
  }
46746
46767
  }
46747
46768
  }
46748
- this.unusedPivots = [...unusedPivots];
46749
- return this.unusedPivots;
46769
+ this.unusedPivotsInFormulas = [...unusedPivots];
46770
+ return this.unusedPivotsInFormulas;
46750
46771
  }
46751
46772
  }
46752
46773
 
@@ -52151,6 +52172,7 @@ stores.inject(MyMetaStore, storeInstance);
52151
52172
  "getVisibleFigures",
52152
52173
  "getVisibleRect",
52153
52174
  "getVisibleRectWithoutHeaders",
52175
+ "getVisibleRectWithZoom",
52154
52176
  "getVisibleCellPositions",
52155
52177
  "getColRowOffsetInViewport",
52156
52178
  "getMainViewportCoordinates",
@@ -52166,6 +52188,8 @@ stores.inject(MyMetaStore, storeInstance);
52166
52188
  "getFigureUI",
52167
52189
  "getPositionAnchorOffset",
52168
52190
  "getGridOffset",
52191
+ "getViewportZoomLevel",
52192
+ "getScrollBarWidth",
52169
52193
  ];
52170
52194
  viewports = {};
52171
52195
  /**
@@ -52178,6 +52202,7 @@ stores.inject(MyMetaStore, storeInstance);
52178
52202
  sheetViewHeight = getDefaultSheetViewSize();
52179
52203
  gridOffsetX = 0;
52180
52204
  gridOffsetY = 0;
52205
+ zoomLevel = 1;
52181
52206
  sheetsWithDirtyViewports = new Set();
52182
52207
  shouldAdjustViewports = false;
52183
52208
  // ---------------------------------------------------------------------------
@@ -52244,6 +52269,9 @@ stores.inject(MyMetaStore, storeInstance);
52244
52269
  case "SET_VIEWPORT_OFFSET":
52245
52270
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
52246
52271
  break;
52272
+ case "SET_ZOOM":
52273
+ this.zoomLevel = cmd.zoom || 1;
52274
+ break;
52247
52275
  case "SHIFT_VIEWPORT_DOWN":
52248
52276
  const sheetId = this.getters.getActiveSheetId();
52249
52277
  const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
@@ -52447,7 +52475,7 @@ stores.inject(MyMetaStore, storeInstance);
52447
52475
  for (const i of relevantIndexes) {
52448
52476
  offset += this.getters.getHeaderSize(sheetId, dimension, i);
52449
52477
  }
52450
- return offset;
52478
+ return offset * this.zoomLevel;
52451
52479
  }
52452
52480
  /**
52453
52481
  * Check if a given position is visible in the viewport.
@@ -52455,6 +52483,9 @@ stores.inject(MyMetaStore, storeInstance);
52455
52483
  isVisibleInViewport({ sheetId, col, row }) {
52456
52484
  return this.getSubViewports(sheetId).some((pane) => pane.isVisible(col, row));
52457
52485
  }
52486
+ getScrollBarWidth() {
52487
+ return SCROLLBAR_WIDTH / this.zoomLevel;
52488
+ }
52458
52489
  // => returns the new offset
52459
52490
  getEdgeScrollCol(x, previousX, startingX) {
52460
52491
  let canEdgeScroll = false;
@@ -52533,6 +52564,18 @@ stores.inject(MyMetaStore, storeInstance);
52533
52564
  const rect = this.getVisibleRectWithoutHeaders(zone);
52534
52565
  return { ...rect, x: rect.x + this.gridOffsetX, y: rect.y + this.gridOffsetY };
52535
52566
  }
52567
+ /**
52568
+ * Computes the coordinates and size to draw the zone on the canvas after it has been zoomed
52569
+ */
52570
+ getVisibleRectWithZoom(zone) {
52571
+ const zoom = this.getViewportZoomLevel();
52572
+ const rect = this.getVisibleRectWithoutHeaders(zone);
52573
+ rect.width = rect.width * zoom;
52574
+ rect.height = rect.height * zoom;
52575
+ rect.x = rect.x * zoom + this.gridOffsetX * zoom;
52576
+ rect.y = rect.y * zoom + this.gridOffsetY * zoom;
52577
+ return rect;
52578
+ }
52536
52579
  /**
52537
52580
  * Computes the coordinates and size to draw the zone without taking the grid offset into account
52538
52581
  */
@@ -52614,6 +52657,9 @@ stores.inject(MyMetaStore, storeInstance);
52614
52657
  };
52615
52658
  });
52616
52659
  }
52660
+ getViewportZoomLevel() {
52661
+ return this.zoomLevel;
52662
+ }
52617
52663
  // ---------------------------------------------------------------------------
52618
52664
  // Private
52619
52665
  // ---------------------------------------------------------------------------
@@ -58261,22 +58307,26 @@ stores.inject(MyMetaStore, storeInstance);
58261
58307
  }
58262
58308
  onPointerDownInMasterChart(ev) {
58263
58309
  this.removeEventListeners();
58264
- const position = ev.offsetX;
58310
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58311
+ const position = zoomedEvent.offsetX;
58265
58312
  if (!this.masterChart?.chartArea || !this.chart?.scales?.x) {
58266
58313
  return;
58267
58314
  }
58268
58315
  const { left, right, top, bottom } = this.masterChart.chartArea;
58269
58316
  const xMax = this.upperBound ?? right;
58270
58317
  const xMin = this.lowerBound ?? left;
58271
- if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
58318
+ if (position < left - 5 ||
58319
+ position > right + 5 ||
58320
+ zoomedEvent.offsetY < top ||
58321
+ zoomedEvent.offsetY > bottom) {
58272
58322
  return;
58273
58323
  }
58274
58324
  ev.preventDefault();
58275
58325
  ev.stopPropagation();
58276
58326
  let startingPositionOnChart, windowSize, startX;
58277
- const startingEventPosition = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58327
+ const startingEventPosition = position;
58278
58328
  if ((xMin !== left || xMax !== right) && position > xMin + 5 && position < xMax - 5) {
58279
- startingPositionOnChart = ev.offsetX - xMin;
58329
+ startingPositionOnChart = zoomedEvent.offsetX - xMin;
58280
58330
  this.mode = "moveInMaster";
58281
58331
  const currentLimits = this.store.currentAxesLimits[this.chartId]?.x;
58282
58332
  windowSize =
@@ -58325,7 +58375,8 @@ stores.inject(MyMetaStore, storeInstance);
58325
58375
  return { min: xMin, max: xMax };
58326
58376
  };
58327
58377
  const onDragFromMasterChart = (ev) => {
58328
- const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58378
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58379
+ const position = zoomedEvent.offsetX;
58329
58380
  if (Math.abs(position - startingEventPosition) < 5) {
58330
58381
  return;
58331
58382
  }
@@ -58336,7 +58387,8 @@ stores.inject(MyMetaStore, storeInstance);
58336
58387
  };
58337
58388
  const onPointerUpInMasterChart = (ev) => {
58338
58389
  this.removeEventListeners();
58339
- const position = ev.clientX - (this.masterChartCanvas.el?.getBoundingClientRect().left ?? 0);
58390
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58391
+ const position = zoomedEvent.offsetX;
58340
58392
  if (Math.abs(position - startingEventPosition) > 5) {
58341
58393
  let { min: xMin, max: xMax } = computeNewAxisLimits(position);
58342
58394
  if (xMin !== undefined && xMax !== undefined) {
@@ -58363,7 +58415,7 @@ stores.inject(MyMetaStore, storeInstance);
58363
58415
  window.addEventListener("pointerup", onPointerUpInMasterChart, true);
58364
58416
  }
58365
58417
  onPointerMoveInMasterChart(ev) {
58366
- const { offsetX: x, offsetY: y } = ev;
58418
+ const { offsetX: x, offsetY: y } = withZoom(this.env, ev, ev.target?.getBoundingClientRect());
58367
58419
  if (this.mode === undefined) {
58368
58420
  const target = ev.target;
58369
58421
  if (!this.masterChart?.chartArea) {
@@ -58396,7 +58448,8 @@ stores.inject(MyMetaStore, storeInstance);
58396
58448
  }
58397
58449
  onDoubleClickInMasterChart(ev) {
58398
58450
  this.mode = undefined;
58399
- const position = ev.offsetX;
58451
+ const zoomedEvent = withZoom(this.env, ev, this.masterChartCanvas.el?.getBoundingClientRect());
58452
+ const position = zoomedEvent.offsetX;
58400
58453
  if (!this.masterChart?.chartArea || !this.chart?.scales.x) {
58401
58454
  return;
58402
58455
  }
@@ -58406,7 +58459,10 @@ stores.inject(MyMetaStore, storeInstance);
58406
58459
  if (upperBound < lowerBound) {
58407
58460
  [upperBound, lowerBound] = [lowerBound, upperBound];
58408
58461
  }
58409
- if (position < left - 5 || position > right + 5 || ev.offsetY < top || ev.offsetY > bottom) {
58462
+ if (position < left - 5 ||
58463
+ position > right + 5 ||
58464
+ zoomedEvent.offsetY < top ||
58465
+ zoomedEvent.offsetY > bottom) {
58410
58466
  return;
58411
58467
  }
58412
58468
  ev.preventDefault();
@@ -58841,7 +58897,7 @@ stores.inject(MyMetaStore, storeInstance);
58841
58897
  });
58842
58898
  }
58843
58899
  drawGaugeWithAnimation() {
58844
- drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue: 0 });
58900
+ drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue: 0 }, undefined);
58845
58901
  const gaugeValue = this.runtime.gaugeValue?.value || 0;
58846
58902
  const upperBound = this.runtime.maxValue.value;
58847
58903
  const finalValue = Math.sign(gaugeValue) * Math.min(Math.abs(gaugeValue), Math.abs(upperBound));
@@ -58849,7 +58905,7 @@ stores.inject(MyMetaStore, storeInstance);
58849
58905
  return null;
58850
58906
  }
58851
58907
  const lowerBound = this.runtime.minValue.value;
58852
- const animation = new Animation(lowerBound, finalValue, ANIMATION_DURATION, (animationValue) => drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue }));
58908
+ const animation = new Animation(lowerBound, finalValue, ANIMATION_DURATION, (animationValue) => drawGaugeChart(this.canvasEl, { ...this.runtime, animationValue }, undefined));
58853
58909
  animation.start();
58854
58910
  return animation;
58855
58911
  }
@@ -60069,7 +60125,13 @@ stores.inject(MyMetaStore, storeInstance);
60069
60125
  onContextMenu(ev) {
60070
60126
  if (this.env.isDashboard())
60071
60127
  return;
60072
- this.openContextMenu({ x: ev.clientX, y: ev.clientY, width: 0, height: 0 });
60128
+ const zoomedMouseEvent = withZoom(this.env, ev);
60129
+ this.openContextMenu({
60130
+ x: zoomedMouseEvent.clientX,
60131
+ y: zoomedMouseEvent.clientY,
60132
+ width: 0,
60133
+ height: 0,
60134
+ });
60073
60135
  }
60074
60136
  showMenu() {
60075
60137
  this.openContextMenu(getRefBoundingRect(this.menuButtonRef));
@@ -61905,7 +61967,7 @@ stores.inject(MyMetaStore, storeInstance);
61905
61967
  else {
61906
61968
  text += NEWLINE;
61907
61969
  }
61908
- emptyParagraph = ["<br>", "<span><br></span>"].includes(current.value.innerHTML);
61970
+ emptyParagraph = isEmptyParagraph(current.value);
61909
61971
  continue;
61910
61972
  }
61911
61973
  if (!current.value.hasChildNodes()) {
@@ -61926,12 +61988,28 @@ stores.inject(MyMetaStore, storeInstance);
61926
61988
  const sameContent = node.innerText === content.value;
61927
61989
  return sameColor && sameClass && sameContent;
61928
61990
  }
61991
+ const doc = new DOMParser();
61992
+ const brNode = doc.parseFromString("<br>", "text/html").body.firstChild;
61993
+ const spanBrNode = doc.parseFromString("<span><br></span>", "text/html").body.firstChild;
61994
+ function isEmptyParagraph(node) {
61995
+ if (node.childNodes.length > 1)
61996
+ return false;
61997
+ const node2 = node.firstChild?.cloneNode(true);
61998
+ if (!node2)
61999
+ return true;
62000
+ if (!(node2 instanceof Element))
62001
+ return false;
62002
+ node2.removeAttribute("class");
62003
+ node2.removeAttribute("style");
62004
+ return node2.isEqualNode(brNode) || node2.isEqualNode(spanBrNode) || false;
62005
+ }
61929
62006
 
61930
62007
  class FunctionDescriptionProvider extends owl.Component {
61931
62008
  static template = "o-spreadsheet-FunctionDescriptionProvider";
61932
62009
  static props = {
61933
62010
  functionDescription: Object,
61934
62011
  argsToFocus: Array,
62012
+ repeatingArgGroupIndex: { type: Number, optional: true },
61935
62013
  };
61936
62014
  static components = { Collapse };
61937
62015
  state = owl.useState({
@@ -61943,8 +62021,70 @@ stores.inject(MyMetaStore, storeInstance);
61943
62021
  getContext() {
61944
62022
  return this.props;
61945
62023
  }
61946
- get formulaArgSeparator() {
61947
- return this.env.model.getters.getLocale().formulaArgSeparator + " ";
62024
+ get formulaHeaderContent() {
62025
+ const { functionDescription, repeatingArgGroupIndex, argsToFocus } = this.props;
62026
+ const argSeparator = this.env.model.getters.getLocale().formulaArgSeparator + " ";
62027
+ const result = [
62028
+ { content: functionDescription.name + " ( " },
62029
+ ];
62030
+ for (let i = 0; i < functionDescription.args.length; i++) {
62031
+ const arg = functionDescription.args[i];
62032
+ const isRepeating = arg.repeating;
62033
+ if (i > 0) {
62034
+ result.push({ content: argSeparator });
62035
+ }
62036
+ if (isRepeating) {
62037
+ // treat all repeating args in one go
62038
+ const displayBrackets = arg.optional || (repeatingArgGroupIndex ?? 0) > 0;
62039
+ const repeatingArgNames = functionDescription.args
62040
+ .slice(i, i + functionDescription.nbrArgRepeating)
62041
+ .map((arg) => arg.name);
62042
+ if (repeatingArgGroupIndex) {
62043
+ result.push({ content: "... " + argSeparator });
62044
+ }
62045
+ if (displayBrackets) {
62046
+ result.push({ content: "[" });
62047
+ }
62048
+ for (let idx = 0; idx < repeatingArgNames.length; idx++) {
62049
+ const name = repeatingArgNames[idx];
62050
+ const argIndex = i + idx;
62051
+ const focused = argsToFocus.includes(argIndex);
62052
+ result.push({ content: name + ((repeatingArgGroupIndex ?? 0) + 1), focused });
62053
+ // Add separator after each element except the last
62054
+ if (idx < repeatingArgNames.length - 1) {
62055
+ result.push({ content: argSeparator });
62056
+ }
62057
+ }
62058
+ if (displayBrackets) {
62059
+ result.push({ content: "]" });
62060
+ }
62061
+ result.push({ content: argSeparator + "[" });
62062
+ for (let idx = 0; idx < repeatingArgNames.length; idx++) {
62063
+ const name = repeatingArgNames[idx];
62064
+ result.push({ content: name + ((repeatingArgGroupIndex ?? 0) + 2) });
62065
+ // Add separator after each element except the last
62066
+ if (idx < repeatingArgNames.length - 1) {
62067
+ result.push({ content: argSeparator });
62068
+ }
62069
+ }
62070
+ result.push({ content: "]" + argSeparator + "... " });
62071
+ // Skip the processed repeating args
62072
+ i += functionDescription.nbrArgRepeating - 1;
62073
+ }
62074
+ else {
62075
+ const displayBrackets = arg.optional || arg.default;
62076
+ const focused = argsToFocus.includes(i);
62077
+ if (displayBrackets) {
62078
+ result.push({ content: "[" });
62079
+ }
62080
+ result.push({ content: arg.name, focused });
62081
+ if (displayBrackets) {
62082
+ result.push({ content: "]" });
62083
+ }
62084
+ }
62085
+ }
62086
+ result.push({ content: " )" });
62087
+ return result;
61948
62088
  }
61949
62089
  }
61950
62090
 
@@ -62014,6 +62154,7 @@ stores.inject(MyMetaStore, storeInstance);
62014
62154
  showDescription: false,
62015
62155
  functionDescription: {},
62016
62156
  argsToFocus: [],
62157
+ repeatingArgGroupIndex: 0,
62017
62158
  });
62018
62159
  assistant = owl.useState({
62019
62160
  forcedClosed: false,
@@ -62552,9 +62693,21 @@ stores.inject(MyMetaStore, storeInstance);
62552
62693
  const isParenthesisClosed = this.props.composerStore.currentTokens.some((t) => t.type === "RIGHT_PAREN" && t.parenthesesCode === token.parenthesesCode);
62553
62694
  this.functionDescriptionState.argsToFocus = this.getArgsToFocus(isParenthesisClosed, description, nbrArgSupplied, argPosition);
62554
62695
  this.functionDescriptionState.showDescription = true;
62696
+ this.functionDescriptionState.repeatingArgGroupIndex = this.getRepeatingArgGroupIndex(description, nbrArgSupplied, argPosition);
62555
62697
  }
62556
62698
  }
62557
62699
  }
62700
+ getRepeatingArgGroupIndex(description, nbrArgSupplied, argPosition) {
62701
+ const { minArgRequired, maxArgPossible, nbrArgRepeating } = description;
62702
+ if (!nbrArgRepeating) {
62703
+ return undefined;
62704
+ }
62705
+ const groupsOfOptionalRepeatingValues = nbrArgRepeating
62706
+ ? Math.ceil((nbrArgSupplied - minArgRequired) / nbrArgRepeating)
62707
+ : 0;
62708
+ const nbrArgSuppliedRoundedToGroupOfRepeating = groupsOfOptionalRepeatingValues * nbrArgRepeating + minArgRequired;
62709
+ return (argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSuppliedRoundedToGroupOfRepeating), minArgRequired))(argPosition).repeatingGroupIndex ?? 0);
62710
+ }
62558
62711
  /**
62559
62712
  * Compute the arguments to focus depending on the current value position.
62560
62713
  *
@@ -62564,11 +62717,11 @@ stores.inject(MyMetaStore, storeInstance);
62564
62717
  * This function computes all the possible arguments to focus for different numbers of arguments supplied.
62565
62718
  */
62566
62719
  getArgsToFocus(isParenthesisClosed, description, nbrArgSupplied, argPosition) {
62567
- const { nbrArgRepeating, minArgRequired, nbrArgOptional, maxArgPossible } = description;
62720
+ const { nbrArgRepeating, minArgRequired, nbrOptionalNonRepeatingArgs, maxArgPossible } = description;
62568
62721
  // When the parenthesis is closed, we consider the user is done with the function,
62569
62722
  // so we know exactly the number of arguments supplied.
62570
62723
  if (isParenthesisClosed) {
62571
- const focusedArg = argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSupplied), minArgRequired))(argPosition);
62724
+ const focusedArg = argTargeting(description, Math.max(Math.min(maxArgPossible, nbrArgSupplied), minArgRequired))(argPosition)?.index;
62572
62725
  return focusedArg !== undefined ? [focusedArg] : [];
62573
62726
  }
62574
62727
  // Otherwise, the user is still typing the formula, so we don't know yet how many arguments the user will supply.
@@ -62577,11 +62730,11 @@ stores.inject(MyMetaStore, storeInstance);
62577
62730
  const maxArgsNumberPossibility = nbrArgRepeating
62578
62731
  ? minArgRequired +
62579
62732
  Math.ceil((minArgsNumberPossibility - minArgRequired) / nbrArgRepeating) * nbrArgRepeating +
62580
- nbrArgOptional
62733
+ nbrOptionalNonRepeatingArgs
62581
62734
  : maxArgPossible;
62582
62735
  const argsToFocus = [];
62583
62736
  for (let i = minArgsNumberPossibility; i <= maxArgsNumberPossibility; i++) {
62584
- const focusedArg = argTargeting(description, i)(argPosition);
62737
+ const focusedArg = argTargeting(description, i)(argPosition)?.index;
62585
62738
  if (focusedArg !== undefined) {
62586
62739
  argsToFocus.push(focusedArg);
62587
62740
  }
@@ -67486,6 +67639,17 @@ stores.inject(MyMetaStore, storeInstance);
67486
67639
  isReadonlyAllowed: true,
67487
67640
  icon: "o-spreadsheet-Icon.IRREGULARITY_MAP",
67488
67641
  };
67642
+ function zoomAction(zoom) {
67643
+ return {
67644
+ name: _t$1("%(zoom_percentage)s%", { zoom_percentage: zoom }),
67645
+ execute: (env) => {
67646
+ env.model.dispatch("SET_ZOOM", { zoom: zoom / 100 });
67647
+ },
67648
+ isActive: (env) => env.model.getters.getViewportZoomLevel() === zoom / 100,
67649
+ isReadonlyAllowed: true,
67650
+ sequence: zoom,
67651
+ };
67652
+ }
67489
67653
  const viewFormulas = {
67490
67654
  name: _t$1("Formulas"),
67491
67655
  isActive: (env) => env.model.getters.shouldShowFormulas(),
@@ -69612,13 +69776,14 @@ stores.inject(MyMetaStore, storeInstance);
69612
69776
  }
69613
69777
  const sheetId = getters.getActiveSheetId();
69614
69778
  const position = gridOverlayPosition();
69779
+ const zoomedMouseEvent = withZoom(env, currentEv, position);
69615
69780
  const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
69616
69781
  const { top, left, bottom, right } = getters.getActiveMainViewport();
69617
69782
  let { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
69618
69783
  const { xSplit, ySplit } = getters.getPaneDivisions(sheetId);
69619
69784
  let canEdgeScroll = false;
69620
69785
  let timeoutDelay = MAX_DELAY;
69621
- const x = currentEv.clientX - position.left;
69786
+ const x = zoomedMouseEvent.clientX - position.left;
69622
69787
  let colIndex = getters.getColIndex(x);
69623
69788
  if (scrollDirection !== "vertical") {
69624
69789
  const previousX = previousEvClientPosition.clientX - position.left;
@@ -69646,7 +69811,7 @@ stores.inject(MyMetaStore, storeInstance);
69646
69811
  scrollX = getters.getColDimensions(sheetId, newTarget).start - offsetCorrectionX;
69647
69812
  }
69648
69813
  }
69649
- const y = currentEv.clientY - position.top;
69814
+ const y = zoomedMouseEvent.clientY - position.top;
69650
69815
  let rowIndex = getters.getRowIndex(y);
69651
69816
  if (scrollDirection !== "horizontal") {
69652
69817
  const previousY = previousEvClientPosition.clientY - position.top;
@@ -69686,7 +69851,10 @@ stores.inject(MyMetaStore, storeInstance);
69686
69851
  pointerMoveHandler(currentEv);
69687
69852
  }, Math.round(timeoutDelay));
69688
69853
  }
69689
- previousEvClientPosition = { clientX: currentEv.clientX, clientY: currentEv.clientY };
69854
+ previousEvClientPosition = {
69855
+ clientX: zoomedMouseEvent.clientX,
69856
+ clientY: zoomedMouseEvent.clientY,
69857
+ };
69690
69858
  };
69691
69859
  const pointerUpHandler = () => {
69692
69860
  pointerUpCallback?.();
@@ -69728,30 +69896,30 @@ stores.inject(MyMetaStore, storeInstance);
69728
69896
  isVisible: Boolean,
69729
69897
  };
69730
69898
  state = owl.useState({
69731
- position: { left: 0, top: 0 },
69899
+ position: { x: 0, y: 0 },
69732
69900
  handler: false,
69733
69901
  });
69734
69902
  dragNDropGrid = useDragAndDropBeyondTheViewport(this.env);
69735
69903
  get style() {
69736
- const { left, top } = this.props.position;
69904
+ const { x, y } = this.props.position;
69737
69905
  return cssPropertiesToCss({
69738
- top: `${top}px`,
69739
- left: `${left}px`,
69906
+ top: `${y}px`,
69907
+ left: `${x}px`,
69740
69908
  visibility: this.props.isVisible ? "visible" : "hidden",
69741
69909
  });
69742
69910
  }
69743
69911
  get handlerStyle() {
69744
- const { left, top } = this.state.handler ? this.state.position : this.props.position;
69912
+ const { x, y } = this.state.handler ? this.state.position : this.props.position;
69745
69913
  return cssPropertiesToCss({
69746
- top: `${top}px`,
69747
- left: `${left}px`,
69914
+ top: `${y}px`,
69915
+ left: `${x}px`,
69748
69916
  });
69749
69917
  }
69750
69918
  get styleNextValue() {
69751
- const { left, top } = this.state.position;
69919
+ const { x, y } = this.state.position;
69752
69920
  return cssPropertiesToCss({
69753
- top: `${top + 5}px`,
69754
- left: `${left + 15}px`,
69921
+ top: `${y + 5}px`,
69922
+ left: `${x + 15}px`,
69755
69923
  });
69756
69924
  }
69757
69925
  getTooltip() {
@@ -69763,11 +69931,13 @@ stores.inject(MyMetaStore, storeInstance);
69763
69931
  }
69764
69932
  onMouseDown(ev) {
69765
69933
  this.state.handler = true;
69934
+ const zoomedMouseEvent = withZoom(this.env, ev);
69935
+ const zoom = this.env.model.getters.getViewportZoomLevel();
69766
69936
  let lastCol;
69767
69937
  let lastRow;
69768
69938
  const start = {
69769
- left: ev.clientX - this.props.position.left,
69770
- top: ev.clientY - this.props.position.top,
69939
+ x: ev.clientX / zoom - this.props.position.x,
69940
+ y: ev.clientY / zoom - this.props.position.y,
69771
69941
  };
69772
69942
  const onMouseUp = () => {
69773
69943
  this.state.handler = false;
@@ -69776,8 +69946,8 @@ stores.inject(MyMetaStore, storeInstance);
69776
69946
  };
69777
69947
  const onMouseMove = (col, row, ev) => {
69778
69948
  this.state.position = {
69779
- left: ev.clientX - start.left,
69780
- top: ev.clientY - start.top,
69949
+ x: ev.clientX / zoom - start.x,
69950
+ y: ev.clientY / zoom - start.y,
69781
69951
  };
69782
69952
  if (lastCol !== col || lastRow !== row) {
69783
69953
  const activeSheetId = this.env.model.getters.getActiveSheetId();
@@ -69790,7 +69960,7 @@ stores.inject(MyMetaStore, storeInstance);
69790
69960
  }
69791
69961
  }
69792
69962
  };
69793
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
69963
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
69794
69964
  }
69795
69965
  onDblClick() {
69796
69966
  this.env.model.dispatch("AUTOFILL_AUTO");
@@ -70725,7 +70895,8 @@ stores.inject(MyMetaStore, storeInstance);
70725
70895
  return;
70726
70896
  }
70727
70897
  const sheetId = this.env.model.getters.getActiveSheetId();
70728
- const initialMousePosition = { x: ev.clientX, y: ev.clientY };
70898
+ const zoom = this.env.model.getters.getViewportZoomLevel();
70899
+ const initialMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70729
70900
  const initialScrollPosition = this.env.model.getters.getActiveSheetScrollInfo();
70730
70901
  const initialFigure = this.toBottomRightViewport(figureUI);
70731
70902
  const maxDimensions = {
@@ -70735,7 +70906,7 @@ stores.inject(MyMetaStore, storeInstance);
70735
70906
  let hasStartedDnd = false;
70736
70907
  const onMouseMove = (ev) => {
70737
70908
  const getters = this.env.model.getters;
70738
- const currentMousePosition = { x: ev.clientX, y: ev.clientY };
70909
+ const currentMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70739
70910
  const offsetX = Math.abs(currentMousePosition.x - initialMousePosition.x);
70740
70911
  const offsetY = Math.abs(currentMousePosition.y - initialMousePosition.y);
70741
70912
  if (!hasStartedDnd && offsetX < DRAG_THRESHOLD && offsetY < DRAG_THRESHOLD) {
@@ -70798,17 +70969,18 @@ stores.inject(MyMetaStore, storeInstance);
70798
70969
  */
70799
70970
  startResize(figureUI, dirX, dirY, ev) {
70800
70971
  ev.stopPropagation();
70801
- const initialMousePosition = { x: ev.clientX, y: ev.clientY };
70802
70972
  const initialScrollPosition = this.env.model.getters.getActiveSheetScrollInfo();
70803
70973
  const keepRatio = figureRegistry.get(figureUI.tag).keepRatio || false;
70804
70974
  const minFigSize = figureRegistry.get(figureUI.tag).minFigSize || MIN_FIG_SIZE;
70975
+ const zoom = this.env.model.getters.getViewportZoomLevel();
70805
70976
  const sheetId = this.env.model.getters.getActiveSheetId();
70977
+ const initialMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70806
70978
  const maxDimensions = {
70807
70979
  maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
70808
70980
  maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
70809
70981
  };
70810
70982
  const onMouseMove = (ev) => {
70811
- const currentMousePosition = { x: ev.clientX, y: ev.clientY };
70983
+ const currentMousePosition = { x: ev.clientX / zoom, y: ev.clientY / zoom };
70812
70984
  const draggedFigure = dragFigureForResize(figureUI, dirX, dirY, currentMousePosition, initialMousePosition, keepRatio, minFigSize, initialScrollPosition, this.env.model.getters.getActiveSheetScrollInfo(), maxDimensions);
70813
70985
  const otherFigures = this.getOtherFigures(figureUI.id);
70814
70986
  const snapResult = snapForResize(this.env.model.getters, dirX, dirY, draggedFigure, otherFigures);
@@ -71220,11 +71392,11 @@ stores.inject(MyMetaStore, storeInstance);
71220
71392
  const row = env.model.getters.getRowIndex(y);
71221
71393
  return { col, row };
71222
71394
  }
71223
- function getOffsetRelativeToOverlay(ev) {
71395
+ function getOffsetRelativeToOverlay(zoomedMouseEvent) {
71224
71396
  const gridRect = getBoundingRectAsPOJO(gridRef.el);
71225
71397
  return {
71226
- x: ev.clientX - gridRect.x,
71227
- y: ev.clientY - gridRect.y,
71398
+ x: zoomedMouseEvent.clientX - gridRect.x,
71399
+ y: zoomedMouseEvent.clientY - gridRect.y,
71228
71400
  };
71229
71401
  }
71230
71402
  const { pause, resume } = useInterval(checkTiming, 200);
@@ -71241,9 +71413,9 @@ stores.inject(MyMetaStore, storeInstance);
71241
71413
  setPosition(col, row);
71242
71414
  }
71243
71415
  }
71244
- function updateMousePosition(e) {
71245
- if (isChildEvent(gridRef.el, e)) {
71246
- ({ x, y } = getOffsetRelativeToOverlay(e));
71416
+ function updateMousePosition(zoomedMouseEvent) {
71417
+ if (isChildEvent(gridRef.el, zoomedMouseEvent.ev)) {
71418
+ ({ x, y } = getOffsetRelativeToOverlay(zoomedMouseEvent));
71247
71419
  lastMoved = Date.now();
71248
71420
  hoveredTable.hover(getPosition());
71249
71421
  }
@@ -71255,20 +71427,21 @@ stores.inject(MyMetaStore, storeInstance);
71255
71427
  }
71256
71428
  }
71257
71429
  function onMouseLeave(e) {
71258
- const { x, y } = getOffsetRelativeToOverlay(e);
71430
+ const zoomedMouseEvent = withZoom(env, e);
71431
+ const { x, y } = getOffsetRelativeToOverlay(zoomedMouseEvent);
71259
71432
  const gridRect = getBoundingRectAsPOJO(gridRef.el);
71260
71433
  if (y < 0 || y > gridRect.height || x < 0 || x > gridRect.width) {
71261
- return updateMousePosition(e);
71434
+ return updateMousePosition(zoomedMouseEvent);
71262
71435
  }
71263
71436
  else {
71264
71437
  return pause();
71265
71438
  }
71266
71439
  }
71267
- useRefListener(gridRef, "pointermove", (ev) => !env.isMobile() && updateMousePosition(ev));
71440
+ useRefListener(gridRef, "pointermove", (ev) => !env.isMobile() && updateMousePosition(withZoom(env, ev)));
71268
71441
  useRefListener(gridRef, "mouseleave", onMouseLeave);
71269
71442
  useRefListener(gridRef, "mouseenter", resume);
71270
71443
  useRefListener(gridRef, "pointerdown", recompute);
71271
- useRefListener(gridRef, "pointerdown", (ev) => env.isMobile() && updateMousePosition(ev));
71444
+ useRefListener(gridRef, "pointerdown", (ev) => env.isMobile() && updateMousePosition(withZoom(env, ev)));
71272
71445
  owl.useExternalListener(window, "click", handleGlobalClick);
71273
71446
  function handleGlobalClick(e) {
71274
71447
  const target = e.target;
@@ -71353,7 +71526,7 @@ stores.inject(MyMetaStore, storeInstance);
71353
71526
  if (this.env.isMobile()) {
71354
71527
  return;
71355
71528
  }
71356
- const icon = this.getInteractiveIconAtEvent(ev);
71529
+ const icon = this.getInteractiveIconAtEvent(withZoom(this.env, ev));
71357
71530
  const hoveredIcon = icon?.type ? { id: icon.type, position: icon.position } : undefined;
71358
71531
  if (!deepEquals$1(hoveredIcon, this.hoveredIconStore.hoveredIcon)) {
71359
71532
  this.hoveredIconStore.setHoveredIcon(hoveredIcon);
@@ -71364,30 +71537,30 @@ stores.inject(MyMetaStore, storeInstance);
71364
71537
  // not main button, probably a context menu
71365
71538
  return;
71366
71539
  }
71367
- this.onCellClicked(ev);
71540
+ this.onCellClicked(withZoom(this.env, ev));
71368
71541
  }
71369
71542
  onClick(ev) {
71370
71543
  if (ev.button > 0 || !this.env.isMobile()) {
71371
71544
  // not main button, probably a context menu
71372
71545
  return;
71373
71546
  }
71374
- this.onCellClicked(ev);
71547
+ this.onCellClicked(withZoom(this.env, ev));
71375
71548
  }
71376
- onCellClicked(ev) {
71549
+ onCellClicked(zoomedMouseEvent) {
71377
71550
  const openedPopover = this.cellPopovers.persistentCellPopover;
71378
- const [col, row] = this.getCartesianCoordinates(ev);
71379
- const clickedIcon = this.getInteractiveIconAtEvent(ev);
71551
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71552
+ const clickedIcon = this.getInteractiveIconAtEvent(zoomedMouseEvent);
71380
71553
  if (clickedIcon) {
71381
71554
  this.env.model.selection.getBackToDefault();
71382
71555
  }
71383
71556
  this.props.onCellClicked(col, row, {
71384
- expandZone: ev.shiftKey,
71385
- addZone: isCtrlKey(ev),
71386
- }, ev);
71557
+ expandZone: zoomedMouseEvent.ev.shiftKey,
71558
+ addZone: isCtrlKey(zoomedMouseEvent.ev),
71559
+ }, zoomedMouseEvent);
71387
71560
  if (clickedIcon?.onClick) {
71388
71561
  clickedIcon.onClick(clickedIcon.position, this.env);
71389
71562
  }
71390
- if (ev.target === this.gridOverlay.el &&
71563
+ if (zoomedMouseEvent.ev.target === this.gridOverlay.el &&
71391
71564
  this.cellPopovers.isOpen &&
71392
71565
  deepEquals$1(openedPopover, this.cellPopovers.persistentCellPopover)) {
71393
71566
  // Only close the popover if props.click/icon.click didn't open a new one
@@ -71396,30 +71569,28 @@ stores.inject(MyMetaStore, storeInstance);
71396
71569
  }
71397
71570
  }
71398
71571
  onDoubleClick(ev) {
71399
- if (this.getInteractiveIconAtEvent(ev)) {
71572
+ const zoomedMouseEvent = withZoom(this.env, ev);
71573
+ if (this.getInteractiveIconAtEvent(zoomedMouseEvent)) {
71400
71574
  return;
71401
71575
  }
71402
- const [col, row] = this.getCartesianCoordinates(ev);
71576
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71403
71577
  this.props.onCellDoubleClicked(col, row);
71404
71578
  }
71405
71579
  onContextMenu(ev) {
71406
- const [col, row] = this.getCartesianCoordinates(ev);
71580
+ const [col, row] = this.getCartesianCoordinates(withZoom(this.env, ev));
71407
71581
  this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
71408
71582
  }
71409
- getCartesianCoordinates(ev) {
71410
- const gridOverLayRect = getRefBoundingRect(this.gridOverlay);
71411
- const x = ev.clientX - gridOverLayRect.x;
71412
- const y = ev.clientY - gridOverLayRect.y;
71413
- const colIndex = this.env.model.getters.getColIndex(x);
71414
- const rowIndex = this.env.model.getters.getRowIndex(y);
71583
+ getCartesianCoordinates(zoomedMouseEvent) {
71584
+ const colIndex = this.env.model.getters.getColIndex(zoomedMouseEvent.offsetX);
71585
+ const rowIndex = this.env.model.getters.getRowIndex(zoomedMouseEvent.offsetY);
71415
71586
  return [colIndex, rowIndex];
71416
71587
  }
71417
- getInteractiveIconAtEvent(ev) {
71588
+ getInteractiveIconAtEvent(zoomedMouseEvent) {
71418
71589
  const gridOverLayRect = getRefBoundingRect(this.gridOverlay);
71419
71590
  const gridOffset = this.env.model.getters.getGridOffset();
71420
- const x = ev.clientX - gridOverLayRect.x + gridOffset.x;
71421
- const y = ev.clientY - gridOverLayRect.y + gridOffset.y;
71422
- const [col, row] = this.getCartesianCoordinates(ev);
71591
+ const x = zoomedMouseEvent.clientX - gridOverLayRect.x + gridOffset.x;
71592
+ const y = zoomedMouseEvent.clientY - gridOverLayRect.y + gridOffset.y;
71593
+ const [col, row] = this.getCartesianCoordinates(zoomedMouseEvent);
71423
71594
  const sheetId = this.env.model.getters.getActiveSheetId();
71424
71595
  let position = { col, row, sheetId };
71425
71596
  const merge = this.env.model.getters.getMerge(position);
@@ -71454,7 +71625,8 @@ stores.inject(MyMetaStore, storeInstance);
71454
71625
  if (!popover.isOpen) {
71455
71626
  return { isOpen: false };
71456
71627
  }
71457
- const anchorRect = popover.anchorRect;
71628
+ const zoom = this.env.model.getters.getViewportZoomLevel();
71629
+ const anchorRect = getZoomedRect(zoom, popover.anchorRect);
71458
71630
  return {
71459
71631
  ...popover,
71460
71632
  // transform from the "canvas coordinate system" to the "body coordinate system"
@@ -71559,8 +71731,8 @@ stores.inject(MyMetaStore, storeInstance);
71559
71731
  setup() {
71560
71732
  this.composerFocusStore = useStore(ComposerFocusStore);
71561
71733
  }
71562
- _computeHandleDisplay(ev) {
71563
- const position = this._getEvOffset(ev);
71734
+ _computeHandleDisplay(zoomedMouseEvent) {
71735
+ const position = this._getEvOffset(zoomedMouseEvent);
71564
71736
  const elementIndex = this._getElementIndex(position);
71565
71737
  if (elementIndex < 0) {
71566
71738
  return;
@@ -71580,8 +71752,8 @@ stores.inject(MyMetaStore, storeInstance);
71580
71752
  this.state.resizerIsActive = false;
71581
71753
  }
71582
71754
  }
71583
- _computeGrabDisplay(ev) {
71584
- const index = this._getElementIndex(this._getEvOffset(ev));
71755
+ _computeGrabDisplay(zoomedMouseEvent) {
71756
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71585
71757
  const activeElements = this._getActiveElements();
71586
71758
  const selectedZoneStart = this._getSelectedZoneStart();
71587
71759
  const selectedZoneEnd = this._getSelectedZoneEnd();
@@ -71597,26 +71769,29 @@ stores.inject(MyMetaStore, storeInstance);
71597
71769
  if (this.env.isMobile()) {
71598
71770
  return;
71599
71771
  }
71772
+ const zoomedMouseEvent = withZoom(this.env, ev);
71600
71773
  if (this.state.isResizing || this.state.isMoving || this.state.isSelecting) {
71601
71774
  return;
71602
71775
  }
71603
- this._computeHandleDisplay(ev);
71604
- this._computeGrabDisplay(ev);
71776
+ this._computeHandleDisplay(zoomedMouseEvent);
71777
+ this._computeGrabDisplay(zoomedMouseEvent);
71605
71778
  }
71606
71779
  onMouseLeave() {
71607
71780
  this.state.resizerIsActive = this.state.isResizing;
71608
71781
  this.state.waitingForMove = false;
71609
71782
  }
71610
71783
  onDblClick(ev) {
71784
+ const zoomedMouseEvent = withZoom(this.env, ev);
71611
71785
  this._fitElementSize(this.state.activeElement);
71612
71786
  this.state.isResizing = false;
71613
- this._computeHandleDisplay(ev);
71614
- this._computeGrabDisplay(ev);
71787
+ this._computeHandleDisplay(zoomedMouseEvent);
71788
+ this._computeGrabDisplay(zoomedMouseEvent);
71615
71789
  }
71616
71790
  onMouseDown(ev) {
71617
71791
  this.state.isResizing = true;
71618
71792
  this.state.delta = 0;
71619
- const initialPosition = this._getClientPosition(ev);
71793
+ const zoomedMouseEvent = withZoom(this.env, ev);
71794
+ const initialPosition = this._getClientPosition(zoomedMouseEvent);
71620
71795
  const styleValue = this.state.draggerLinePosition;
71621
71796
  const size = this._getElementSize(this.state.activeElement);
71622
71797
  const minSize = styleValue - size + this.MIN_ELEMENT_SIZE;
@@ -71628,7 +71803,7 @@ stores.inject(MyMetaStore, storeInstance);
71628
71803
  }
71629
71804
  };
71630
71805
  const onMouseMove = (ev) => {
71631
- this.state.delta = this._getClientPosition(ev) - initialPosition;
71806
+ this.state.delta = this._getClientPosition(withZoom(this.env, ev)) - initialPosition;
71632
71807
  this.state.draggerLinePosition = styleValue + this.state.delta;
71633
71808
  if (this.state.draggerLinePosition < minSize) {
71634
71809
  this.state.draggerLinePosition = minSize;
@@ -71649,7 +71824,8 @@ stores.inject(MyMetaStore, storeInstance);
71649
71824
  // not main button, probably a context menu
71650
71825
  return;
71651
71826
  }
71652
- const index = this._getElementIndex(this._getEvOffset(ev));
71827
+ const zoomedMouseEvent = withZoom(this.env, ev);
71828
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71653
71829
  this._selectElement(index, false);
71654
71830
  }
71655
71831
  select(ev) {
@@ -71660,7 +71836,8 @@ stores.inject(MyMetaStore, storeInstance);
71660
71836
  // not main button, probably a context menu
71661
71837
  return;
71662
71838
  }
71663
- const index = this._getElementIndex(this._getEvOffset(ev));
71839
+ const zoomedMouseEvent = withZoom(this.env, ev);
71840
+ const index = this._getElementIndex(this._getEvOffset(zoomedMouseEvent));
71664
71841
  if (index < 0) {
71665
71842
  return;
71666
71843
  }
@@ -71683,6 +71860,7 @@ stores.inject(MyMetaStore, storeInstance);
71683
71860
  startMovement(ev) {
71684
71861
  this.state.waitingForMove = false;
71685
71862
  this.state.isMoving = true;
71863
+ const zoomedMouseEvent = withZoom(this.env, ev);
71686
71864
  const startDimensions = this._getDimensionsInViewport(this._getSelectedZoneStart());
71687
71865
  const endDimensions = this._getDimensionsInViewport(this._getSelectedZoneEnd());
71688
71866
  const defaultPosition = startDimensions.start;
@@ -71719,9 +71897,10 @@ stores.inject(MyMetaStore, storeInstance);
71719
71897
  if (this.state.base !== this._getSelectedZoneStart()) {
71720
71898
  this._moveElements();
71721
71899
  }
71722
- this._computeGrabDisplay(ev);
71900
+ const zoomedMouseEvent = withZoom(this.env, ev);
71901
+ this._computeGrabDisplay(zoomedMouseEvent);
71723
71902
  };
71724
- this.dragNDropGrid.start(ev, mouseMoveMovement, mouseUpMovement);
71903
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMoveMovement, mouseUpMovement);
71725
71904
  }
71726
71905
  startSelection(ev, index) {
71727
71906
  if (this.env.isMobile()) {
@@ -71735,6 +71914,7 @@ stores.inject(MyMetaStore, storeInstance);
71735
71914
  this._selectElement(index, isCtrlKey(ev));
71736
71915
  }
71737
71916
  this.lastSelectedElementIndex = index;
71917
+ const zoomedMouseEvent = withZoom(this.env, ev);
71738
71918
  const mouseMoveSelect = (col, row) => {
71739
71919
  const newIndex = this._getType() === "COL" ? col : row;
71740
71920
  if (newIndex !== this.lastSelectedElementIndex && newIndex !== -1) {
@@ -71745,16 +71925,16 @@ stores.inject(MyMetaStore, storeInstance);
71745
71925
  const mouseUpSelect = () => {
71746
71926
  this.state.isSelecting = false;
71747
71927
  this.lastSelectedElementIndex = null;
71748
- this._computeGrabDisplay(ev);
71928
+ this._computeGrabDisplay(zoomedMouseEvent);
71749
71929
  };
71750
- this.dragNDropGrid.start(ev, mouseMoveSelect, mouseUpSelect);
71930
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMoveSelect, mouseUpSelect);
71751
71931
  }
71752
71932
  onMouseUp(ev) {
71753
71933
  this.lastSelectedElementIndex = null;
71754
71934
  }
71755
71935
  onContextMenu(ev) {
71756
71936
  ev.preventDefault();
71757
- const index = this._getElementIndex(this._getEvOffset(ev));
71937
+ const index = this._getElementIndex(this._getEvOffset(withZoom(this.env, ev)));
71758
71938
  if (index < 0)
71759
71939
  return;
71760
71940
  if (!this._getActiveElements().has(index)) {
@@ -71781,14 +71961,14 @@ stores.inject(MyMetaStore, storeInstance);
71781
71961
  get sheetId() {
71782
71962
  return this.env.model.getters.getActiveSheetId();
71783
71963
  }
71784
- _getEvOffset(ev) {
71785
- return ev.offsetX;
71964
+ _getEvOffset(zoomedMouseEvent) {
71965
+ return zoomedMouseEvent.offsetX;
71786
71966
  }
71787
71967
  _getViewportOffset() {
71788
71968
  return this.env.model.getters.getActiveMainViewport().left;
71789
71969
  }
71790
- _getClientPosition(ev) {
71791
- return ev.clientX;
71970
+ _getClientPosition(zoomedMouseEvent) {
71971
+ return zoomedMouseEvent.clientX;
71792
71972
  }
71793
71973
  _getElementIndex(position) {
71794
71974
  return this.env.model.getters.getColIndex(position);
@@ -71923,14 +72103,14 @@ stores.inject(MyMetaStore, storeInstance);
71923
72103
  get sheetId() {
71924
72104
  return this.env.model.getters.getActiveSheetId();
71925
72105
  }
71926
- _getEvOffset(ev) {
71927
- return ev.offsetY;
72106
+ _getEvOffset(zoomedMouseEvent) {
72107
+ return zoomedMouseEvent.offsetY;
71928
72108
  }
71929
72109
  _getViewportOffset() {
71930
72110
  return this.env.model.getters.getActiveMainViewport().top;
71931
72111
  }
71932
- _getClientPosition(ev) {
71933
- return ev.clientY;
72112
+ _getClientPosition(zoomedMouseEvent) {
72113
+ return zoomedMouseEvent.clientY;
71934
72114
  }
71935
72115
  _getElementIndex(position) {
71936
72116
  return this.env.model.getters.getRowIndex(position);
@@ -72879,18 +73059,21 @@ stores.inject(MyMetaStore, storeInstance);
72879
73059
  const canvas = canvasRef.el;
72880
73060
  const dpr = window.devicePixelRatio || 1;
72881
73061
  const ctx = canvas.getContext("2d", { alpha: false });
73062
+ const zoom = Math.max(model.getters.getViewportZoomLevel(), 1);
72882
73063
  const thinLineWidth = 0.4 * dpr;
72883
73064
  const renderingContext = {
72884
73065
  ctx,
72885
73066
  dpr,
72886
73067
  thinLineWidth,
72887
73068
  };
72888
- const { width, height } = canvasSize();
73069
+ let { width, height } = canvasSize();
73070
+ width = zoom * width;
73071
+ height = zoom * height;
72889
73072
  canvas.style.width = `${width}px`;
72890
73073
  canvas.style.height = `${height}px`;
72891
73074
  canvas.width = width * dpr;
72892
73075
  canvas.height = height * dpr;
72893
- canvas.setAttribute("style", `width:${width}px;height:${height}px;`);
73076
+ canvas.setAttribute("style", `width:${width}px;height:${height}px;zoom:${1 / zoom}`);
72894
73077
  if (width === 0 || height === 0) {
72895
73078
  return;
72896
73079
  }
@@ -72901,7 +73084,7 @@ stores.inject(MyMetaStore, storeInstance);
72901
73084
  // you need to shift the coordinates by 0.5 perpendicular to the line's direction.
72902
73085
  // http://diveintohtml5.info/canvas.html#pixel-madness
72903
73086
  ctx.translate(-CANVAS_SHIFT, -CANVAS_SHIFT);
72904
- ctx.scale(dpr, dpr);
73087
+ ctx.scale(dpr * zoom, dpr * zoom);
72905
73088
  rendererStore.draw(renderingContext);
72906
73089
  }
72907
73090
  }
@@ -73137,6 +73320,7 @@ stores.inject(MyMetaStore, storeInstance);
73137
73320
  }
73138
73321
  onResizeHighlight(ev, dirX, dirY) {
73139
73322
  const activeSheetId = this.env.model.getters.getActiveSheetId();
73323
+ const zoomedMouseEvent = withZoom(this.env, ev);
73140
73324
  this.highlightState.shiftingMode = "isResizing";
73141
73325
  const z = this.props.range.zone;
73142
73326
  const pivotCol = dirX === 1 ? z.left : z.right;
@@ -73175,11 +73359,12 @@ stores.inject(MyMetaStore, storeInstance);
73175
73359
  const mouseUp = () => {
73176
73360
  this.highlightState.shiftingMode = "none";
73177
73361
  };
73178
- this.dragNDropGrid.start(ev, mouseMove, mouseUp, scrollDirection);
73362
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMove, mouseUp, scrollDirection);
73179
73363
  }
73180
73364
  onMoveHighlight(ev) {
73181
73365
  this.highlightState.shiftingMode = "isMoving";
73182
73366
  const z = this.props.range.zone;
73367
+ const zoomedMouseEvent = withZoom(this.env, ev);
73183
73368
  const position = gridOverlayPosition();
73184
73369
  const activeSheetId = this.env.model.getters.getActiveSheetId();
73185
73370
  const initCol = this.env.model.getters.getColIndex(ev.clientX - position.left);
@@ -73216,7 +73401,7 @@ stores.inject(MyMetaStore, storeInstance);
73216
73401
  const mouseUp = () => {
73217
73402
  this.highlightState.shiftingMode = "none";
73218
73403
  };
73219
- this.dragNDropGrid.start(ev, mouseMove, mouseUp);
73404
+ this.dragNDropGrid.start(zoomedMouseEvent, mouseMove, mouseUp);
73220
73405
  }
73221
73406
  }
73222
73407
 
@@ -73322,11 +73507,12 @@ stores.inject(MyMetaStore, storeInstance);
73322
73507
  }
73323
73508
  get position() {
73324
73509
  const { x } = this.env.model.getters.getMainViewportRect();
73510
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
73325
73511
  return {
73326
73512
  left: `${this.props.leftOffset + x}px`,
73327
73513
  bottom: "0px",
73328
- height: `${SCROLLBAR_WIDTH}px`,
73329
- right: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
73514
+ height: `${scrollbarWidth}px`,
73515
+ right: isBrowserFirefox() ? `${scrollbarWidth}px` : "0",
73330
73516
  };
73331
73517
  }
73332
73518
  onScroll(offset) {
@@ -73367,11 +73553,12 @@ stores.inject(MyMetaStore, storeInstance);
73367
73553
  }
73368
73554
  get position() {
73369
73555
  const { y } = this.env.model.getters.getMainViewportRect();
73556
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
73370
73557
  return {
73371
73558
  top: `${this.props.topOffset + y}px`,
73372
73559
  right: "0px",
73373
- width: `${SCROLLBAR_WIDTH}px`,
73374
- bottom: isBrowserFirefox() ? `${SCROLLBAR_WIDTH}px` : "0",
73560
+ width: `${scrollbarWidth}px`,
73561
+ bottom: isBrowserFirefox() ? `${scrollbarWidth}px` : "0",
73375
73562
  };
73376
73563
  }
73377
73564
  onScroll(offset) {
@@ -73580,34 +73767,38 @@ stores.inject(MyMetaStore, storeInstance);
73580
73767
  }
73581
73768
  }
73582
73769
 
73583
- class FontSizeEditor extends owl.Component {
73584
- static template = "o-spreadsheet-FontSizeEditor";
73770
+ class NumberEditor extends owl.Component {
73771
+ static template = "o-spreadsheet-NumberEditor";
73585
73772
  static props = {
73586
- currentFontSize: Number,
73587
- onFontSizeChanged: Function,
73773
+ currentValue: Number,
73774
+ onValueChange: Function,
73588
73775
  onToggle: { type: Function, optional: true },
73589
73776
  onFocusInput: { type: Function, optional: true },
73590
73777
  class: String,
73778
+ valueIcon: { type: String, optional: true },
73779
+ min: Number,
73780
+ max: Number,
73781
+ title: String,
73782
+ valueList: (Array),
73591
73783
  };
73592
73784
  static defaultProps = {
73593
73785
  onFocusInput: () => { },
73594
73786
  };
73595
73787
  static components = { Popover };
73596
- fontSizes = FONT_SIZES;
73597
73788
  dropdown = owl.useState({ isOpen: false });
73598
- inputRef = owl.useRef("inputFontSize");
73599
- rootEditorRef = owl.useRef("FontSizeEditor");
73600
- fontSizeListRef = owl.useRef("fontSizeList");
73789
+ inputRef = owl.useRef("inputNumber");
73790
+ rootEditorRef = owl.useRef("NumberEditor");
73791
+ valueListRef = owl.useRef("numberList");
73601
73792
  setup() {
73602
73793
  owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
73603
73794
  owl.onWillUpdateProps((nextProps) => {
73604
73795
  if (this.inputRef.el && document.activeElement !== this.inputRef.el) {
73605
- this.inputRef.el.value = nextProps.currentFontSize;
73796
+ this.inputRef.el.value = nextProps.currentValue;
73606
73797
  }
73607
73798
  });
73608
73799
  owl.onMounted(() => {
73609
73800
  if (this.inputRef.el) {
73610
- this.inputRef.el.value = this.props.currentFontSize.toString();
73801
+ this.inputRef.el.value = this.props.currentValue.toString();
73611
73802
  }
73612
73803
  });
73613
73804
  }
@@ -73620,33 +73811,36 @@ stores.inject(MyMetaStore, storeInstance);
73620
73811
  };
73621
73812
  }
73622
73813
  onExternalClick(ev) {
73623
- if (!isChildEvent(this.fontSizeListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
73624
- this.closeFontList();
73814
+ if (!isChildEvent(this.valueListRef.el, ev) && !isChildEvent(this.rootEditorRef.el, ev)) {
73815
+ this.closeList();
73625
73816
  }
73626
73817
  }
73627
- toggleFontList() {
73818
+ toggleList() {
73628
73819
  const isOpen = this.dropdown.isOpen;
73629
73820
  if (!isOpen) {
73630
73821
  this.props.onToggle?.();
73631
73822
  this.inputRef.el.focus();
73632
73823
  }
73633
73824
  else {
73634
- this.closeFontList();
73825
+ this.closeList();
73635
73826
  }
73636
73827
  }
73637
- closeFontList() {
73828
+ closeList() {
73638
73829
  this.dropdown.isOpen = false;
73639
73830
  }
73640
- setSize(fontSizeStr) {
73641
- const fontSize = clip(Math.floor(parseFloat(fontSizeStr)), 1, 400);
73642
- this.props.onFontSizeChanged(fontSize);
73643
- this.closeFontList();
73831
+ setValue(valueStr) {
73832
+ const value = clip(Math.floor(parseFloat(valueStr)), this.props.min, this.props.max);
73833
+ this.props.onValueChange(value);
73834
+ this.closeList();
73835
+ }
73836
+ setValueFromInput(ev) {
73837
+ this.setValue(ev.target.value);
73644
73838
  }
73645
- setSizeFromInput(ev) {
73646
- this.setSize(ev.target.value);
73839
+ setValueFromList(valueStr) {
73840
+ this.setValue(valueStr);
73647
73841
  }
73648
- setSizeFromList(fontSizeStr) {
73649
- this.setSize(fontSizeStr);
73842
+ get currentValue() {
73843
+ return `${this.props.currentValue}`;
73650
73844
  }
73651
73845
  onInputFocused(ev) {
73652
73846
  this.dropdown.isOpen = true;
@@ -73654,17 +73848,33 @@ stores.inject(MyMetaStore, storeInstance);
73654
73848
  }
73655
73849
  onInputKeydown(ev) {
73656
73850
  if (ev.key === "Enter" || ev.key === "Escape") {
73657
- this.closeFontList();
73851
+ this.closeList();
73658
73852
  const target = ev.target;
73659
73853
  // In the case of a ESCAPE key, we get the previous font size back
73660
73854
  if (ev.key === "Escape") {
73661
- target.value = `${this.props.currentFontSize}`;
73855
+ target.value = `${this.props.currentValue}`;
73662
73856
  }
73663
73857
  this.props.onToggle?.();
73664
73858
  }
73665
73859
  }
73666
73860
  }
73667
73861
 
73862
+ class FontSizeEditor extends owl.Component {
73863
+ static template = "o-spreadsheet-FontSizeEditor";
73864
+ static components = { NumberEditor };
73865
+ static props = {
73866
+ currentFontSize: Number,
73867
+ onFontSizeChanged: Function,
73868
+ onToggle: { type: Function, optional: true },
73869
+ onFocusInput: { type: Function, optional: true },
73870
+ class: String,
73871
+ };
73872
+ static defaultProps = {
73873
+ onFocusInput: () => { },
73874
+ };
73875
+ fontSizes = FONT_SIZES;
73876
+ }
73877
+
73668
73878
  class TextStyler extends owl.Component {
73669
73879
  static template = "o-spreadsheet.TextStyler";
73670
73880
  static components = { ColorPickerWidget, ActionButton, FontSizeEditor };
@@ -80204,6 +80414,7 @@ stores.inject(MyMetaStore, storeInstance);
80204
80414
  const tableZone = this.props.table.range.zone;
80205
80415
  const topLeft = { col: tableZone.left, row: tableZone.top };
80206
80416
  document.body.style.cursor = "nwse-resize";
80417
+ const zoomedMouseEvent = withZoom(this.env, ev);
80207
80418
  const onMouseUp = () => {
80208
80419
  document.body.style.cursor = "";
80209
80420
  const newTableZone = this.state.highlightZone;
@@ -80225,7 +80436,7 @@ stores.inject(MyMetaStore, storeInstance);
80225
80436
  bottom: Math.max(row, topLeft.row),
80226
80437
  };
80227
80438
  };
80228
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
80439
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
80229
80440
  }
80230
80441
  get highlights() {
80231
80442
  if (!this.state.highlightZone)
@@ -80300,7 +80511,9 @@ stores.inject(MyMetaStore, storeInstance);
80300
80511
  this.paintFormatStore = useStore(PaintFormatStore);
80301
80512
  this.clientFocusStore = useStore(ClientFocusStore);
80302
80513
  useStore(ArrayFormulaHighlight);
80303
- owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
80514
+ owl.useChildSubEnv({
80515
+ getPopoverContainerRect: () => getZoomedRect(this.env.model.getters.getViewportZoomLevel(), this.getGridRect()),
80516
+ });
80304
80517
  owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
80305
80518
  owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
80306
80519
  owl.useExternalListener(document.body, "paste", this.paste);
@@ -80326,11 +80539,12 @@ stores.inject(MyMetaStore, storeInstance);
80326
80539
  return this.highlightStore.highlights;
80327
80540
  }
80328
80541
  get gridOverlayDimensions() {
80542
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
80329
80543
  return cssPropertiesToCss({
80330
80544
  top: `${HEADER_HEIGHT}px`,
80331
80545
  left: `${HEADER_WIDTH}px`,
80332
- height: `calc(100% - ${HEADER_HEIGHT + SCROLLBAR_WIDTH}px)`,
80333
- width: `calc(100% - ${HEADER_WIDTH + SCROLLBAR_WIDTH}px)`,
80546
+ height: `calc(100% - ${HEADER_HEIGHT + scrollbarWidth}px)`,
80547
+ width: `calc(100% - ${HEADER_WIDTH + scrollbarWidth}px)`,
80334
80548
  });
80335
80549
  }
80336
80550
  onClosePopover() {
@@ -80536,8 +80750,8 @@ stores.inject(MyMetaStore, storeInstance);
80536
80750
  const zone = this.env.model.getters.getSelectedZone();
80537
80751
  const rect = this.env.model.getters.getVisibleRect(zone);
80538
80752
  return {
80539
- left: rect.x + rect.width - AUTOFILL_EDGE_LENGTH / 2,
80540
- top: rect.y + rect.height - AUTOFILL_EDGE_LENGTH / 2,
80753
+ x: rect.x + rect.width - AUTOFILL_EDGE_LENGTH / 2,
80754
+ y: rect.y + rect.height - AUTOFILL_EDGE_LENGTH / 2,
80541
80755
  };
80542
80756
  }
80543
80757
  get isAutofillVisible() {
@@ -80593,8 +80807,8 @@ stores.inject(MyMetaStore, storeInstance);
80593
80807
  // ---------------------------------------------------------------------------
80594
80808
  // Zone selection with mouse
80595
80809
  // ---------------------------------------------------------------------------
80596
- onCellClicked(col, row, modifiers, ev) {
80597
- ev.preventDefault();
80810
+ onCellClicked(col, row, modifiers, zoomedMouseEvent) {
80811
+ zoomedMouseEvent.ev.preventDefault();
80598
80812
  if (this.composerFocusStore.activeComposer.editionMode === "editing") {
80599
80813
  this.composerFocusStore.activeComposer.stopEdition();
80600
80814
  }
@@ -80628,7 +80842,7 @@ stores.inject(MyMetaStore, storeInstance);
80628
80842
  this.paintFormatStore.pasteFormat(this.env.model.getters.getSelectedZones());
80629
80843
  }
80630
80844
  };
80631
- this.dragNDropGrid.start(ev, onMouseMove, onMouseUp);
80845
+ this.dragNDropGrid.start(zoomedMouseEvent, onMouseMove, onMouseUp);
80632
80846
  }
80633
80847
  onCellDoubleClicked(col, row) {
80634
80848
  const sheetId = this.env.model.getters.getActiveSheetId();
@@ -82703,6 +82917,11 @@ stores.inject(MyMetaStore, storeInstance);
82703
82917
  .addChild("view_formulas", ["view", "show"], {
82704
82918
  ...viewFormulas,
82705
82919
  sequence: 10,
82920
+ })
82921
+ .addChild("zoom", ["view"], {
82922
+ name: _t$1("Zoom"),
82923
+ sequence: 1,
82924
+ icon: "o-spreadsheet-Icon.ZOOM",
82706
82925
  })
82707
82926
  .addChild("view_irregularity_map", ["view"], {
82708
82927
  ...irregularityMap,
@@ -82991,6 +83210,10 @@ stores.inject(MyMetaStore, storeInstance);
82991
83210
  })
82992
83211
  .addChild("reinsert_dynamic_pivot", ["data"], reinsertDynamicPivotMenu)
82993
83212
  .addChild("reinsert_static_pivot", ["data"], reinsertStaticPivotMenu);
83213
+ // Zoom
83214
+ ZOOM_VALUES.forEach((zoom) => {
83215
+ topbarMenuRegistry.addChild(`zoom${zoom}`, ["view", "zoom"], zoomAction(zoom));
83216
+ });
82994
83217
 
82995
83218
  const genericRepeatsTransforms = [
82996
83219
  repeatSheetDependantCommand,
@@ -84021,7 +84244,9 @@ stores.inject(MyMetaStore, storeInstance);
84021
84244
  this.gridRef = owl.useRef("grid");
84022
84245
  this.hoveredCell = useStore(DelayedHoveredCellStore);
84023
84246
  this.clickableCellsStore = useStore(ClickableCellsStore);
84024
- owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
84247
+ owl.useChildSubEnv({
84248
+ getPopoverContainerRect: () => getZoomedRect(this.env.model.getters.getViewportZoomLevel(), this.getGridRect()),
84249
+ });
84025
84250
  useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimension());
84026
84251
  this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
84027
84252
  this.moveCanvas(deltaX, deltaY);
@@ -85087,6 +85312,35 @@ stores.inject(MyMetaStore, storeInstance);
85087
85312
  }
85088
85313
  }
85089
85314
 
85315
+ class ToolBarZoom extends owl.Component {
85316
+ static template = "o-spreadsheet-TopBarZoom";
85317
+ static components = { NumberEditor };
85318
+ static props = { class: String };
85319
+ topBarToolStore;
85320
+ valueList = ZOOM_VALUES;
85321
+ setup() {
85322
+ this.topBarToolStore = useToolBarDropdownStore();
85323
+ }
85324
+ get currentFontSize() {
85325
+ const zoom = this.env.model.getters.getViewportZoomLevel() || 1;
85326
+ return zoom * 100;
85327
+ }
85328
+ setZoom(fontSize) {
85329
+ this.env.model.dispatch("SET_ZOOM", { zoom: fontSize / 100 });
85330
+ }
85331
+ toggle() {
85332
+ if (this.topBarToolStore.isActive) {
85333
+ this.topBarToolStore.closeDropdowns();
85334
+ }
85335
+ else {
85336
+ this.topBarToolStore.openDropdown();
85337
+ }
85338
+ }
85339
+ onFocusInput() {
85340
+ this.topBarToolStore.openDropdown();
85341
+ }
85342
+ }
85343
+
85090
85344
  const topBarToolBarRegistry = new ToolBarRegistry();
85091
85345
  topBarToolBarRegistry
85092
85346
  .add("edit")
@@ -85120,6 +85374,13 @@ stores.inject(MyMetaStore, storeInstance);
85120
85374
  class: "o-hoverable-button o-toolbar-button",
85121
85375
  },
85122
85376
  sequence: 4,
85377
+ })
85378
+ .addChild("edit", {
85379
+ component: ToolBarZoom,
85380
+ props: {
85381
+ class: "o-menu-item-button o-hoverable-button o-toolbar-button",
85382
+ },
85383
+ sequence: 5,
85123
85384
  })
85124
85385
  .add("numberFormat")
85125
85386
  .addChild("numberFormat", {
@@ -85586,6 +85847,7 @@ stores.inject(MyMetaStore, storeInstance);
85586
85847
  }
85587
85848
  getStyle() {
85588
85849
  const properties = {};
85850
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
85589
85851
  if (this.env.isDashboard()) {
85590
85852
  properties["grid-template-rows"] = `auto`;
85591
85853
  }
@@ -85596,6 +85858,7 @@ stores.inject(MyMetaStore, storeInstance);
85596
85858
  ? `${this.sidePanel.totalPanelSize || DEFAULT_SIDE_PANEL_SIZE}px`
85597
85859
  : "auto";
85598
85860
  properties["grid-template-columns"] = `auto ${columnWidth}`;
85861
+ properties["--os-scrollbar-width"] = `${scrollbarWidth}px`;
85599
85862
  return cssPropertiesToCss(properties);
85600
85863
  }
85601
85864
  setup() {
@@ -85724,9 +85987,11 @@ stores.inject(MyMetaStore, storeInstance);
85724
85987
  get gridContainerStyle() {
85725
85988
  const gridColSize = GROUP_LAYER_WIDTH * this.rowLayers.length;
85726
85989
  const gridRowSize = GROUP_LAYER_WIDTH * this.colLayers.length;
85990
+ const zoom = this.env.model.getters.getViewportZoomLevel();
85727
85991
  return cssPropertiesToCss({
85728
85992
  "grid-template-columns": `${gridColSize ? gridColSize + 2 : 0}px auto`, // +2: margins
85729
85993
  "grid-template-rows": `${gridRowSize ? gridRowSize + 2 : 0}px auto`,
85994
+ zoom: `${zoom}`,
85730
85995
  });
85731
85996
  }
85732
85997
  get rowLayers() {
@@ -85738,6 +86003,8 @@ stores.inject(MyMetaStore, storeInstance);
85738
86003
  return this.env.model.getters.getVisibleGroupLayers(sheetId, "COL");
85739
86004
  }
85740
86005
  getGridSize() {
86006
+ const zoom = this.env.model.getters.getViewportZoomLevel();
86007
+ const scrollbarWidth = this.env.model.getters.getScrollBarWidth();
85741
86008
  const topBarHeight = this.spreadsheetRef.el
85742
86009
  ?.querySelector(".o-spreadsheet-topbar-wrapper")
85743
86010
  ?.getBoundingClientRect().height || 0;
@@ -85751,8 +86018,8 @@ stores.inject(MyMetaStore, storeInstance);
85751
86018
  topBarHeight -
85752
86019
  bottomBarHeight;
85753
86020
  return {
85754
- width: Math.max(gridWidth - SCROLLBAR_WIDTH, 0),
85755
- height: Math.max(gridHeight - SCROLLBAR_WIDTH, 0),
86021
+ width: Math.max(gridWidth / zoom - scrollbarWidth, 0),
86022
+ height: Math.max(gridHeight / zoom - scrollbarWidth, 0),
85756
86023
  };
85757
86024
  }
85758
86025
  }
@@ -88305,9 +88572,9 @@ stores.inject(MyMetaStore, storeInstance);
88305
88572
  exports.tokenize = tokenize;
88306
88573
 
88307
88574
 
88308
- __info__.version = "19.1.0-alpha.10";
88309
- __info__.date = "2025-10-30T12:26:30.196Z";
88310
- __info__.hash = "d0b65e9";
88575
+ __info__.version = "19.1.0-alpha.11";
88576
+ __info__.date = "2025-11-03T12:34:28.925Z";
88577
+ __info__.hash = "d9230f3";
88311
88578
 
88312
88579
 
88313
88580
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);