@odoo/o-spreadsheet 16.1.28 → 16.1.31

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.
@@ -306,15 +306,76 @@
306
306
  // -----------------------------------------------------------------------------
307
307
  // Date Type
308
308
  // -----------------------------------------------------------------------------
309
+ /**
310
+ * A DateTime object that can be used to manipulate spreadsheet dates.
311
+ * Conceptually, a spreadsheet date is simply a number with a date format,
312
+ * and it is timezone-agnostic.
313
+ * This DateTime object consistently uses UTC time to represent a naive date and time.
314
+ */
315
+ class DateTime {
316
+ constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
317
+ this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
318
+ }
319
+ static fromTimestamp(timestamp) {
320
+ const date = new Date(timestamp);
321
+ return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
322
+ }
323
+ static now() {
324
+ const now = new Date();
325
+ return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
326
+ }
327
+ toString() {
328
+ return this.jsDate.toString();
329
+ }
330
+ getTime() {
331
+ return this.jsDate.getTime();
332
+ }
333
+ getFullYear() {
334
+ return this.jsDate.getUTCFullYear();
335
+ }
336
+ getMonth() {
337
+ return this.jsDate.getUTCMonth();
338
+ }
339
+ getDate() {
340
+ return this.jsDate.getUTCDate();
341
+ }
342
+ getDay() {
343
+ return this.jsDate.getUTCDay();
344
+ }
345
+ getHours() {
346
+ return this.jsDate.getUTCHours();
347
+ }
348
+ getMinutes() {
349
+ return this.jsDate.getUTCMinutes();
350
+ }
351
+ getSeconds() {
352
+ return this.jsDate.getUTCSeconds();
353
+ }
354
+ setFullYear(year) {
355
+ this.jsDate.setFullYear(year);
356
+ }
357
+ setDate(date) {
358
+ this.jsDate.setUTCDate(date);
359
+ }
360
+ setHours(hours) {
361
+ this.jsDate.setUTCHours(hours);
362
+ }
363
+ setMinutes(minutes) {
364
+ this.jsDate.setUTCMinutes(minutes);
365
+ }
366
+ setSeconds(seconds) {
367
+ this.jsDate.setUTCSeconds(seconds);
368
+ }
369
+ }
309
370
  // -----------------------------------------------------------------------------
310
371
  // Parsing
311
372
  // -----------------------------------------------------------------------------
312
- const INITIAL_1900_DAY = new Date(1899, 11, 30);
373
+ const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
313
374
  const MS_PER_DAY = 24 * 60 * 60 * 1000;
314
375
  const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
315
- const CURRENT_YEAR = new Date().getFullYear();
316
- const INITIAL_JS_DAY = new Date(0);
317
- const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY;
376
+ const CURRENT_YEAR = DateTime.now().getFullYear();
377
+ const INITIAL_JS_DAY = DateTime.fromTimestamp(0);
378
+ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY.getTime() - INITIAL_1900_DAY.getTime();
318
379
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
319
380
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
320
381
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
@@ -363,7 +424,7 @@
363
424
  return {
364
425
  value: date.value + time.value,
365
426
  format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
366
- jsDate: new Date(date.jsDate.getFullYear() + time.jsDate.getFullYear() - 1899, date.jsDate.getMonth() + time.jsDate.getMonth() - 11, date.jsDate.getDate() + time.jsDate.getDate() - 30, date.jsDate.getHours() + time.jsDate.getHours(), date.jsDate.getMinutes() + time.jsDate.getMinutes(), date.jsDate.getSeconds() + time.jsDate.getSeconds()),
427
+ jsDate: new DateTime(date.jsDate.getFullYear() + time.jsDate.getFullYear() - 1899, date.jsDate.getMonth() + time.jsDate.getMonth() - 11, date.jsDate.getDate() + time.jsDate.getDate() - 30, date.jsDate.getHours() + time.jsDate.getHours(), date.jsDate.getMinutes() + time.jsDate.getMinutes(), date.jsDate.getSeconds() + time.jsDate.getSeconds()),
367
428
  };
368
429
  }
369
430
  return date || time;
@@ -380,13 +441,13 @@
380
441
  const day = Number(parts[dayIndex]);
381
442
  const leadingZero = (parts[monthIndex].length === 2 && month < 10) || (parts[dayIndex].length === 2 && day < 10);
382
443
  const year = parts[yearIndex] ? inferYear(parts[yearIndex]) : CURRENT_YEAR;
383
- const jsDate = new Date(year, month - 1, day);
444
+ const jsDate = new DateTime(year, month - 1, day);
384
445
  const sep = str.match(/\/|-|\s/)[0];
385
446
  if (jsDate.getMonth() !== month - 1 || jsDate.getDate() !== day) {
386
447
  // invalid date
387
448
  return null;
388
449
  }
389
- const delta = jsDate - INITIAL_1900_DAY;
450
+ const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
390
451
  let format = leadingZero ? `mm${sep}dd` : `m${sep}d`;
391
452
  if (parts[yearIndex]) {
392
453
  format = isMDY ? format + sep + "yyyy" : "yyyy" + sep + format;
@@ -446,7 +507,7 @@
446
507
  if (hours >= 24) {
447
508
  format = "hhhh:mm:ss";
448
509
  }
449
- const jsDate = new Date(1899, 11, 30, hours, minutes, seconds);
510
+ const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
450
511
  return {
451
512
  value: hours / 24 + minutes / 1440 + seconds / 86400,
452
513
  format: format,
@@ -460,7 +521,7 @@
460
521
  // -----------------------------------------------------------------------------
461
522
  function numberToJsDate(value) {
462
523
  const truncValue = Math.trunc(value);
463
- let date = new Date(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
524
+ let date = DateTime.fromTimestamp(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
464
525
  let time = value - truncValue;
465
526
  time = time < 0 ? 1 + time : time;
466
527
  const hours = Math.round(time * 24);
@@ -477,7 +538,7 @@
477
538
  }
478
539
  /** Return the number of days in the current month of the given date */
479
540
  function getDaysInMonth(date) {
480
- return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
541
+ return new DateTime(date.getFullYear(), date.getMonth() + 1, 0).getDate();
481
542
  }
482
543
  function isLastDayOfMonth(date) {
483
544
  return getDaysInMonth(date) === date.getDate();
@@ -495,7 +556,7 @@
495
556
  const yStart = date.getFullYear();
496
557
  const mStart = date.getMonth();
497
558
  const dStart = date.getDate();
498
- const jsDate = new Date(yStart, mStart + months);
559
+ const jsDate = new DateTime(yStart, mStart + months, 1);
499
560
  if (keepEndOfMonth && dStart === getDaysInMonth(date)) {
500
561
  jsDate.setDate(getDaysInMonth(jsDate));
501
562
  }
@@ -1344,8 +1405,10 @@
1344
1405
  const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
1345
1406
  // Same as above, but matches the exact string (nothing before or after)
1346
1407
  const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
1347
- /** Reference of a column header (eg. A, AB) */
1348
- const colHeader = new RegExp(/^([A-Z]{1,3})+$/, "i");
1408
+ /** Reference of a column header (eg. A, AB, $A) */
1409
+ const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
1410
+ /** Reference of a row header (eg. 1, $1) */
1411
+ const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
1349
1412
  /** Reference of a column (eg. A, $CA, Sheet1!B) */
1350
1413
  const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
1351
1414
  /** Reference of a row (eg. 1, 59, Sheet1!9) */
@@ -1375,6 +1438,9 @@
1375
1438
  function isColHeader(str) {
1376
1439
  return colHeader.test(str);
1377
1440
  }
1441
+ function isRowHeader(str) {
1442
+ return rowHeader.test(str);
1443
+ }
1378
1444
  /**
1379
1445
  * Return true if the given xc is the reference of a single cell,
1380
1446
  * without any specified sheet (e.g. A1)
@@ -1873,7 +1939,7 @@
1873
1939
  .map((p) => {
1874
1940
  switch (p) {
1875
1941
  case "hhhh":
1876
- const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY) / (60 * 60 * 1000));
1942
+ const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY.getTime()) / (60 * 60 * 1000));
1877
1943
  return helapsedHours.toString();
1878
1944
  case "hh":
1879
1945
  return hours.toString().padStart(2, "0");
@@ -2164,18 +2230,10 @@
2164
2230
  if (isFullCol) {
2165
2231
  parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2166
2232
  parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2167
- if (zone.left === zone.right) {
2168
- parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
2169
- parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
2170
- }
2171
2233
  }
2172
2234
  if (isFullRow) {
2173
2235
  parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
2174
2236
  parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
2175
- if (zone.top === zone.bottom) {
2176
- parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2177
- parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
2178
- }
2179
2237
  }
2180
2238
  return parts;
2181
2239
  }
@@ -5702,6 +5760,7 @@
5702
5760
  return node.description ? node.description : "";
5703
5761
  }
5704
5762
 
5763
+ const macRegex = /Mac/i;
5705
5764
  /**
5706
5765
  * Return true if the event was triggered from
5707
5766
  * a child element.
@@ -5719,6 +5778,17 @@
5719
5778
  }
5720
5779
  function getOpenedMenus() {
5721
5780
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
5781
+ }
5782
+ function isMacOS() {
5783
+ return Boolean(macRegex.test(navigator.userAgent));
5784
+ }
5785
+ /**
5786
+ * @param {KeyboardEvent | MouseEvent} ev
5787
+ * @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
5788
+ * On Mac, this is the "meta" or "command" key.
5789
+ */
5790
+ function isCtrlKey(ev) {
5791
+ return isMacOS() ? ev.metaKey : ev.ctrlKey;
5722
5792
  }
5723
5793
 
5724
5794
  /**
@@ -10879,7 +10949,7 @@
10879
10949
  if (_year < 1900) {
10880
10950
  _year += 1900;
10881
10951
  }
10882
- const jsDate = new Date(_year, _month - 1, _day);
10952
+ const jsDate = new DateTime(_year, _month - 1, _day);
10883
10953
  const result = jsDateToRoundNumber(jsDate);
10884
10954
  assert(() => result >= 0, _lt(`The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900.`));
10885
10955
  return result;
@@ -10991,7 +11061,7 @@
10991
11061
  const _months = Math.trunc(toNumber(months));
10992
11062
  const yStart = _startDate.getFullYear();
10993
11063
  const mStart = _startDate.getMonth();
10994
- const jsDate = new Date(yStart, mStart + _months + 1, 0);
11064
+ const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
10995
11065
  return jsDateToRoundNumber(jsDate);
10996
11066
  },
10997
11067
  isExported: true,
@@ -11030,17 +11100,17 @@
11030
11100
  // The first week of the year is the week that contains the first
11031
11101
  // Thursday of the year.
11032
11102
  let firstThursday = 1;
11033
- while (new Date(y, 0, firstThursday).getDay() !== 4) {
11103
+ while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
11034
11104
  firstThursday += 1;
11035
11105
  }
11036
- const firstDayOfFirstWeek = new Date(y, 0, firstThursday - 3);
11106
+ const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
11037
11107
  // The last week of the year is the week that contains the last Thursday of
11038
11108
  // the year.
11039
11109
  let lastThursday = 31;
11040
- while (new Date(y, 11, lastThursday).getDay() !== 4) {
11110
+ while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
11041
11111
  lastThursday -= 1;
11042
11112
  }
11043
- const lastDayOfLastWeek = new Date(y, 11, lastThursday + 3);
11113
+ const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
11044
11114
  // B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
11045
11115
  // If our date < firstDayOfFirstWeek then it's in the weeks of the year before
11046
11116
  let offsetYear;
@@ -11066,17 +11136,17 @@
11066
11136
  case 1:
11067
11137
  // firstDay is the 1st day of the 1st week of the year after
11068
11138
  // firstDay = lastDayOfLastWeek + 1 Day
11069
- firstDay = new Date(y, 11, lastThursday + 3 + 1);
11139
+ firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
11070
11140
  break;
11071
11141
  case -1:
11072
11142
  // firstDay is the 1st day of the 1st week of the previous year.
11073
11143
  // The first week of the previous year is the week that contains the
11074
11144
  // first Thursday of the previous year.
11075
11145
  let firstThursdayPreviousYear = 1;
11076
- while (new Date(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
11146
+ while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
11077
11147
  firstThursdayPreviousYear += 1;
11078
11148
  }
11079
- firstDay = new Date(y - 1, 0, firstThursdayPreviousYear - 3);
11149
+ firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
11080
11150
  break;
11081
11151
  }
11082
11152
  const diff = (_date.getTime() - firstDay.getTime()) / MS_PER_DAY;
@@ -11215,8 +11285,8 @@
11215
11285
  });
11216
11286
  }
11217
11287
  const invertDate = _startDate.getTime() > _endDate.getTime();
11218
- const stopDate = new Date((invertDate ? _startDate : _endDate).getTime());
11219
- let stepDate = new Date((invertDate ? _endDate : _startDate).getTime());
11288
+ const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
11289
+ let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
11220
11290
  const timeStopDate = stopDate.getTime();
11221
11291
  let timeStepDate = stepDate.getTime();
11222
11292
  let netWorkingDay = 0;
@@ -11240,8 +11310,7 @@
11240
11310
  returns: ["DATE"],
11241
11311
  computeFormat: () => "m/d/yyyy hh:mm:ss",
11242
11312
  compute: function () {
11243
- let today = new Date();
11244
- today.setMilliseconds(0);
11313
+ let today = DateTime.now();
11245
11314
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
11246
11315
  const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
11247
11316
  return Math.floor(delta / MS_PER_DAY) + time;
@@ -11315,8 +11384,8 @@
11315
11384
  returns: ["DATE"],
11316
11385
  computeFormat: () => "m/d/yyyy",
11317
11386
  compute: function () {
11318
- const today = new Date();
11319
- const jsDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
11387
+ const today = DateTime.now();
11388
+ const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
11320
11389
  return jsDateToRoundNumber(jsDate);
11321
11390
  },
11322
11391
  isExported: true,
@@ -11371,10 +11440,10 @@
11371
11440
  }
11372
11441
  const y = _date.getFullYear();
11373
11442
  let dayStart = 1;
11374
- let startDayOfFirstWeek = new Date(y, 0, dayStart);
11443
+ let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
11375
11444
  while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
11376
11445
  dayStart += 1;
11377
- startDayOfFirstWeek = new Date(y, 0, dayStart);
11446
+ startDayOfFirstWeek = new DateTime(y, 0, dayStart);
11378
11447
  }
11379
11448
  const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / MS_PER_DAY;
11380
11449
  if (dif < 0) {
@@ -11428,7 +11497,7 @@
11428
11497
  timesHoliday.add(holiday.getTime());
11429
11498
  });
11430
11499
  }
11431
- let stepDate = new Date(_startDate.getTime());
11500
+ let stepDate = DateTime.fromTimestamp(_startDate.getTime());
11432
11501
  let timeStepDate = stepDate.getTime();
11433
11502
  const unitDay = Math.sign(_numDays);
11434
11503
  let stepDay = Math.abs(_numDays);
@@ -11494,7 +11563,7 @@
11494
11563
  const _startDate = toJsDate(date);
11495
11564
  const yStart = _startDate.getFullYear();
11496
11565
  const mStart = _startDate.getMonth();
11497
- const jsDate = new Date(yStart, mStart, 1);
11566
+ const jsDate = new DateTime(yStart, mStart, 1);
11498
11567
  return jsDateToRoundNumber(jsDate);
11499
11568
  },
11500
11569
  };
@@ -11538,7 +11607,7 @@
11538
11607
  compute: function (date) {
11539
11608
  const quarter = QUARTER.compute(date);
11540
11609
  const year = YEAR.compute(date);
11541
- const jsDate = new Date(year, (quarter - 1) * 3, 1);
11610
+ const jsDate = new DateTime(year, (quarter - 1) * 3, 1);
11542
11611
  return jsDateToRoundNumber(jsDate);
11543
11612
  },
11544
11613
  };
@@ -11555,7 +11624,7 @@
11555
11624
  compute: function (date) {
11556
11625
  const quarter = QUARTER.compute(date);
11557
11626
  const year = YEAR.compute(date);
11558
- const jsDate = new Date(year, quarter * 3, 0);
11627
+ const jsDate = new DateTime(year, quarter * 3, 0);
11559
11628
  return jsDateToRoundNumber(jsDate);
11560
11629
  },
11561
11630
  };
@@ -11571,7 +11640,7 @@
11571
11640
  computeFormat: () => "m/d/yyyy",
11572
11641
  compute: function (date) {
11573
11642
  const year = YEAR.compute(date);
11574
- const jsDate = new Date(year, 0, 1);
11643
+ const jsDate = new DateTime(year, 0, 1);
11575
11644
  return jsDateToRoundNumber(jsDate);
11576
11645
  },
11577
11646
  };
@@ -11587,7 +11656,7 @@
11587
11656
  computeFormat: () => "m/d/yyyy",
11588
11657
  compute: function (date) {
11589
11658
  const year = YEAR.compute(date);
11590
- const jsDate = new Date(year + 1, 0, 0);
11659
+ const jsDate = new DateTime(year + 1, 0, 0);
11591
11660
  return jsDateToRoundNumber(jsDate);
11592
11661
  },
11593
11662
  };
@@ -11721,7 +11790,7 @@
11721
11790
  function assertSettlementLessThanOneYearBeforeMaturity(settlement, maturity) {
11722
11791
  const startDate = toJsDate(settlement);
11723
11792
  const endDate = toJsDate(maturity);
11724
- const startDatePlusOneYear = new Date(startDate);
11793
+ const startDatePlusOneYear = toJsDate(settlement);
11725
11794
  startDatePlusOneYear.setFullYear(startDate.getFullYear() + 1);
11726
11795
  assert(() => endDate.getTime() <= startDatePlusOneYear.getTime(), _lt("The settlement date (%s) must at most one year after the maturity date (%s).", settlement.toString(), maturity.toString()));
11727
11796
  }
@@ -15647,7 +15716,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
15647
15716
  SPACE: goTo(State.RightRef),
15648
15717
  NUMBER: goTo(State.Found),
15649
15718
  REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
15650
- SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
15719
+ SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
15651
15720
  },
15652
15721
  [State.RightColumnRef]: {
15653
15722
  SPACE: goTo(State.RightColumnRef),
@@ -15658,6 +15727,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
15658
15727
  SPACE: goTo(State.RightRowRef),
15659
15728
  NUMBER: goTo(State.Found),
15660
15729
  REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
15730
+ SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
15661
15731
  },
15662
15732
  [State.Found]: {},
15663
15733
  };
@@ -16167,6 +16237,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
16167
16237
  return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
16168
16238
  case "colrow":
16169
16239
  indexOfNumber = xc.search(/[0-9]/);
16240
+ if (indexOfNumber === -1 || indexOfNumber === 0) {
16241
+ // no row number (eg. A) or no column (eg. 1)
16242
+ return "$" + xc;
16243
+ }
16170
16244
  xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
16171
16245
  return "$" + xc;
16172
16246
  case "none":
@@ -16940,10 +17014,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
16940
17014
  function updateSelectionWithArrowKeys(ev, selection) {
16941
17015
  const direction = arrowMap[ev.key];
16942
17016
  if (ev.shiftKey) {
16943
- selection.resizeAnchorZone(direction, ev.ctrlKey ? "end" : 1);
17017
+ selection.resizeAnchorZone(direction, isCtrlKey(ev) ? "end" : 1);
16944
17018
  }
16945
17019
  else {
16946
- selection.moveAnchorCell(direction, ev.ctrlKey ? "end" : 1);
17020
+ selection.moveAnchorCell(direction, isCtrlKey(ev) ? "end" : 1);
16947
17021
  }
16948
17022
  }
16949
17023
 
@@ -22600,7 +22674,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22600
22674
  return;
22601
22675
  }
22602
22676
  const [col, row] = this.getCartesianCoordinates(ev);
22603
- this.props.onCellClicked(col, row, { shiftKey: ev.shiftKey, ctrlKey: ev.ctrlKey });
22677
+ this.props.onCellClicked(col, row, {
22678
+ expandZone: ev.shiftKey,
22679
+ addZone: isCtrlKey(ev),
22680
+ });
22604
22681
  }
22605
22682
  onDoubleClick(ev) {
22606
22683
  const [col, row] = this.getCartesianCoordinates(ev);
@@ -22688,6 +22765,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22688
22765
  draggerShadowThickness: 0,
22689
22766
  delta: 0,
22690
22767
  base: 0,
22768
+ position: "before",
22691
22769
  });
22692
22770
  }
22693
22771
  _computeHandleDisplay(ev) {
@@ -22813,11 +22891,13 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22813
22891
  this.state.draggerLinePosition = dimensions.start;
22814
22892
  this.state.draggerShadowPosition = dimensions.start;
22815
22893
  this.state.base = elementIndex;
22894
+ this.state.position = "before";
22816
22895
  }
22817
22896
  else if (this._getSelectedZoneEnd() < elementIndex) {
22818
22897
  this.state.draggerLinePosition = dimensions.end;
22819
22898
  this.state.draggerShadowPosition = dimensions.end - this.state.draggerShadowThickness;
22820
- this.state.base = elementIndex + 1;
22899
+ this.state.base = elementIndex;
22900
+ this.state.position = "after";
22821
22901
  }
22822
22902
  else {
22823
22903
  this.state.draggerLinePosition = startDimensions.start;
@@ -22841,7 +22921,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22841
22921
  this._increaseSelection(index);
22842
22922
  }
22843
22923
  else {
22844
- this._selectElement(index, ev.ctrlKey);
22924
+ this._selectElement(index, isCtrlKey(ev));
22845
22925
  }
22846
22926
  this.lastSelectedElementIndex = index;
22847
22927
  const mouseMoveSelect = (col, row) => {
@@ -22854,7 +22934,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22854
22934
  const mouseUpSelect = () => {
22855
22935
  this.state.isSelecting = false;
22856
22936
  this.lastSelectedElementIndex = null;
22857
- this.env.model.dispatch(ev.ctrlKey ? "PREPARE_SELECTION_INPUT_EXPANSION" : "STOP_SELECTION_INPUT");
22937
+ this.env.model.dispatch(isCtrlKey(ev) ? "PREPARE_SELECTION_INPUT_EXPANSION" : "STOP_SELECTION_INPUT");
22858
22938
  this._computeGrabDisplay(ev);
22859
22939
  };
22860
22940
  dragAndDropBeyondTheViewport(this.env, mouseMoveSelect, mouseUpSelect);
@@ -22998,13 +23078,14 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
22998
23078
  dimension: "COL",
22999
23079
  base: this.state.base,
23000
23080
  elements,
23081
+ position: this.state.position,
23001
23082
  });
23002
23083
  if (!result.isSuccessful && result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
23003
23084
  this.env.raiseError(MergeErrorMessage);
23004
23085
  }
23005
23086
  }
23006
- _selectElement(index, ctrlKey) {
23007
- this.env.model.selection.selectColumn(index, ctrlKey ? "newAnchor" : "overrideSelection");
23087
+ _selectElement(index, addDistinctHeader) {
23088
+ this.env.model.selection.selectColumn(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
23008
23089
  }
23009
23090
  _increaseSelection(index) {
23010
23091
  this.env.model.selection.selectColumn(index, "updateAnchor");
@@ -23170,13 +23251,14 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
23170
23251
  dimension: "ROW",
23171
23252
  base: this.state.base,
23172
23253
  elements,
23254
+ position: this.state.position,
23173
23255
  });
23174
23256
  if (!result.isSuccessful && result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
23175
23257
  this.env.raiseError(MergeErrorMessage);
23176
23258
  }
23177
23259
  }
23178
- _selectElement(index, ctrlKey) {
23179
- this.env.model.selection.selectRow(index, ctrlKey ? "newAnchor" : "overrideSelection");
23260
+ _selectElement(index, addDistinctHeader) {
23261
+ this.env.model.selection.selectRow(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
23180
23262
  }
23181
23263
  _increaseSelection(index) {
23182
23264
  this.env.model.selection.selectRow(index, "updateAnchor");
@@ -23278,8 +23360,8 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
23278
23360
  return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
23279
23361
  }
23280
23362
  const onMouseWheel = (ev) => {
23281
- const deltaX = normalize(ev.shiftKey ? ev.deltaY : ev.deltaX, ev.deltaMode);
23282
- const deltaY = normalize(ev.shiftKey ? ev.deltaX : ev.deltaY, ev.deltaMode);
23363
+ const deltaX = normalize(ev.shiftKey && !isMacOS() ? ev.deltaY : ev.deltaX, ev.deltaMode);
23364
+ const deltaY = normalize(ev.shiftKey && !isMacOS() ? ev.deltaX : ev.deltaY, ev.deltaMode);
23283
23365
  handler(deltaX, deltaY);
23284
23366
  };
23285
23367
  return onMouseWheel;
@@ -23923,8 +24005,8 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
23923
24005
  // ---------------------------------------------------------------------------
23924
24006
  // Zone selection with mouse
23925
24007
  // ---------------------------------------------------------------------------
23926
- onCellClicked(col, row, { ctrlKey, shiftKey }) {
23927
- if (ctrlKey) {
24008
+ onCellClicked(col, row, { addZone, expandZone }) {
24009
+ if (addZone) {
23928
24010
  this.env.model.dispatch("PREPARE_SELECTION_INPUT_EXPANSION");
23929
24011
  }
23930
24012
  if (this.env.model.getters.hasOpenedPopover()) {
@@ -23933,10 +24015,10 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
23933
24015
  if (this.env.model.getters.getEditionMode() === "editing") {
23934
24016
  this.env.model.dispatch("STOP_EDITION");
23935
24017
  }
23936
- if (shiftKey) {
24018
+ if (expandZone) {
23937
24019
  this.env.model.selection.setAnchorCorner(col, row);
23938
24020
  }
23939
- else if (ctrlKey) {
24021
+ else if (addZone) {
23940
24022
  this.env.model.selection.addCellToSelection(col, row);
23941
24023
  }
23942
24024
  else {
@@ -23998,9 +24080,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
23998
24080
  return;
23999
24081
  }
24000
24082
  let keyDownString = "";
24001
- if (ev.ctrlKey)
24002
- keyDownString += "CTRL+";
24003
- if (ev.metaKey)
24083
+ if (isCtrlKey(ev))
24004
24084
  keyDownString += "CTRL+";
24005
24085
  if (ev.altKey)
24006
24086
  keyDownString += "ALT+";
@@ -31348,7 +31428,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
31348
31428
  const elements = cmd.dimension === "COL"
31349
31429
  ? this.getNumberCols(cmd.sheetId)
31350
31430
  : this.getNumberRows(cmd.sheetId);
31351
- if (cmd.base < 0 || cmd.base > elements) {
31431
+ if (cmd.base < 0 || cmd.base >= elements) {
31352
31432
  return 86 /* CommandResult.InvalidHeaderIndex */;
31353
31433
  }
31354
31434
  else if (cmd.quantity <= 0) {
@@ -32371,13 +32451,18 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32371
32451
  // Getters
32372
32452
  // ---------------------------------------------------------------------------
32373
32453
  evaluateFormula(formulaString, sheetId = this.getters.getActiveSheetId()) {
32374
- const compiledFormula = compile(formulaString);
32375
- const params = this.getCompilationParameters((cell) => this.getEvaluatedCell(this.getters.getCellPosition(cell.id)));
32376
- const ranges = [];
32377
- for (let xc of compiledFormula.dependencies) {
32378
- ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
32454
+ try {
32455
+ const compiledFormula = compile(formulaString);
32456
+ const params = this.getCompilationParameters((cell) => this.getEvaluatedCell(this.getters.getCellPosition(cell.id)));
32457
+ const ranges = [];
32458
+ for (let xc of compiledFormula.dependencies) {
32459
+ ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
32460
+ }
32461
+ return compiledFormula.execute(ranges, ...params).value;
32462
+ }
32463
+ catch (error) {
32464
+ return error instanceof EvaluationError ? error.errorType : CellErrorType.GenericError;
32379
32465
  }
32380
- return compiledFormula.execute(ranges, ...params).value;
32381
32466
  }
32382
32467
  /**
32383
32468
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -32869,39 +32954,34 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32869
32954
  this.computedIcons[sheetId] = {};
32870
32955
  const computedStyle = this.computedStyles[sheetId];
32871
32956
  for (let cf of this.getters.getConditionalFormats(sheetId).reverse()) {
32872
- try {
32873
- switch (cf.rule.type) {
32874
- case "ColorScaleRule":
32875
- for (let range of cf.ranges) {
32876
- this.applyColorScale(range, cf.rule);
32877
- }
32878
- break;
32879
- case "IconSetRule":
32880
- for (let range of cf.ranges) {
32881
- this.applyIcon(range, cf.rule);
32882
- }
32883
- break;
32884
- default:
32885
- for (let ref of cf.ranges) {
32886
- const zone = this.getters.getRangeFromSheetXC(sheetId, ref).zone;
32887
- for (let row = zone.top; row <= zone.bottom; row++) {
32888
- for (let col = zone.left; col <= zone.right; col++) {
32889
- const pr = this.rulePredicate[cf.rule.type];
32890
- let cell = this.getters.getEvaluatedCell({ sheetId, col, row });
32891
- if (pr && pr(cell, cf.rule)) {
32892
- if (!computedStyle[col])
32893
- computedStyle[col] = [];
32894
- // we must combine all the properties of all the CF rules applied to the given cell
32895
- computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
32896
- }
32957
+ switch (cf.rule.type) {
32958
+ case "ColorScaleRule":
32959
+ for (let range of cf.ranges) {
32960
+ this.applyColorScale(range, cf.rule);
32961
+ }
32962
+ break;
32963
+ case "IconSetRule":
32964
+ for (let range of cf.ranges) {
32965
+ this.applyIcon(range, cf.rule);
32966
+ }
32967
+ break;
32968
+ default:
32969
+ for (let ref of cf.ranges) {
32970
+ const zone = this.getters.getRangeFromSheetXC(sheetId, ref).zone;
32971
+ for (let row = zone.top; row <= zone.bottom; row++) {
32972
+ for (let col = zone.left; col <= zone.right; col++) {
32973
+ const pr = this.rulePredicate[cf.rule.type];
32974
+ let cell = this.getters.getEvaluatedCell({ sheetId, col, row });
32975
+ if (pr && pr(cell, cf.rule)) {
32976
+ if (!computedStyle[col])
32977
+ computedStyle[col] = [];
32978
+ // we must combine all the properties of all the CF rules applied to the given cell
32979
+ computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
32897
32980
  }
32898
32981
  }
32899
32982
  }
32900
- break;
32901
- }
32902
- }
32903
- catch (_) {
32904
- // we don't care about the errors within the evaluation of a rule
32983
+ }
32984
+ break;
32905
32985
  }
32906
32986
  }
32907
32987
  }
@@ -32926,7 +33006,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
32926
33006
  return percentile(rangeValues, Number(threshold.value) / 100, true);
32927
33007
  case "formula":
32928
33008
  const value = threshold.value && this.getters.evaluateFormula(threshold.value);
32929
- return !(value instanceof Promise) ? value : null;
33009
+ return typeof value === "number" ? value : null;
32930
33010
  default:
32931
33011
  return null;
32932
33012
  }
@@ -34488,24 +34568,27 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
34488
34568
  * autofiller
34489
34569
  */
34490
34570
  autofillAuto() {
34571
+ var _a, _b;
34491
34572
  const zone = this.getters.getSelectedZone();
34492
34573
  const sheetId = this.getters.getActiveSheetId();
34493
34574
  let col = zone.left;
34494
34575
  let row = zone.bottom;
34495
34576
  if (col > 0) {
34496
- let left = this.getters.getEvaluatedCell({ sheetId, col: col - 1, row });
34497
- while (left.type !== CellValueType.empty) {
34577
+ let leftPosition = { sheetId, col: col - 1, row };
34578
+ while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty ||
34579
+ ((_a = this.getters.getCell(leftPosition)) === null || _a === void 0 ? void 0 : _a.content)) {
34498
34580
  row += 1;
34499
- left = this.getters.getEvaluatedCell({ sheetId, col: col - 1, row });
34581
+ leftPosition = { sheetId, col: col - 1, row };
34500
34582
  }
34501
34583
  }
34502
34584
  if (row === zone.bottom) {
34503
34585
  col = zone.right;
34504
34586
  if (col <= this.getters.getNumberCols(sheetId)) {
34505
- let right = this.getters.getEvaluatedCell({ sheetId, col: col + 1, row });
34506
- while (right.type !== CellValueType.empty) {
34587
+ let rightPosition = { sheetId, col: col + 1, row };
34588
+ while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty ||
34589
+ ((_b = this.getters.getCell(rightPosition)) === null || _b === void 0 ? void 0 : _b.content)) {
34507
34590
  row += 1;
34508
- right = this.getters.getEvaluatedCell({ sheetId, col: col + 1, row });
34591
+ rightPosition = { sheetId, col: col + 1, row };
34509
34592
  }
34510
34593
  }
34511
34594
  }
@@ -39237,7 +39320,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
39237
39320
  sheetId: cmd.sheetId,
39238
39321
  base: cmd.base,
39239
39322
  quantity: thickness,
39240
- position: "before",
39323
+ position: cmd.position,
39241
39324
  });
39242
39325
  const isCol = cmd.dimension === "COL";
39243
39326
  const start = cmd.elements[0];
@@ -39254,12 +39337,13 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
39254
39337
  },
39255
39338
  ];
39256
39339
  const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
39340
+ const base = isBasedBefore ? cmd.base : cmd.base + 1;
39257
39341
  const pasteTarget = [
39258
39342
  {
39259
- left: isCol ? cmd.base : 0,
39260
- right: isCol ? cmd.base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
39261
- top: !isCol ? cmd.base : 0,
39262
- bottom: !isCol ? cmd.base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
39343
+ left: isCol ? base : 0,
39344
+ right: isCol ? base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
39345
+ top: !isCol ? base : 0,
39346
+ bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
39263
39347
  },
39264
39348
  ];
39265
39349
  state.paste(pasteTarget, { selectTarget: true });
@@ -39296,6 +39380,11 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
39296
39380
  doesElementsHaveCommonMerges(id, cmd.base - 1, cmd.base)) {
39297
39381
  return 2 /* CommandResult.WillRemoveExistingMerge */;
39298
39382
  }
39383
+ const headers = [cmd.base, ...cmd.elements];
39384
+ const maxHeaderValue = isCol ? this.getters.getNumberCols(id) : this.getters.getNumberRows(id);
39385
+ if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
39386
+ return 86 /* CommandResult.InvalidHeaderIndex */;
39387
+ }
39299
39388
  return 0 /* CommandResult.Success */;
39300
39389
  }
39301
39390
  //-------------------------------------------
@@ -40849,7 +40938,7 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
40849
40938
  }
40850
40939
  onKeydown(ev) {
40851
40940
  let keyDownString = "";
40852
- if (ev.ctrlKey || ev.metaKey) {
40941
+ if (isCtrlKey(ev)) {
40853
40942
  keyDownString += "CTRL+";
40854
40943
  }
40855
40944
  keyDownString += ev.key.toUpperCase();
@@ -44476,9 +44565,9 @@ day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} ) ${_lt("A
44476
44565
  Object.defineProperty(exports, '__esModule', { value: true });
44477
44566
 
44478
44567
 
44479
- __info__.version = '16.1.28';
44480
- __info__.date = '2023-11-24T13:11:01.992Z';
44481
- __info__.hash = '257f369';
44568
+ __info__.version = '16.1.31';
44569
+ __info__.date = '2024-01-12T13:42:11.001Z';
44570
+ __info__.hash = 'f51befa';
44482
44571
 
44483
44572
 
44484
44573
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);