@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.
- package/dist/o-spreadsheet.cjs.js +165 -95
- package/dist/o-spreadsheet.d.ts +37 -10
- package/dist/o-spreadsheet.esm.js +165 -95
- package/dist/o-spreadsheet.iife.js +165 -95
- package/dist/o-spreadsheet.iife.min.js +246 -246
- package/dist/o_spreadsheet.xml +3 -3
- package/package.json +1 -1
|
@@ -307,15 +307,76 @@ for (let font of fontSizes) {
|
|
|
307
307
|
// -----------------------------------------------------------------------------
|
|
308
308
|
// Date Type
|
|
309
309
|
// -----------------------------------------------------------------------------
|
|
310
|
+
/**
|
|
311
|
+
* A DateTime object that can be used to manipulate spreadsheet dates.
|
|
312
|
+
* Conceptually, a spreadsheet date is simply a number with a date format,
|
|
313
|
+
* and it is timezone-agnostic.
|
|
314
|
+
* This DateTime object consistently uses UTC time to represent a naive date and time.
|
|
315
|
+
*/
|
|
316
|
+
class DateTime {
|
|
317
|
+
constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
|
|
318
|
+
this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
|
|
319
|
+
}
|
|
320
|
+
static fromTimestamp(timestamp) {
|
|
321
|
+
const date = new Date(timestamp);
|
|
322
|
+
return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
|
|
323
|
+
}
|
|
324
|
+
static now() {
|
|
325
|
+
const now = new Date();
|
|
326
|
+
return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
|
|
327
|
+
}
|
|
328
|
+
toString() {
|
|
329
|
+
return this.jsDate.toString();
|
|
330
|
+
}
|
|
331
|
+
getTime() {
|
|
332
|
+
return this.jsDate.getTime();
|
|
333
|
+
}
|
|
334
|
+
getFullYear() {
|
|
335
|
+
return this.jsDate.getUTCFullYear();
|
|
336
|
+
}
|
|
337
|
+
getMonth() {
|
|
338
|
+
return this.jsDate.getUTCMonth();
|
|
339
|
+
}
|
|
340
|
+
getDate() {
|
|
341
|
+
return this.jsDate.getUTCDate();
|
|
342
|
+
}
|
|
343
|
+
getDay() {
|
|
344
|
+
return this.jsDate.getUTCDay();
|
|
345
|
+
}
|
|
346
|
+
getHours() {
|
|
347
|
+
return this.jsDate.getUTCHours();
|
|
348
|
+
}
|
|
349
|
+
getMinutes() {
|
|
350
|
+
return this.jsDate.getUTCMinutes();
|
|
351
|
+
}
|
|
352
|
+
getSeconds() {
|
|
353
|
+
return this.jsDate.getUTCSeconds();
|
|
354
|
+
}
|
|
355
|
+
setFullYear(year) {
|
|
356
|
+
this.jsDate.setFullYear(year);
|
|
357
|
+
}
|
|
358
|
+
setDate(date) {
|
|
359
|
+
this.jsDate.setUTCDate(date);
|
|
360
|
+
}
|
|
361
|
+
setHours(hours) {
|
|
362
|
+
this.jsDate.setUTCHours(hours);
|
|
363
|
+
}
|
|
364
|
+
setMinutes(minutes) {
|
|
365
|
+
this.jsDate.setUTCMinutes(minutes);
|
|
366
|
+
}
|
|
367
|
+
setSeconds(seconds) {
|
|
368
|
+
this.jsDate.setUTCSeconds(seconds);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
310
371
|
// -----------------------------------------------------------------------------
|
|
311
372
|
// Parsing
|
|
312
373
|
// -----------------------------------------------------------------------------
|
|
313
|
-
const INITIAL_1900_DAY = new
|
|
374
|
+
const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
|
|
314
375
|
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
315
376
|
const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
|
|
316
|
-
const CURRENT_YEAR =
|
|
317
|
-
const INITIAL_JS_DAY =
|
|
318
|
-
const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY;
|
|
377
|
+
const CURRENT_YEAR = DateTime.now().getFullYear();
|
|
378
|
+
const INITIAL_JS_DAY = DateTime.fromTimestamp(0);
|
|
379
|
+
const DATE_JS_1900_OFFSET = INITIAL_JS_DAY.getTime() - INITIAL_1900_DAY.getTime();
|
|
319
380
|
const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
|
|
320
381
|
const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
|
|
321
382
|
const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
|
|
@@ -364,7 +425,7 @@ function _parseDateTime(str) {
|
|
|
364
425
|
return {
|
|
365
426
|
value: date.value + time.value,
|
|
366
427
|
format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
|
|
367
|
-
jsDate: new
|
|
428
|
+
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()),
|
|
368
429
|
};
|
|
369
430
|
}
|
|
370
431
|
return date || time;
|
|
@@ -381,13 +442,13 @@ function parseDate(str, dateFormat) {
|
|
|
381
442
|
const day = Number(parts[dayIndex]);
|
|
382
443
|
const leadingZero = (parts[monthIndex].length === 2 && month < 10) || (parts[dayIndex].length === 2 && day < 10);
|
|
383
444
|
const year = parts[yearIndex] ? inferYear(parts[yearIndex]) : CURRENT_YEAR;
|
|
384
|
-
const jsDate = new
|
|
445
|
+
const jsDate = new DateTime(year, month - 1, day);
|
|
385
446
|
const sep = str.match(/\/|-|\s/)[0];
|
|
386
447
|
if (jsDate.getMonth() !== month - 1 || jsDate.getDate() !== day) {
|
|
387
448
|
// invalid date
|
|
388
449
|
return null;
|
|
389
450
|
}
|
|
390
|
-
const delta = jsDate - INITIAL_1900_DAY;
|
|
451
|
+
const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
|
|
391
452
|
let format = leadingZero ? `mm${sep}dd` : `m${sep}d`;
|
|
392
453
|
if (parts[yearIndex]) {
|
|
393
454
|
format = isMDY ? format + sep + "yyyy" : "yyyy" + sep + format;
|
|
@@ -447,7 +508,7 @@ function parseTime(str) {
|
|
|
447
508
|
if (hours >= 24) {
|
|
448
509
|
format = "hhhh:mm:ss";
|
|
449
510
|
}
|
|
450
|
-
const jsDate = new
|
|
511
|
+
const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
|
|
451
512
|
return {
|
|
452
513
|
value: hours / 24 + minutes / 1440 + seconds / 86400,
|
|
453
514
|
format: format,
|
|
@@ -461,7 +522,7 @@ function parseTime(str) {
|
|
|
461
522
|
// -----------------------------------------------------------------------------
|
|
462
523
|
function numberToJsDate(value) {
|
|
463
524
|
const truncValue = Math.trunc(value);
|
|
464
|
-
let date =
|
|
525
|
+
let date = DateTime.fromTimestamp(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
|
|
465
526
|
let time = value - truncValue;
|
|
466
527
|
time = time < 0 ? 1 + time : time;
|
|
467
528
|
const hours = Math.round(time * 24);
|
|
@@ -478,7 +539,7 @@ function jsDateToRoundNumber(date) {
|
|
|
478
539
|
}
|
|
479
540
|
/** Return the number of days in the current month of the given date */
|
|
480
541
|
function getDaysInMonth(date) {
|
|
481
|
-
return new
|
|
542
|
+
return new DateTime(date.getFullYear(), date.getMonth() + 1, 0).getDate();
|
|
482
543
|
}
|
|
483
544
|
function isLastDayOfMonth(date) {
|
|
484
545
|
return getDaysInMonth(date) === date.getDate();
|
|
@@ -496,7 +557,7 @@ function addMonthsToDate(date, months, keepEndOfMonth) {
|
|
|
496
557
|
const yStart = date.getFullYear();
|
|
497
558
|
const mStart = date.getMonth();
|
|
498
559
|
const dStart = date.getDate();
|
|
499
|
-
const jsDate = new
|
|
560
|
+
const jsDate = new DateTime(yStart, mStart + months, 1);
|
|
500
561
|
if (keepEndOfMonth && dStart === getDaysInMonth(date)) {
|
|
501
562
|
jsDate.setDate(getDaysInMonth(jsDate));
|
|
502
563
|
}
|
|
@@ -849,7 +910,7 @@ function isBoolean(str) {
|
|
|
849
910
|
function isDateTime(str) {
|
|
850
911
|
return parseDateTime(str) !== null;
|
|
851
912
|
}
|
|
852
|
-
const MARKDOWN_LINK_REGEX = /^\[(
|
|
913
|
+
const MARKDOWN_LINK_REGEX = /^\[(.+)\]\((.+)\)$/;
|
|
853
914
|
//link must start with http or https
|
|
854
915
|
//https://stackoverflow.com/a/3809435/4760614
|
|
855
916
|
const WEB_LINK_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/;
|
|
@@ -1772,7 +1833,7 @@ function formatJSTime(jsDate, format) {
|
|
|
1772
1833
|
.map((p) => {
|
|
1773
1834
|
switch (p) {
|
|
1774
1835
|
case "hhhh":
|
|
1775
|
-
const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY) / (60 * 60 * 1000));
|
|
1836
|
+
const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY.getTime()) / (60 * 60 * 1000));
|
|
1776
1837
|
return helapsedHours.toString();
|
|
1777
1838
|
case "hh":
|
|
1778
1839
|
return hours.toString().padStart(2, "0");
|
|
@@ -3887,6 +3948,7 @@ function getMenuDescription(node) {
|
|
|
3887
3948
|
return node.description ? node.description : "";
|
|
3888
3949
|
}
|
|
3889
3950
|
|
|
3951
|
+
const macRegex = /Mac/i;
|
|
3890
3952
|
/**
|
|
3891
3953
|
* Return true if the event was triggered from
|
|
3892
3954
|
* a child element.
|
|
@@ -3906,7 +3968,15 @@ function getOpenedMenus() {
|
|
|
3906
3968
|
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
3907
3969
|
}
|
|
3908
3970
|
function isMacOS() {
|
|
3909
|
-
return navigator.userAgent
|
|
3971
|
+
return Boolean(macRegex.test(navigator.userAgent));
|
|
3972
|
+
}
|
|
3973
|
+
/**
|
|
3974
|
+
* @param {KeyboardEvent | MouseEvent} ev
|
|
3975
|
+
* @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
|
|
3976
|
+
* On Mac, this is the "meta" or "command" key.
|
|
3977
|
+
*/
|
|
3978
|
+
function isCtrlKey(ev) {
|
|
3979
|
+
return isMacOS() ? ev.metaKey : ev.ctrlKey;
|
|
3910
3980
|
}
|
|
3911
3981
|
|
|
3912
3982
|
/**
|
|
@@ -13839,7 +13909,7 @@ const DATE = {
|
|
|
13839
13909
|
if (_year < 1900) {
|
|
13840
13910
|
_year += 1900;
|
|
13841
13911
|
}
|
|
13842
|
-
const jsDate = new
|
|
13912
|
+
const jsDate = new DateTime(_year, _month - 1, _day);
|
|
13843
13913
|
const result = jsDateToRoundNumber(jsDate);
|
|
13844
13914
|
assert(() => result >= 0, _lt(`The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900.`));
|
|
13845
13915
|
return result;
|
|
@@ -13951,7 +14021,7 @@ const EOMONTH = {
|
|
|
13951
14021
|
const _months = Math.trunc(toNumber(months));
|
|
13952
14022
|
const yStart = _startDate.getFullYear();
|
|
13953
14023
|
const mStart = _startDate.getMonth();
|
|
13954
|
-
const jsDate = new
|
|
14024
|
+
const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
|
|
13955
14025
|
return jsDateToRoundNumber(jsDate);
|
|
13956
14026
|
},
|
|
13957
14027
|
isExported: true,
|
|
@@ -13990,17 +14060,17 @@ const ISOWEEKNUM = {
|
|
|
13990
14060
|
// The first week of the year is the week that contains the first
|
|
13991
14061
|
// Thursday of the year.
|
|
13992
14062
|
let firstThursday = 1;
|
|
13993
|
-
while (new
|
|
14063
|
+
while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
|
|
13994
14064
|
firstThursday += 1;
|
|
13995
14065
|
}
|
|
13996
|
-
const firstDayOfFirstWeek = new
|
|
14066
|
+
const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
|
|
13997
14067
|
// The last week of the year is the week that contains the last Thursday of
|
|
13998
14068
|
// the year.
|
|
13999
14069
|
let lastThursday = 31;
|
|
14000
|
-
while (new
|
|
14070
|
+
while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
|
|
14001
14071
|
lastThursday -= 1;
|
|
14002
14072
|
}
|
|
14003
|
-
const lastDayOfLastWeek = new
|
|
14073
|
+
const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
|
|
14004
14074
|
// B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
|
|
14005
14075
|
// If our date < firstDayOfFirstWeek then it's in the weeks of the year before
|
|
14006
14076
|
let offsetYear;
|
|
@@ -14026,17 +14096,17 @@ const ISOWEEKNUM = {
|
|
|
14026
14096
|
case 1:
|
|
14027
14097
|
// firstDay is the 1st day of the 1st week of the year after
|
|
14028
14098
|
// firstDay = lastDayOfLastWeek + 1 Day
|
|
14029
|
-
firstDay = new
|
|
14099
|
+
firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
|
|
14030
14100
|
break;
|
|
14031
14101
|
case -1:
|
|
14032
14102
|
// firstDay is the 1st day of the 1st week of the previous year.
|
|
14033
14103
|
// The first week of the previous year is the week that contains the
|
|
14034
14104
|
// first Thursday of the previous year.
|
|
14035
14105
|
let firstThursdayPreviousYear = 1;
|
|
14036
|
-
while (new
|
|
14106
|
+
while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
|
|
14037
14107
|
firstThursdayPreviousYear += 1;
|
|
14038
14108
|
}
|
|
14039
|
-
firstDay = new
|
|
14109
|
+
firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
|
|
14040
14110
|
break;
|
|
14041
14111
|
}
|
|
14042
14112
|
const diff = (_date.getTime() - firstDay.getTime()) / MS_PER_DAY;
|
|
@@ -14175,8 +14245,8 @@ const NETWORKDAYS_INTL = {
|
|
|
14175
14245
|
});
|
|
14176
14246
|
}
|
|
14177
14247
|
const invertDate = _startDate.getTime() > _endDate.getTime();
|
|
14178
|
-
const stopDate =
|
|
14179
|
-
let stepDate =
|
|
14248
|
+
const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
|
|
14249
|
+
let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
|
|
14180
14250
|
const timeStopDate = stopDate.getTime();
|
|
14181
14251
|
let timeStepDate = stepDate.getTime();
|
|
14182
14252
|
let netWorkingDay = 0;
|
|
@@ -14200,8 +14270,7 @@ const NOW = {
|
|
|
14200
14270
|
returns: ["DATE"],
|
|
14201
14271
|
computeFormat: () => "m/d/yyyy hh:mm:ss",
|
|
14202
14272
|
compute: function () {
|
|
14203
|
-
let today =
|
|
14204
|
-
today.setMilliseconds(0);
|
|
14273
|
+
let today = DateTime.now();
|
|
14205
14274
|
const delta = today.getTime() - INITIAL_1900_DAY.getTime();
|
|
14206
14275
|
const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
|
|
14207
14276
|
return Math.floor(delta / MS_PER_DAY) + time;
|
|
@@ -14275,8 +14344,8 @@ const TODAY = {
|
|
|
14275
14344
|
returns: ["DATE"],
|
|
14276
14345
|
computeFormat: () => "m/d/yyyy",
|
|
14277
14346
|
compute: function () {
|
|
14278
|
-
const today =
|
|
14279
|
-
const jsDate = new
|
|
14347
|
+
const today = DateTime.now();
|
|
14348
|
+
const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
|
|
14280
14349
|
return jsDateToRoundNumber(jsDate);
|
|
14281
14350
|
},
|
|
14282
14351
|
isExported: true,
|
|
@@ -14331,10 +14400,10 @@ const WEEKNUM = {
|
|
|
14331
14400
|
}
|
|
14332
14401
|
const y = _date.getFullYear();
|
|
14333
14402
|
let dayStart = 1;
|
|
14334
|
-
let startDayOfFirstWeek = new
|
|
14403
|
+
let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
|
|
14335
14404
|
while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
|
|
14336
14405
|
dayStart += 1;
|
|
14337
|
-
startDayOfFirstWeek = new
|
|
14406
|
+
startDayOfFirstWeek = new DateTime(y, 0, dayStart);
|
|
14338
14407
|
}
|
|
14339
14408
|
const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / MS_PER_DAY;
|
|
14340
14409
|
if (dif < 0) {
|
|
@@ -14388,7 +14457,7 @@ const WORKDAY_INTL = {
|
|
|
14388
14457
|
timesHoliday.add(holiday.getTime());
|
|
14389
14458
|
});
|
|
14390
14459
|
}
|
|
14391
|
-
let stepDate =
|
|
14460
|
+
let stepDate = DateTime.fromTimestamp(_startDate.getTime());
|
|
14392
14461
|
let timeStepDate = stepDate.getTime();
|
|
14393
14462
|
const unitDay = Math.sign(_numDays);
|
|
14394
14463
|
let stepDay = Math.abs(_numDays);
|
|
@@ -14454,7 +14523,7 @@ const MONTH_START = {
|
|
|
14454
14523
|
const _startDate = toJsDate(date);
|
|
14455
14524
|
const yStart = _startDate.getFullYear();
|
|
14456
14525
|
const mStart = _startDate.getMonth();
|
|
14457
|
-
const jsDate = new
|
|
14526
|
+
const jsDate = new DateTime(yStart, mStart, 1);
|
|
14458
14527
|
return jsDateToRoundNumber(jsDate);
|
|
14459
14528
|
},
|
|
14460
14529
|
};
|
|
@@ -14498,7 +14567,7 @@ const QUARTER_START = {
|
|
|
14498
14567
|
compute: function (date) {
|
|
14499
14568
|
const quarter = QUARTER.compute(date);
|
|
14500
14569
|
const year = YEAR.compute(date);
|
|
14501
|
-
const jsDate = new
|
|
14570
|
+
const jsDate = new DateTime(year, (quarter - 1) * 3, 1);
|
|
14502
14571
|
return jsDateToRoundNumber(jsDate);
|
|
14503
14572
|
},
|
|
14504
14573
|
};
|
|
@@ -14515,7 +14584,7 @@ const QUARTER_END = {
|
|
|
14515
14584
|
compute: function (date) {
|
|
14516
14585
|
const quarter = QUARTER.compute(date);
|
|
14517
14586
|
const year = YEAR.compute(date);
|
|
14518
|
-
const jsDate = new
|
|
14587
|
+
const jsDate = new DateTime(year, quarter * 3, 0);
|
|
14519
14588
|
return jsDateToRoundNumber(jsDate);
|
|
14520
14589
|
},
|
|
14521
14590
|
};
|
|
@@ -14531,7 +14600,7 @@ const YEAR_START = {
|
|
|
14531
14600
|
computeFormat: () => "m/d/yyyy",
|
|
14532
14601
|
compute: function (date) {
|
|
14533
14602
|
const year = YEAR.compute(date);
|
|
14534
|
-
const jsDate = new
|
|
14603
|
+
const jsDate = new DateTime(year, 0, 1);
|
|
14535
14604
|
return jsDateToRoundNumber(jsDate);
|
|
14536
14605
|
},
|
|
14537
14606
|
};
|
|
@@ -14547,7 +14616,7 @@ const YEAR_END = {
|
|
|
14547
14616
|
computeFormat: () => "m/d/yyyy",
|
|
14548
14617
|
compute: function (date) {
|
|
14549
14618
|
const year = YEAR.compute(date);
|
|
14550
|
-
const jsDate = new
|
|
14619
|
+
const jsDate = new DateTime(year + 1, 0, 0);
|
|
14551
14620
|
return jsDateToRoundNumber(jsDate);
|
|
14552
14621
|
},
|
|
14553
14622
|
};
|
|
@@ -14681,7 +14750,7 @@ function assertDeprecationFactorStrictlyPositive(factor) {
|
|
|
14681
14750
|
function assertSettlementLessThanOneYearBeforeMaturity(settlement, maturity) {
|
|
14682
14751
|
const startDate = toJsDate(settlement);
|
|
14683
14752
|
const endDate = toJsDate(maturity);
|
|
14684
|
-
const startDatePlusOneYear =
|
|
14753
|
+
const startDatePlusOneYear = toJsDate(settlement);
|
|
14685
14754
|
startDatePlusOneYear.setFullYear(startDate.getFullYear() + 1);
|
|
14686
14755
|
assert(() => endDate.getTime() <= startDatePlusOneYear.getTime(), _lt("The settlement date (%s) must at most one year after the maturity date (%s).", settlement.toString(), maturity.toString()));
|
|
14687
14756
|
}
|
|
@@ -21476,7 +21545,10 @@ class GridOverlay extends owl.Component {
|
|
|
21476
21545
|
return;
|
|
21477
21546
|
}
|
|
21478
21547
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
21479
|
-
this.props.onCellClicked(col, row, {
|
|
21548
|
+
this.props.onCellClicked(col, row, {
|
|
21549
|
+
expandZone: ev.shiftKey,
|
|
21550
|
+
addZone: isCtrlKey(ev),
|
|
21551
|
+
});
|
|
21480
21552
|
}
|
|
21481
21553
|
onDoubleClick(ev) {
|
|
21482
21554
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
@@ -21704,7 +21776,7 @@ class AbstractResizer extends owl.Component {
|
|
|
21704
21776
|
this._increaseSelection(index);
|
|
21705
21777
|
}
|
|
21706
21778
|
else {
|
|
21707
|
-
this._selectElement(index, ev
|
|
21779
|
+
this._selectElement(index, isCtrlKey(ev));
|
|
21708
21780
|
}
|
|
21709
21781
|
this.lastSelectedElementIndex = index;
|
|
21710
21782
|
const mouseMoveSelect = (col, row) => {
|
|
@@ -21717,7 +21789,7 @@ class AbstractResizer extends owl.Component {
|
|
|
21717
21789
|
const mouseUpSelect = () => {
|
|
21718
21790
|
this.state.isSelecting = false;
|
|
21719
21791
|
this.lastSelectedElementIndex = null;
|
|
21720
|
-
this.env.model.dispatch(ev
|
|
21792
|
+
this.env.model.dispatch(isCtrlKey(ev) ? "PREPARE_SELECTION_INPUT_EXPANSION" : "STOP_SELECTION_INPUT");
|
|
21721
21793
|
this._computeGrabDisplay(ev);
|
|
21722
21794
|
};
|
|
21723
21795
|
dragAndDropBeyondTheViewport(this.env, mouseMoveSelect, mouseUpSelect);
|
|
@@ -21864,8 +21936,8 @@ class ColResizer extends AbstractResizer {
|
|
|
21864
21936
|
this.env.raiseError(MergeErrorMessage);
|
|
21865
21937
|
}
|
|
21866
21938
|
}
|
|
21867
|
-
_selectElement(index,
|
|
21868
|
-
this.env.model.selection.selectColumn(index,
|
|
21939
|
+
_selectElement(index, addDistinctHeader) {
|
|
21940
|
+
this.env.model.selection.selectColumn(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
|
|
21869
21941
|
}
|
|
21870
21942
|
_increaseSelection(index) {
|
|
21871
21943
|
this.env.model.selection.selectColumn(index, "updateAnchor");
|
|
@@ -22034,8 +22106,8 @@ class RowResizer extends AbstractResizer {
|
|
|
22034
22106
|
this.env.raiseError(MergeErrorMessage);
|
|
22035
22107
|
}
|
|
22036
22108
|
}
|
|
22037
|
-
_selectElement(index,
|
|
22038
|
-
this.env.model.selection.selectRow(index,
|
|
22109
|
+
_selectElement(index, addDistinctHeader) {
|
|
22110
|
+
this.env.model.selection.selectRow(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
|
|
22039
22111
|
}
|
|
22040
22112
|
_increaseSelection(index) {
|
|
22041
22113
|
this.env.model.selection.selectRow(index, "updateAnchor");
|
|
@@ -22726,18 +22798,18 @@ class Grid extends owl.Component {
|
|
|
22726
22798
|
// ---------------------------------------------------------------------------
|
|
22727
22799
|
// Zone selection with mouse
|
|
22728
22800
|
// ---------------------------------------------------------------------------
|
|
22729
|
-
onCellClicked(col, row, {
|
|
22730
|
-
if (
|
|
22801
|
+
onCellClicked(col, row, { addZone, expandZone }) {
|
|
22802
|
+
if (addZone) {
|
|
22731
22803
|
this.env.model.dispatch("PREPARE_SELECTION_INPUT_EXPANSION");
|
|
22732
22804
|
}
|
|
22733
22805
|
this.closeOpenedPopover();
|
|
22734
22806
|
if (this.env.model.getters.getEditionMode() === "editing") {
|
|
22735
22807
|
this.env.model.dispatch("STOP_EDITION");
|
|
22736
22808
|
}
|
|
22737
|
-
if (
|
|
22809
|
+
if (expandZone) {
|
|
22738
22810
|
this.env.model.selection.setAnchorCorner(col, row);
|
|
22739
22811
|
}
|
|
22740
|
-
else if (
|
|
22812
|
+
else if (addZone) {
|
|
22741
22813
|
this.env.model.selection.addCellToSelection(col, row);
|
|
22742
22814
|
}
|
|
22743
22815
|
else {
|
|
@@ -22791,10 +22863,10 @@ class Grid extends owl.Component {
|
|
|
22791
22863
|
};
|
|
22792
22864
|
const direction = arrowMap[ev.key];
|
|
22793
22865
|
if (ev.shiftKey) {
|
|
22794
|
-
this.env.model.selection.resizeAnchorZone(direction, ev
|
|
22866
|
+
this.env.model.selection.resizeAnchorZone(direction, isCtrlKey(ev) ? "end" : 1);
|
|
22795
22867
|
}
|
|
22796
22868
|
else {
|
|
22797
|
-
this.env.model.selection.moveAnchorCell(direction, ev
|
|
22869
|
+
this.env.model.selection.moveAnchorCell(direction, isCtrlKey(ev) ? "end" : 1);
|
|
22798
22870
|
}
|
|
22799
22871
|
if (this.env.model.getters.isPaintingFormat()) {
|
|
22800
22872
|
this.env.model.dispatch("PASTE", {
|
|
@@ -22808,9 +22880,7 @@ class Grid extends owl.Component {
|
|
|
22808
22880
|
return;
|
|
22809
22881
|
}
|
|
22810
22882
|
let keyDownString = "";
|
|
22811
|
-
if (ev
|
|
22812
|
-
keyDownString += "CTRL+";
|
|
22813
|
-
if (ev.metaKey)
|
|
22883
|
+
if (isCtrlKey(ev))
|
|
22814
22884
|
keyDownString += "CTRL+";
|
|
22815
22885
|
if (ev.altKey)
|
|
22816
22886
|
keyDownString += "ALT+";
|
|
@@ -32571,13 +32641,18 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
32571
32641
|
// Getters
|
|
32572
32642
|
// ---------------------------------------------------------------------------
|
|
32573
32643
|
evaluateFormula(formulaString, sheetId = this.getters.getActiveSheetId()) {
|
|
32574
|
-
|
|
32575
|
-
|
|
32576
|
-
|
|
32577
|
-
|
|
32578
|
-
|
|
32644
|
+
try {
|
|
32645
|
+
const compiledFormula = compile(formulaString);
|
|
32646
|
+
const params = this.getCompilationParameters(() => { });
|
|
32647
|
+
const ranges = [];
|
|
32648
|
+
for (let xc of compiledFormula.dependencies) {
|
|
32649
|
+
ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
32650
|
+
}
|
|
32651
|
+
return compiledFormula.execute(ranges, ...params).value;
|
|
32652
|
+
}
|
|
32653
|
+
catch (error) {
|
|
32654
|
+
return error instanceof EvaluationError ? error.errorType : CellErrorType.GenericError;
|
|
32579
32655
|
}
|
|
32580
|
-
return compiledFormula.execute(ranges, ...params).value;
|
|
32581
32656
|
}
|
|
32582
32657
|
/**
|
|
32583
32658
|
* Return the value of each cell in the range as they are displayed in the grid.
|
|
@@ -32979,39 +33054,34 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
32979
33054
|
this.computedIcons[activeSheetId] = {};
|
|
32980
33055
|
const computedStyle = this.computedStyles[activeSheetId];
|
|
32981
33056
|
for (let cf of this.getters.getConditionalFormats(activeSheetId).reverse()) {
|
|
32982
|
-
|
|
32983
|
-
|
|
32984
|
-
|
|
32985
|
-
|
|
32986
|
-
|
|
32987
|
-
|
|
32988
|
-
|
|
32989
|
-
|
|
32990
|
-
|
|
32991
|
-
|
|
32992
|
-
|
|
32993
|
-
|
|
32994
|
-
|
|
32995
|
-
|
|
32996
|
-
|
|
32997
|
-
for (let
|
|
32998
|
-
|
|
32999
|
-
|
|
33000
|
-
|
|
33001
|
-
if (
|
|
33002
|
-
|
|
33003
|
-
|
|
33004
|
-
|
|
33005
|
-
computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
|
|
33006
|
-
}
|
|
33057
|
+
switch (cf.rule.type) {
|
|
33058
|
+
case "ColorScaleRule":
|
|
33059
|
+
for (let range of cf.ranges) {
|
|
33060
|
+
this.applyColorScale(range, cf.rule);
|
|
33061
|
+
}
|
|
33062
|
+
break;
|
|
33063
|
+
case "IconSetRule":
|
|
33064
|
+
for (let range of cf.ranges) {
|
|
33065
|
+
this.applyIcon(range, cf.rule);
|
|
33066
|
+
}
|
|
33067
|
+
break;
|
|
33068
|
+
default:
|
|
33069
|
+
for (let ref of cf.ranges) {
|
|
33070
|
+
const zone = this.getters.getRangeFromSheetXC(activeSheetId, ref).zone;
|
|
33071
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
33072
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
33073
|
+
const pr = this.rulePredicate[cf.rule.type];
|
|
33074
|
+
let cell = this.getters.getCell(activeSheetId, col, row);
|
|
33075
|
+
if (pr && pr(cell, cf.rule)) {
|
|
33076
|
+
if (!computedStyle[col])
|
|
33077
|
+
computedStyle[col] = [];
|
|
33078
|
+
// we must combine all the properties of all the CF rules applied to the given cell
|
|
33079
|
+
computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
|
|
33007
33080
|
}
|
|
33008
33081
|
}
|
|
33009
33082
|
}
|
|
33010
|
-
|
|
33011
|
-
|
|
33012
|
-
}
|
|
33013
|
-
catch (_) {
|
|
33014
|
-
// we don't care about the errors within the evaluation of a rule
|
|
33083
|
+
}
|
|
33084
|
+
break;
|
|
33015
33085
|
}
|
|
33016
33086
|
}
|
|
33017
33087
|
}
|
|
@@ -33035,7 +33105,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
33035
33105
|
return percentile(rangeValues, Number(threshold.value) / 100, true);
|
|
33036
33106
|
case "formula":
|
|
33037
33107
|
const value = threshold.value && this.getters.evaluateFormula(threshold.value);
|
|
33038
|
-
return
|
|
33108
|
+
return typeof value === "number" ? value : null;
|
|
33039
33109
|
default:
|
|
33040
33110
|
return null;
|
|
33041
33111
|
}
|
|
@@ -39114,7 +39184,7 @@ class Spreadsheet extends owl.Component {
|
|
|
39114
39184
|
}
|
|
39115
39185
|
onKeydown(ev) {
|
|
39116
39186
|
let keyDownString = "";
|
|
39117
|
-
if (ev
|
|
39187
|
+
if (isCtrlKey(ev)) {
|
|
39118
39188
|
keyDownString += "CTRL+";
|
|
39119
39189
|
}
|
|
39120
39190
|
keyDownString += ev.key.toUpperCase();
|
|
@@ -43061,6 +43131,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
43061
43131
|
exports.tokenize = tokenize;
|
|
43062
43132
|
|
|
43063
43133
|
|
|
43064
|
-
__info__.version = '16.0.
|
|
43065
|
-
__info__.date = '
|
|
43066
|
-
__info__.hash = '
|
|
43134
|
+
__info__.version = '16.0.28';
|
|
43135
|
+
__info__.date = '2024-01-12T13:42:04.756Z';
|
|
43136
|
+
__info__.hash = '7251a47';
|
package/dist/o-spreadsheet.d.ts
CHANGED
|
@@ -243,6 +243,33 @@ declare function toCartesian(xc: string): Position$1;
|
|
|
243
243
|
*/
|
|
244
244
|
declare function toXC(col: HeaderIndex, row: HeaderIndex, rangePart?: RangePart): string;
|
|
245
245
|
|
|
246
|
+
/**
|
|
247
|
+
* A DateTime object that can be used to manipulate spreadsheet dates.
|
|
248
|
+
* Conceptually, a spreadsheet date is simply a number with a date format,
|
|
249
|
+
* and it is timezone-agnostic.
|
|
250
|
+
* This DateTime object consistently uses UTC time to represent a naive date and time.
|
|
251
|
+
*/
|
|
252
|
+
declare class DateTime {
|
|
253
|
+
private jsDate;
|
|
254
|
+
constructor(year: number, month: number, day: number, hours?: number, minutes?: number, seconds?: number);
|
|
255
|
+
static fromTimestamp(timestamp: number): DateTime;
|
|
256
|
+
static now(): DateTime;
|
|
257
|
+
toString(): string;
|
|
258
|
+
getTime(): number;
|
|
259
|
+
getFullYear(): number;
|
|
260
|
+
getMonth(): number;
|
|
261
|
+
getDate(): number;
|
|
262
|
+
getDay(): number;
|
|
263
|
+
getHours(): number;
|
|
264
|
+
getMinutes(): number;
|
|
265
|
+
getSeconds(): number;
|
|
266
|
+
setFullYear(year: number): void;
|
|
267
|
+
setDate(date: number): void;
|
|
268
|
+
setHours(hours: number): void;
|
|
269
|
+
setMinutes(minutes: number): void;
|
|
270
|
+
setSeconds(seconds: number): void;
|
|
271
|
+
}
|
|
272
|
+
|
|
246
273
|
/**
|
|
247
274
|
* Formats a cell value with its format.
|
|
248
275
|
*/
|
|
@@ -3872,7 +3899,7 @@ declare class EvaluationPlugin extends UIPlugin {
|
|
|
3872
3899
|
constructor(getters: Getters, state: StateObserver, dispatch: CommandDispatcher["dispatch"], config: ModelConfig, selection: SelectionStreamProcessor);
|
|
3873
3900
|
handle(cmd: Command): void;
|
|
3874
3901
|
finalize(): void;
|
|
3875
|
-
evaluateFormula(formulaString: string, sheetId?: UID):
|
|
3902
|
+
evaluateFormula(formulaString: string, sheetId?: UID): FunctionReturnValue | null;
|
|
3876
3903
|
/**
|
|
3877
3904
|
* Return the value of each cell in the range as they are displayed in the grid.
|
|
3878
3905
|
*/
|
|
@@ -5759,8 +5786,8 @@ interface Props$d {
|
|
|
5759
5786
|
onCellHovered: (position: Partial<Position$1>) => void;
|
|
5760
5787
|
onCellDoubleClicked: (col: HeaderIndex, row: HeaderIndex) => void;
|
|
5761
5788
|
onCellClicked: (col: HeaderIndex, row: HeaderIndex, modifiers: {
|
|
5762
|
-
|
|
5763
|
-
|
|
5789
|
+
addZone: boolean;
|
|
5790
|
+
expandZone: boolean;
|
|
5764
5791
|
}) => void;
|
|
5765
5792
|
onCellRightClicked: (col: HeaderIndex, row: HeaderIndex, coordinates: DOMCoordinates) => void;
|
|
5766
5793
|
onGridResized: (dimension: DOMDimension) => void;
|
|
@@ -5842,7 +5869,7 @@ declare abstract class AbstractResizer extends Component<ResizerProps, Spreadshe
|
|
|
5842
5869
|
abstract _getMaxSize(): Pixel;
|
|
5843
5870
|
abstract _updateSize(): void;
|
|
5844
5871
|
abstract _moveElements(): void;
|
|
5845
|
-
abstract _selectElement(index: HeaderIndex,
|
|
5872
|
+
abstract _selectElement(index: HeaderIndex, addDistinctHeader: boolean): void;
|
|
5846
5873
|
abstract _increaseSelection(index: HeaderIndex): void;
|
|
5847
5874
|
abstract _fitElementSize(index: HeaderIndex): void;
|
|
5848
5875
|
abstract _getType(): ContextMenuType;
|
|
@@ -5876,7 +5903,7 @@ declare class ColResizer extends AbstractResizer {
|
|
|
5876
5903
|
_getMaxSize(): Pixel;
|
|
5877
5904
|
_updateSize(): void;
|
|
5878
5905
|
_moveElements(): void;
|
|
5879
|
-
_selectElement(index: HeaderIndex,
|
|
5906
|
+
_selectElement(index: HeaderIndex, addDistinctHeader: boolean): void;
|
|
5880
5907
|
_increaseSelection(index: HeaderIndex): void;
|
|
5881
5908
|
_fitElementSize(index: HeaderIndex): void;
|
|
5882
5909
|
_getType(): ContextMenuType;
|
|
@@ -5901,7 +5928,7 @@ declare class RowResizer extends AbstractResizer {
|
|
|
5901
5928
|
_getMaxSize(): Pixel;
|
|
5902
5929
|
_updateSize(): void;
|
|
5903
5930
|
_moveElements(): void;
|
|
5904
|
-
_selectElement(index: HeaderIndex,
|
|
5931
|
+
_selectElement(index: HeaderIndex, addDistinctHeader: boolean): void;
|
|
5905
5932
|
_increaseSelection(index: HeaderIndex): void;
|
|
5906
5933
|
_fitElementSize(index: HeaderIndex): void;
|
|
5907
5934
|
_getType(): ContextMenuType;
|
|
@@ -6105,9 +6132,9 @@ declare class Grid extends Component<Props$5, SpreadsheetChildEnv> {
|
|
|
6105
6132
|
private moveCanvas;
|
|
6106
6133
|
getClientPositionKey(client: Client): string;
|
|
6107
6134
|
isCellHovered(col: HeaderIndex, row: HeaderIndex): boolean;
|
|
6108
|
-
onCellClicked(col: HeaderIndex, row: HeaderIndex, {
|
|
6109
|
-
|
|
6110
|
-
|
|
6135
|
+
onCellClicked(col: HeaderIndex, row: HeaderIndex, { addZone, expandZone }: {
|
|
6136
|
+
addZone: boolean;
|
|
6137
|
+
expandZone: boolean;
|
|
6111
6138
|
}): void;
|
|
6112
6139
|
onCellDoubleClicked(col: HeaderIndex, row: HeaderIndex): void;
|
|
6113
6140
|
closeOpenedPopover(): void;
|
|
@@ -6141,7 +6168,7 @@ declare class ChartPanel extends Component<Props$4, SpreadsheetChildEnv> {
|
|
|
6141
6168
|
declare function toNumber(value: string | number | boolean | null | undefined): number;
|
|
6142
6169
|
declare function toString(value: string | number | boolean | null | undefined): string;
|
|
6143
6170
|
declare function toBoolean(value: string | number | boolean | null | undefined): boolean;
|
|
6144
|
-
declare function toJsDate(value: string | number | boolean | null | undefined):
|
|
6171
|
+
declare function toJsDate(value: string | number | boolean | null | undefined): DateTime;
|
|
6145
6172
|
|
|
6146
6173
|
/**
|
|
6147
6174
|
* This function is meant to be used as a tag for a template strings.
|