@odoo/o-spreadsheet 16.3.17 → 16.3.22
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 +318 -196
- package/dist/o-spreadsheet.d.ts +49 -25
- package/dist/o-spreadsheet.esm.js +318 -196
- package/dist/o-spreadsheet.iife.js +318 -196
- package/dist/o-spreadsheet.iife.min.js +256 -256
- package/dist/o_spreadsheet.xml +6 -7
- package/package.json +1 -1
|
@@ -299,15 +299,80 @@
|
|
|
299
299
|
// -----------------------------------------------------------------------------
|
|
300
300
|
// Date Type
|
|
301
301
|
// -----------------------------------------------------------------------------
|
|
302
|
+
/**
|
|
303
|
+
* A DateTime object that can be used to manipulate spreadsheet dates.
|
|
304
|
+
* Conceptually, a spreadsheet date is simply a number with a date format,
|
|
305
|
+
* and it is timezone-agnostic.
|
|
306
|
+
* This DateTime object consistently uses UTC time to represent a naive date and time.
|
|
307
|
+
*/
|
|
308
|
+
class DateTime {
|
|
309
|
+
jsDate;
|
|
310
|
+
constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
|
|
311
|
+
this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
|
|
312
|
+
}
|
|
313
|
+
static fromTimestamp(timestamp) {
|
|
314
|
+
const date = new Date(timestamp);
|
|
315
|
+
return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
|
|
316
|
+
}
|
|
317
|
+
static now() {
|
|
318
|
+
const now = new Date();
|
|
319
|
+
return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
|
|
320
|
+
}
|
|
321
|
+
toString() {
|
|
322
|
+
return this.jsDate.toString();
|
|
323
|
+
}
|
|
324
|
+
toLocaleDateString() {
|
|
325
|
+
return this.jsDate.toLocaleDateString();
|
|
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
|
+
}
|
|
302
367
|
// -----------------------------------------------------------------------------
|
|
303
368
|
// Parsing
|
|
304
369
|
// -----------------------------------------------------------------------------
|
|
305
|
-
const INITIAL_1900_DAY = new
|
|
370
|
+
const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
|
|
306
371
|
const MS_PER_DAY = 24 * 60 * 60 * 1000;
|
|
307
372
|
const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
|
|
308
|
-
const CURRENT_YEAR =
|
|
309
|
-
const INITIAL_JS_DAY =
|
|
310
|
-
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();
|
|
311
376
|
const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
|
|
312
377
|
const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
|
|
313
378
|
const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
|
|
@@ -356,7 +421,7 @@
|
|
|
356
421
|
return {
|
|
357
422
|
value: date.value + time.value,
|
|
358
423
|
format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
|
|
359
|
-
jsDate: new
|
|
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()),
|
|
360
425
|
};
|
|
361
426
|
}
|
|
362
427
|
return date || time;
|
|
@@ -373,13 +438,13 @@
|
|
|
373
438
|
const day = Number(parts[dayIndex]);
|
|
374
439
|
const leadingZero = (parts[monthIndex].length === 2 && month < 10) || (parts[dayIndex].length === 2 && day < 10);
|
|
375
440
|
const year = parts[yearIndex] ? inferYear(parts[yearIndex]) : CURRENT_YEAR;
|
|
376
|
-
const jsDate = new
|
|
441
|
+
const jsDate = new DateTime(year, month - 1, day);
|
|
377
442
|
const sep = str.match(/\/|-|\s/)[0];
|
|
378
443
|
if (jsDate.getMonth() !== month - 1 || jsDate.getDate() !== day) {
|
|
379
444
|
// invalid date
|
|
380
445
|
return null;
|
|
381
446
|
}
|
|
382
|
-
const delta = jsDate - INITIAL_1900_DAY;
|
|
447
|
+
const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
|
|
383
448
|
let format = leadingZero ? `mm${sep}dd` : `m${sep}d`;
|
|
384
449
|
if (parts[yearIndex]) {
|
|
385
450
|
format = isMDY ? format + sep + "yyyy" : "yyyy" + sep + format;
|
|
@@ -439,7 +504,7 @@
|
|
|
439
504
|
if (hours >= 24) {
|
|
440
505
|
format = "hhhh:mm:ss";
|
|
441
506
|
}
|
|
442
|
-
const jsDate = new
|
|
507
|
+
const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
|
|
443
508
|
return {
|
|
444
509
|
value: hours / 24 + minutes / 1440 + seconds / 86400,
|
|
445
510
|
format: format,
|
|
@@ -453,7 +518,7 @@
|
|
|
453
518
|
// -----------------------------------------------------------------------------
|
|
454
519
|
function numberToJsDate(value) {
|
|
455
520
|
const truncValue = Math.trunc(value);
|
|
456
|
-
let date =
|
|
521
|
+
let date = DateTime.fromTimestamp(truncValue * MS_PER_DAY - DATE_JS_1900_OFFSET);
|
|
457
522
|
let time = value - truncValue;
|
|
458
523
|
time = time < 0 ? 1 + time : time;
|
|
459
524
|
const hours = Math.round(time * 24);
|
|
@@ -470,7 +535,7 @@
|
|
|
470
535
|
}
|
|
471
536
|
/** Return the number of days in the current month of the given date */
|
|
472
537
|
function getDaysInMonth(date) {
|
|
473
|
-
return new
|
|
538
|
+
return new DateTime(date.getFullYear(), date.getMonth() + 1, 0).getDate();
|
|
474
539
|
}
|
|
475
540
|
function isLastDayOfMonth(date) {
|
|
476
541
|
return getDaysInMonth(date) === date.getDate();
|
|
@@ -488,7 +553,7 @@
|
|
|
488
553
|
const yStart = date.getFullYear();
|
|
489
554
|
const mStart = date.getMonth();
|
|
490
555
|
const dStart = date.getDate();
|
|
491
|
-
const jsDate = new
|
|
556
|
+
const jsDate = new DateTime(yStart, mStart + months, 1);
|
|
492
557
|
if (keepEndOfMonth && dStart === getDaysInMonth(date)) {
|
|
493
558
|
jsDate.setDate(getDaysInMonth(jsDate));
|
|
494
559
|
}
|
|
@@ -648,13 +713,6 @@
|
|
|
648
713
|
}
|
|
649
714
|
|
|
650
715
|
//------------------------------------------------------------------------------
|
|
651
|
-
/**
|
|
652
|
-
* Stringify an object, like JSON.stringify, except that the first level of keys
|
|
653
|
-
* is ordered.
|
|
654
|
-
*/
|
|
655
|
-
function stringify(obj) {
|
|
656
|
-
return JSON.stringify(obj, Object.keys(obj).sort());
|
|
657
|
-
}
|
|
658
716
|
/**
|
|
659
717
|
* Remove quotes from a quoted string
|
|
660
718
|
* ```js
|
|
@@ -884,7 +942,7 @@
|
|
|
884
942
|
function isDateTime(str) {
|
|
885
943
|
return parseDateTime(str) !== null;
|
|
886
944
|
}
|
|
887
|
-
const MARKDOWN_LINK_REGEX = /^\[(
|
|
945
|
+
const MARKDOWN_LINK_REGEX = /^\[(.+)\]\((.+)\)$/;
|
|
888
946
|
//link must start with http or https
|
|
889
947
|
//https://stackoverflow.com/a/3809435/4760614
|
|
890
948
|
const WEB_LINK_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/;
|
|
@@ -953,7 +1011,7 @@
|
|
|
953
1011
|
*/
|
|
954
1012
|
function getItemId(item, itemsDic) {
|
|
955
1013
|
for (let [key, value] of Object.entries(itemsDic)) {
|
|
956
|
-
if (
|
|
1014
|
+
if (deepEquals(value, item)) {
|
|
957
1015
|
return parseInt(key, 10);
|
|
958
1016
|
}
|
|
959
1017
|
}
|
|
@@ -1019,6 +1077,22 @@
|
|
|
1019
1077
|
lazyValue.map = (callback) => lazy(() => callback(lazyValue()));
|
|
1020
1078
|
return lazyValue;
|
|
1021
1079
|
}
|
|
1080
|
+
/**
|
|
1081
|
+
* Creates a version of the function that's memoized on the value of its first
|
|
1082
|
+
* argument, if any.
|
|
1083
|
+
*/
|
|
1084
|
+
function memoize(func) {
|
|
1085
|
+
const cache = new Map();
|
|
1086
|
+
const funcName = func.name ? func.name + " (memoized)" : "memoized";
|
|
1087
|
+
return {
|
|
1088
|
+
[funcName](...args) {
|
|
1089
|
+
if (!cache.has(args[0])) {
|
|
1090
|
+
cache.set(args[0], func(...args));
|
|
1091
|
+
}
|
|
1092
|
+
return cache.get(args[0]);
|
|
1093
|
+
},
|
|
1094
|
+
}[funcName];
|
|
1095
|
+
}
|
|
1022
1096
|
/**
|
|
1023
1097
|
* Find the next defined value after the given index in an array of strings. If there is no defined value
|
|
1024
1098
|
* after the index, return the closest defined value before the index. Return an empty string if no
|
|
@@ -1937,7 +2011,7 @@
|
|
|
1937
2011
|
.map((p) => {
|
|
1938
2012
|
switch (p) {
|
|
1939
2013
|
case "hhhh":
|
|
1940
|
-
const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY) / (60 * 60 * 1000));
|
|
2014
|
+
const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY.getTime()) / (60 * 60 * 1000));
|
|
1941
2015
|
return helapsedHours.toString();
|
|
1942
2016
|
case "hh":
|
|
1943
2017
|
return hours.toString().padStart(2, "0");
|
|
@@ -2184,8 +2258,10 @@
|
|
|
2184
2258
|
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
2185
2259
|
// Same as above, but matches the exact string (nothing before or after)
|
|
2186
2260
|
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
2187
|
-
/** Reference of a column header (eg. A, AB) */
|
|
2188
|
-
const colHeader = new RegExp(
|
|
2261
|
+
/** Reference of a column header (eg. A, AB, $A) */
|
|
2262
|
+
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
2263
|
+
/** Reference of a row header (eg. 1, $1) */
|
|
2264
|
+
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
2189
2265
|
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
2190
2266
|
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
2191
2267
|
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
@@ -2215,6 +2291,9 @@
|
|
|
2215
2291
|
function isColHeader(str) {
|
|
2216
2292
|
return colHeader.test(str);
|
|
2217
2293
|
}
|
|
2294
|
+
function isRowHeader(str) {
|
|
2295
|
+
return rowHeader.test(str);
|
|
2296
|
+
}
|
|
2218
2297
|
/**
|
|
2219
2298
|
* Return true if the given xc is the reference of a single cell,
|
|
2220
2299
|
* without any specified sheet (e.g. A1)
|
|
@@ -2281,18 +2360,10 @@
|
|
|
2281
2360
|
if (isFullCol) {
|
|
2282
2361
|
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2283
2362
|
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2284
|
-
if (zone.left === zone.right) {
|
|
2285
|
-
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2286
|
-
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2287
|
-
}
|
|
2288
2363
|
}
|
|
2289
2364
|
if (isFullRow) {
|
|
2290
2365
|
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2291
2366
|
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
2292
|
-
if (zone.top === zone.bottom) {
|
|
2293
|
-
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2294
|
-
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
2295
|
-
}
|
|
2296
2367
|
}
|
|
2297
2368
|
return parts;
|
|
2298
2369
|
}
|
|
@@ -3691,12 +3762,12 @@
|
|
|
3691
3762
|
}
|
|
3692
3763
|
}
|
|
3693
3764
|
/** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
|
|
3694
|
-
function normalizeString(str) {
|
|
3765
|
+
const normalizeString = memoize(function normalizeString(str) {
|
|
3695
3766
|
return str
|
|
3696
3767
|
.toLowerCase()
|
|
3697
3768
|
.normalize("NFD")
|
|
3698
3769
|
.replace(/[\u0300-\u036f]/g, "");
|
|
3699
|
-
}
|
|
3770
|
+
});
|
|
3700
3771
|
/**
|
|
3701
3772
|
* Normalize a value.
|
|
3702
3773
|
* If the cell value is a string, this will set it to lowercase and replacing accent letters with plain letters
|
|
@@ -4427,6 +4498,7 @@
|
|
|
4427
4498
|
CommandResult[CommandResult["SplitWillOverwriteContent"] = 90] = "SplitWillOverwriteContent";
|
|
4428
4499
|
CommandResult[CommandResult["NoSplitSeparatorInSelection"] = 91] = "NoSplitSeparatorInSelection";
|
|
4429
4500
|
CommandResult[CommandResult["NoActiveSheet"] = 92] = "NoActiveSheet";
|
|
4501
|
+
CommandResult[CommandResult["NoChanges"] = 93] = "NoChanges";
|
|
4430
4502
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
4431
4503
|
|
|
4432
4504
|
const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
|
|
@@ -5151,6 +5223,7 @@
|
|
|
5151
5223
|
},
|
|
5152
5224
|
};
|
|
5153
5225
|
|
|
5226
|
+
const macRegex = /Mac/i;
|
|
5154
5227
|
/**
|
|
5155
5228
|
* Return true if the event was triggered from
|
|
5156
5229
|
* a child element.
|
|
@@ -5196,6 +5269,17 @@
|
|
|
5196
5269
|
}
|
|
5197
5270
|
function getOpenedMenus() {
|
|
5198
5271
|
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
5272
|
+
}
|
|
5273
|
+
function isMacOS() {
|
|
5274
|
+
return Boolean(macRegex.test(navigator.userAgent));
|
|
5275
|
+
}
|
|
5276
|
+
/**
|
|
5277
|
+
* @param {KeyboardEvent | MouseEvent} ev
|
|
5278
|
+
* @returns Returns true if the event was triggered with the "ctrl" modifier pressed.
|
|
5279
|
+
* On Mac, this is the "meta" or "command" key.
|
|
5280
|
+
*/
|
|
5281
|
+
function isCtrlKey(ev) {
|
|
5282
|
+
return isMacOS() ? ev.metaKey : ev.ctrlKey;
|
|
5199
5283
|
}
|
|
5200
5284
|
|
|
5201
5285
|
/**
|
|
@@ -9582,6 +9666,9 @@
|
|
|
9582
9666
|
function makeArg(str, description) {
|
|
9583
9667
|
let parts = str.match(ARG_REGEXP);
|
|
9584
9668
|
let name = parts[1].trim();
|
|
9669
|
+
if (!name) {
|
|
9670
|
+
throw new Error(`Function argument definition is missing a name: '${str}'.`);
|
|
9671
|
+
}
|
|
9585
9672
|
let types = [];
|
|
9586
9673
|
let isOptional = false;
|
|
9587
9674
|
let isRepeating = false;
|
|
@@ -12035,7 +12122,7 @@
|
|
|
12035
12122
|
if (_year < 1900) {
|
|
12036
12123
|
_year += 1900;
|
|
12037
12124
|
}
|
|
12038
|
-
const jsDate = new
|
|
12125
|
+
const jsDate = new DateTime(_year, _month - 1, _day);
|
|
12039
12126
|
const result = jsDateToRoundNumber(jsDate);
|
|
12040
12127
|
assert(() => result >= 0, _lt(`The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900.`));
|
|
12041
12128
|
return result;
|
|
@@ -12078,7 +12165,7 @@
|
|
|
12078
12165
|
// See: https://support.microsoft.com/en-us/office/datedif-function-25dba1a4-2812-480b-84dd-8b32a451b35c
|
|
12079
12166
|
let days = jsEndDate.getDate() - jsStartDate.getDate();
|
|
12080
12167
|
if (days < 0) {
|
|
12081
|
-
const monthBeforeEndMonth = new
|
|
12168
|
+
const monthBeforeEndMonth = new DateTime(jsEndDate.getFullYear(), jsEndDate.getMonth() - 1, 1);
|
|
12082
12169
|
const daysInMonthBeforeEndMonth = getDaysInMonth(monthBeforeEndMonth);
|
|
12083
12170
|
days = daysInMonthBeforeEndMonth - Math.abs(days);
|
|
12084
12171
|
}
|
|
@@ -12087,7 +12174,7 @@
|
|
|
12087
12174
|
if (areTwoDatesWithinOneYear(_startDate, _endDate)) {
|
|
12088
12175
|
return getTimeDifferenceInWholeDays(jsStartDate, jsEndDate);
|
|
12089
12176
|
}
|
|
12090
|
-
const endDateWithinOneYear = new
|
|
12177
|
+
const endDateWithinOneYear = new DateTime(jsStartDate.getFullYear(), jsEndDate.getMonth(), jsEndDate.getDate());
|
|
12091
12178
|
let days = getTimeDifferenceInWholeDays(jsStartDate, endDateWithinOneYear);
|
|
12092
12179
|
if (days < 0) {
|
|
12093
12180
|
endDateWithinOneYear.setFullYear(jsStartDate.getFullYear() + 1);
|
|
@@ -12200,7 +12287,7 @@
|
|
|
12200
12287
|
const _months = Math.trunc(toNumber(months));
|
|
12201
12288
|
const yStart = _startDate.getFullYear();
|
|
12202
12289
|
const mStart = _startDate.getMonth();
|
|
12203
|
-
const jsDate = new
|
|
12290
|
+
const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
|
|
12204
12291
|
return jsDateToRoundNumber(jsDate);
|
|
12205
12292
|
},
|
|
12206
12293
|
isExported: true,
|
|
@@ -12237,17 +12324,17 @@
|
|
|
12237
12324
|
// The first week of the year is the week that contains the first
|
|
12238
12325
|
// Thursday of the year.
|
|
12239
12326
|
let firstThursday = 1;
|
|
12240
|
-
while (new
|
|
12327
|
+
while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
|
|
12241
12328
|
firstThursday += 1;
|
|
12242
12329
|
}
|
|
12243
|
-
const firstDayOfFirstWeek = new
|
|
12330
|
+
const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
|
|
12244
12331
|
// The last week of the year is the week that contains the last Thursday of
|
|
12245
12332
|
// the year.
|
|
12246
12333
|
let lastThursday = 31;
|
|
12247
|
-
while (new
|
|
12334
|
+
while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
|
|
12248
12335
|
lastThursday -= 1;
|
|
12249
12336
|
}
|
|
12250
|
-
const lastDayOfLastWeek = new
|
|
12337
|
+
const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
|
|
12251
12338
|
// B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
|
|
12252
12339
|
// If our date < firstDayOfFirstWeek then it's in the weeks of the year before
|
|
12253
12340
|
let offsetYear;
|
|
@@ -12273,17 +12360,17 @@
|
|
|
12273
12360
|
case 1:
|
|
12274
12361
|
// firstDay is the 1st day of the 1st week of the year after
|
|
12275
12362
|
// firstDay = lastDayOfLastWeek + 1 Day
|
|
12276
|
-
firstDay = new
|
|
12363
|
+
firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
|
|
12277
12364
|
break;
|
|
12278
12365
|
case -1:
|
|
12279
12366
|
// firstDay is the 1st day of the 1st week of the previous year.
|
|
12280
12367
|
// The first week of the previous year is the week that contains the
|
|
12281
12368
|
// first Thursday of the previous year.
|
|
12282
12369
|
let firstThursdayPreviousYear = 1;
|
|
12283
|
-
while (new
|
|
12370
|
+
while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
|
|
12284
12371
|
firstThursdayPreviousYear += 1;
|
|
12285
12372
|
}
|
|
12286
|
-
firstDay = new
|
|
12373
|
+
firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
|
|
12287
12374
|
break;
|
|
12288
12375
|
}
|
|
12289
12376
|
const diff = (_date.getTime() - firstDay.getTime()) / MS_PER_DAY;
|
|
@@ -12418,8 +12505,8 @@
|
|
|
12418
12505
|
});
|
|
12419
12506
|
}
|
|
12420
12507
|
const invertDate = _startDate.getTime() > _endDate.getTime();
|
|
12421
|
-
const stopDate =
|
|
12422
|
-
let stepDate =
|
|
12508
|
+
const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
|
|
12509
|
+
let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
|
|
12423
12510
|
const timeStopDate = stopDate.getTime();
|
|
12424
12511
|
let timeStepDate = stepDate.getTime();
|
|
12425
12512
|
let netWorkingDay = 0;
|
|
@@ -12443,8 +12530,7 @@
|
|
|
12443
12530
|
returns: ["DATE"],
|
|
12444
12531
|
computeFormat: () => "m/d/yyyy hh:mm:ss",
|
|
12445
12532
|
compute: function () {
|
|
12446
|
-
let today =
|
|
12447
|
-
today.setMilliseconds(0);
|
|
12533
|
+
let today = DateTime.now();
|
|
12448
12534
|
const delta = today.getTime() - INITIAL_1900_DAY.getTime();
|
|
12449
12535
|
const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
|
|
12450
12536
|
return Math.floor(delta / MS_PER_DAY) + time;
|
|
@@ -12514,8 +12600,8 @@
|
|
|
12514
12600
|
returns: ["DATE"],
|
|
12515
12601
|
computeFormat: () => "m/d/yyyy",
|
|
12516
12602
|
compute: function () {
|
|
12517
|
-
const today =
|
|
12518
|
-
const jsDate = new
|
|
12603
|
+
const today = DateTime.now();
|
|
12604
|
+
const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
|
|
12519
12605
|
return jsDateToRoundNumber(jsDate);
|
|
12520
12606
|
},
|
|
12521
12607
|
isExported: true,
|
|
@@ -12570,10 +12656,10 @@
|
|
|
12570
12656
|
}
|
|
12571
12657
|
const y = _date.getFullYear();
|
|
12572
12658
|
let dayStart = 1;
|
|
12573
|
-
let startDayOfFirstWeek = new
|
|
12659
|
+
let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
|
|
12574
12660
|
while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
|
|
12575
12661
|
dayStart += 1;
|
|
12576
|
-
startDayOfFirstWeek = new
|
|
12662
|
+
startDayOfFirstWeek = new DateTime(y, 0, dayStart);
|
|
12577
12663
|
}
|
|
12578
12664
|
const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / MS_PER_DAY;
|
|
12579
12665
|
if (dif < 0) {
|
|
@@ -12627,7 +12713,7 @@
|
|
|
12627
12713
|
timesHoliday.add(holiday.getTime());
|
|
12628
12714
|
});
|
|
12629
12715
|
}
|
|
12630
|
-
let stepDate =
|
|
12716
|
+
let stepDate = DateTime.fromTimestamp(_startDate.getTime());
|
|
12631
12717
|
let timeStepDate = stepDate.getTime();
|
|
12632
12718
|
const unitDay = Math.sign(_numDays);
|
|
12633
12719
|
let stepDay = Math.abs(_numDays);
|
|
@@ -12689,7 +12775,7 @@
|
|
|
12689
12775
|
const _startDate = toJsDate(date);
|
|
12690
12776
|
const yStart = _startDate.getFullYear();
|
|
12691
12777
|
const mStart = _startDate.getMonth();
|
|
12692
|
-
const jsDate = new
|
|
12778
|
+
const jsDate = new DateTime(yStart, mStart, 1);
|
|
12693
12779
|
return jsDateToRoundNumber(jsDate);
|
|
12694
12780
|
},
|
|
12695
12781
|
};
|
|
@@ -12727,7 +12813,7 @@
|
|
|
12727
12813
|
compute: function (date) {
|
|
12728
12814
|
const quarter = QUARTER.compute(date);
|
|
12729
12815
|
const year = YEAR.compute(date);
|
|
12730
|
-
const jsDate = new
|
|
12816
|
+
const jsDate = new DateTime(year, (quarter - 1) * 3, 1);
|
|
12731
12817
|
return jsDateToRoundNumber(jsDate);
|
|
12732
12818
|
},
|
|
12733
12819
|
};
|
|
@@ -12742,7 +12828,7 @@
|
|
|
12742
12828
|
compute: function (date) {
|
|
12743
12829
|
const quarter = QUARTER.compute(date);
|
|
12744
12830
|
const year = YEAR.compute(date);
|
|
12745
|
-
const jsDate = new
|
|
12831
|
+
const jsDate = new DateTime(year, quarter * 3, 0);
|
|
12746
12832
|
return jsDateToRoundNumber(jsDate);
|
|
12747
12833
|
},
|
|
12748
12834
|
};
|
|
@@ -12756,7 +12842,7 @@
|
|
|
12756
12842
|
computeFormat: () => "m/d/yyyy",
|
|
12757
12843
|
compute: function (date) {
|
|
12758
12844
|
const year = YEAR.compute(date);
|
|
12759
|
-
const jsDate = new
|
|
12845
|
+
const jsDate = new DateTime(year, 0, 1);
|
|
12760
12846
|
return jsDateToRoundNumber(jsDate);
|
|
12761
12847
|
},
|
|
12762
12848
|
};
|
|
@@ -12770,7 +12856,7 @@
|
|
|
12770
12856
|
computeFormat: () => "m/d/yyyy",
|
|
12771
12857
|
compute: function (date) {
|
|
12772
12858
|
const year = YEAR.compute(date);
|
|
12773
|
-
const jsDate = new
|
|
12859
|
+
const jsDate = new DateTime(year + 1, 0, 0);
|
|
12774
12860
|
return jsDateToRoundNumber(jsDate);
|
|
12775
12861
|
},
|
|
12776
12862
|
};
|
|
@@ -12818,8 +12904,8 @@
|
|
|
12818
12904
|
const DELTA = {
|
|
12819
12905
|
description: _lt("Compare two numeric values, returning 1 if they're equal."),
|
|
12820
12906
|
args: [
|
|
12821
|
-
arg(" (number)", _lt("The first number to compare.")),
|
|
12822
|
-
arg(` (number, default=${DEFAULT_DELTA_ARG})`, _lt("The second number to compare.")),
|
|
12907
|
+
arg("number1 (number)", _lt("The first number to compare.")),
|
|
12908
|
+
arg(`number2 (number, default=${DEFAULT_DELTA_ARG})`, _lt("The second number to compare.")),
|
|
12823
12909
|
],
|
|
12824
12910
|
returns: ["NUMBER"],
|
|
12825
12911
|
compute: function (number1, number2 = DEFAULT_DELTA_ARG) {
|
|
@@ -12905,7 +12991,7 @@
|
|
|
12905
12991
|
function assertSettlementLessThanOneYearBeforeMaturity(settlement, maturity) {
|
|
12906
12992
|
const startDate = toJsDate(settlement);
|
|
12907
12993
|
const endDate = toJsDate(maturity);
|
|
12908
|
-
const startDatePlusOneYear =
|
|
12994
|
+
const startDatePlusOneYear = toJsDate(settlement);
|
|
12909
12995
|
startDatePlusOneYear.setFullYear(startDate.getFullYear() + 1);
|
|
12910
12996
|
assert(() => endDate.getTime() <= startDatePlusOneYear.getTime(), _lt("The settlement date (%s) must at most one year after the maturity date (%s).", settlement.toString(), maturity.toString()));
|
|
12911
12997
|
}
|
|
@@ -13040,7 +13126,7 @@
|
|
|
13040
13126
|
arg("salvage (number)", _lt("The value of the asset at the end of depreciation.")),
|
|
13041
13127
|
arg("period (number)", _lt("The single period within life for which to calculate depreciation.")),
|
|
13042
13128
|
arg("rate (number)", _lt("The deprecation rate.")),
|
|
13043
|
-
arg(" (number, optional)", _lt("An indicator of what day count method to use.")),
|
|
13129
|
+
arg("day_count_convention (number, optional)", _lt("An indicator of what day count method to use.")),
|
|
13044
13130
|
],
|
|
13045
13131
|
returns: ["NUMBER"],
|
|
13046
13132
|
compute: function (cost, purchaseDate, firstPeriodEnd, salvage, period, rate, dayCountConvention = DEFAULT_DAY_COUNT_CONVENTION) {
|
|
@@ -16023,8 +16109,8 @@
|
|
|
16023
16109
|
description: _lt("A segment of a string."),
|
|
16024
16110
|
args: [
|
|
16025
16111
|
arg("text (string)", _lt("The string to extract a segment from.")),
|
|
16026
|
-
arg(" (number)", _lt("The index from the left of string from which to begin extracting. The first character in string has the index 1.")),
|
|
16027
|
-
arg(" (number)", _lt("The length of the segment to extract.")),
|
|
16112
|
+
arg("starting_at (number)", _lt("The index from the left of string from which to begin extracting. The first character in string has the index 1.")),
|
|
16113
|
+
arg("extract_length (number)", _lt("The length of the segment to extract.")),
|
|
16028
16114
|
],
|
|
16029
16115
|
returns: ["STRING"],
|
|
16030
16116
|
compute: function (text, starting_at, extract_length) {
|
|
@@ -17693,10 +17779,10 @@
|
|
|
17693
17779
|
function updateSelectionWithArrowKeys(ev, selection) {
|
|
17694
17780
|
const direction = arrowMap[ev.key];
|
|
17695
17781
|
if (ev.shiftKey) {
|
|
17696
|
-
selection.resizeAnchorZone(direction, ev
|
|
17782
|
+
selection.resizeAnchorZone(direction, isCtrlKey(ev) ? "end" : 1);
|
|
17697
17783
|
}
|
|
17698
17784
|
else {
|
|
17699
|
-
selection.moveAnchorCell(direction, ev
|
|
17785
|
+
selection.moveAnchorCell(direction, isCtrlKey(ev) ? "end" : 1);
|
|
17700
17786
|
}
|
|
17701
17787
|
}
|
|
17702
17788
|
|
|
@@ -22393,7 +22479,10 @@
|
|
|
22393
22479
|
return;
|
|
22394
22480
|
}
|
|
22395
22481
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
22396
|
-
this.props.onCellClicked(col, row, {
|
|
22482
|
+
this.props.onCellClicked(col, row, {
|
|
22483
|
+
expandZone: ev.shiftKey,
|
|
22484
|
+
addZone: isCtrlKey(ev),
|
|
22485
|
+
});
|
|
22397
22486
|
}
|
|
22398
22487
|
onDoubleClick(ev) {
|
|
22399
22488
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
@@ -22466,6 +22555,7 @@
|
|
|
22466
22555
|
draggerShadowThickness: 0,
|
|
22467
22556
|
delta: 0,
|
|
22468
22557
|
base: 0,
|
|
22558
|
+
position: "before",
|
|
22469
22559
|
});
|
|
22470
22560
|
_computeHandleDisplay(ev) {
|
|
22471
22561
|
const position = this._getEvOffset(ev);
|
|
@@ -22590,11 +22680,13 @@
|
|
|
22590
22680
|
this.state.draggerLinePosition = dimensions.start;
|
|
22591
22681
|
this.state.draggerShadowPosition = dimensions.start;
|
|
22592
22682
|
this.state.base = elementIndex;
|
|
22683
|
+
this.state.position = "before";
|
|
22593
22684
|
}
|
|
22594
22685
|
else if (this._getSelectedZoneEnd() < elementIndex) {
|
|
22595
22686
|
this.state.draggerLinePosition = dimensions.end;
|
|
22596
22687
|
this.state.draggerShadowPosition = dimensions.end - this.state.draggerShadowThickness;
|
|
22597
|
-
this.state.base = elementIndex
|
|
22688
|
+
this.state.base = elementIndex;
|
|
22689
|
+
this.state.position = "after";
|
|
22598
22690
|
}
|
|
22599
22691
|
else {
|
|
22600
22692
|
this.state.draggerLinePosition = startDimensions.start;
|
|
@@ -22618,7 +22710,7 @@
|
|
|
22618
22710
|
this._increaseSelection(index);
|
|
22619
22711
|
}
|
|
22620
22712
|
else {
|
|
22621
|
-
this._selectElement(index, ev
|
|
22713
|
+
this._selectElement(index, isCtrlKey(ev));
|
|
22622
22714
|
}
|
|
22623
22715
|
this.lastSelectedElementIndex = index;
|
|
22624
22716
|
const mouseMoveSelect = (col, row) => {
|
|
@@ -22631,7 +22723,7 @@
|
|
|
22631
22723
|
const mouseUpSelect = () => {
|
|
22632
22724
|
this.state.isSelecting = false;
|
|
22633
22725
|
this.lastSelectedElementIndex = null;
|
|
22634
|
-
this.env.model.dispatch(ev
|
|
22726
|
+
this.env.model.dispatch(isCtrlKey(ev) ? "PREPARE_SELECTION_INPUT_EXPANSION" : "STOP_SELECTION_INPUT");
|
|
22635
22727
|
this._computeGrabDisplay(ev);
|
|
22636
22728
|
};
|
|
22637
22729
|
dragAndDropBeyondTheViewport(this.env, mouseMoveSelect, mouseUpSelect);
|
|
@@ -22777,13 +22869,14 @@
|
|
|
22777
22869
|
dimension: "COL",
|
|
22778
22870
|
base: this.state.base,
|
|
22779
22871
|
elements,
|
|
22872
|
+
position: this.state.position,
|
|
22780
22873
|
});
|
|
22781
22874
|
if (!result.isSuccessful && result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
|
|
22782
22875
|
this.env.raiseError(MergeErrorMessage);
|
|
22783
22876
|
}
|
|
22784
22877
|
}
|
|
22785
|
-
_selectElement(index,
|
|
22786
|
-
this.env.model.selection.selectColumn(index,
|
|
22878
|
+
_selectElement(index, addDistinctHeader) {
|
|
22879
|
+
this.env.model.selection.selectColumn(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
|
|
22787
22880
|
}
|
|
22788
22881
|
_increaseSelection(index) {
|
|
22789
22882
|
this.env.model.selection.selectColumn(index, "updateAnchor");
|
|
@@ -22950,13 +23043,14 @@
|
|
|
22950
23043
|
dimension: "ROW",
|
|
22951
23044
|
base: this.state.base,
|
|
22952
23045
|
elements,
|
|
23046
|
+
position: this.state.position,
|
|
22953
23047
|
});
|
|
22954
23048
|
if (!result.isSuccessful && result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
|
|
22955
23049
|
this.env.raiseError(MergeErrorMessage);
|
|
22956
23050
|
}
|
|
22957
23051
|
}
|
|
22958
|
-
_selectElement(index,
|
|
22959
|
-
this.env.model.selection.selectRow(index,
|
|
23052
|
+
_selectElement(index, addDistinctHeader) {
|
|
23053
|
+
this.env.model.selection.selectRow(index, addDistinctHeader ? "newAnchor" : "overrideSelection");
|
|
22960
23054
|
}
|
|
22961
23055
|
_increaseSelection(index) {
|
|
22962
23056
|
this.env.model.selection.selectRow(index, "updateAnchor");
|
|
@@ -23057,8 +23151,8 @@
|
|
|
23057
23151
|
return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
|
|
23058
23152
|
}
|
|
23059
23153
|
const onMouseWheel = (ev) => {
|
|
23060
|
-
const deltaX = normalize(ev.shiftKey ? ev.deltaY : ev.deltaX, ev.deltaMode);
|
|
23061
|
-
const deltaY = normalize(ev.shiftKey ? ev.deltaX : ev.deltaY, ev.deltaMode);
|
|
23154
|
+
const deltaX = normalize(ev.shiftKey && !isMacOS() ? ev.deltaY : ev.deltaX, ev.deltaMode);
|
|
23155
|
+
const deltaY = normalize(ev.shiftKey && !isMacOS() ? ev.deltaX : ev.deltaY, ev.deltaMode);
|
|
23062
23156
|
handler(deltaX, deltaY);
|
|
23063
23157
|
};
|
|
23064
23158
|
return onMouseWheel;
|
|
@@ -23760,8 +23854,8 @@
|
|
|
23760
23854
|
// ---------------------------------------------------------------------------
|
|
23761
23855
|
// Zone selection with mouse
|
|
23762
23856
|
// ---------------------------------------------------------------------------
|
|
23763
|
-
onCellClicked(col, row, {
|
|
23764
|
-
if (
|
|
23857
|
+
onCellClicked(col, row, { addZone, expandZone }) {
|
|
23858
|
+
if (addZone) {
|
|
23765
23859
|
this.env.model.dispatch("PREPARE_SELECTION_INPUT_EXPANSION");
|
|
23766
23860
|
}
|
|
23767
23861
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
@@ -23770,10 +23864,10 @@
|
|
|
23770
23864
|
if (this.env.model.getters.getEditionMode() === "editing") {
|
|
23771
23865
|
this.env.model.dispatch("STOP_EDITION");
|
|
23772
23866
|
}
|
|
23773
|
-
if (
|
|
23867
|
+
if (expandZone) {
|
|
23774
23868
|
this.env.model.selection.setAnchorCorner(col, row);
|
|
23775
23869
|
}
|
|
23776
|
-
else if (
|
|
23870
|
+
else if (addZone) {
|
|
23777
23871
|
this.env.model.selection.addCellToSelection(col, row);
|
|
23778
23872
|
}
|
|
23779
23873
|
else {
|
|
@@ -23835,9 +23929,7 @@
|
|
|
23835
23929
|
return;
|
|
23836
23930
|
}
|
|
23837
23931
|
let keyDownString = "";
|
|
23838
|
-
if (ev
|
|
23839
|
-
keyDownString += "CTRL+";
|
|
23840
|
-
if (ev.metaKey)
|
|
23932
|
+
if (isCtrlKey(ev))
|
|
23841
23933
|
keyDownString += "CTRL+";
|
|
23842
23934
|
if (ev.altKey)
|
|
23843
23935
|
keyDownString += "ALT+";
|
|
@@ -25745,7 +25837,7 @@
|
|
|
25745
25837
|
SPACE: goTo(State.RightRef),
|
|
25746
25838
|
NUMBER: goTo(State.Found),
|
|
25747
25839
|
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
25748
|
-
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
|
|
25840
|
+
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
|
|
25749
25841
|
},
|
|
25750
25842
|
[State.RightColumnRef]: {
|
|
25751
25843
|
SPACE: goTo(State.RightColumnRef),
|
|
@@ -25756,6 +25848,7 @@
|
|
|
25756
25848
|
SPACE: goTo(State.RightRowRef),
|
|
25757
25849
|
NUMBER: goTo(State.Found),
|
|
25758
25850
|
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
25851
|
+
SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
|
|
25759
25852
|
},
|
|
25760
25853
|
[State.Found]: {},
|
|
25761
25854
|
};
|
|
@@ -28992,6 +29085,14 @@
|
|
|
28992
29085
|
// ---------------------------------------------------------------------------
|
|
28993
29086
|
// Command Handling
|
|
28994
29087
|
// ---------------------------------------------------------------------------
|
|
29088
|
+
allowDispatch(cmd) {
|
|
29089
|
+
switch (cmd.type) {
|
|
29090
|
+
case "SET_BORDER":
|
|
29091
|
+
return this.checkBordersUnchanged(cmd);
|
|
29092
|
+
default:
|
|
29093
|
+
return 0 /* CommandResult.Success */;
|
|
29094
|
+
}
|
|
29095
|
+
}
|
|
28995
29096
|
handle(cmd) {
|
|
28996
29097
|
switch (cmd.type) {
|
|
28997
29098
|
case "ADD_MERGE":
|
|
@@ -29411,6 +29512,14 @@
|
|
|
29411
29512
|
this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
|
|
29412
29513
|
}
|
|
29413
29514
|
}
|
|
29515
|
+
checkBordersUnchanged(cmd) {
|
|
29516
|
+
const currentBorder = this.getCellBorder(cmd);
|
|
29517
|
+
const areAllNewBordersUndefined = !cmd.border?.bottom && !cmd.border?.left && !cmd.border?.right && !cmd.border?.top;
|
|
29518
|
+
if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
|
|
29519
|
+
return 93 /* CommandResult.NoChanges */;
|
|
29520
|
+
}
|
|
29521
|
+
return 0 /* CommandResult.Success */;
|
|
29522
|
+
}
|
|
29414
29523
|
// ---------------------------------------------------------------------------
|
|
29415
29524
|
// Import/Export
|
|
29416
29525
|
// ---------------------------------------------------------------------------
|
|
@@ -29447,7 +29556,7 @@
|
|
|
29447
29556
|
*/
|
|
29448
29557
|
function getBorderId(border) {
|
|
29449
29558
|
for (let [key, value] of Object.entries(borders)) {
|
|
29450
|
-
if (
|
|
29559
|
+
if (deepEquals(value, border)) {
|
|
29451
29560
|
return parseInt(key, 10);
|
|
29452
29561
|
}
|
|
29453
29562
|
}
|
|
@@ -29518,8 +29627,9 @@
|
|
|
29518
29627
|
allowDispatch(cmd) {
|
|
29519
29628
|
switch (cmd.type) {
|
|
29520
29629
|
case "UPDATE_CELL":
|
|
29630
|
+
return this.checkCellOutOfSheet(cmd);
|
|
29521
29631
|
case "CLEAR_CELL":
|
|
29522
|
-
return this.
|
|
29632
|
+
return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
|
|
29523
29633
|
default:
|
|
29524
29634
|
return 0 /* CommandResult.Success */;
|
|
29525
29635
|
}
|
|
@@ -29678,14 +29788,9 @@
|
|
|
29678
29788
|
*/
|
|
29679
29789
|
getCellById(cellId) {
|
|
29680
29790
|
// this must be as fast as possible
|
|
29681
|
-
|
|
29682
|
-
|
|
29683
|
-
|
|
29684
|
-
if (cell) {
|
|
29685
|
-
return cell;
|
|
29686
|
-
}
|
|
29687
|
-
}
|
|
29688
|
-
return undefined;
|
|
29791
|
+
const position = this.getters.getCellPosition(cellId);
|
|
29792
|
+
const sheet = this.cells[position.sheetId];
|
|
29793
|
+
return sheet[cellId];
|
|
29689
29794
|
}
|
|
29690
29795
|
/*
|
|
29691
29796
|
* Reconstructs the original formula string based on a normalized form and its dependencies
|
|
@@ -29922,13 +30027,23 @@
|
|
|
29922
30027
|
dependencies: [],
|
|
29923
30028
|
};
|
|
29924
30029
|
}
|
|
29925
|
-
checkCellOutOfSheet(
|
|
30030
|
+
checkCellOutOfSheet(cmd) {
|
|
30031
|
+
const { sheetId, col, row } = cmd;
|
|
29926
30032
|
const sheet = this.getters.tryGetSheet(sheetId);
|
|
29927
30033
|
if (!sheet)
|
|
29928
30034
|
return 27 /* CommandResult.InvalidSheetId */;
|
|
29929
30035
|
const sheetZone = this.getters.getSheetZone(sheetId);
|
|
29930
30036
|
return isInside(col, row, sheetZone) ? 0 /* CommandResult.Success */ : 18 /* CommandResult.TargetOutOfSheet */;
|
|
29931
30037
|
}
|
|
30038
|
+
checkUselessClearCell(cmd) {
|
|
30039
|
+
const cell = this.getters.getCell(cmd);
|
|
30040
|
+
if (!cell)
|
|
30041
|
+
return 93 /* CommandResult.NoChanges */;
|
|
30042
|
+
if (!cell.content && !cell.style && !cell.format) {
|
|
30043
|
+
return 93 /* CommandResult.NoChanges */;
|
|
30044
|
+
}
|
|
30045
|
+
return 0 /* CommandResult.Success */;
|
|
30046
|
+
}
|
|
29932
30047
|
}
|
|
29933
30048
|
|
|
29934
30049
|
class ChartPlugin extends CorePlugin {
|
|
@@ -32409,7 +32524,7 @@
|
|
|
32409
32524
|
const elements = cmd.dimension === "COL"
|
|
32410
32525
|
? this.getNumberCols(cmd.sheetId)
|
|
32411
32526
|
: this.getNumberRows(cmd.sheetId);
|
|
32412
|
-
if (cmd.base < 0 || cmd.base
|
|
32527
|
+
if (cmd.base < 0 || cmd.base >= elements) {
|
|
32413
32528
|
return 86 /* CommandResult.InvalidHeaderIndex */;
|
|
32414
32529
|
}
|
|
32415
32530
|
else if (cmd.quantity <= 0) {
|
|
@@ -33031,10 +33146,13 @@
|
|
|
33031
33146
|
// begin with the end.
|
|
33032
33147
|
rows.sort((a, b) => b - a);
|
|
33033
33148
|
for (let group of groupConsecutive(rows)) {
|
|
33149
|
+
// indexes are sorted in the descending order
|
|
33150
|
+
const from = group[group.length - 1];
|
|
33151
|
+
const to = group[0];
|
|
33034
33152
|
// Move the cells.
|
|
33035
|
-
this.moveCellOnRowsDeletion(sheet,
|
|
33036
|
-
// Effectively delete the
|
|
33037
|
-
|
|
33153
|
+
this.moveCellOnRowsDeletion(sheet, from, to);
|
|
33154
|
+
// Effectively delete the rows
|
|
33155
|
+
this.updateRowsStructureOnDeletion(sheet, from, to);
|
|
33038
33156
|
}
|
|
33039
33157
|
const count = rows.filter((row) => row < sheet.panes.ySplit).length;
|
|
33040
33158
|
if (count) {
|
|
@@ -33056,8 +33174,6 @@
|
|
|
33056
33174
|
this.addEmptyRows(sheet, quantity);
|
|
33057
33175
|
// Move the cells.
|
|
33058
33176
|
this.moveCellsOnAddition(sheet, index, quantity, "rows");
|
|
33059
|
-
// Recompute the left-right/top-bottom.
|
|
33060
|
-
this.updateRowsStructureOnAddition(sheet, row, quantity);
|
|
33061
33177
|
if (index < sheet.panes.ySplit) {
|
|
33062
33178
|
this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
|
|
33063
33179
|
}
|
|
@@ -33158,35 +33274,20 @@
|
|
|
33158
33274
|
}
|
|
33159
33275
|
}
|
|
33160
33276
|
}
|
|
33161
|
-
updateRowsStructureOnDeletion(
|
|
33277
|
+
updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
|
|
33162
33278
|
const rows = [];
|
|
33163
|
-
const cellsQueue = sheet.rows.map((row) => row.cells);
|
|
33279
|
+
const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
|
|
33164
33280
|
for (let i in sheet.rows) {
|
|
33165
|
-
|
|
33281
|
+
const row = Number(i);
|
|
33282
|
+
if (row >= deleteFromRow && row <= deleteToRow) {
|
|
33166
33283
|
continue;
|
|
33167
33284
|
}
|
|
33168
33285
|
rows.push({
|
|
33169
|
-
cells: cellsQueue.
|
|
33286
|
+
cells: cellsQueue.pop(),
|
|
33170
33287
|
});
|
|
33171
33288
|
}
|
|
33172
33289
|
this.history.update("sheets", sheet.id, "rows", rows);
|
|
33173
33290
|
}
|
|
33174
|
-
/**
|
|
33175
|
-
* Update the rows of the sheet after an addition:
|
|
33176
|
-
* - Rename the rows
|
|
33177
|
-
*
|
|
33178
|
-
* @param sheet Sheet on which the deletion occurs
|
|
33179
|
-
* @param addedRow Index of the added row
|
|
33180
|
-
* @param rowsToAdd Number of the rows to add
|
|
33181
|
-
*/
|
|
33182
|
-
updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
|
|
33183
|
-
const rows = [];
|
|
33184
|
-
const cellsQueue = sheet.rows.map((row) => row.cells);
|
|
33185
|
-
sheet.rows.forEach(() => rows.push({
|
|
33186
|
-
cells: cellsQueue.shift(),
|
|
33187
|
-
}));
|
|
33188
|
-
this.history.update("sheets", sheet.id, "rows", rows);
|
|
33189
|
-
}
|
|
33190
33291
|
/**
|
|
33191
33292
|
* Add empty rows at the end of the rows
|
|
33192
33293
|
*
|
|
@@ -33456,13 +33557,18 @@
|
|
|
33456
33557
|
// Getters
|
|
33457
33558
|
// ---------------------------------------------------------------------------
|
|
33458
33559
|
evaluateFormula(formulaString, sheetId = this.getters.getActiveSheetId()) {
|
|
33459
|
-
|
|
33460
|
-
|
|
33461
|
-
|
|
33462
|
-
|
|
33463
|
-
|
|
33560
|
+
try {
|
|
33561
|
+
const compiledFormula = compile(formulaString);
|
|
33562
|
+
const params = this.getCompilationParameters((cell) => this.getEvaluatedCell(this.getters.getCellPosition(cell.id)));
|
|
33563
|
+
const ranges = [];
|
|
33564
|
+
for (let xc of compiledFormula.dependencies) {
|
|
33565
|
+
ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
33566
|
+
}
|
|
33567
|
+
return compiledFormula.execute(ranges, ...params).value;
|
|
33568
|
+
}
|
|
33569
|
+
catch (error) {
|
|
33570
|
+
return error instanceof EvaluationError ? error.errorType : CellErrorType.GenericError;
|
|
33464
33571
|
}
|
|
33465
|
-
return compiledFormula.execute(ranges, ...params).value;
|
|
33466
33572
|
}
|
|
33467
33573
|
/**
|
|
33468
33574
|
* Return the value of each cell in the range as they are displayed in the grid.
|
|
@@ -33637,6 +33743,7 @@
|
|
|
33637
33743
|
}
|
|
33638
33744
|
return evaluatedCell;
|
|
33639
33745
|
};
|
|
33746
|
+
const rangeCache = {};
|
|
33640
33747
|
/**
|
|
33641
33748
|
* Return the values of the cell(s) used in reference, but always in the format of a range even
|
|
33642
33749
|
* if a single cell is referenced. It is a list of col values. This is useful for the formulas that describe parameters as
|
|
@@ -33653,21 +33760,26 @@
|
|
|
33653
33760
|
// Performance issue: Avoid fetching data on positions that are out of the spreadsheet
|
|
33654
33761
|
// e.g. A1:ZZZ9999 in a sheet with 10 cols and 10 rows should ignore everything past J10 and return a 10x10 array
|
|
33655
33762
|
const sheetZone = getters.getSheetZone(sheetId);
|
|
33656
|
-
const result = [];
|
|
33657
33763
|
const zone = intersection(range.zone, sheetZone);
|
|
33658
33764
|
if (!zone) {
|
|
33659
|
-
|
|
33660
|
-
|
|
33765
|
+
return [[]];
|
|
33766
|
+
}
|
|
33767
|
+
const { top, left, bottom, right } = zone;
|
|
33768
|
+
const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
|
|
33769
|
+
if (cacheKey in rangeCache) {
|
|
33770
|
+
return rangeCache[cacheKey];
|
|
33661
33771
|
}
|
|
33772
|
+
const result = new Array(right - left + 1);
|
|
33662
33773
|
// Performance issue: nested loop is faster than a map here
|
|
33663
|
-
for (let col =
|
|
33664
|
-
const rowValues =
|
|
33665
|
-
for (let row =
|
|
33774
|
+
for (let col = left; col <= right; col++) {
|
|
33775
|
+
const rowValues = new Array(bottom - top + 1);
|
|
33776
|
+
for (let row = top; row <= bottom; row++) {
|
|
33666
33777
|
const cell = evalContext.getters.getCell({ sheetId: range.sheetId, col, row });
|
|
33667
|
-
rowValues
|
|
33778
|
+
rowValues[row - top] = cell ? getEvaluatedCell(cell) : undefined;
|
|
33668
33779
|
}
|
|
33669
|
-
result
|
|
33780
|
+
result[col - left] = rowValues;
|
|
33670
33781
|
}
|
|
33782
|
+
rangeCache[cacheKey] = result;
|
|
33671
33783
|
return result;
|
|
33672
33784
|
}
|
|
33673
33785
|
/**
|
|
@@ -33881,39 +33993,34 @@
|
|
|
33881
33993
|
this.computedIcons[sheetId] = {};
|
|
33882
33994
|
const computedStyle = this.computedStyles[sheetId];
|
|
33883
33995
|
for (let cf of this.getters.getConditionalFormats(sheetId).reverse()) {
|
|
33884
|
-
|
|
33885
|
-
|
|
33886
|
-
|
|
33887
|
-
|
|
33888
|
-
|
|
33889
|
-
|
|
33890
|
-
|
|
33891
|
-
|
|
33892
|
-
|
|
33893
|
-
|
|
33894
|
-
|
|
33895
|
-
|
|
33896
|
-
|
|
33897
|
-
|
|
33898
|
-
|
|
33899
|
-
for (let
|
|
33900
|
-
|
|
33901
|
-
|
|
33902
|
-
|
|
33903
|
-
if (
|
|
33904
|
-
|
|
33905
|
-
|
|
33906
|
-
|
|
33907
|
-
computedStyle[col][row] = Object.assign(computedStyle[col]?.[row] || {}, cf.rule.style);
|
|
33908
|
-
}
|
|
33996
|
+
switch (cf.rule.type) {
|
|
33997
|
+
case "ColorScaleRule":
|
|
33998
|
+
for (let range of cf.ranges) {
|
|
33999
|
+
this.applyColorScale(range, cf.rule);
|
|
34000
|
+
}
|
|
34001
|
+
break;
|
|
34002
|
+
case "IconSetRule":
|
|
34003
|
+
for (let range of cf.ranges) {
|
|
34004
|
+
this.applyIcon(range, cf.rule);
|
|
34005
|
+
}
|
|
34006
|
+
break;
|
|
34007
|
+
default:
|
|
34008
|
+
for (let ref of cf.ranges) {
|
|
34009
|
+
const zone = this.getters.getRangeFromSheetXC(sheetId, ref).zone;
|
|
34010
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
34011
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
34012
|
+
const pr = this.rulePredicate[cf.rule.type];
|
|
34013
|
+
let cell = this.getters.getEvaluatedCell({ sheetId, col, row });
|
|
34014
|
+
if (pr && pr(cell, cf.rule)) {
|
|
34015
|
+
if (!computedStyle[col])
|
|
34016
|
+
computedStyle[col] = [];
|
|
34017
|
+
// we must combine all the properties of all the CF rules applied to the given cell
|
|
34018
|
+
computedStyle[col][row] = Object.assign(computedStyle[col]?.[row] || {}, cf.rule.style);
|
|
33909
34019
|
}
|
|
33910
34020
|
}
|
|
33911
34021
|
}
|
|
33912
|
-
|
|
33913
|
-
|
|
33914
|
-
}
|
|
33915
|
-
catch (_) {
|
|
33916
|
-
// we don't care about the errors within the evaluation of a rule
|
|
34022
|
+
}
|
|
34023
|
+
break;
|
|
33917
34024
|
}
|
|
33918
34025
|
}
|
|
33919
34026
|
}
|
|
@@ -33938,7 +34045,7 @@
|
|
|
33938
34045
|
return percentile(rangeValues, Number(threshold.value) / 100, true);
|
|
33939
34046
|
case "formula":
|
|
33940
34047
|
const value = threshold.value && this.getters.evaluateFormula(threshold.value);
|
|
33941
|
-
return
|
|
34048
|
+
return typeof value === "number" ? value : null;
|
|
33942
34049
|
default:
|
|
33943
34050
|
return null;
|
|
33944
34051
|
}
|
|
@@ -35587,19 +35694,21 @@
|
|
|
35587
35694
|
let col = zone.left;
|
|
35588
35695
|
let row = zone.bottom;
|
|
35589
35696
|
if (col > 0) {
|
|
35590
|
-
let
|
|
35591
|
-
while (
|
|
35697
|
+
let leftPosition = { sheetId, col: col - 1, row };
|
|
35698
|
+
while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty ||
|
|
35699
|
+
this.getters.getCell(leftPosition)?.content) {
|
|
35592
35700
|
row += 1;
|
|
35593
|
-
|
|
35701
|
+
leftPosition = { sheetId, col: col - 1, row };
|
|
35594
35702
|
}
|
|
35595
35703
|
}
|
|
35596
35704
|
if (row === zone.bottom) {
|
|
35597
35705
|
col = zone.right;
|
|
35598
35706
|
if (col <= this.getters.getNumberCols(sheetId)) {
|
|
35599
|
-
let
|
|
35600
|
-
while (
|
|
35707
|
+
let rightPosition = { sheetId, col: col + 1, row };
|
|
35708
|
+
while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty ||
|
|
35709
|
+
this.getters.getCell(rightPosition)?.content) {
|
|
35601
35710
|
row += 1;
|
|
35602
|
-
|
|
35711
|
+
rightPosition = { sheetId, col: col + 1, row };
|
|
35603
35712
|
}
|
|
35604
35713
|
}
|
|
35605
35714
|
}
|
|
@@ -40547,6 +40656,10 @@
|
|
|
40547
40656
|
return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
40548
40657
|
case "colrow":
|
|
40549
40658
|
indexOfNumber = xc.search(/[0-9]/);
|
|
40659
|
+
if (indexOfNumber === -1 || indexOfNumber === 0) {
|
|
40660
|
+
// no row number (eg. A) or no column (eg. 1)
|
|
40661
|
+
return "$" + xc;
|
|
40662
|
+
}
|
|
40550
40663
|
xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
40551
40664
|
return "$" + xc;
|
|
40552
40665
|
case "none":
|
|
@@ -41728,7 +41841,7 @@
|
|
|
41728
41841
|
sheetId: cmd.sheetId,
|
|
41729
41842
|
base: cmd.base,
|
|
41730
41843
|
quantity: thickness,
|
|
41731
|
-
position:
|
|
41844
|
+
position: cmd.position,
|
|
41732
41845
|
});
|
|
41733
41846
|
const isCol = cmd.dimension === "COL";
|
|
41734
41847
|
const start = cmd.elements[0];
|
|
@@ -41745,12 +41858,13 @@
|
|
|
41745
41858
|
},
|
|
41746
41859
|
];
|
|
41747
41860
|
const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
|
|
41861
|
+
const base = isBasedBefore ? cmd.base : cmd.base + 1;
|
|
41748
41862
|
const pasteTarget = [
|
|
41749
41863
|
{
|
|
41750
|
-
left: isCol ?
|
|
41751
|
-
right: isCol ?
|
|
41752
|
-
top: !isCol ?
|
|
41753
|
-
bottom: !isCol ?
|
|
41864
|
+
left: isCol ? base : 0,
|
|
41865
|
+
right: isCol ? base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
|
|
41866
|
+
top: !isCol ? base : 0,
|
|
41867
|
+
bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
|
|
41754
41868
|
},
|
|
41755
41869
|
];
|
|
41756
41870
|
state.paste(pasteTarget, { selectTarget: true });
|
|
@@ -41787,6 +41901,11 @@
|
|
|
41787
41901
|
doesElementsHaveCommonMerges(id, cmd.base - 1, cmd.base)) {
|
|
41788
41902
|
return 2 /* CommandResult.WillRemoveExistingMerge */;
|
|
41789
41903
|
}
|
|
41904
|
+
const headers = [cmd.base, ...cmd.elements];
|
|
41905
|
+
const maxHeaderValue = isCol ? this.getters.getNumberCols(id) : this.getters.getNumberRows(id);
|
|
41906
|
+
if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
|
|
41907
|
+
return 86 /* CommandResult.InvalidHeaderIndex */;
|
|
41908
|
+
}
|
|
41790
41909
|
return 0 /* CommandResult.Success */;
|
|
41791
41910
|
}
|
|
41792
41911
|
//-------------------------------------------
|
|
@@ -44068,7 +44187,7 @@
|
|
|
44068
44187
|
}
|
|
44069
44188
|
onKeydown(ev) {
|
|
44070
44189
|
let keyDownString = "";
|
|
44071
|
-
if (ev
|
|
44190
|
+
if (isCtrlKey(ev)) {
|
|
44072
44191
|
keyDownString += "CTRL+";
|
|
44073
44192
|
}
|
|
44074
44193
|
keyDownString += ev.key.toUpperCase();
|
|
@@ -44939,9 +45058,9 @@
|
|
|
44939
45058
|
* Apply the changes of the given HistoryChange to the state
|
|
44940
45059
|
*/
|
|
44941
45060
|
function applyChange(change, target) {
|
|
44942
|
-
let val = change.
|
|
44943
|
-
|
|
44944
|
-
for (let pathIndex =
|
|
45061
|
+
let val = change.path[0];
|
|
45062
|
+
const key = change.path[change.path.length - 1];
|
|
45063
|
+
for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
|
|
44945
45064
|
const p = change.path[pathIndex];
|
|
44946
45065
|
if (val[p] === undefined) {
|
|
44947
45066
|
const nextPath = change.path[pathIndex + 1];
|
|
@@ -45608,13 +45727,14 @@
|
|
|
45608
45727
|
}
|
|
45609
45728
|
addChange(...args) {
|
|
45610
45729
|
const val = args.pop();
|
|
45611
|
-
const
|
|
45730
|
+
const root = args[0];
|
|
45612
45731
|
let value = root;
|
|
45613
|
-
let key =
|
|
45614
|
-
|
|
45615
|
-
|
|
45732
|
+
let key = args[args.length - 1];
|
|
45733
|
+
const pathLength = args.length - 2;
|
|
45734
|
+
for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
|
|
45735
|
+
const p = args[pathIndex];
|
|
45616
45736
|
if (value[p] === undefined) {
|
|
45617
|
-
const nextPath =
|
|
45737
|
+
const nextPath = args[pathIndex + 1];
|
|
45618
45738
|
value[p] = createEmptyStructure(nextPath);
|
|
45619
45739
|
}
|
|
45620
45740
|
value = value[p];
|
|
@@ -45623,8 +45743,7 @@
|
|
|
45623
45743
|
return;
|
|
45624
45744
|
}
|
|
45625
45745
|
this.changes.push({
|
|
45626
|
-
|
|
45627
|
-
path,
|
|
45746
|
+
path: args,
|
|
45628
45747
|
before: value[key],
|
|
45629
45748
|
after: val,
|
|
45630
45749
|
});
|
|
@@ -47474,19 +47593,22 @@
|
|
|
47474
47593
|
* Check if the given command is allowed by all the plugins and the history.
|
|
47475
47594
|
*/
|
|
47476
47595
|
checkDispatchAllowed(command) {
|
|
47477
|
-
|
|
47478
|
-
|
|
47596
|
+
const results = isCoreCommand(command)
|
|
47597
|
+
? this.checkDispatchAllowedCoreCommand(command)
|
|
47598
|
+
: this.checkDispatchAllowedLocalCommand(command);
|
|
47599
|
+
if (results.some((r) => r !== 0 /* CommandResult.Success */)) {
|
|
47600
|
+
return new DispatchResult(results.flat());
|
|
47479
47601
|
}
|
|
47480
|
-
return
|
|
47602
|
+
return DispatchResult.Success;
|
|
47481
47603
|
}
|
|
47482
47604
|
checkDispatchAllowedCoreCommand(command) {
|
|
47483
47605
|
const results = this.corePlugins.map((handler) => handler.allowDispatch(command));
|
|
47484
47606
|
results.push(this.range.allowDispatch(command));
|
|
47485
|
-
return
|
|
47607
|
+
return results;
|
|
47486
47608
|
}
|
|
47487
47609
|
checkDispatchAllowedLocalCommand(command) {
|
|
47488
47610
|
const results = this.uiHandlers.map((handler) => handler.allowDispatch(command));
|
|
47489
|
-
return
|
|
47611
|
+
return results;
|
|
47490
47612
|
}
|
|
47491
47613
|
finalize() {
|
|
47492
47614
|
this.status = 3 /* Status.Finalizing */;
|
|
@@ -47804,9 +47926,9 @@
|
|
|
47804
47926
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
47805
47927
|
|
|
47806
47928
|
|
|
47807
|
-
__info__.version = '16.3.
|
|
47808
|
-
__info__.date = '
|
|
47809
|
-
__info__.hash = '
|
|
47929
|
+
__info__.version = '16.3.22';
|
|
47930
|
+
__info__.date = '2024-01-17T10:24:07.652Z';
|
|
47931
|
+
__info__.hash = '2c1b136';
|
|
47810
47932
|
|
|
47811
47933
|
|
|
47812
47934
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|