@odoo/o-spreadsheet 16.0.26 → 16.0.28

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.
@@ -303,15 +303,76 @@ for (let font of fontSizes) {
303
303
  // -----------------------------------------------------------------------------
304
304
  // Date Type
305
305
  // -----------------------------------------------------------------------------
306
+ /**
307
+ * A DateTime object that can be used to manipulate spreadsheet dates.
308
+ * Conceptually, a spreadsheet date is simply a number with a date format,
309
+ * and it is timezone-agnostic.
310
+ * This DateTime object consistently uses UTC time to represent a naive date and time.
311
+ */
312
+ class DateTime {
313
+ constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
314
+ this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
315
+ }
316
+ static fromTimestamp(timestamp) {
317
+ const date = new Date(timestamp);
318
+ return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
319
+ }
320
+ static now() {
321
+ const now = new Date();
322
+ return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
323
+ }
324
+ toString() {
325
+ return this.jsDate.toString();
326
+ }
327
+ getTime() {
328
+ return this.jsDate.getTime();
329
+ }
330
+ getFullYear() {
331
+ return this.jsDate.getUTCFullYear();
332
+ }
333
+ getMonth() {
334
+ return this.jsDate.getUTCMonth();
335
+ }
336
+ getDate() {
337
+ return this.jsDate.getUTCDate();
338
+ }
339
+ getDay() {
340
+ return this.jsDate.getUTCDay();
341
+ }
342
+ getHours() {
343
+ return this.jsDate.getUTCHours();
344
+ }
345
+ getMinutes() {
346
+ return this.jsDate.getUTCMinutes();
347
+ }
348
+ getSeconds() {
349
+ return this.jsDate.getUTCSeconds();
350
+ }
351
+ setFullYear(year) {
352
+ this.jsDate.setFullYear(year);
353
+ }
354
+ setDate(date) {
355
+ this.jsDate.setUTCDate(date);
356
+ }
357
+ setHours(hours) {
358
+ this.jsDate.setUTCHours(hours);
359
+ }
360
+ setMinutes(minutes) {
361
+ this.jsDate.setUTCMinutes(minutes);
362
+ }
363
+ setSeconds(seconds) {
364
+ this.jsDate.setUTCSeconds(seconds);
365
+ }
366
+ }
306
367
  // -----------------------------------------------------------------------------
307
368
  // Parsing
308
369
  // -----------------------------------------------------------------------------
309
- const INITIAL_1900_DAY = new Date(1899, 11, 30);
370
+ const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
310
371
  const MS_PER_DAY = 24 * 60 * 60 * 1000;
311
372
  const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
312
- const CURRENT_YEAR = new Date().getFullYear();
313
- const INITIAL_JS_DAY = new Date(0);
314
- const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY;
373
+ const CURRENT_YEAR = DateTime.now().getFullYear();
374
+ const INITIAL_JS_DAY = DateTime.fromTimestamp(0);
375
+ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY.getTime() - INITIAL_1900_DAY.getTime();
315
376
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
316
377
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
317
378
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
@@ -360,7 +421,7 @@ function _parseDateTime(str) {
360
421
  return {
361
422
  value: date.value + time.value,
362
423
  format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
363
- 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()),
424
+ 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()),
364
425
  };
365
426
  }
366
427
  return date || time;
@@ -377,13 +438,13 @@ function parseDate(str, dateFormat) {
377
438
  const day = Number(parts[dayIndex]);
378
439
  const leadingZero = (parts[monthIndex].length === 2 && month < 10) || (parts[dayIndex].length === 2 && day < 10);
379
440
  const year = parts[yearIndex] ? inferYear(parts[yearIndex]) : CURRENT_YEAR;
380
- const jsDate = new Date(year, month - 1, day);
441
+ const jsDate = new DateTime(year, month - 1, day);
381
442
  const sep = str.match(/\/|-|\s/)[0];
382
443
  if (jsDate.getMonth() !== month - 1 || jsDate.getDate() !== day) {
383
444
  // invalid date
384
445
  return null;
385
446
  }
386
- const delta = jsDate - INITIAL_1900_DAY;
447
+ const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
387
448
  let format = leadingZero ? `mm${sep}dd` : `m${sep}d`;
388
449
  if (parts[yearIndex]) {
389
450
  format = isMDY ? format + sep + "yyyy" : "yyyy" + sep + format;
@@ -443,7 +504,7 @@ function parseTime(str) {
443
504
  if (hours >= 24) {
444
505
  format = "hhhh:mm:ss";
445
506
  }
446
- const jsDate = new Date(1899, 11, 30, hours, minutes, seconds);
507
+ const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
447
508
  return {
448
509
  value: hours / 24 + minutes / 1440 + seconds / 86400,
449
510
  format: format,
@@ -457,7 +518,7 @@ function parseTime(str) {
457
518
  // -----------------------------------------------------------------------------
458
519
  function numberToJsDate(value) {
459
520
  const truncValue = Math.trunc(value);
460
- let date = new Date(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
521
+ let date = DateTime.fromTimestamp(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
461
522
  let time = value - truncValue;
462
523
  time = time < 0 ? 1 + time : time;
463
524
  const hours = Math.round(time * 24);
@@ -474,7 +535,7 @@ function jsDateToRoundNumber(date) {
474
535
  }
475
536
  /** Return the number of days in the current month of the given date */
476
537
  function getDaysInMonth(date) {
477
- return new Date(date.getFullYear(), date.getMonth() + 1, 0).getDate();
538
+ return new DateTime(date.getFullYear(), date.getMonth() + 1, 0).getDate();
478
539
  }
479
540
  function isLastDayOfMonth(date) {
480
541
  return getDaysInMonth(date) === date.getDate();
@@ -492,7 +553,7 @@ function addMonthsToDate(date, months, keepEndOfMonth) {
492
553
  const yStart = date.getFullYear();
493
554
  const mStart = date.getMonth();
494
555
  const dStart = date.getDate();
495
- const jsDate = new Date(yStart, mStart + months);
556
+ const jsDate = new DateTime(yStart, mStart + months, 1);
496
557
  if (keepEndOfMonth && dStart === getDaysInMonth(date)) {
497
558
  jsDate.setDate(getDaysInMonth(jsDate));
498
559
  }
@@ -845,7 +906,7 @@ function isBoolean(str) {
845
906
  function isDateTime(str) {
846
907
  return parseDateTime(str) !== null;
847
908
  }
848
- const MARKDOWN_LINK_REGEX = /^\[([^\[]+)\]\((.+)\)$/;
909
+ const MARKDOWN_LINK_REGEX = /^\[(.+)\]\((.+)\)$/;
849
910
  //link must start with http or https
850
911
  //https://stackoverflow.com/a/3809435/4760614
851
912
  const WEB_LINK_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/;
@@ -1768,7 +1829,7 @@ function formatJSTime(jsDate, format) {
1768
1829
  .map((p) => {
1769
1830
  switch (p) {
1770
1831
  case "hhhh":
1771
- const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY) / (60 * 60 * 1000));
1832
+ const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY.getTime()) / (60 * 60 * 1000));
1772
1833
  return helapsedHours.toString();
1773
1834
  case "hh":
1774
1835
  return hours.toString().padStart(2, "0");
@@ -3883,6 +3944,7 @@ function getMenuDescription(node) {
3883
3944
  return node.description ? node.description : "";
3884
3945
  }
3885
3946
 
3947
+ const macRegex = /Mac/i;
3886
3948
  /**
3887
3949
  * Return true if the event was triggered from
3888
3950
  * a child element.
@@ -3902,7 +3964,15 @@ function getOpenedMenus() {
3902
3964
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
3903
3965
  }
3904
3966
  function isMacOS() {
3905
- return navigator.userAgent.toUpperCase().indexOf("MAC") >= 0;
3967
+ return Boolean(macRegex.test(navigator.userAgent));
3968
+ }
3969
+ /**
3970
+ * @param {KeyboardEvent | MouseEvent} ev
3971
+ * @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
3972
+ * On Mac, this is the "meta" or "command" key.
3973
+ */
3974
+ function isCtrlKey(ev) {
3975
+ return isMacOS() ? ev.metaKey : ev.ctrlKey;
3906
3976
  }
3907
3977
 
3908
3978
  /**
@@ -13835,7 +13905,7 @@ const DATE = {
13835
13905
  if (_year < 1900) {
13836
13906
  _year += 1900;
13837
13907
  }
13838
- const jsDate = new Date(_year, _month - 1, _day);
13908
+ const jsDate = new DateTime(_year, _month - 1, _day);
13839
13909
  const result = jsDateToRoundNumber(jsDate);
13840
13910
  assert(() => result >= 0, _lt(`The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900.`));
13841
13911
  return result;
@@ -13947,7 +14017,7 @@ const EOMONTH = {
13947
14017
  const _months = Math.trunc(toNumber(months));
13948
14018
  const yStart = _startDate.getFullYear();
13949
14019
  const mStart = _startDate.getMonth();
13950
- const jsDate = new Date(yStart, mStart + _months + 1, 0);
14020
+ const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
13951
14021
  return jsDateToRoundNumber(jsDate);
13952
14022
  },
13953
14023
  isExported: true,
@@ -13986,17 +14056,17 @@ const ISOWEEKNUM = {
13986
14056
  // The first week of the year is the week that contains the first
13987
14057
  // Thursday of the year.
13988
14058
  let firstThursday = 1;
13989
- while (new Date(y, 0, firstThursday).getDay() !== 4) {
14059
+ while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
13990
14060
  firstThursday += 1;
13991
14061
  }
13992
- const firstDayOfFirstWeek = new Date(y, 0, firstThursday - 3);
14062
+ const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
13993
14063
  // The last week of the year is the week that contains the last Thursday of
13994
14064
  // the year.
13995
14065
  let lastThursday = 31;
13996
- while (new Date(y, 11, lastThursday).getDay() !== 4) {
14066
+ while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
13997
14067
  lastThursday -= 1;
13998
14068
  }
13999
- const lastDayOfLastWeek = new Date(y, 11, lastThursday + 3);
14069
+ const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
14000
14070
  // B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
14001
14071
  // If our date < firstDayOfFirstWeek then it's in the weeks of the year before
14002
14072
  let offsetYear;
@@ -14022,17 +14092,17 @@ const ISOWEEKNUM = {
14022
14092
  case 1:
14023
14093
  // firstDay is the 1st day of the 1st week of the year after
14024
14094
  // firstDay = lastDayOfLastWeek + 1 Day
14025
- firstDay = new Date(y, 11, lastThursday + 3 + 1);
14095
+ firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
14026
14096
  break;
14027
14097
  case -1:
14028
14098
  // firstDay is the 1st day of the 1st week of the previous year.
14029
14099
  // The first week of the previous year is the week that contains the
14030
14100
  // first Thursday of the previous year.
14031
14101
  let firstThursdayPreviousYear = 1;
14032
- while (new Date(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
14102
+ while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
14033
14103
  firstThursdayPreviousYear += 1;
14034
14104
  }
14035
- firstDay = new Date(y - 1, 0, firstThursdayPreviousYear - 3);
14105
+ firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
14036
14106
  break;
14037
14107
  }
14038
14108
  const diff = (_date.getTime() - firstDay.getTime()) / MS_PER_DAY;
@@ -14171,8 +14241,8 @@ const NETWORKDAYS_INTL = {
14171
14241
  });
14172
14242
  }
14173
14243
  const invertDate = _startDate.getTime() > _endDate.getTime();
14174
- const stopDate = new Date((invertDate ? _startDate : _endDate).getTime());
14175
- let stepDate = new Date((invertDate ? _endDate : _startDate).getTime());
14244
+ const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
14245
+ let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
14176
14246
  const timeStopDate = stopDate.getTime();
14177
14247
  let timeStepDate = stepDate.getTime();
14178
14248
  let netWorkingDay = 0;
@@ -14196,8 +14266,7 @@ const NOW = {
14196
14266
  returns: ["DATE"],
14197
14267
  computeFormat: () => "m/d/yyyy hh:mm:ss",
14198
14268
  compute: function () {
14199
- let today = new Date();
14200
- today.setMilliseconds(0);
14269
+ let today = DateTime.now();
14201
14270
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
14202
14271
  const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
14203
14272
  return Math.floor(delta / MS_PER_DAY) + time;
@@ -14271,8 +14340,8 @@ const TODAY = {
14271
14340
  returns: ["DATE"],
14272
14341
  computeFormat: () => "m/d/yyyy",
14273
14342
  compute: function () {
14274
- const today = new Date();
14275
- const jsDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
14343
+ const today = DateTime.now();
14344
+ const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
14276
14345
  return jsDateToRoundNumber(jsDate);
14277
14346
  },
14278
14347
  isExported: true,
@@ -14327,10 +14396,10 @@ const WEEKNUM = {
14327
14396
  }
14328
14397
  const y = _date.getFullYear();
14329
14398
  let dayStart = 1;
14330
- let startDayOfFirstWeek = new Date(y, 0, dayStart);
14399
+ let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
14331
14400
  while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
14332
14401
  dayStart += 1;
14333
- startDayOfFirstWeek = new Date(y, 0, dayStart);
14402
+ startDayOfFirstWeek = new DateTime(y, 0, dayStart);
14334
14403
  }
14335
14404
  const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / MS_PER_DAY;
14336
14405
  if (dif < 0) {
@@ -14384,7 +14453,7 @@ const WORKDAY_INTL = {
14384
14453
  timesHoliday.add(holiday.getTime());
14385
14454
  });
14386
14455
  }
14387
- let stepDate = new Date(_startDate.getTime());
14456
+ let stepDate = DateTime.fromTimestamp(_startDate.getTime());
14388
14457
  let timeStepDate = stepDate.getTime();
14389
14458
  const unitDay = Math.sign(_numDays);
14390
14459
  let stepDay = Math.abs(_numDays);
@@ -14450,7 +14519,7 @@ const MONTH_START = {
14450
14519
  const _startDate = toJsDate(date);
14451
14520
  const yStart = _startDate.getFullYear();
14452
14521
  const mStart = _startDate.getMonth();
14453
- const jsDate = new Date(yStart, mStart, 1);
14522
+ const jsDate = new DateTime(yStart, mStart, 1);
14454
14523
  return jsDateToRoundNumber(jsDate);
14455
14524
  },
14456
14525
  };
@@ -14494,7 +14563,7 @@ const QUARTER_START = {
14494
14563
  compute: function (date) {
14495
14564
  const quarter = QUARTER.compute(date);
14496
14565
  const year = YEAR.compute(date);
14497
- const jsDate = new Date(year, (quarter - 1) * 3, 1);
14566
+ const jsDate = new DateTime(year, (quarter - 1) * 3, 1);
14498
14567
  return jsDateToRoundNumber(jsDate);
14499
14568
  },
14500
14569
  };
@@ -14511,7 +14580,7 @@ const QUARTER_END = {
14511
14580
  compute: function (date) {
14512
14581
  const quarter = QUARTER.compute(date);
14513
14582
  const year = YEAR.compute(date);
14514
- const jsDate = new Date(year, quarter * 3, 0);
14583
+ const jsDate = new DateTime(year, quarter * 3, 0);
14515
14584
  return jsDateToRoundNumber(jsDate);
14516
14585
  },
14517
14586
  };
@@ -14527,7 +14596,7 @@ const YEAR_START = {
14527
14596
  computeFormat: () => "m/d/yyyy",
14528
14597
  compute: function (date) {
14529
14598
  const year = YEAR.compute(date);
14530
- const jsDate = new Date(year, 0, 1);
14599
+ const jsDate = new DateTime(year, 0, 1);
14531
14600
  return jsDateToRoundNumber(jsDate);
14532
14601
  },
14533
14602
  };
@@ -14543,7 +14612,7 @@ const YEAR_END = {
14543
14612
  computeFormat: () => "m/d/yyyy",
14544
14613
  compute: function (date) {
14545
14614
  const year = YEAR.compute(date);
14546
- const jsDate = new Date(year + 1, 0, 0);
14615
+ const jsDate = new DateTime(year + 1, 0, 0);
14547
14616
  return jsDateToRoundNumber(jsDate);
14548
14617
  },
14549
14618
  };
@@ -14677,7 +14746,7 @@ function assertDeprecationFactorStrictlyPositive(factor) {
14677
14746
  function assertSettlementLessThanOneYearBeforeMaturity(settlement, maturity) {
14678
14747
  const startDate = toJsDate(settlement);
14679
14748
  const endDate = toJsDate(maturity);
14680
- const startDatePlusOneYear = new Date(startDate);
14749
+ const startDatePlusOneYear = toJsDate(settlement);
14681
14750
  startDatePlusOneYear.setFullYear(startDate.getFullYear() + 1);
14682
14751
  assert(() => endDate.getTime() <= startDatePlusOneYear.getTime(), _lt("The settlement date (%s) must at most one year after the maturity date (%s).", settlement.toString(), maturity.toString()));
14683
14752
  }
@@ -21472,7 +21541,10 @@ class GridOverlay extends Component {
21472
21541
  return;
21473
21542
  }
21474
21543
  const [col, row] = this.getCartesianCoordinates(ev);
21475
- this.props.onCellClicked(col, row, { shiftKey: ev.shiftKey, ctrlKey: ev.ctrlKey });
21544
+ this.props.onCellClicked(col, row, {
21545
+ expandZone: ev.shiftKey,
21546
+ addZone: isCtrlKey(ev),
21547
+ });
21476
21548
  }
21477
21549
  onDoubleClick(ev) {
21478
21550
  const [col, row] = this.getCartesianCoordinates(ev);
@@ -21700,7 +21772,7 @@ class AbstractResizer extends Component {
21700
21772
  this._increaseSelection(index);
21701
21773
  }
21702
21774
  else {
21703
- this._selectElement(index, ev.ctrlKey);
21775
+ this._selectElement(index, isCtrlKey(ev));
21704
21776
  }
21705
21777
  this.lastSelectedElementIndex = index;
21706
21778
  const mouseMoveSelect = (col, row) => {
@@ -21713,7 +21785,7 @@ class AbstractResizer extends Component {
21713
21785
  const mouseUpSelect = () => {
21714
21786
  this.state.isSelecting = false;
21715
21787
  this.lastSelectedElementIndex = null;
21716
- this.env.model.dispatch(ev.ctrlKey ? "PREPARE_SELECTION_INPUT_EXPANSION" : "STOP_SELECTION_INPUT");
21788
+ this.env.model.dispatch(isCtrlKey(ev) ? "PREPARE_SELECTION_INPUT_EXPANSION" : "STOP_SELECTION_INPUT");
21717
21789
  this._computeGrabDisplay(ev);
21718
21790
  };
21719
21791
  dragAndDropBeyondTheViewport(this.env, mouseMoveSelect, mouseUpSelect);
@@ -21860,8 +21932,8 @@ class ColResizer extends AbstractResizer {
21860
21932
  this.env.raiseError(MergeErrorMessage);
21861
21933
  }
21862
21934
  }
21863
- _selectElement(index, ctrlKey) {
21864
- this.env.model.selection.selectColumn(index, ctrlKey ? "newAnchor" : "overrideSelection");
21935
+ _selectElement(index, addDistinctHeader) {
21936
+ this.env.model.selection.selectColumn(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
21865
21937
  }
21866
21938
  _increaseSelection(index) {
21867
21939
  this.env.model.selection.selectColumn(index, "updateAnchor");
@@ -22030,8 +22102,8 @@ class RowResizer extends AbstractResizer {
22030
22102
  this.env.raiseError(MergeErrorMessage);
22031
22103
  }
22032
22104
  }
22033
- _selectElement(index, ctrlKey) {
22034
- this.env.model.selection.selectRow(index, ctrlKey ? "newAnchor" : "overrideSelection");
22105
+ _selectElement(index, addDistinctHeader) {
22106
+ this.env.model.selection.selectRow(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
22035
22107
  }
22036
22108
  _increaseSelection(index) {
22037
22109
  this.env.model.selection.selectRow(index, "updateAnchor");
@@ -22722,18 +22794,18 @@ class Grid extends Component {
22722
22794
  // ---------------------------------------------------------------------------
22723
22795
  // Zone selection with mouse
22724
22796
  // ---------------------------------------------------------------------------
22725
- onCellClicked(col, row, { ctrlKey, shiftKey }) {
22726
- if (ctrlKey) {
22797
+ onCellClicked(col, row, { addZone, expandZone }) {
22798
+ if (addZone) {
22727
22799
  this.env.model.dispatch("PREPARE_SELECTION_INPUT_EXPANSION");
22728
22800
  }
22729
22801
  this.closeOpenedPopover();
22730
22802
  if (this.env.model.getters.getEditionMode() === "editing") {
22731
22803
  this.env.model.dispatch("STOP_EDITION");
22732
22804
  }
22733
- if (shiftKey) {
22805
+ if (expandZone) {
22734
22806
  this.env.model.selection.setAnchorCorner(col, row);
22735
22807
  }
22736
- else if (ctrlKey) {
22808
+ else if (addZone) {
22737
22809
  this.env.model.selection.addCellToSelection(col, row);
22738
22810
  }
22739
22811
  else {
@@ -22787,10 +22859,10 @@ class Grid extends Component {
22787
22859
  };
22788
22860
  const direction = arrowMap[ev.key];
22789
22861
  if (ev.shiftKey) {
22790
- this.env.model.selection.resizeAnchorZone(direction, ev.ctrlKey ? "end" : 1);
22862
+ this.env.model.selection.resizeAnchorZone(direction, isCtrlKey(ev) ? "end" : 1);
22791
22863
  }
22792
22864
  else {
22793
- this.env.model.selection.moveAnchorCell(direction, ev.ctrlKey ? "end" : 1);
22865
+ this.env.model.selection.moveAnchorCell(direction, isCtrlKey(ev) ? "end" : 1);
22794
22866
  }
22795
22867
  if (this.env.model.getters.isPaintingFormat()) {
22796
22868
  this.env.model.dispatch("PASTE", {
@@ -22804,9 +22876,7 @@ class Grid extends Component {
22804
22876
  return;
22805
22877
  }
22806
22878
  let keyDownString = "";
22807
- if (ev.ctrlKey)
22808
- keyDownString += "CTRL+";
22809
- if (ev.metaKey)
22879
+ if (isCtrlKey(ev))
22810
22880
  keyDownString += "CTRL+";
22811
22881
  if (ev.altKey)
22812
22882
  keyDownString += "ALT+";
@@ -32567,13 +32637,18 @@ class EvaluationPlugin extends UIPlugin {
32567
32637
  // Getters
32568
32638
  // ---------------------------------------------------------------------------
32569
32639
  evaluateFormula(formulaString, sheetId = this.getters.getActiveSheetId()) {
32570
- const compiledFormula = compile(formulaString);
32571
- const params = this.getCompilationParameters(() => { });
32572
- const ranges = [];
32573
- for (let xc of compiledFormula.dependencies) {
32574
- ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
32640
+ try {
32641
+ const compiledFormula = compile(formulaString);
32642
+ const params = this.getCompilationParameters(() => { });
32643
+ const ranges = [];
32644
+ for (let xc of compiledFormula.dependencies) {
32645
+ ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
32646
+ }
32647
+ return compiledFormula.execute(ranges, ...params).value;
32648
+ }
32649
+ catch (error) {
32650
+ return error instanceof EvaluationError ? error.errorType : CellErrorType.GenericError;
32575
32651
  }
32576
- return compiledFormula.execute(ranges, ...params).value;
32577
32652
  }
32578
32653
  /**
32579
32654
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -32975,39 +33050,34 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
32975
33050
  this.computedIcons[activeSheetId] = {};
32976
33051
  const computedStyle = this.computedStyles[activeSheetId];
32977
33052
  for (let cf of this.getters.getConditionalFormats(activeSheetId).reverse()) {
32978
- try {
32979
- switch (cf.rule.type) {
32980
- case "ColorScaleRule":
32981
- for (let range of cf.ranges) {
32982
- this.applyColorScale(range, cf.rule);
32983
- }
32984
- break;
32985
- case "IconSetRule":
32986
- for (let range of cf.ranges) {
32987
- this.applyIcon(range, cf.rule);
32988
- }
32989
- break;
32990
- default:
32991
- for (let ref of cf.ranges) {
32992
- const zone = this.getters.getRangeFromSheetXC(activeSheetId, ref).zone;
32993
- for (let row = zone.top; row <= zone.bottom; row++) {
32994
- for (let col = zone.left; col <= zone.right; col++) {
32995
- const pr = this.rulePredicate[cf.rule.type];
32996
- let cell = this.getters.getCell(activeSheetId, col, row);
32997
- if (pr && pr(cell, cf.rule)) {
32998
- if (!computedStyle[col])
32999
- computedStyle[col] = [];
33000
- // we must combine all the properties of all the CF rules applied to the given cell
33001
- computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
33002
- }
33053
+ switch (cf.rule.type) {
33054
+ case "ColorScaleRule":
33055
+ for (let range of cf.ranges) {
33056
+ this.applyColorScale(range, cf.rule);
33057
+ }
33058
+ break;
33059
+ case "IconSetRule":
33060
+ for (let range of cf.ranges) {
33061
+ this.applyIcon(range, cf.rule);
33062
+ }
33063
+ break;
33064
+ default:
33065
+ for (let ref of cf.ranges) {
33066
+ const zone = this.getters.getRangeFromSheetXC(activeSheetId, ref).zone;
33067
+ for (let row = zone.top; row <= zone.bottom; row++) {
33068
+ for (let col = zone.left; col <= zone.right; col++) {
33069
+ const pr = this.rulePredicate[cf.rule.type];
33070
+ let cell = this.getters.getCell(activeSheetId, col, row);
33071
+ if (pr && pr(cell, cf.rule)) {
33072
+ if (!computedStyle[col])
33073
+ computedStyle[col] = [];
33074
+ // we must combine all the properties of all the CF rules applied to the given cell
33075
+ computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
33003
33076
  }
33004
33077
  }
33005
33078
  }
33006
- break;
33007
- }
33008
- }
33009
- catch (_) {
33010
- // we don't care about the errors within the evaluation of a rule
33079
+ }
33080
+ break;
33011
33081
  }
33012
33082
  }
33013
33083
  }
@@ -33031,7 +33101,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
33031
33101
  return percentile(rangeValues, Number(threshold.value) / 100, true);
33032
33102
  case "formula":
33033
33103
  const value = threshold.value && this.getters.evaluateFormula(threshold.value);
33034
- return !(value instanceof Promise) ? value : null;
33104
+ return typeof value === "number" ? value : null;
33035
33105
  default:
33036
33106
  return null;
33037
33107
  }
@@ -39110,7 +39180,7 @@ class Spreadsheet extends Component {
39110
39180
  }
39111
39181
  onKeydown(ev) {
39112
39182
  let keyDownString = "";
39113
- if (ev.ctrlKey || ev.metaKey) {
39183
+ if (isCtrlKey(ev)) {
39114
39184
  keyDownString += "CTRL+";
39115
39185
  }
39116
39186
  keyDownString += ev.key.toUpperCase();
@@ -43029,6 +43099,6 @@ function addFunction(functionName, functionDescription) {
43029
43099
  export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, cellTypes, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, load, parse, readonlyAllowedCommands, registries, setTranslationMethod, tokenize };
43030
43100
 
43031
43101
 
43032
- __info__.version = '16.0.26';
43033
- __info__.date = '2023-12-05T09:37:20.450Z';
43034
- __info__.hash = '10de093';
43102
+ __info__.version = '16.0.28';
43103
+ __info__.date = '2024-01-12T13:42:04.756Z';
43104
+ __info__.hash = '7251a47';