@odoo/o-spreadsheet 17.0.3 → 17.0.5
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 +276 -207
- package/dist/o-spreadsheet.d.ts +16 -20
- package/dist/o-spreadsheet.esm.js +276 -207
- package/dist/o-spreadsheet.iife.js +276 -207
- package/dist/o-spreadsheet.iife.min.js +284 -286
- package/dist/o_spreadsheet.xml +7 -8
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 17.0.
|
|
6
|
-
* @date 2023-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 17.0.5
|
|
6
|
+
* @date 2023-12-05T09:51:44.657Z
|
|
7
|
+
* @hash 2480a5d
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -693,8 +693,7 @@ function removeFalsyAttributes(obj) {
|
|
|
693
693
|
*
|
|
694
694
|
* https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
|
|
695
695
|
*/
|
|
696
|
-
const
|
|
697
|
-
" ",
|
|
696
|
+
const whiteSpaceSpecialCharacters = [
|
|
698
697
|
"\t",
|
|
699
698
|
"\f",
|
|
700
699
|
"\v",
|
|
@@ -709,8 +708,7 @@ const whiteSpaceCharacters = [
|
|
|
709
708
|
String.fromCharCode(parseInt("3000", 16)),
|
|
710
709
|
String.fromCharCode(parseInt("feff", 16)),
|
|
711
710
|
];
|
|
712
|
-
const whiteSpaceRegexp = new RegExp(
|
|
713
|
-
const newLineRegex = /\r\n|\r|\n/g;
|
|
711
|
+
const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|") + "|(\r\n|\r|\n)", "g");
|
|
714
712
|
/**
|
|
715
713
|
* Replace all the special spaces in a string (non-breaking, tabs, ...) by normal spaces, and all the
|
|
716
714
|
* different newlines types by \n.
|
|
@@ -718,9 +716,9 @@ const newLineRegex = /\r\n|\r|\n/g;
|
|
|
718
716
|
function replaceSpecialSpaces(text) {
|
|
719
717
|
if (!text)
|
|
720
718
|
return "";
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
return text;
|
|
719
|
+
if (!whiteSpaceRegexp.test(text))
|
|
720
|
+
return text;
|
|
721
|
+
return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
|
|
724
722
|
}
|
|
725
723
|
/**
|
|
726
724
|
* Determine if the numbers are consecutive.
|
|
@@ -2062,6 +2060,7 @@ exports.CommandResult = void 0;
|
|
|
2062
2060
|
CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
|
|
2063
2061
|
CommandResult["BlockingValidationRule"] = "BlockingValidationRule";
|
|
2064
2062
|
CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
|
|
2063
|
+
CommandResult["NoChanges"] = "NoChanges";
|
|
2065
2064
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
2066
2065
|
|
|
2067
2066
|
const DEFAULT_LOCALES = [
|
|
@@ -2191,12 +2190,12 @@ function toString(value) {
|
|
|
2191
2190
|
}
|
|
2192
2191
|
}
|
|
2193
2192
|
/** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
|
|
2194
|
-
function normalizeString(str) {
|
|
2193
|
+
const normalizeString = memoize(function normalizeString(str) {
|
|
2195
2194
|
return str
|
|
2196
2195
|
.toLowerCase()
|
|
2197
2196
|
.normalize("NFD")
|
|
2198
2197
|
.replace(/[\u0300-\u036f]/g, "");
|
|
2199
|
-
}
|
|
2198
|
+
});
|
|
2200
2199
|
const expectBooleanValueError = (value) => _t("The function [[FUNCTION_NAME]] expects a boolean value, but '%s' is a text, and cannot be coerced to a number.", value);
|
|
2201
2200
|
function toBoolean(value) {
|
|
2202
2201
|
switch (typeof value) {
|
|
@@ -3390,8 +3389,10 @@ function convertInternalFormatToFormat(internalFormat) {
|
|
|
3390
3389
|
const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
|
|
3391
3390
|
// Same as above, but matches the exact string (nothing before or after)
|
|
3392
3391
|
const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
|
|
3393
|
-
/** Reference of a column header (eg. A, AB) */
|
|
3394
|
-
const colHeader = new RegExp(
|
|
3392
|
+
/** Reference of a column header (eg. A, AB, $A) */
|
|
3393
|
+
const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
|
|
3394
|
+
/** Reference of a row header (eg. 1, $1) */
|
|
3395
|
+
const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
|
|
3395
3396
|
/** Reference of a column (eg. A, $CA, Sheet1!B) */
|
|
3396
3397
|
const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
|
|
3397
3398
|
/** Reference of a row (eg. 1, 59, Sheet1!9) */
|
|
@@ -3421,6 +3422,9 @@ function isRowReference(xc) {
|
|
|
3421
3422
|
function isColHeader(str) {
|
|
3422
3423
|
return colHeader.test(str);
|
|
3423
3424
|
}
|
|
3425
|
+
function isRowHeader(str) {
|
|
3426
|
+
return rowHeader.test(str);
|
|
3427
|
+
}
|
|
3424
3428
|
/**
|
|
3425
3429
|
* Return true if the given xc is the reference of a single cell,
|
|
3426
3430
|
* without any specified sheet (e.g. A1)
|
|
@@ -4104,18 +4108,10 @@ class RangeImpl {
|
|
|
4104
4108
|
if (isFullCol) {
|
|
4105
4109
|
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
4106
4110
|
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
4107
|
-
if (zone.left === zone.right) {
|
|
4108
|
-
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
4109
|
-
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
4110
|
-
}
|
|
4111
4111
|
}
|
|
4112
4112
|
if (isFullRow) {
|
|
4113
4113
|
parts[0].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
4114
4114
|
parts[1].colFixed = parts[0].colFixed || parts[1].colFixed;
|
|
4115
|
-
if (zone.top === zone.bottom) {
|
|
4116
|
-
parts[0].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
4117
|
-
parts[1].rowFixed = parts[0].rowFixed || parts[1].rowFixed;
|
|
4118
|
-
}
|
|
4119
4115
|
}
|
|
4120
4116
|
return parts;
|
|
4121
4117
|
}
|
|
@@ -4357,7 +4353,7 @@ function computeTextLinesHeight(textLineHeight, numberOfLines = 1) {
|
|
|
4357
4353
|
function getDefaultCellHeight(ctx, cell, colSize) {
|
|
4358
4354
|
if (!cell || !cell.content)
|
|
4359
4355
|
return DEFAULT_CELL_HEIGHT;
|
|
4360
|
-
const maxWidth = cell.style?.wrapping ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
4356
|
+
const maxWidth = cell.style?.wrapping === "wrap" ? colSize - 2 * MIN_CELL_TEXT_MARGIN : undefined;
|
|
4361
4357
|
const numberOfLines = cell.isFormula
|
|
4362
4358
|
? 1
|
|
4363
4359
|
: splitTextToWidth(ctx, cell.content, cell.style, maxWidth).length;
|
|
@@ -6252,10 +6248,6 @@ css /* scss */ `
|
|
|
6252
6248
|
|
|
6253
6249
|
.o-error-tooltip-message {
|
|
6254
6250
|
overflow: hidden;
|
|
6255
|
-
display: -webkit-box; /* Limit to 3 lines */
|
|
6256
|
-
-webkit-line-clamp: 3;
|
|
6257
|
-
line-clamp: 3;
|
|
6258
|
-
-webkit-box-orient: vertical;
|
|
6259
6251
|
}
|
|
6260
6252
|
}
|
|
6261
6253
|
`;
|
|
@@ -6638,6 +6630,9 @@ function* iterateChildren(el) {
|
|
|
6638
6630
|
function getOpenedMenus() {
|
|
6639
6631
|
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
6640
6632
|
}
|
|
6633
|
+
function isMacOS() {
|
|
6634
|
+
return navigator.userAgent.toUpperCase().indexOf("MAC") >= 0;
|
|
6635
|
+
}
|
|
6641
6636
|
|
|
6642
6637
|
/**
|
|
6643
6638
|
* Return the o-spreadsheet element position relative
|
|
@@ -7331,7 +7326,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
|
|
|
7331
7326
|
return result;
|
|
7332
7327
|
}
|
|
7333
7328
|
function tokenizeDebugger(chars) {
|
|
7334
|
-
if (chars.current
|
|
7329
|
+
if (chars.current === "?") {
|
|
7335
7330
|
chars.shift();
|
|
7336
7331
|
return { type: "DEBUGGER", value: "?" };
|
|
7337
7332
|
}
|
|
@@ -7342,7 +7337,7 @@ const misc$1 = {
|
|
|
7342
7337
|
")": "RIGHT_PAREN",
|
|
7343
7338
|
};
|
|
7344
7339
|
function tokenizeMisc(chars) {
|
|
7345
|
-
if (chars.current
|
|
7340
|
+
if (chars.current in misc$1) {
|
|
7346
7341
|
const value = chars.shift();
|
|
7347
7342
|
const type = misc$1[value];
|
|
7348
7343
|
return { type, value };
|
|
@@ -7350,7 +7345,7 @@ function tokenizeMisc(chars) {
|
|
|
7350
7345
|
return null;
|
|
7351
7346
|
}
|
|
7352
7347
|
function tokenizeArgsSeparator(chars, locale) {
|
|
7353
|
-
if (chars.current
|
|
7348
|
+
if (chars.current === locale.formulaArgSeparator) {
|
|
7354
7349
|
const value = chars.shift();
|
|
7355
7350
|
const type = "ARG_SEPARATOR";
|
|
7356
7351
|
return { type, value };
|
|
@@ -7375,14 +7370,13 @@ function tokenizeNumber(chars, locale) {
|
|
|
7375
7370
|
return null;
|
|
7376
7371
|
}
|
|
7377
7372
|
function tokenizeString(chars) {
|
|
7378
|
-
if (chars.current
|
|
7373
|
+
if (chars.current === '"') {
|
|
7379
7374
|
const startChar = chars.shift();
|
|
7380
7375
|
let letters = startChar;
|
|
7381
|
-
while (chars.current()
|
|
7382
|
-
(chars.current() !== startChar || letters[letters.length - 1] === "\\")) {
|
|
7376
|
+
while (chars.current && (chars.current !== startChar || letters[letters.length - 1] === "\\")) {
|
|
7383
7377
|
letters += chars.shift();
|
|
7384
7378
|
}
|
|
7385
|
-
if (chars.current
|
|
7379
|
+
if (chars.current === '"') {
|
|
7386
7380
|
letters += chars.shift();
|
|
7387
7381
|
}
|
|
7388
7382
|
return {
|
|
@@ -7409,14 +7403,14 @@ function tokenizeSymbol(chars) {
|
|
|
7409
7403
|
let result = "";
|
|
7410
7404
|
// there are two main cases to manage: either something which starts with
|
|
7411
7405
|
// a ', like 'Sheet 2'A2, or a word-like element.
|
|
7412
|
-
if (chars.current
|
|
7406
|
+
if (chars.current === "'") {
|
|
7413
7407
|
let lastChar = chars.shift();
|
|
7414
7408
|
result += lastChar;
|
|
7415
|
-
while (chars.current
|
|
7409
|
+
while (chars.current) {
|
|
7416
7410
|
lastChar = chars.shift();
|
|
7417
7411
|
result += lastChar;
|
|
7418
7412
|
if (lastChar === "'") {
|
|
7419
|
-
if (chars.current
|
|
7413
|
+
if (chars.current && chars.current === "'") {
|
|
7420
7414
|
lastChar = chars.shift();
|
|
7421
7415
|
result += lastChar;
|
|
7422
7416
|
}
|
|
@@ -7432,7 +7426,7 @@ function tokenizeSymbol(chars) {
|
|
|
7432
7426
|
};
|
|
7433
7427
|
}
|
|
7434
7428
|
}
|
|
7435
|
-
while (chars.current
|
|
7429
|
+
while (chars.current && separatorRegexp.test(chars.current)) {
|
|
7436
7430
|
result += chars.shift();
|
|
7437
7431
|
}
|
|
7438
7432
|
if (result.length) {
|
|
@@ -7447,14 +7441,14 @@ function tokenizeSymbol(chars) {
|
|
|
7447
7441
|
}
|
|
7448
7442
|
function tokenizeSpace(chars) {
|
|
7449
7443
|
let length = 0;
|
|
7450
|
-
while (chars.current
|
|
7444
|
+
while (chars.current === NEWLINE) {
|
|
7451
7445
|
length++;
|
|
7452
7446
|
chars.shift();
|
|
7453
7447
|
}
|
|
7454
7448
|
if (length) {
|
|
7455
7449
|
return { type: "SPACE", value: NEWLINE.repeat(length) };
|
|
7456
7450
|
}
|
|
7457
|
-
while (chars.current
|
|
7451
|
+
while (chars.current === " ") {
|
|
7458
7452
|
length++;
|
|
7459
7453
|
chars.shift();
|
|
7460
7454
|
}
|
|
@@ -7473,17 +7467,20 @@ function tokenizeInvalidRange(chars) {
|
|
|
7473
7467
|
class TokenizingChars {
|
|
7474
7468
|
text;
|
|
7475
7469
|
currentIndex = 0;
|
|
7470
|
+
current;
|
|
7476
7471
|
constructor(text) {
|
|
7477
7472
|
this.text = text;
|
|
7478
|
-
|
|
7479
|
-
current() {
|
|
7480
|
-
return this.text[this.currentIndex];
|
|
7473
|
+
this.current = text[0];
|
|
7481
7474
|
}
|
|
7482
7475
|
shift() {
|
|
7483
|
-
|
|
7476
|
+
const current = this.current;
|
|
7477
|
+
const next = this.text[++this.currentIndex];
|
|
7478
|
+
this.current = next;
|
|
7479
|
+
return current;
|
|
7484
7480
|
}
|
|
7485
7481
|
advanceBy(length) {
|
|
7486
7482
|
this.currentIndex += length;
|
|
7483
|
+
this.current = this.text[this.currentIndex];
|
|
7487
7484
|
}
|
|
7488
7485
|
isOver() {
|
|
7489
7486
|
return this.currentIndex >= this.text.length;
|
|
@@ -28280,6 +28277,7 @@ class AbstractResizer extends owl.Component {
|
|
|
28280
28277
|
draggerShadowThickness: 0,
|
|
28281
28278
|
delta: 0,
|
|
28282
28279
|
base: 0,
|
|
28280
|
+
position: "before",
|
|
28283
28281
|
});
|
|
28284
28282
|
_computeHandleDisplay(ev) {
|
|
28285
28283
|
const position = this._getEvOffset(ev);
|
|
@@ -28404,11 +28402,13 @@ class AbstractResizer extends owl.Component {
|
|
|
28404
28402
|
this.state.draggerLinePosition = dimensions.start;
|
|
28405
28403
|
this.state.draggerShadowPosition = dimensions.start;
|
|
28406
28404
|
this.state.base = elementIndex;
|
|
28405
|
+
this.state.position = "before";
|
|
28407
28406
|
}
|
|
28408
28407
|
else if (this._getSelectedZoneEnd() < elementIndex) {
|
|
28409
28408
|
this.state.draggerLinePosition = dimensions.end;
|
|
28410
28409
|
this.state.draggerShadowPosition = dimensions.end - this.state.draggerShadowThickness;
|
|
28411
|
-
this.state.base = elementIndex
|
|
28410
|
+
this.state.base = elementIndex;
|
|
28411
|
+
this.state.position = "after";
|
|
28412
28412
|
}
|
|
28413
28413
|
else {
|
|
28414
28414
|
this.state.draggerLinePosition = startDimensions.start;
|
|
@@ -28590,6 +28590,7 @@ class ColResizer extends AbstractResizer {
|
|
|
28590
28590
|
dimension: "COL",
|
|
28591
28591
|
base: this.state.base,
|
|
28592
28592
|
elements,
|
|
28593
|
+
position: this.state.position,
|
|
28593
28594
|
});
|
|
28594
28595
|
if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
|
|
28595
28596
|
this.env.raiseError(MergeErrorMessage);
|
|
@@ -28763,6 +28764,7 @@ class RowResizer extends AbstractResizer {
|
|
|
28763
28764
|
dimension: "ROW",
|
|
28764
28765
|
base: this.state.base,
|
|
28765
28766
|
elements,
|
|
28767
|
+
position: this.state.position,
|
|
28766
28768
|
});
|
|
28767
28769
|
if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
|
|
28768
28770
|
this.env.raiseError(MergeErrorMessage);
|
|
@@ -28870,8 +28872,8 @@ function useWheelHandler(handler) {
|
|
|
28870
28872
|
return val * (deltaMode === 0 ? 1 : DEFAULT_CELL_HEIGHT);
|
|
28871
28873
|
}
|
|
28872
28874
|
const onMouseWheel = (ev) => {
|
|
28873
|
-
const deltaX = normalize(ev.shiftKey ? ev.deltaY : ev.deltaX, ev.deltaMode);
|
|
28874
|
-
const deltaY = normalize(ev.shiftKey ? ev.deltaX : ev.deltaY, ev.deltaMode);
|
|
28875
|
+
const deltaX = normalize(ev.shiftKey && !isMacOS() ? ev.deltaY : ev.deltaX, ev.deltaMode);
|
|
28876
|
+
const deltaY = normalize(ev.shiftKey && !isMacOS() ? ev.deltaX : ev.deltaY, ev.deltaMode);
|
|
28875
28877
|
handler(deltaX, deltaY);
|
|
28876
28878
|
};
|
|
28877
28879
|
return onMouseWheel;
|
|
@@ -29759,6 +29761,7 @@ class Grid extends owl.Component {
|
|
|
29759
29761
|
const content = clipboardData.getData(ClipboardMIMEType.PlainText);
|
|
29760
29762
|
const target = this.env.model.getters.getSelectedZones();
|
|
29761
29763
|
const clipboardString = this.env.model.getters.getClipboardTextContent();
|
|
29764
|
+
const isCutOperation = this.env.model.getters.isCutOperation();
|
|
29762
29765
|
if (clipboardString === content) {
|
|
29763
29766
|
// the paste actually comes from o-spreadsheet itself
|
|
29764
29767
|
interactivePaste(this.env, target);
|
|
@@ -29766,7 +29769,7 @@ class Grid extends owl.Component {
|
|
|
29766
29769
|
else {
|
|
29767
29770
|
interactivePasteFromOS(this.env, target, content);
|
|
29768
29771
|
}
|
|
29769
|
-
if (
|
|
29772
|
+
if (isCutOperation) {
|
|
29770
29773
|
await this.env.clipboard.write({ [ClipboardMIMEType.PlainText]: "" });
|
|
29771
29774
|
}
|
|
29772
29775
|
}
|
|
@@ -33324,7 +33327,7 @@ const machine = {
|
|
|
33324
33327
|
SPACE: goTo(State.RightRef),
|
|
33325
33328
|
NUMBER: goTo(State.Found),
|
|
33326
33329
|
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
33327
|
-
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value)),
|
|
33330
|
+
SYMBOL: goTo(State.Found, (token) => isColHeader(token.value) || isRowHeader(token.value)),
|
|
33328
33331
|
},
|
|
33329
33332
|
[State.RightColumnRef]: {
|
|
33330
33333
|
SPACE: goTo(State.RightColumnRef),
|
|
@@ -33335,6 +33338,7 @@ const machine = {
|
|
|
33335
33338
|
SPACE: goTo(State.RightRowRef),
|
|
33336
33339
|
NUMBER: goTo(State.Found),
|
|
33337
33340
|
REFERENCE: goTo(State.Found, (token) => isSingleCellReference(token.value)),
|
|
33341
|
+
SYMBOL: goTo(State.Found, (token) => isRowHeader(token.value)),
|
|
33338
33342
|
},
|
|
33339
33343
|
[State.Found]: {},
|
|
33340
33344
|
};
|
|
@@ -34060,6 +34064,14 @@ class BordersPlugin extends CorePlugin {
|
|
|
34060
34064
|
// ---------------------------------------------------------------------------
|
|
34061
34065
|
// Command Handling
|
|
34062
34066
|
// ---------------------------------------------------------------------------
|
|
34067
|
+
allowDispatch(cmd) {
|
|
34068
|
+
switch (cmd.type) {
|
|
34069
|
+
case "SET_BORDER":
|
|
34070
|
+
return this.checkBordersUnchanged(cmd);
|
|
34071
|
+
default:
|
|
34072
|
+
return "Success" /* CommandResult.Success */;
|
|
34073
|
+
}
|
|
34074
|
+
}
|
|
34063
34075
|
handle(cmd) {
|
|
34064
34076
|
switch (cmd.type) {
|
|
34065
34077
|
case "ADD_MERGE":
|
|
@@ -34479,6 +34491,14 @@ class BordersPlugin extends CorePlugin {
|
|
|
34479
34491
|
this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
|
|
34480
34492
|
}
|
|
34481
34493
|
}
|
|
34494
|
+
checkBordersUnchanged(cmd) {
|
|
34495
|
+
const currentBorder = this.getCellBorder(cmd);
|
|
34496
|
+
const areAllNewBordersUndefined = !cmd.border?.bottom && !cmd.border?.left && !cmd.border?.right && !cmd.border?.top;
|
|
34497
|
+
if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
|
|
34498
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
34499
|
+
}
|
|
34500
|
+
return "Success" /* CommandResult.Success */;
|
|
34501
|
+
}
|
|
34482
34502
|
// ---------------------------------------------------------------------------
|
|
34483
34503
|
// Import/Export
|
|
34484
34504
|
// ---------------------------------------------------------------------------
|
|
@@ -35334,8 +35354,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35334
35354
|
allowDispatch(cmd) {
|
|
35335
35355
|
switch (cmd.type) {
|
|
35336
35356
|
case "UPDATE_CELL":
|
|
35357
|
+
return this.checkCellOutOfSheet(cmd);
|
|
35337
35358
|
case "CLEAR_CELL":
|
|
35338
|
-
return this.
|
|
35359
|
+
return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
|
|
35339
35360
|
default:
|
|
35340
35361
|
return "Success" /* CommandResult.Success */;
|
|
35341
35362
|
}
|
|
@@ -35504,14 +35525,9 @@ class CellPlugin extends CorePlugin {
|
|
|
35504
35525
|
*/
|
|
35505
35526
|
getCellById(cellId) {
|
|
35506
35527
|
// this must be as fast as possible
|
|
35507
|
-
|
|
35508
|
-
|
|
35509
|
-
|
|
35510
|
-
if (cell) {
|
|
35511
|
-
return cell;
|
|
35512
|
-
}
|
|
35513
|
-
}
|
|
35514
|
-
return undefined;
|
|
35528
|
+
const position = this.getters.getCellPosition(cellId);
|
|
35529
|
+
const sheet = this.cells[position.sheetId];
|
|
35530
|
+
return sheet[cellId];
|
|
35515
35531
|
}
|
|
35516
35532
|
/*
|
|
35517
35533
|
* Reconstructs the original formula string based on a normalized form and its dependencies
|
|
@@ -35742,13 +35758,23 @@ class CellPlugin extends CorePlugin {
|
|
|
35742
35758
|
},
|
|
35743
35759
|
};
|
|
35744
35760
|
}
|
|
35745
|
-
checkCellOutOfSheet(
|
|
35761
|
+
checkCellOutOfSheet(cmd) {
|
|
35762
|
+
const { sheetId, col, row } = cmd;
|
|
35746
35763
|
const sheet = this.getters.tryGetSheet(sheetId);
|
|
35747
35764
|
if (!sheet)
|
|
35748
35765
|
return "InvalidSheetId" /* CommandResult.InvalidSheetId */;
|
|
35749
35766
|
const sheetZone = this.getters.getSheetZone(sheetId);
|
|
35750
35767
|
return isInside(col, row, sheetZone) ? "Success" /* CommandResult.Success */ : "TargetOutOfSheet" /* CommandResult.TargetOutOfSheet */;
|
|
35751
35768
|
}
|
|
35769
|
+
checkUselessClearCell(cmd) {
|
|
35770
|
+
const cell = this.getters.getCell(cmd);
|
|
35771
|
+
if (!cell)
|
|
35772
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35773
|
+
if (!cell.content && !cell.style && !cell.format) {
|
|
35774
|
+
return "NoChanges" /* CommandResult.NoChanges */;
|
|
35775
|
+
}
|
|
35776
|
+
return "Success" /* CommandResult.Success */;
|
|
35777
|
+
}
|
|
35752
35778
|
}
|
|
35753
35779
|
class FormulaCellWithDependencies {
|
|
35754
35780
|
id;
|
|
@@ -36438,6 +36464,9 @@ class DataValidationPlugin extends CorePlugin {
|
|
|
36438
36464
|
return this.rules[sheetId].find((rule) => rule.id === id);
|
|
36439
36465
|
}
|
|
36440
36466
|
getValidationRuleForCell({ sheetId, col, row }) {
|
|
36467
|
+
if (!this.rules[sheetId]) {
|
|
36468
|
+
return undefined;
|
|
36469
|
+
}
|
|
36441
36470
|
for (const rule of this.rules[sheetId]) {
|
|
36442
36471
|
for (const range of rule.ranges) {
|
|
36443
36472
|
if (isInside(col, row, range.zone)) {
|
|
@@ -37291,7 +37320,16 @@ class HeaderVisibilityPlugin extends CorePlugin {
|
|
|
37291
37320
|
return consecutiveIndexes;
|
|
37292
37321
|
}
|
|
37293
37322
|
getAllVisibleHeaders(sheetId, dimension) {
|
|
37294
|
-
|
|
37323
|
+
const headers = range(0, this.getters.getNumberHeaders(sheetId, dimension));
|
|
37324
|
+
const foldedHeaders = [];
|
|
37325
|
+
this.getters.getHeaderGroups(sheetId, dimension).forEach((group) => {
|
|
37326
|
+
if (group.isFolded) {
|
|
37327
|
+
foldedHeaders.push(...range(group.start, group.end + 1));
|
|
37328
|
+
}
|
|
37329
|
+
});
|
|
37330
|
+
return headers.filter((i) => {
|
|
37331
|
+
return !this.hiddenHeaders[sheetId][dimension][i] && !foldedHeaders.includes(i);
|
|
37332
|
+
});
|
|
37295
37333
|
}
|
|
37296
37334
|
import(data) {
|
|
37297
37335
|
for (let sheet of data.sheets) {
|
|
@@ -39035,10 +39073,13 @@ class SheetPlugin extends CorePlugin {
|
|
|
39035
39073
|
// begin with the end.
|
|
39036
39074
|
rows.sort((a, b) => b - a);
|
|
39037
39075
|
for (let group of groupConsecutive(rows)) {
|
|
39076
|
+
// indexes are sorted in the descending order
|
|
39077
|
+
const from = group[group.length - 1];
|
|
39078
|
+
const to = group[0];
|
|
39038
39079
|
// Move the cells.
|
|
39039
|
-
this.moveCellOnRowsDeletion(sheet,
|
|
39040
|
-
// Effectively delete the
|
|
39041
|
-
|
|
39080
|
+
this.moveCellOnRowsDeletion(sheet, from, to);
|
|
39081
|
+
// Effectively delete the rows
|
|
39082
|
+
this.updateRowsStructureOnDeletion(sheet, from, to);
|
|
39042
39083
|
}
|
|
39043
39084
|
const count = rows.filter((row) => row < sheet.panes.ySplit).length;
|
|
39044
39085
|
if (count) {
|
|
@@ -39060,8 +39101,6 @@ class SheetPlugin extends CorePlugin {
|
|
|
39060
39101
|
this.addEmptyRows(sheet, quantity);
|
|
39061
39102
|
// Move the cells.
|
|
39062
39103
|
this.moveCellsOnAddition(sheet, index, quantity, "rows");
|
|
39063
|
-
// Recompute the left-right/top-bottom.
|
|
39064
|
-
this.updateRowsStructureOnAddition(sheet, row, quantity);
|
|
39065
39104
|
if (index < sheet.panes.ySplit) {
|
|
39066
39105
|
this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
|
|
39067
39106
|
}
|
|
@@ -39162,35 +39201,20 @@ class SheetPlugin extends CorePlugin {
|
|
|
39162
39201
|
}
|
|
39163
39202
|
}
|
|
39164
39203
|
}
|
|
39165
|
-
updateRowsStructureOnDeletion(
|
|
39204
|
+
updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
|
|
39166
39205
|
const rows = [];
|
|
39167
|
-
const cellsQueue = sheet.rows.map((row) => row.cells);
|
|
39206
|
+
const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
|
|
39168
39207
|
for (let i in sheet.rows) {
|
|
39169
|
-
|
|
39208
|
+
const row = Number(i);
|
|
39209
|
+
if (row >= deleteFromRow && row <= deleteToRow) {
|
|
39170
39210
|
continue;
|
|
39171
39211
|
}
|
|
39172
39212
|
rows.push({
|
|
39173
|
-
cells: cellsQueue.
|
|
39213
|
+
cells: cellsQueue.pop(),
|
|
39174
39214
|
});
|
|
39175
39215
|
}
|
|
39176
39216
|
this.history.update("sheets", sheet.id, "rows", rows);
|
|
39177
39217
|
}
|
|
39178
|
-
/**
|
|
39179
|
-
* Update the rows of the sheet after an addition:
|
|
39180
|
-
* - Rename the rows
|
|
39181
|
-
*
|
|
39182
|
-
* @param sheet Sheet on which the deletion occurs
|
|
39183
|
-
* @param addedRow Index of the added row
|
|
39184
|
-
* @param rowsToAdd Number of the rows to add
|
|
39185
|
-
*/
|
|
39186
|
-
updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
|
|
39187
|
-
const rows = [];
|
|
39188
|
-
const cellsQueue = sheet.rows.map((row) => row.cells);
|
|
39189
|
-
sheet.rows.forEach(() => rows.push({
|
|
39190
|
-
cells: cellsQueue.shift(),
|
|
39191
|
-
}));
|
|
39192
|
-
this.history.update("sheets", sheet.id, "rows", rows);
|
|
39193
|
-
}
|
|
39194
39218
|
/**
|
|
39195
39219
|
* Add empty rows at the end of the rows
|
|
39196
39220
|
*
|
|
@@ -39717,6 +39741,7 @@ class CompilationParametersBuilder {
|
|
|
39717
39741
|
getters;
|
|
39718
39742
|
computeCell;
|
|
39719
39743
|
evalContext;
|
|
39744
|
+
rangeCache = {};
|
|
39720
39745
|
constructor(context, getters, computeCell) {
|
|
39721
39746
|
this.getters = getters;
|
|
39722
39747
|
this.computeCell = computeCell;
|
|
@@ -39764,10 +39789,13 @@ class CompilationParametersBuilder {
|
|
|
39764
39789
|
if (evaluatedCell === undefined) {
|
|
39765
39790
|
return { value: null, format: this.getters.getCell(position)?.format };
|
|
39766
39791
|
}
|
|
39792
|
+
if (evaluatedCell.type === CellValueType.error) {
|
|
39793
|
+
throw evaluatedCell.error;
|
|
39794
|
+
}
|
|
39767
39795
|
return evaluatedCell;
|
|
39768
39796
|
}
|
|
39769
39797
|
getEvaluatedCellIfNotEmpty(position) {
|
|
39770
|
-
const evaluatedCell = this.
|
|
39798
|
+
const evaluatedCell = this.computeCell(position);
|
|
39771
39799
|
if (evaluatedCell.type === CellValueType.empty) {
|
|
39772
39800
|
const cell = this.getters.getCell(position);
|
|
39773
39801
|
if (!cell || (!cell.isFormula && cell.content === "")) {
|
|
@@ -39776,13 +39804,6 @@ class CompilationParametersBuilder {
|
|
|
39776
39804
|
}
|
|
39777
39805
|
return evaluatedCell;
|
|
39778
39806
|
}
|
|
39779
|
-
getEvaluatedCell(position) {
|
|
39780
|
-
const evaluatedCell = this.computeCell(position);
|
|
39781
|
-
if (evaluatedCell.type === CellValueType.error) {
|
|
39782
|
-
throw evaluatedCell.error;
|
|
39783
|
-
}
|
|
39784
|
-
return evaluatedCell;
|
|
39785
|
-
}
|
|
39786
39807
|
/**
|
|
39787
39808
|
* Return the values of the cell(s) used in reference, but always in the format of a range even
|
|
39788
39809
|
* if a single cell is referenced. It is a list of col values. This is useful for the formulas that describe parameters as
|
|
@@ -39802,17 +39823,33 @@ class CompilationParametersBuilder {
|
|
|
39802
39823
|
if (!_zone) {
|
|
39803
39824
|
return [[]];
|
|
39804
39825
|
}
|
|
39826
|
+
const { top, left, bottom, right } = zone;
|
|
39827
|
+
const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
|
|
39828
|
+
if (cacheKey in this.rangeCache) {
|
|
39829
|
+
const result = this.rangeCache[cacheKey];
|
|
39830
|
+
if (result instanceof EvaluationError) {
|
|
39831
|
+
throw result;
|
|
39832
|
+
}
|
|
39833
|
+
return result;
|
|
39834
|
+
}
|
|
39805
39835
|
const height = _zone.bottom - _zone.top + 1;
|
|
39806
39836
|
const width = _zone.right - _zone.left + 1;
|
|
39807
|
-
const matrix = Array
|
|
39837
|
+
const matrix = new Array(width);
|
|
39808
39838
|
// Performance issue: nested loop is faster than a map here
|
|
39809
39839
|
for (let col = _zone.left; col <= _zone.right; col++) {
|
|
39840
|
+
const colIndex = col - _zone.left;
|
|
39841
|
+
matrix[colIndex] = new Array(height);
|
|
39810
39842
|
for (let row = _zone.top; row <= _zone.bottom; row++) {
|
|
39811
|
-
const
|
|
39843
|
+
const evaluatedCell = this.getEvaluatedCellIfNotEmpty({ sheetId, col, row });
|
|
39844
|
+
if (evaluatedCell?.type === CellValueType.error) {
|
|
39845
|
+
this.rangeCache[cacheKey] = evaluatedCell.error;
|
|
39846
|
+
throw evaluatedCell.error;
|
|
39847
|
+
}
|
|
39812
39848
|
const rowIndex = row - _zone.top;
|
|
39813
39849
|
matrix[colIndex][rowIndex] = this.readCell({ sheetId, col, row });
|
|
39814
39850
|
}
|
|
39815
39851
|
}
|
|
39852
|
+
this.rangeCache[cacheKey] = matrix;
|
|
39816
39853
|
return matrix;
|
|
39817
39854
|
}
|
|
39818
39855
|
}
|
|
@@ -40018,6 +40055,7 @@ class Evaluator {
|
|
|
40018
40055
|
this.formulaDependencies().addDependencies(positionId, dependencies);
|
|
40019
40056
|
}
|
|
40020
40057
|
updateCompilationParameters() {
|
|
40058
|
+
// rebuild the compilation parameters (with a clean cache)
|
|
40021
40059
|
this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
|
|
40022
40060
|
}
|
|
40023
40061
|
evaluateCells(positions) {
|
|
@@ -40061,6 +40099,16 @@ class Evaluator {
|
|
|
40061
40099
|
this.evaluatedCells = new Map();
|
|
40062
40100
|
this.evaluate(this.getAllCells());
|
|
40063
40101
|
}
|
|
40102
|
+
evaluateFormula(sheetId, formulaString) {
|
|
40103
|
+
const compiledFormula = compile(formulaString);
|
|
40104
|
+
const ranges = compiledFormula.dependencies.map((xc) => this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
40105
|
+
this.updateCompilationParameters();
|
|
40106
|
+
const array = compiledFormula.execute(ranges, ...this.compilationParams);
|
|
40107
|
+
if (isMatrix(array)) {
|
|
40108
|
+
return matrixMap(array, (cell) => cell.value);
|
|
40109
|
+
}
|
|
40110
|
+
return array.value;
|
|
40111
|
+
}
|
|
40064
40112
|
getAllCells() {
|
|
40065
40113
|
const positionIds = new JetSet();
|
|
40066
40114
|
for (const sheetId of this.getters.getSheetIds()) {
|
|
@@ -40087,6 +40135,7 @@ class Evaluator {
|
|
|
40087
40135
|
this.nextPositionsToUpdate = cells;
|
|
40088
40136
|
let currentIteration = 0;
|
|
40089
40137
|
while (this.nextPositionsToUpdate.size && currentIteration++ < MAX_ITERATION) {
|
|
40138
|
+
this.updateCompilationParameters();
|
|
40090
40139
|
const positionIds = Array.from(this.nextPositionsToUpdate);
|
|
40091
40140
|
this.nextPositionsToUpdate.clear();
|
|
40092
40141
|
for (let i = 0; i < positionIds.length; ++i) {
|
|
@@ -40450,7 +40499,6 @@ class PositionBitsEncoder {
|
|
|
40450
40499
|
// of other cells depending on it, at the next iteration.
|
|
40451
40500
|
//#endregion
|
|
40452
40501
|
class EvaluationPlugin extends UIPlugin {
|
|
40453
|
-
config;
|
|
40454
40502
|
static getters = [
|
|
40455
40503
|
"evaluateFormula",
|
|
40456
40504
|
"getCorrespondingFormulaCell",
|
|
@@ -40461,15 +40509,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40461
40509
|
"getEvaluatedCells",
|
|
40462
40510
|
"getEvaluatedCellsInZone",
|
|
40463
40511
|
"getSpreadPositionsOf",
|
|
40512
|
+
"getArrayFormulaSpreadingOn",
|
|
40464
40513
|
];
|
|
40465
40514
|
shouldRebuildDependenciesGraph = true;
|
|
40466
40515
|
evaluator;
|
|
40467
|
-
compilationParams;
|
|
40468
40516
|
positionsToUpdate = [];
|
|
40469
40517
|
constructor(config) {
|
|
40470
40518
|
super(config);
|
|
40471
|
-
this.config = config;
|
|
40472
|
-
this.compilationParams = this.getCompilationParameters();
|
|
40473
40519
|
this.evaluator = new Evaluator(config.custom, this.getters);
|
|
40474
40520
|
}
|
|
40475
40521
|
// ---------------------------------------------------------------------------
|
|
@@ -40494,10 +40540,6 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40494
40540
|
case "EVALUATE_CELLS":
|
|
40495
40541
|
this.evaluator.evaluateAllCells();
|
|
40496
40542
|
break;
|
|
40497
|
-
case "UPDATE_LOCALE":
|
|
40498
|
-
this.compilationParams = this.getCompilationParameters();
|
|
40499
|
-
this.evaluator.updateCompilationParameters();
|
|
40500
|
-
break;
|
|
40501
40543
|
}
|
|
40502
40544
|
}
|
|
40503
40545
|
finalize() {
|
|
@@ -40515,16 +40557,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40515
40557
|
// Getters
|
|
40516
40558
|
// ---------------------------------------------------------------------------
|
|
40517
40559
|
evaluateFormula(sheetId, formulaString) {
|
|
40518
|
-
|
|
40519
|
-
const ranges = [];
|
|
40520
|
-
for (let xc of compiledFormula.dependencies) {
|
|
40521
|
-
ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
|
|
40522
|
-
}
|
|
40523
|
-
const array = compiledFormula.execute(ranges, ...this.compilationParams);
|
|
40524
|
-
if (isMatrix(array)) {
|
|
40525
|
-
return array.map((col) => col.map((row) => row.value));
|
|
40526
|
-
}
|
|
40527
|
-
return array.value;
|
|
40560
|
+
return this.evaluator.evaluateFormula(sheetId, formulaString);
|
|
40528
40561
|
}
|
|
40529
40562
|
/**
|
|
40530
40563
|
* Return the value of each cell in the range as they are displayed in the grid.
|
|
@@ -40573,6 +40606,9 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40573
40606
|
getSpreadPositionsOf(position) {
|
|
40574
40607
|
return this.evaluator.getSpreadPositionsOf(position);
|
|
40575
40608
|
}
|
|
40609
|
+
getArrayFormulaSpreadingOn(position) {
|
|
40610
|
+
return this.evaluator.getArrayFormulaSpreadingOn(position);
|
|
40611
|
+
}
|
|
40576
40612
|
// ---------------------------------------------------------------------------
|
|
40577
40613
|
// Export
|
|
40578
40614
|
// ---------------------------------------------------------------------------
|
|
@@ -40616,7 +40652,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40616
40652
|
else if (cell && cell.content) {
|
|
40617
40653
|
return undefined;
|
|
40618
40654
|
}
|
|
40619
|
-
const spreadingFormulaPosition = this.
|
|
40655
|
+
const spreadingFormulaPosition = this.getArrayFormulaSpreadingOn(position);
|
|
40620
40656
|
if (spreadingFormulaPosition === undefined) {
|
|
40621
40657
|
return undefined;
|
|
40622
40658
|
}
|
|
@@ -40626,9 +40662,6 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
40626
40662
|
}
|
|
40627
40663
|
return undefined;
|
|
40628
40664
|
}
|
|
40629
|
-
getCompilationParameters() {
|
|
40630
|
-
return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
|
|
40631
|
-
}
|
|
40632
40665
|
}
|
|
40633
40666
|
function isBadExpression(tokens) {
|
|
40634
40667
|
try {
|
|
@@ -41769,19 +41802,21 @@ class AutofillPlugin extends UIPlugin {
|
|
|
41769
41802
|
let col = zone.left;
|
|
41770
41803
|
let row = zone.bottom;
|
|
41771
41804
|
if (col > 0) {
|
|
41772
|
-
let
|
|
41773
|
-
while (
|
|
41805
|
+
let leftPosition = { sheetId, col: col - 1, row };
|
|
41806
|
+
while (this.getters.getEvaluatedCell(leftPosition).type !== CellValueType.empty ||
|
|
41807
|
+
this.getters.getCell(leftPosition)?.content) {
|
|
41774
41808
|
row += 1;
|
|
41775
|
-
|
|
41809
|
+
leftPosition = { sheetId, col: col - 1, row };
|
|
41776
41810
|
}
|
|
41777
41811
|
}
|
|
41778
41812
|
if (row === zone.bottom) {
|
|
41779
41813
|
col = zone.right;
|
|
41780
41814
|
if (col <= this.getters.getNumberCols(sheetId)) {
|
|
41781
|
-
let
|
|
41782
|
-
while (
|
|
41815
|
+
let rightPosition = { sheetId, col: col + 1, row };
|
|
41816
|
+
while (this.getters.getEvaluatedCell(rightPosition).type !== CellValueType.empty ||
|
|
41817
|
+
this.getters.getCell(rightPosition)?.content) {
|
|
41783
41818
|
row += 1;
|
|
41784
|
-
|
|
41819
|
+
rightPosition = { sheetId, col: col + 1, row };
|
|
41785
41820
|
}
|
|
41786
41821
|
}
|
|
41787
41822
|
}
|
|
@@ -42773,6 +42808,7 @@ class Session extends EventBus {
|
|
|
42773
42808
|
isReplayingInitialRevisions = false;
|
|
42774
42809
|
processedRevisions = new Set();
|
|
42775
42810
|
uuidGenerator = new UuidGenerator();
|
|
42811
|
+
lastLocalOperation;
|
|
42776
42812
|
/**
|
|
42777
42813
|
* Manages the collaboration between multiple users on the same spreadsheet.
|
|
42778
42814
|
* It can forward local state changes to other users to ensure they all eventually
|
|
@@ -42805,6 +42841,11 @@ class Session extends EventBus {
|
|
|
42805
42841
|
return;
|
|
42806
42842
|
const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes, Date.now());
|
|
42807
42843
|
this.revisions.append(revision.id, revision);
|
|
42844
|
+
// REQUEST_REDO just repeats the last operation, the
|
|
42845
|
+
// last operation is still the same and should not change.
|
|
42846
|
+
if (rootCommand.type !== "REQUEST_REDO") {
|
|
42847
|
+
this.lastLocalOperation = revision;
|
|
42848
|
+
}
|
|
42808
42849
|
this.trigger("new-local-state-update", { id: revision.id });
|
|
42809
42850
|
this.sendUpdateMessage({
|
|
42810
42851
|
type: "REMOTE_REVISION",
|
|
@@ -42901,19 +42942,10 @@ class Session extends EventBus {
|
|
|
42901
42942
|
return this.pendingMessages.length === 0;
|
|
42902
42943
|
}
|
|
42903
42944
|
/**
|
|
42904
|
-
* Get the last local revision
|
|
42945
|
+
* Get the last local revision
|
|
42905
42946
|
* */
|
|
42906
|
-
getLastLocalNonEmptyRevision(
|
|
42907
|
-
|
|
42908
|
-
for (const rev of revisions) {
|
|
42909
|
-
if (rev.rootCommand === "SNAPSHOT")
|
|
42910
|
-
return undefined;
|
|
42911
|
-
if (!rev.rootCommand || rev.rootCommand === "REMOTE")
|
|
42912
|
-
continue;
|
|
42913
|
-
if (!ignoredRootCommands.includes(rev.rootCommand?.type) && rev.commands.length)
|
|
42914
|
-
return rev;
|
|
42915
|
-
}
|
|
42916
|
-
return undefined;
|
|
42947
|
+
getLastLocalNonEmptyRevision() {
|
|
42948
|
+
return this.lastLocalOperation;
|
|
42917
42949
|
}
|
|
42918
42950
|
_move(position) {
|
|
42919
42951
|
// this method is debounced and might be called after the client
|
|
@@ -42973,7 +43005,7 @@ class Session extends EventBus {
|
|
|
42973
43005
|
break;
|
|
42974
43006
|
case "REMOTE_REVISION":
|
|
42975
43007
|
const { clientId, commands, timestamp } = message;
|
|
42976
|
-
const revision = new Revision(message.nextRevisionId, clientId, commands,
|
|
43008
|
+
const revision = new Revision(message.nextRevisionId, clientId, commands, undefined, undefined, timestamp);
|
|
42977
43009
|
if (revision.clientId !== this.clientId) {
|
|
42978
43010
|
this.revisions.insert(revision.id, revision, message.serverRevisionId);
|
|
42979
43011
|
const pendingCommands = this.pendingMessages
|
|
@@ -42986,10 +43018,11 @@ class Session extends EventBus {
|
|
|
42986
43018
|
}
|
|
42987
43019
|
break;
|
|
42988
43020
|
case "SNAPSHOT_CREATED": {
|
|
42989
|
-
const revision = new Revision(message.nextRevisionId, "server", [],
|
|
43021
|
+
const revision = new Revision(message.nextRevisionId, "server", [], undefined, undefined, Date.now());
|
|
42990
43022
|
this.revisions.insert(revision.id, revision, message.serverRevisionId);
|
|
42991
43023
|
this.dropPendingHistoryMessages();
|
|
42992
43024
|
this.trigger("snapshot");
|
|
43025
|
+
this.lastLocalOperation = undefined;
|
|
42993
43026
|
break;
|
|
42994
43027
|
}
|
|
42995
43028
|
}
|
|
@@ -43327,11 +43360,26 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43327
43360
|
let cellsInRow = [];
|
|
43328
43361
|
for (let col of columnsIndex) {
|
|
43329
43362
|
const position = { col, row, sheetId };
|
|
43363
|
+
const spreader = getters.getArrayFormulaSpreadingOn(position);
|
|
43364
|
+
let cell = getters.getCell(position);
|
|
43365
|
+
const evaluatedCell = getters.getEvaluatedCell(position);
|
|
43366
|
+
if (spreader) {
|
|
43367
|
+
const isSpreaderCopied = rowsIndex.includes(spreader.row) && columnsIndex.includes(spreader.col);
|
|
43368
|
+
const content = isSpreaderCopied
|
|
43369
|
+
? ""
|
|
43370
|
+
: formatValue(evaluatedCell.value, { locale: getters.getLocale() });
|
|
43371
|
+
cell = {
|
|
43372
|
+
id: cell?.id || "",
|
|
43373
|
+
style: cell?.style,
|
|
43374
|
+
format: evaluatedCell.format,
|
|
43375
|
+
content,
|
|
43376
|
+
isFormula: false,
|
|
43377
|
+
};
|
|
43378
|
+
}
|
|
43330
43379
|
cellsInRow.push({
|
|
43331
|
-
cell
|
|
43332
|
-
style: getters.getCellComputedStyle(position),
|
|
43333
|
-
evaluatedCell: getters.getEvaluatedCell(position),
|
|
43380
|
+
cell,
|
|
43334
43381
|
border: getters.getCellBorder(position) || undefined,
|
|
43382
|
+
evaluatedCell,
|
|
43335
43383
|
position,
|
|
43336
43384
|
});
|
|
43337
43385
|
}
|
|
@@ -43453,13 +43501,6 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43453
43501
|
});
|
|
43454
43502
|
}
|
|
43455
43503
|
this.pasteCopiedTables(target);
|
|
43456
|
-
this.cells.forEach((row) => {
|
|
43457
|
-
row.forEach((c) => {
|
|
43458
|
-
if (c.cell) {
|
|
43459
|
-
c.cell = undefined;
|
|
43460
|
-
}
|
|
43461
|
-
});
|
|
43462
|
-
});
|
|
43463
43504
|
}
|
|
43464
43505
|
/**
|
|
43465
43506
|
* The clipped zone is copied as many times as it fits in the target.
|
|
@@ -43531,7 +43572,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43531
43572
|
clearClippedZones() {
|
|
43532
43573
|
for (const row of this.cells) {
|
|
43533
43574
|
for (const cell of row) {
|
|
43534
|
-
if (cell
|
|
43575
|
+
if (cell?.cell) {
|
|
43535
43576
|
this.dispatch("CLEAR_CELL", cell.position);
|
|
43536
43577
|
}
|
|
43537
43578
|
}
|
|
@@ -43557,6 +43598,9 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43557
43598
|
const rowCells = this.cells[r];
|
|
43558
43599
|
for (let c = 0; c < width; c++) {
|
|
43559
43600
|
const origin = rowCells[c];
|
|
43601
|
+
if (!origin) {
|
|
43602
|
+
continue;
|
|
43603
|
+
}
|
|
43560
43604
|
const position = { col: col + c, row: row + r, sheetId: sheetId };
|
|
43561
43605
|
// TODO: refactor this part. the "Paste merge" action is also executed with
|
|
43562
43606
|
// MOVE_RANGES in pasteFromCut. Adding a condition on the operation type here
|
|
@@ -43580,53 +43624,42 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43580
43624
|
pasteCell(origin, target, operation, clipboardOption) {
|
|
43581
43625
|
const { sheetId, col, row } = target;
|
|
43582
43626
|
const targetCell = this.getters.getEvaluatedCell(target);
|
|
43583
|
-
if (clipboardOption?.pasteOption
|
|
43584
|
-
const
|
|
43585
|
-
const
|
|
43586
|
-
|
|
43587
|
-
|
|
43588
|
-
bottom: targetBorders?.bottom || originBorders?.bottom,
|
|
43589
|
-
left: targetBorders?.left || originBorders?.left,
|
|
43590
|
-
right: targetBorders?.right || originBorders?.right,
|
|
43591
|
-
};
|
|
43592
|
-
this.dispatch("SET_BORDER", { sheetId, col, row, border });
|
|
43627
|
+
if (clipboardOption?.pasteOption === "onlyValue") {
|
|
43628
|
+
const locale = this.getters.getLocale();
|
|
43629
|
+
const content = formatValue(origin.evaluatedCell.value, { locale });
|
|
43630
|
+
this.dispatch("UPDATE_CELL", { ...target, content });
|
|
43631
|
+
return;
|
|
43593
43632
|
}
|
|
43594
|
-
|
|
43595
|
-
|
|
43596
|
-
|
|
43597
|
-
|
|
43598
|
-
|
|
43599
|
-
|
|
43600
|
-
|
|
43601
|
-
|
|
43602
|
-
|
|
43603
|
-
|
|
43604
|
-
|
|
43605
|
-
|
|
43606
|
-
|
|
43607
|
-
|
|
43608
|
-
}
|
|
43609
|
-
|
|
43610
|
-
|
|
43611
|
-
|
|
43612
|
-
|
|
43633
|
+
const targetBorders = this.getters.getCellBorder(target);
|
|
43634
|
+
const originBorders = origin.border;
|
|
43635
|
+
const border = {
|
|
43636
|
+
top: targetBorders?.top || originBorders?.top,
|
|
43637
|
+
bottom: targetBorders?.bottom || originBorders?.bottom,
|
|
43638
|
+
left: targetBorders?.left || originBorders?.left,
|
|
43639
|
+
right: targetBorders?.right || originBorders?.right,
|
|
43640
|
+
};
|
|
43641
|
+
this.dispatch("SET_BORDER", { sheetId, col, row, border });
|
|
43642
|
+
if (clipboardOption?.pasteOption === "onlyFormat") {
|
|
43643
|
+
this.dispatch("UPDATE_CELL", {
|
|
43644
|
+
...target,
|
|
43645
|
+
style: origin.cell?.style ?? null,
|
|
43646
|
+
format: origin.cell?.format ?? origin.evaluatedCell.format ?? targetCell.format,
|
|
43647
|
+
});
|
|
43648
|
+
return;
|
|
43649
|
+
}
|
|
43650
|
+
const content = origin.cell && origin.cell.isFormula && operation === "COPY"
|
|
43651
|
+
? this.getters.getTranslatedCellFormula(sheetId, col - origin.position.col, row - origin.position.row, origin.cell.compiledFormula)
|
|
43652
|
+
: origin.cell?.content;
|
|
43653
|
+
if (content !== "" || origin.cell?.format || origin.cell?.style) {
|
|
43613
43654
|
this.dispatch("UPDATE_CELL", {
|
|
43614
43655
|
...target,
|
|
43615
43656
|
content,
|
|
43616
|
-
style: origin.cell
|
|
43617
|
-
format: origin.cell
|
|
43657
|
+
style: origin.cell?.style || null,
|
|
43658
|
+
format: origin.cell?.format,
|
|
43618
43659
|
});
|
|
43619
43660
|
}
|
|
43620
43661
|
else if (targetCell) {
|
|
43621
|
-
|
|
43622
|
-
this.dispatch("UPDATE_CELL", { ...target, content: "" });
|
|
43623
|
-
}
|
|
43624
|
-
else if (clipboardOption?.pasteOption === "onlyFormat") {
|
|
43625
|
-
this.dispatch("UPDATE_CELL", { ...target, style: null, format: "" });
|
|
43626
|
-
}
|
|
43627
|
-
else {
|
|
43628
|
-
this.dispatch("CLEAR_CELL", target);
|
|
43629
|
-
}
|
|
43662
|
+
this.dispatch("CLEAR_CELL", target);
|
|
43630
43663
|
}
|
|
43631
43664
|
}
|
|
43632
43665
|
/**
|
|
@@ -43688,22 +43721,28 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
43688
43721
|
return (this.cells
|
|
43689
43722
|
.map((cells) => {
|
|
43690
43723
|
return cells
|
|
43691
|
-
.map((c) => this.getters.shouldShowFormulas() && c
|
|
43724
|
+
.map((c) => this.getters.shouldShowFormulas() && c?.cell?.isFormula
|
|
43692
43725
|
? c.cell?.content || ""
|
|
43693
|
-
: c
|
|
43726
|
+
: c?.evaluatedCell?.formattedValue || "")
|
|
43694
43727
|
.join("\t");
|
|
43695
43728
|
})
|
|
43696
43729
|
.join("\n") || "\t");
|
|
43697
43730
|
}
|
|
43698
43731
|
getHTMLContent() {
|
|
43699
43732
|
if (this.cells.length === 1 && this.cells[0].length === 1) {
|
|
43733
|
+
if (!this.cells[0][0]) {
|
|
43734
|
+
return "";
|
|
43735
|
+
}
|
|
43700
43736
|
return this.getters.getCellText(this.cells[0][0].position);
|
|
43701
43737
|
}
|
|
43702
43738
|
let htmlTable = '<table border="1" style="border-collapse:collapse">';
|
|
43703
43739
|
for (const row of this.cells) {
|
|
43704
43740
|
htmlTable += "<tr>";
|
|
43705
43741
|
for (const cell of row) {
|
|
43706
|
-
|
|
43742
|
+
if (!cell) {
|
|
43743
|
+
continue;
|
|
43744
|
+
}
|
|
43745
|
+
const cssStyle = cssPropertiesToCss(cellStyleToCss(this.getters.getCellComputedStyle(cell.position)));
|
|
43707
43746
|
const cellText = this.getters.getCellText(cell.position);
|
|
43708
43747
|
htmlTable += `<td style="${cssStyle}">` + xmlEscape(cellText) + "</td>";
|
|
43709
43748
|
}
|
|
@@ -45538,6 +45577,9 @@ class SelectionInputsManagerPlugin extends UIPlugin {
|
|
|
45538
45577
|
// Other
|
|
45539
45578
|
// ---------------------------------------------------------------------------
|
|
45540
45579
|
initInput(id, initialRanges, inputHasSingleRange = false) {
|
|
45580
|
+
if (this.inputs[id]) {
|
|
45581
|
+
this.unfocus();
|
|
45582
|
+
}
|
|
45541
45583
|
this.inputs[id] = new SelectionInputPlugin(this.config, initialRanges, inputHasSingleRange);
|
|
45542
45584
|
if (initialRanges.length === 0) {
|
|
45543
45585
|
const input = this.inputs[id];
|
|
@@ -46336,7 +46378,7 @@ class HistoryPlugin extends UIPlugin {
|
|
|
46336
46378
|
* Ignore standard undo/redo revisions (that are empty)
|
|
46337
46379
|
*/
|
|
46338
46380
|
getPossibleRevisionToRepeat() {
|
|
46339
|
-
return this.session.getLastLocalNonEmptyRevision(
|
|
46381
|
+
return this.session.getLastLocalNonEmptyRevision();
|
|
46340
46382
|
}
|
|
46341
46383
|
}
|
|
46342
46384
|
|
|
@@ -46833,11 +46875,14 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
46833
46875
|
}
|
|
46834
46876
|
const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
|
|
46835
46877
|
this.state.paste(cmd.target, { pasteOption, shouldPasteCF: true, selectTarget: true });
|
|
46878
|
+
if (this.state.operation === "CUT") {
|
|
46879
|
+
this.state = undefined;
|
|
46880
|
+
}
|
|
46836
46881
|
this.lastPasteState = this.state;
|
|
46837
46882
|
if (this.paintFormatStatus === "oneOff") {
|
|
46838
46883
|
this.paintFormatStatus = "inactive";
|
|
46839
|
-
this.status = "invisible";
|
|
46840
46884
|
}
|
|
46885
|
+
this.status = "invisible";
|
|
46841
46886
|
break;
|
|
46842
46887
|
case "COPY_PASTE_CELLS_ABOVE":
|
|
46843
46888
|
{
|
|
@@ -47118,6 +47163,10 @@ function setXcToReferenceType(xc, referenceType) {
|
|
|
47118
47163
|
return xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
47119
47164
|
case "colrow":
|
|
47120
47165
|
indexOfNumber = xc.search(/[0-9]/);
|
|
47166
|
+
if (indexOfNumber === -1 || indexOfNumber === 0) {
|
|
47167
|
+
// no row number (eg. A) or no column (eg. 1)
|
|
47168
|
+
return "$" + xc;
|
|
47169
|
+
}
|
|
47121
47170
|
xc = xc.slice(0, indexOfNumber) + "$" + xc.slice(indexOfNumber);
|
|
47122
47171
|
return "$" + xc;
|
|
47123
47172
|
case "none":
|
|
@@ -47888,6 +47937,12 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
47888
47937
|
break;
|
|
47889
47938
|
case "HIDE_COLUMNS_ROWS":
|
|
47890
47939
|
case "UNHIDE_COLUMNS_ROWS":
|
|
47940
|
+
case "GROUP_HEADERS":
|
|
47941
|
+
case "UNGROUP_HEADERS":
|
|
47942
|
+
case "FOLD_HEADER_GROUP":
|
|
47943
|
+
case "UNFOLD_HEADER_GROUP":
|
|
47944
|
+
case "FOLD_ALL_HEADER_GROUPS":
|
|
47945
|
+
case "UNFOLD_ALL_HEADER_GROUPS":
|
|
47891
47946
|
this.updateHiddenRows();
|
|
47892
47947
|
break;
|
|
47893
47948
|
case "UPDATE_FILTER":
|
|
@@ -48589,7 +48644,7 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
48589
48644
|
sheetId: cmd.sheetId,
|
|
48590
48645
|
base: cmd.base,
|
|
48591
48646
|
quantity: thickness,
|
|
48592
|
-
position:
|
|
48647
|
+
position: cmd.position,
|
|
48593
48648
|
});
|
|
48594
48649
|
const isCol = cmd.dimension === "COL";
|
|
48595
48650
|
const start = cmd.elements[0];
|
|
@@ -48606,12 +48661,13 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
48606
48661
|
},
|
|
48607
48662
|
];
|
|
48608
48663
|
const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
|
|
48664
|
+
const base = isBasedBefore ? cmd.base : cmd.base + 1;
|
|
48609
48665
|
const pasteTarget = [
|
|
48610
48666
|
{
|
|
48611
|
-
left: isCol ?
|
|
48612
|
-
right: isCol ?
|
|
48613
|
-
top: !isCol ?
|
|
48614
|
-
bottom: !isCol ?
|
|
48667
|
+
left: isCol ? base : 0,
|
|
48668
|
+
right: isCol ? base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
|
|
48669
|
+
top: !isCol ? base : 0,
|
|
48670
|
+
bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
|
|
48615
48671
|
},
|
|
48616
48672
|
];
|
|
48617
48673
|
state.paste(pasteTarget, { selectTarget: true });
|
|
@@ -48646,6 +48702,11 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
48646
48702
|
doesElementsHaveCommonMerges(id, cmd.base - 1, cmd.base)) {
|
|
48647
48703
|
return "WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */;
|
|
48648
48704
|
}
|
|
48705
|
+
const headers = [cmd.base, ...cmd.elements];
|
|
48706
|
+
const maxHeaderValue = isCol ? this.getters.getNumberCols(id) : this.getters.getNumberRows(id);
|
|
48707
|
+
if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
|
|
48708
|
+
return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
|
|
48709
|
+
}
|
|
48649
48710
|
return "Success" /* CommandResult.Success */;
|
|
48650
48711
|
}
|
|
48651
48712
|
//-------------------------------------------
|
|
@@ -49691,10 +49752,13 @@ class HeaderPositionsUIPlugin extends UIPlugin {
|
|
|
49691
49752
|
}
|
|
49692
49753
|
break;
|
|
49693
49754
|
case "UPDATE_CELL":
|
|
49694
|
-
if ("content" in cmd || "format" in cmd
|
|
49755
|
+
if ("content" in cmd || "format" in cmd) {
|
|
49695
49756
|
this.headerPositions = {};
|
|
49696
49757
|
this.isDirty = true;
|
|
49697
49758
|
}
|
|
49759
|
+
else {
|
|
49760
|
+
this.headerPositions[cmd.sheetId] = this.computeHeaderPositionsOfSheet(cmd.sheetId);
|
|
49761
|
+
}
|
|
49698
49762
|
break;
|
|
49699
49763
|
case "UPDATE_FILTER":
|
|
49700
49764
|
case "REMOVE_FILTER_TABLE":
|
|
@@ -51851,6 +51915,8 @@ css /* scss */ `
|
|
|
51851
51915
|
*:before,
|
|
51852
51916
|
*:after {
|
|
51853
51917
|
box-sizing: content-box;
|
|
51918
|
+
/** rtl not supported ATM */
|
|
51919
|
+
direction: ltr;
|
|
51854
51920
|
}
|
|
51855
51921
|
.o-separator {
|
|
51856
51922
|
border-bottom: ${MENU_SEPARATOR_BORDER_WIDTH}px solid ${SEPARATOR_COLOR};
|
|
@@ -55561,19 +55627,22 @@ class Model extends EventBus {
|
|
|
55561
55627
|
* Check if the given command is allowed by all the plugins and the history.
|
|
55562
55628
|
*/
|
|
55563
55629
|
checkDispatchAllowed(command) {
|
|
55564
|
-
|
|
55565
|
-
|
|
55630
|
+
const results = isCoreCommand(command)
|
|
55631
|
+
? this.checkDispatchAllowedCoreCommand(command)
|
|
55632
|
+
: this.checkDispatchAllowedLocalCommand(command);
|
|
55633
|
+
if (results.some((r) => r !== "Success" /* CommandResult.Success */)) {
|
|
55634
|
+
return new DispatchResult(results.flat());
|
|
55566
55635
|
}
|
|
55567
|
-
return
|
|
55636
|
+
return DispatchResult.Success;
|
|
55568
55637
|
}
|
|
55569
55638
|
checkDispatchAllowedCoreCommand(command) {
|
|
55570
55639
|
const results = this.corePlugins.map((handler) => handler.allowDispatch(command));
|
|
55571
55640
|
results.push(this.range.allowDispatch(command));
|
|
55572
|
-
return
|
|
55641
|
+
return results;
|
|
55573
55642
|
}
|
|
55574
55643
|
checkDispatchAllowedLocalCommand(command) {
|
|
55575
55644
|
const results = this.uiHandlers.map((handler) => handler.allowDispatch(command));
|
|
55576
|
-
return
|
|
55645
|
+
return results;
|
|
55577
55646
|
}
|
|
55578
55647
|
finalize() {
|
|
55579
55648
|
this.status = 3 /* Status.Finalizing */;
|
|
@@ -55920,6 +55989,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
55920
55989
|
exports.tokenize = tokenize;
|
|
55921
55990
|
|
|
55922
55991
|
|
|
55923
|
-
__info__.version = "17.0.
|
|
55924
|
-
__info__.date = "2023-
|
|
55925
|
-
__info__.hash = "
|
|
55992
|
+
__info__.version = "17.0.5";
|
|
55993
|
+
__info__.date = "2023-12-05T09:51:44.657Z";
|
|
55994
|
+
__info__.hash = "2480a5d";
|