@odoo/o-spreadsheet 16.4.20 → 16.4.23
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 +270 -175
- package/dist/o-spreadsheet.d.ts +31 -16
- package/dist/o-spreadsheet.esm.js +270 -175
- package/dist/o-spreadsheet.iife.js +270 -175
- package/dist/o-spreadsheet.iife.min.js +103 -110
- package/dist/o_spreadsheet.xml +15 -33
- package/package.json +1 -1
|
@@ -701,18 +701,18 @@ function isConsecutive(iterable) {
|
|
|
701
701
|
return true;
|
|
702
702
|
}
|
|
703
703
|
class JetSet extends Set {
|
|
704
|
-
|
|
704
|
+
addMany(iterable) {
|
|
705
705
|
for (const element of iterable) {
|
|
706
706
|
super.add(element);
|
|
707
707
|
}
|
|
708
708
|
return this;
|
|
709
709
|
}
|
|
710
|
-
|
|
711
|
-
let
|
|
710
|
+
deleteMany(iterable) {
|
|
711
|
+
let wasDeleted = false;
|
|
712
712
|
for (const element of iterable) {
|
|
713
|
-
|
|
713
|
+
wasDeleted ||= super.delete(element);
|
|
714
714
|
}
|
|
715
|
-
return
|
|
715
|
+
return wasDeleted;
|
|
716
716
|
}
|
|
717
717
|
}
|
|
718
718
|
/**
|
|
@@ -1838,6 +1838,9 @@ function parseFormat(formatString) {
|
|
|
1838
1838
|
function formatValue(value, { format, locale }) {
|
|
1839
1839
|
switch (typeof value) {
|
|
1840
1840
|
case "string":
|
|
1841
|
+
if (value.includes('\\"')) {
|
|
1842
|
+
return value.replace(/\\"/g, '"');
|
|
1843
|
+
}
|
|
1841
1844
|
return value;
|
|
1842
1845
|
case "boolean":
|
|
1843
1846
|
return value ? "TRUE" : "FALSE";
|
|
@@ -15235,6 +15238,9 @@ function isValidLocale(locale) {
|
|
|
15235
15238
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
15236
15239
|
return false;
|
|
15237
15240
|
}
|
|
15241
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
15242
|
+
return false;
|
|
15243
|
+
}
|
|
15238
15244
|
try {
|
|
15239
15245
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
15240
15246
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -15325,7 +15331,7 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
15325
15331
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
15326
15332
|
return content;
|
|
15327
15333
|
}
|
|
15328
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
15334
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
15329
15335
|
}
|
|
15330
15336
|
/**
|
|
15331
15337
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -15971,14 +15977,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
15971
15977
|
: undefined));
|
|
15972
15978
|
}
|
|
15973
15979
|
}
|
|
15974
|
-
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
15975
|
-
// A single cell. If it's only the title, the dataset is not added.
|
|
15976
|
-
if (!dataSetsHaveTitle) {
|
|
15977
|
-
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
15978
|
-
}
|
|
15979
|
-
}
|
|
15980
15980
|
else {
|
|
15981
|
-
/* 1 row or 1 column */
|
|
15981
|
+
/* 1 cell, 1 row or 1 column */
|
|
15982
15982
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
15983
15983
|
? {
|
|
15984
15984
|
top: zone.top,
|
|
@@ -16027,8 +16027,10 @@ function toExcelDataset(getters, ds) {
|
|
|
16027
16027
|
}
|
|
16028
16028
|
const dataRange = ds.dataRange.clone({ zone: dataZone });
|
|
16029
16029
|
return {
|
|
16030
|
-
label: ds.labelCell
|
|
16031
|
-
|
|
16030
|
+
label: ds.labelCell
|
|
16031
|
+
? getters.getRangeString(ds.labelCell, "forceSheetReference", true)
|
|
16032
|
+
: undefined,
|
|
16033
|
+
range: getters.getRangeString(dataRange, "forceSheetReference", true),
|
|
16032
16034
|
};
|
|
16033
16035
|
}
|
|
16034
16036
|
function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
@@ -16041,7 +16043,7 @@ function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
|
16041
16043
|
zone.top = zone.top + 1;
|
|
16042
16044
|
}
|
|
16043
16045
|
const range = labelRange.clone({ zone });
|
|
16044
|
-
return getters.getRangeString(range, "forceSheetReference");
|
|
16046
|
+
return getters.getRangeString(range, "forceSheetReference", true);
|
|
16045
16047
|
}
|
|
16046
16048
|
/**
|
|
16047
16049
|
* Transform a chart definition which supports dataSets (dataSets and LabelRange)
|
|
@@ -16578,7 +16580,7 @@ class BarChart extends AbstractChart {
|
|
|
16578
16580
|
return undefined;
|
|
16579
16581
|
const dataSets = this.dataSets
|
|
16580
16582
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
16581
|
-
.filter((ds) => ds.range !== ""
|
|
16583
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
16582
16584
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
16583
16585
|
return {
|
|
16584
16586
|
...this.getDefinition(),
|
|
@@ -17166,7 +17168,7 @@ class LineChart extends AbstractChart {
|
|
|
17166
17168
|
return undefined;
|
|
17167
17169
|
const dataSets = this.dataSets
|
|
17168
17170
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
17169
|
-
.filter((ds) => ds.range !== ""
|
|
17171
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
17170
17172
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
17171
17173
|
return {
|
|
17172
17174
|
...this.getDefinition(),
|
|
@@ -17453,7 +17455,7 @@ class PieChart extends AbstractChart {
|
|
|
17453
17455
|
return undefined;
|
|
17454
17456
|
const dataSets = this.dataSets
|
|
17455
17457
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
17456
|
-
.filter((ds) => ds.range !== ""
|
|
17458
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
17457
17459
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
17458
17460
|
return {
|
|
17459
17461
|
...this.getDefinition(),
|
|
@@ -18631,6 +18633,12 @@ const INSERT_LINK = (env) => {
|
|
|
18631
18633
|
let { col, row } = env.model.getters.getActivePosition();
|
|
18632
18634
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
18633
18635
|
};
|
|
18636
|
+
const INSERT_LINK_NAME = (env) => {
|
|
18637
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
18638
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
18639
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
18640
|
+
return cell && cell.link ? _lt("Edit link") : _lt("Insert link");
|
|
18641
|
+
};
|
|
18634
18642
|
//------------------------------------------------------------------------------
|
|
18635
18643
|
// Filters action
|
|
18636
18644
|
//------------------------------------------------------------------------------
|
|
@@ -19171,7 +19179,7 @@ cellMenuRegistry
|
|
|
19171
19179
|
})
|
|
19172
19180
|
.add("insert_link", {
|
|
19173
19181
|
...insertLink,
|
|
19174
|
-
name:
|
|
19182
|
+
name: INSERT_LINK_NAME,
|
|
19175
19183
|
sequence: 150,
|
|
19176
19184
|
separator: true,
|
|
19177
19185
|
});
|
|
@@ -24082,6 +24090,7 @@ class Composer extends Component {
|
|
|
24082
24090
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
24083
24091
|
static defaultProps = {
|
|
24084
24092
|
inputStyle: "",
|
|
24093
|
+
isDefaultFocus: false,
|
|
24085
24094
|
};
|
|
24086
24095
|
composerRef = useRef("o_composer");
|
|
24087
24096
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -24134,7 +24143,6 @@ class Composer extends Component {
|
|
|
24134
24143
|
F2: () => console.warn("Not implemented"),
|
|
24135
24144
|
F4: this.processF4Key,
|
|
24136
24145
|
Tab: (ev) => this.processTabKey(ev),
|
|
24137
|
-
" ": (ev) => this.processSpaceKey(ev),
|
|
24138
24146
|
};
|
|
24139
24147
|
keyCodeMapping = {
|
|
24140
24148
|
NumpadDecimal: this.processNumpadDecimal,
|
|
@@ -24142,11 +24150,11 @@ class Composer extends Component {
|
|
|
24142
24150
|
setup() {
|
|
24143
24151
|
onMounted(() => {
|
|
24144
24152
|
const el = this.composerRef.el;
|
|
24153
|
+
if (this.props.isDefaultFocus) {
|
|
24154
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
24155
|
+
}
|
|
24145
24156
|
this.contentHelper.updateEl(el);
|
|
24146
24157
|
});
|
|
24147
|
-
onWillUnmount(() => {
|
|
24148
|
-
this.props.onComposerUnmounted?.();
|
|
24149
|
-
});
|
|
24150
24158
|
useEffect(() => {
|
|
24151
24159
|
this.processContent();
|
|
24152
24160
|
});
|
|
@@ -24155,7 +24163,8 @@ class Composer extends Component {
|
|
|
24155
24163
|
// Handlers
|
|
24156
24164
|
// ---------------------------------------------------------------------------
|
|
24157
24165
|
processArrowKeys(ev) {
|
|
24158
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
24166
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
24167
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
24159
24168
|
this.functionDescriptionState.showDescription = false;
|
|
24160
24169
|
// Prevent the default content editable behavior which moves the cursor
|
|
24161
24170
|
ev.preventDefault();
|
|
@@ -24194,25 +24203,19 @@ class Composer extends Component {
|
|
|
24194
24203
|
processTabKey(ev) {
|
|
24195
24204
|
ev.preventDefault();
|
|
24196
24205
|
ev.stopPropagation();
|
|
24197
|
-
if (this.
|
|
24198
|
-
|
|
24199
|
-
|
|
24200
|
-
|
|
24201
|
-
|
|
24206
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
24207
|
+
if (this.autoCompleteState.showProvider) {
|
|
24208
|
+
const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
|
|
24209
|
+
if (autoCompleteValue) {
|
|
24210
|
+
this.autoComplete(autoCompleteValue);
|
|
24211
|
+
return;
|
|
24212
|
+
}
|
|
24202
24213
|
}
|
|
24214
|
+
this.env.model.dispatch("STOP_EDITION");
|
|
24203
24215
|
}
|
|
24204
24216
|
const direction = ev.shiftKey ? "left" : "right";
|
|
24205
|
-
this.env.model.dispatch("STOP_EDITION");
|
|
24206
24217
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
24207
24218
|
}
|
|
24208
|
-
processSpaceKey(ev) {
|
|
24209
|
-
if (ev.ctrlKey) {
|
|
24210
|
-
ev.preventDefault();
|
|
24211
|
-
ev.stopPropagation();
|
|
24212
|
-
this.showAutocomplete("");
|
|
24213
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
24214
|
-
}
|
|
24215
|
-
}
|
|
24216
24219
|
processEnterKey(ev) {
|
|
24217
24220
|
ev.preventDefault();
|
|
24218
24221
|
ev.stopPropagation();
|
|
@@ -24264,6 +24267,9 @@ class Composer extends Component {
|
|
|
24264
24267
|
this.compositionActive = false;
|
|
24265
24268
|
}
|
|
24266
24269
|
onKeydown(ev) {
|
|
24270
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
24271
|
+
return;
|
|
24272
|
+
}
|
|
24267
24273
|
let handler = this.keyMapping[ev.key] || this.keyCodeMapping[ev.code];
|
|
24268
24274
|
if (handler) {
|
|
24269
24275
|
handler.call(this, ev);
|
|
@@ -24272,14 +24278,33 @@ class Composer extends Component {
|
|
|
24272
24278
|
ev.stopPropagation();
|
|
24273
24279
|
}
|
|
24274
24280
|
}
|
|
24281
|
+
onPaste(ev) {
|
|
24282
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
24283
|
+
ev.stopPropagation();
|
|
24284
|
+
}
|
|
24285
|
+
}
|
|
24275
24286
|
/*
|
|
24276
24287
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
24277
24288
|
* */
|
|
24278
24289
|
onInput(ev) {
|
|
24279
|
-
if (
|
|
24290
|
+
if (!this.shouldProcessInputEvents) {
|
|
24291
|
+
return;
|
|
24292
|
+
}
|
|
24293
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
24294
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
24280
24295
|
return;
|
|
24281
24296
|
}
|
|
24282
|
-
|
|
24297
|
+
ev.stopPropagation();
|
|
24298
|
+
let content;
|
|
24299
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
24300
|
+
content = ev.data || "";
|
|
24301
|
+
}
|
|
24302
|
+
else {
|
|
24303
|
+
content = this.contentHelper.getText();
|
|
24304
|
+
}
|
|
24305
|
+
if (this.props.focus === "inactive") {
|
|
24306
|
+
return this.props.onComposerCellFocused?.(content);
|
|
24307
|
+
}
|
|
24283
24308
|
let selection = this.contentHelper.getCurrentSelection();
|
|
24284
24309
|
if (ev.inputType === "insertParagraph") {
|
|
24285
24310
|
const start = Math.min(selection.start, selection.end);
|
|
@@ -24357,9 +24382,8 @@ class Composer extends Component {
|
|
|
24357
24382
|
}
|
|
24358
24383
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
24359
24384
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
24360
|
-
|
|
24361
|
-
|
|
24362
|
-
}
|
|
24385
|
+
this.props.onComposerContentFocused();
|
|
24386
|
+
if (this.props.focus === "inactive") ;
|
|
24363
24387
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
24364
24388
|
this.processTokenAtCursor();
|
|
24365
24389
|
}
|
|
@@ -24526,7 +24550,7 @@ class Composer extends Component {
|
|
|
24526
24550
|
const highlights = this.env.model.getters.getHighlights();
|
|
24527
24551
|
const refSheet = sheetName
|
|
24528
24552
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
24529
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
24553
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
24530
24554
|
const highlight = highlights.find((highlight) => {
|
|
24531
24555
|
if (highlight.sheetId !== refSheet)
|
|
24532
24556
|
return false;
|
|
@@ -24606,12 +24630,13 @@ class Composer extends Component {
|
|
|
24606
24630
|
}
|
|
24607
24631
|
}
|
|
24608
24632
|
Composer.props = {
|
|
24609
|
-
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
24610
|
-
onComposerContentFocused: Function,
|
|
24611
24633
|
inputStyle: { type: String, optional: true },
|
|
24612
24634
|
rect: { type: Object, optional: true },
|
|
24613
24635
|
delimitation: { type: Object, optional: true },
|
|
24614
|
-
|
|
24636
|
+
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
24637
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
24638
|
+
onComposerContentFocused: Function,
|
|
24639
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
24615
24640
|
};
|
|
24616
24641
|
|
|
24617
24642
|
const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
|
|
@@ -24645,51 +24670,26 @@ css /* scss */ `
|
|
|
24645
24670
|
class GridComposer extends Component {
|
|
24646
24671
|
static template = "o-spreadsheet-GridComposer";
|
|
24647
24672
|
static components = { Composer };
|
|
24648
|
-
|
|
24649
|
-
|
|
24650
|
-
|
|
24673
|
+
// TODORAR see if we can keep it undefined
|
|
24674
|
+
rect = this.defaultRect;
|
|
24675
|
+
isEditing = false;
|
|
24651
24676
|
isCellReferenceVisible;
|
|
24652
|
-
|
|
24677
|
+
get defaultRect() {
|
|
24678
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
24679
|
+
}
|
|
24653
24680
|
setup() {
|
|
24654
|
-
this.gridComposerRef = useRef("gridComposer");
|
|
24655
|
-
this.composerState = useState({
|
|
24656
|
-
rect: undefined,
|
|
24657
|
-
delimitation: undefined,
|
|
24658
|
-
});
|
|
24659
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
24660
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
24661
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
24662
|
-
this.isCellReferenceVisible = false;
|
|
24663
|
-
onMounted(() => {
|
|
24664
|
-
const el = this.gridComposerRef.el;
|
|
24665
|
-
this.composerState.rect = {
|
|
24666
|
-
x: this.rect.x,
|
|
24667
|
-
y: this.rect.y,
|
|
24668
|
-
width: el.clientWidth,
|
|
24669
|
-
height: el.clientHeight,
|
|
24670
|
-
};
|
|
24671
|
-
this.composerState.delimitation = {
|
|
24672
|
-
width: this.props.gridDims.width,
|
|
24673
|
-
height: this.props.gridDims.height,
|
|
24674
|
-
};
|
|
24675
|
-
});
|
|
24676
24681
|
onWillUpdateProps(() => {
|
|
24677
|
-
|
|
24678
|
-
|
|
24679
|
-
}
|
|
24680
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
24681
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
24682
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
24683
|
-
if (!deepEquals(rect, this.rect) ||
|
|
24684
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
24685
|
-
this.isCellReferenceVisible = true;
|
|
24686
|
-
}
|
|
24682
|
+
this.updateComponentPosition();
|
|
24683
|
+
this.updateCellReferenceVisibility();
|
|
24687
24684
|
});
|
|
24688
24685
|
}
|
|
24689
24686
|
get shouldDisplayCellReference() {
|
|
24690
24687
|
return this.isCellReferenceVisible;
|
|
24691
24688
|
}
|
|
24692
24689
|
get cellReference() {
|
|
24690
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
24691
|
+
return "";
|
|
24692
|
+
}
|
|
24693
24693
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
24694
24694
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
24695
24695
|
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
@@ -24701,7 +24701,27 @@ class GridComposer extends Component {
|
|
|
24701
24701
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
24702
24702
|
});
|
|
24703
24703
|
}
|
|
24704
|
+
get composerProps() {
|
|
24705
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
24706
|
+
return {
|
|
24707
|
+
rect: { ...this.rect },
|
|
24708
|
+
delimitation: {
|
|
24709
|
+
width,
|
|
24710
|
+
height,
|
|
24711
|
+
},
|
|
24712
|
+
focus: this.props.focus,
|
|
24713
|
+
isDefaultFocus: true,
|
|
24714
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
24715
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
24716
|
+
};
|
|
24717
|
+
}
|
|
24704
24718
|
get containerStyle() {
|
|
24719
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
24720
|
+
return `
|
|
24721
|
+
position: absolute;
|
|
24722
|
+
z-index: -1000;
|
|
24723
|
+
`;
|
|
24724
|
+
}
|
|
24705
24725
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
24706
24726
|
const cell = this.env.model.getters.getActiveCell();
|
|
24707
24727
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -24721,6 +24741,8 @@ class GridComposer extends Component {
|
|
|
24721
24741
|
if (!isFormula) {
|
|
24722
24742
|
textAlign = style.align || cell.defaultAlign;
|
|
24723
24743
|
}
|
|
24744
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
24745
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
24724
24746
|
/**
|
|
24725
24747
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
24726
24748
|
* including all the paddings/margins of the composer
|
|
@@ -24732,6 +24754,8 @@ class GridComposer extends Component {
|
|
|
24732
24754
|
top: `${top}px`,
|
|
24733
24755
|
"min-width": `${width + 1}px`,
|
|
24734
24756
|
"min-height": `${height + 1}px`,
|
|
24757
|
+
"max-width": `${maxWidth}px`,
|
|
24758
|
+
"max-height": `${maxHeight}px`,
|
|
24735
24759
|
background,
|
|
24736
24760
|
color,
|
|
24737
24761
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -24741,20 +24765,38 @@ class GridComposer extends Component {
|
|
|
24741
24765
|
"text-align": textAlign,
|
|
24742
24766
|
});
|
|
24743
24767
|
}
|
|
24744
|
-
|
|
24745
|
-
const
|
|
24746
|
-
|
|
24747
|
-
|
|
24748
|
-
|
|
24749
|
-
|
|
24750
|
-
|
|
24768
|
+
updateComponentPosition() {
|
|
24769
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
24770
|
+
if (this.isEditing !== isEditing) {
|
|
24771
|
+
this.isEditing = isEditing;
|
|
24772
|
+
if (!isEditing) {
|
|
24773
|
+
this.rect = this.defaultRect;
|
|
24774
|
+
this.env.focusableElement.focus();
|
|
24775
|
+
return;
|
|
24776
|
+
}
|
|
24777
|
+
const position = this.env.model.getters.getActivePosition();
|
|
24778
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
24779
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
24780
|
+
}
|
|
24781
|
+
}
|
|
24782
|
+
updateCellReferenceVisibility() {
|
|
24783
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
24784
|
+
return;
|
|
24785
|
+
}
|
|
24786
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
24787
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
24788
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
24789
|
+
if (!deepEquals(rect, this.rect) ||
|
|
24790
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
24791
|
+
this.isCellReferenceVisible = true;
|
|
24792
|
+
}
|
|
24751
24793
|
}
|
|
24752
24794
|
}
|
|
24753
24795
|
GridComposer.props = {
|
|
24754
24796
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
24755
|
-
onComposerUnmounted: Function,
|
|
24756
24797
|
onComposerContentFocused: Function,
|
|
24757
24798
|
gridDims: Object,
|
|
24799
|
+
onComposerCellFocused: Function,
|
|
24758
24800
|
};
|
|
24759
24801
|
|
|
24760
24802
|
const CSS$1 = css /* scss */ `
|
|
@@ -25635,7 +25677,6 @@ class GridOverlay extends Component {
|
|
|
25635
25677
|
this.props.onCellDoubleClicked(col, row);
|
|
25636
25678
|
}
|
|
25637
25679
|
onContextMenu(ev) {
|
|
25638
|
-
ev.preventDefault();
|
|
25639
25680
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
25640
25681
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
25641
25682
|
}
|
|
@@ -26728,7 +26769,6 @@ class Grid extends Component {
|
|
|
26728
26769
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
26729
26770
|
menuState;
|
|
26730
26771
|
gridRef;
|
|
26731
|
-
hiddenInput;
|
|
26732
26772
|
onMouseWheel;
|
|
26733
26773
|
canvasPosition;
|
|
26734
26774
|
hoveredCell;
|
|
@@ -26739,17 +26779,16 @@ class Grid extends Component {
|
|
|
26739
26779
|
menuItems: [],
|
|
26740
26780
|
});
|
|
26741
26781
|
this.gridRef = useRef("grid");
|
|
26742
|
-
this.hiddenInput = useRef("hiddenInput");
|
|
26743
26782
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
26744
26783
|
this.hoveredCell = useState({ col: undefined, row: undefined });
|
|
26745
26784
|
useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
26746
26785
|
useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
26747
26786
|
useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
26748
26787
|
useExternalListener(document.body, "paste", this.paste);
|
|
26749
|
-
onMounted(() => this.
|
|
26750
|
-
this.props.exposeFocus(() => this.
|
|
26788
|
+
onMounted(() => this.focusDefaultElement());
|
|
26789
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
26751
26790
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
26752
|
-
useEffect(() => this.
|
|
26791
|
+
useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
26753
26792
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
26754
26793
|
this.moveCanvas(deltaX, deltaY);
|
|
26755
26794
|
this.hoveredCell.col = undefined;
|
|
@@ -26772,7 +26811,7 @@ class Grid extends Component {
|
|
|
26772
26811
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
26773
26812
|
this.closeOpenedPopover();
|
|
26774
26813
|
}
|
|
26775
|
-
this.
|
|
26814
|
+
this.focusDefaultElement();
|
|
26776
26815
|
}
|
|
26777
26816
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
26778
26817
|
// down itself
|
|
@@ -26945,10 +26984,10 @@ class Grid extends Component {
|
|
|
26945
26984
|
PAGEUP: () => this.env.model.dispatch("SHIFT_VIEWPORT_UP"),
|
|
26946
26985
|
"CTRL+K": () => INSERT_LINK(this.env),
|
|
26947
26986
|
};
|
|
26948
|
-
|
|
26987
|
+
focusDefaultElement() {
|
|
26949
26988
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
26950
26989
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26951
|
-
this.
|
|
26990
|
+
this.env.focusableElement.focus();
|
|
26952
26991
|
}
|
|
26953
26992
|
}
|
|
26954
26993
|
get gridEl() {
|
|
@@ -27092,19 +27131,6 @@ class Grid extends Component {
|
|
|
27092
27131
|
return;
|
|
27093
27132
|
}
|
|
27094
27133
|
}
|
|
27095
|
-
onInput(ev) {
|
|
27096
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
27097
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
27098
|
-
return;
|
|
27099
|
-
}
|
|
27100
|
-
if (ev.data) {
|
|
27101
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
27102
|
-
// character
|
|
27103
|
-
ev.preventDefault();
|
|
27104
|
-
ev.stopPropagation();
|
|
27105
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
27106
|
-
}
|
|
27107
|
-
}
|
|
27108
27134
|
// ---------------------------------------------------------------------------
|
|
27109
27135
|
// Context Menu
|
|
27110
27136
|
// ---------------------------------------------------------------------------
|
|
@@ -27217,7 +27243,7 @@ class Grid extends Component {
|
|
|
27217
27243
|
}
|
|
27218
27244
|
closeMenu() {
|
|
27219
27245
|
this.menuState.isOpen = false;
|
|
27220
|
-
this.
|
|
27246
|
+
this.focusDefaultElement();
|
|
27221
27247
|
}
|
|
27222
27248
|
}
|
|
27223
27249
|
Grid.props = {
|
|
@@ -30877,6 +30903,31 @@ const MIGRATIONS = [
|
|
|
30877
30903
|
return data;
|
|
30878
30904
|
},
|
|
30879
30905
|
},
|
|
30906
|
+
{
|
|
30907
|
+
description: "Fix datafilter duplication",
|
|
30908
|
+
from: 12,
|
|
30909
|
+
to: 12.5,
|
|
30910
|
+
applyMigration(data) {
|
|
30911
|
+
for (let sheet of data.sheets || []) {
|
|
30912
|
+
let knownDataFilterZones = [];
|
|
30913
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
30914
|
+
const zone = toZone(filterTable.range);
|
|
30915
|
+
// See commit message for the details
|
|
30916
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
30917
|
+
if (intersectZoneIndex !== -1) {
|
|
30918
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
30919
|
+
}
|
|
30920
|
+
else {
|
|
30921
|
+
knownDataFilterZones.push(zone);
|
|
30922
|
+
}
|
|
30923
|
+
}
|
|
30924
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
30925
|
+
range: zoneToXc(zone),
|
|
30926
|
+
}));
|
|
30927
|
+
}
|
|
30928
|
+
return data;
|
|
30929
|
+
},
|
|
30930
|
+
},
|
|
30880
30931
|
{
|
|
30881
30932
|
description: "Change Border description structure",
|
|
30882
30933
|
from: 12,
|
|
@@ -31796,9 +31847,9 @@ class CellPlugin extends CorePlugin {
|
|
|
31796
31847
|
allowDispatch(cmd) {
|
|
31797
31848
|
switch (cmd.type) {
|
|
31798
31849
|
case "UPDATE_CELL":
|
|
31799
|
-
return this.
|
|
31850
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
31800
31851
|
case "CLEAR_CELL":
|
|
31801
|
-
return this.checkValidations(cmd, this.
|
|
31852
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
31802
31853
|
default:
|
|
31803
31854
|
return 0 /* CommandResult.Success */;
|
|
31804
31855
|
}
|
|
@@ -31964,13 +32015,13 @@ class CellPlugin extends CorePlugin {
|
|
|
31964
32015
|
/*
|
|
31965
32016
|
* Reconstructs the original formula string based on a normalized form and its dependencies
|
|
31966
32017
|
*/
|
|
31967
|
-
buildFormulaContent(sheetId, cell, dependencies) {
|
|
32018
|
+
buildFormulaContent(sheetId, cell, dependencies, useFixedZone = false) {
|
|
31968
32019
|
const ranges = dependencies || cell.dependencies;
|
|
31969
32020
|
let rangeIndex = 0;
|
|
31970
32021
|
return concat(cell.compiledFormula.tokens.map((token) => {
|
|
31971
32022
|
if (token.type === "REFERENCE") {
|
|
31972
32023
|
const range = ranges[rangeIndex++];
|
|
31973
|
-
return this.getters.getRangeString(range, sheetId);
|
|
32024
|
+
return this.getters.getRangeString(range, sheetId, useFixedZone);
|
|
31974
32025
|
}
|
|
31975
32026
|
return token.value;
|
|
31976
32027
|
}));
|
|
@@ -32092,10 +32143,7 @@ class CellPlugin extends CorePlugin {
|
|
|
32092
32143
|
else {
|
|
32093
32144
|
style = before ? before.style : undefined;
|
|
32094
32145
|
}
|
|
32095
|
-
const
|
|
32096
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
32097
|
-
detectDateFormat(afterContent, locale) ||
|
|
32098
|
-
detectNumberFormat(afterContent);
|
|
32146
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
32099
32147
|
/* Read the following IF as:
|
|
32100
32148
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
32101
32149
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -32136,12 +32184,11 @@ class CellPlugin extends CorePlugin {
|
|
|
32136
32184
|
}
|
|
32137
32185
|
createLiteralCell(id, content, format, style) {
|
|
32138
32186
|
const locale = this.getters.getLocale();
|
|
32139
|
-
content = parseLiteral(content, locale).toString();
|
|
32140
32187
|
return {
|
|
32141
32188
|
id,
|
|
32142
|
-
content,
|
|
32189
|
+
content: parseLiteral(content, locale).toString(),
|
|
32143
32190
|
style,
|
|
32144
|
-
format,
|
|
32191
|
+
format: format || detectDateFormat(content, locale) || detectNumberFormat(content),
|
|
32145
32192
|
isFormula: false,
|
|
32146
32193
|
};
|
|
32147
32194
|
}
|
|
@@ -32202,6 +32249,18 @@ class CellPlugin extends CorePlugin {
|
|
|
32202
32249
|
}
|
|
32203
32250
|
return 0 /* CommandResult.Success */;
|
|
32204
32251
|
}
|
|
32252
|
+
checkUselessUpdateCell(cmd) {
|
|
32253
|
+
const cell = this.getters.getCell(cmd);
|
|
32254
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
32255
|
+
const hasStyle = "style" in cmd;
|
|
32256
|
+
const hasFormat = "format" in cmd;
|
|
32257
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
32258
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
32259
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
32260
|
+
return 98 /* CommandResult.NoChanges */;
|
|
32261
|
+
}
|
|
32262
|
+
return 0 /* CommandResult.Success */;
|
|
32263
|
+
}
|
|
32205
32264
|
}
|
|
32206
32265
|
class FormulaCellWithDependencies {
|
|
32207
32266
|
id;
|
|
@@ -32539,7 +32598,13 @@ class ConditionalFormatPlugin extends CorePlugin {
|
|
|
32539
32598
|
}
|
|
32540
32599
|
}
|
|
32541
32600
|
exportForExcel(data) {
|
|
32542
|
-
|
|
32601
|
+
if (data.sheets) {
|
|
32602
|
+
for (let sheet of data.sheets) {
|
|
32603
|
+
if (this.cfRules[sheet.id]) {
|
|
32604
|
+
sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useFixedReference: true }));
|
|
32605
|
+
}
|
|
32606
|
+
}
|
|
32607
|
+
}
|
|
32543
32608
|
}
|
|
32544
32609
|
// ---------------------------------------------------------------------------
|
|
32545
32610
|
// Getters
|
|
@@ -32604,11 +32669,11 @@ class ConditionalFormatPlugin extends CorePlugin {
|
|
|
32604
32669
|
// ---------------------------------------------------------------------------
|
|
32605
32670
|
// Private
|
|
32606
32671
|
// ---------------------------------------------------------------------------
|
|
32607
|
-
mapToConditionalFormat(sheetId, cf) {
|
|
32672
|
+
mapToConditionalFormat(sheetId, cf, options = { useFixedReference: false }) {
|
|
32608
32673
|
return {
|
|
32609
32674
|
...cf,
|
|
32610
32675
|
ranges: cf.ranges.map((range) => {
|
|
32611
|
-
return this.getters.getRangeString(range, sheetId);
|
|
32676
|
+
return this.getters.getRangeString(range, sheetId, options.useFixedReference);
|
|
32612
32677
|
}),
|
|
32613
32678
|
};
|
|
32614
32679
|
}
|
|
@@ -34445,8 +34510,9 @@ class RangeAdapter {
|
|
|
34445
34510
|
*
|
|
34446
34511
|
* @param range the range (received from getRangeFromXC or getRangeFromZone)
|
|
34447
34512
|
* @param forSheetId the id of the sheet where the range string is supposed to be used.
|
|
34513
|
+
* @param [useFixedZone=false] if true, the range will be returned with fixed row and column
|
|
34448
34514
|
*/
|
|
34449
|
-
getRangeString(range, forSheetId) {
|
|
34515
|
+
getRangeString(range, forSheetId, useFixedZone = false) {
|
|
34450
34516
|
if (!range) {
|
|
34451
34517
|
return INCORRECT_RANGE_STRING;
|
|
34452
34518
|
}
|
|
@@ -34473,7 +34539,7 @@ class RangeAdapter {
|
|
|
34473
34539
|
if (prefixSheet && !sheetName) {
|
|
34474
34540
|
return INCORRECT_RANGE_STRING;
|
|
34475
34541
|
}
|
|
34476
|
-
let rangeString = this.getRangePartString(rangeImpl, 0);
|
|
34542
|
+
let rangeString = this.getRangePartString(rangeImpl, 0, useFixedZone);
|
|
34477
34543
|
if (rangeImpl.parts && rangeImpl.parts.length === 2) {
|
|
34478
34544
|
// this if converts A2:A2 into A2 except if any part of the original range had fixed row or column (with $)
|
|
34479
34545
|
if (rangeImpl.zone.top !== rangeImpl.zone.bottom ||
|
|
@@ -34483,7 +34549,7 @@ class RangeAdapter {
|
|
|
34483
34549
|
rangeImpl.parts[1].rowFixed ||
|
|
34484
34550
|
rangeImpl.parts[1].colFixed) {
|
|
34485
34551
|
rangeString += ":";
|
|
34486
|
-
rangeString += this.getRangePartString(rangeImpl, 1);
|
|
34552
|
+
rangeString += this.getRangePartString(rangeImpl, 1, useFixedZone);
|
|
34487
34553
|
}
|
|
34488
34554
|
}
|
|
34489
34555
|
return `${prefixSheet ? sheetName + "!" : ""}${rangeString}`;
|
|
@@ -34524,13 +34590,13 @@ class RangeAdapter {
|
|
|
34524
34590
|
/**
|
|
34525
34591
|
* Get a Xc string that represent a part of a range
|
|
34526
34592
|
*/
|
|
34527
|
-
getRangePartString(range, part) {
|
|
34593
|
+
getRangePartString(range, part, useFixedZone = false) {
|
|
34528
34594
|
const colFixed = range.parts && range.parts[part]?.colFixed ? "$" : "";
|
|
34529
34595
|
const col = part === 0 ? numberToLetters(range.zone.left) : numberToLetters(range.zone.right);
|
|
34530
34596
|
const rowFixed = range.parts && range.parts[part]?.rowFixed ? "$" : "";
|
|
34531
34597
|
const row = part === 0 ? String(range.zone.top + 1) : String(range.zone.bottom + 1);
|
|
34532
34598
|
let str = "";
|
|
34533
|
-
if (range.isFullCol) {
|
|
34599
|
+
if (range.isFullCol && !useFixedZone) {
|
|
34534
34600
|
if (part === 0 && range.unboundedZone.hasHeader) {
|
|
34535
34601
|
str = colFixed + col + rowFixed + row;
|
|
34536
34602
|
}
|
|
@@ -34538,7 +34604,7 @@ class RangeAdapter {
|
|
|
34538
34604
|
str = colFixed + col;
|
|
34539
34605
|
}
|
|
34540
34606
|
}
|
|
34541
|
-
else if (range.isFullRow) {
|
|
34607
|
+
else if (range.isFullRow && !useFixedZone) {
|
|
34542
34608
|
if (part === 0 && range.unboundedZone.hasHeader) {
|
|
34543
34609
|
str = colFixed + col + rowFixed + row;
|
|
34544
34610
|
}
|
|
@@ -36335,7 +36401,15 @@ class SpreadsheetRTree {
|
|
|
36335
36401
|
if (!this.rTrees[sheetId]) {
|
|
36336
36402
|
return;
|
|
36337
36403
|
}
|
|
36338
|
-
this.rTrees[sheetId].remove(item,
|
|
36404
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
36405
|
+
}
|
|
36406
|
+
rtreeItemComparer(left, right) {
|
|
36407
|
+
return (left.data == right.data &&
|
|
36408
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
36409
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
36410
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
36411
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
36412
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
36339
36413
|
}
|
|
36340
36414
|
}
|
|
36341
36415
|
/**
|
|
@@ -36413,7 +36487,7 @@ class FormulaDependencyGraph {
|
|
|
36413
36487
|
const queue = Array.from(ranges).reverse();
|
|
36414
36488
|
while (queue.length > 0) {
|
|
36415
36489
|
const range = queue.pop();
|
|
36416
|
-
visited.
|
|
36490
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
36417
36491
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
36418
36492
|
for (const positionId of impactedPositionIds) {
|
|
36419
36493
|
if (!visited.has(positionId)) {
|
|
@@ -36421,7 +36495,7 @@ class FormulaDependencyGraph {
|
|
|
36421
36495
|
}
|
|
36422
36496
|
}
|
|
36423
36497
|
}
|
|
36424
|
-
visited.
|
|
36498
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
36425
36499
|
return visited;
|
|
36426
36500
|
}
|
|
36427
36501
|
}
|
|
@@ -36552,9 +36626,9 @@ class Evaluator {
|
|
|
36552
36626
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
36553
36627
|
const cellsToCompute = new JetSet(cells);
|
|
36554
36628
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
36555
|
-
cellsToCompute.
|
|
36556
|
-
cellsToCompute.
|
|
36557
|
-
cellsToCompute.
|
|
36629
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
36630
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
36631
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
36558
36632
|
this.evaluate(cellsToCompute);
|
|
36559
36633
|
}
|
|
36560
36634
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -36568,7 +36642,7 @@ class Evaluator {
|
|
|
36568
36642
|
}
|
|
36569
36643
|
if (!content) {
|
|
36570
36644
|
// The previous content could have blocked some array formulas
|
|
36571
|
-
impactedPositionIds.
|
|
36645
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
36572
36646
|
}
|
|
36573
36647
|
}
|
|
36574
36648
|
return impactedPositionIds;
|
|
@@ -36616,7 +36690,7 @@ class Evaluator {
|
|
|
36616
36690
|
}
|
|
36617
36691
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
36618
36692
|
const cells = new JetSet(arrayFormulas);
|
|
36619
|
-
cells.
|
|
36693
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
36620
36694
|
return cells;
|
|
36621
36695
|
}
|
|
36622
36696
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -36767,7 +36841,7 @@ class Evaluator {
|
|
|
36767
36841
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
36768
36842
|
// check if formula dependencies present in the spread zone
|
|
36769
36843
|
// if so, they need to be recomputed
|
|
36770
|
-
this.nextPositionsToUpdate.
|
|
36844
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
36771
36845
|
};
|
|
36772
36846
|
}
|
|
36773
36847
|
invalidateSpreading(positionId) {
|
|
@@ -36782,8 +36856,8 @@ class Evaluator {
|
|
|
36782
36856
|
continue;
|
|
36783
36857
|
}
|
|
36784
36858
|
this.evaluatedCells.delete(child);
|
|
36785
|
-
this.nextPositionsToUpdate.
|
|
36786
|
-
this.nextPositionsToUpdate.
|
|
36859
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
36860
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
36787
36861
|
}
|
|
36788
36862
|
this.spreadingRelations.removeNode(positionId);
|
|
36789
36863
|
}
|
|
@@ -37143,7 +37217,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
37143
37217
|
const format = newFormat
|
|
37144
37218
|
? getItemId(newFormat, data.formats)
|
|
37145
37219
|
: exportedCellData.format;
|
|
37146
|
-
|
|
37220
|
+
let content;
|
|
37221
|
+
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
37222
|
+
content = this.getters.buildFormulaContent(exportedSheetData.id, formulaCell, formulaCell.dependencies, true);
|
|
37223
|
+
}
|
|
37224
|
+
else {
|
|
37225
|
+
content = !isExported ? newContent : exportedCellData.content;
|
|
37226
|
+
}
|
|
37147
37227
|
exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
|
|
37148
37228
|
}
|
|
37149
37229
|
}
|
|
@@ -43662,7 +43742,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43662
43742
|
this.replaceText(ref, this.selectionInitialStart, this.selectionEnd);
|
|
43663
43743
|
}
|
|
43664
43744
|
getZoneReference(zone) {
|
|
43665
|
-
const inputSheetId = this.getters.getCurrentEditedCell().
|
|
43745
|
+
const inputSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
43666
43746
|
const sheetId = this.getters.getActiveSheetId();
|
|
43667
43747
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
43668
43748
|
return this.getters.getSelectionRangeString(range, inputSheetId);
|
|
@@ -43676,7 +43756,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43676
43756
|
_fixedParts.pop();
|
|
43677
43757
|
}
|
|
43678
43758
|
const newRange = range.clone({ parts: _fixedParts });
|
|
43679
|
-
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().
|
|
43759
|
+
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId());
|
|
43680
43760
|
}
|
|
43681
43761
|
/**
|
|
43682
43762
|
* Replace the current selection by a new text.
|
|
@@ -43709,7 +43789,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43709
43789
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
43710
43790
|
return;
|
|
43711
43791
|
}
|
|
43712
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
43792
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
43713
43793
|
const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
|
|
43714
43794
|
const colorsToKeep = {};
|
|
43715
43795
|
for (const xc of XCs) {
|
|
@@ -43738,7 +43818,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43738
43818
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
43739
43819
|
return [];
|
|
43740
43820
|
}
|
|
43741
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
43821
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
43742
43822
|
const rangeColor = (rangeString) => {
|
|
43743
43823
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
43744
43824
|
return colors$1[colorIndex % colors$1.length];
|
|
@@ -43756,7 +43836,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43756
43836
|
* Return ranges currently referenced in the composer
|
|
43757
43837
|
*/
|
|
43758
43838
|
getReferencedRanges() {
|
|
43759
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
43839
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
43760
43840
|
const referenceRanges = this.currentTokens
|
|
43761
43841
|
.filter((token) => token.type === "REFERENCE")
|
|
43762
43842
|
.map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
|
|
@@ -45720,6 +45800,16 @@ class ImageProvider {
|
|
|
45720
45800
|
}
|
|
45721
45801
|
}
|
|
45722
45802
|
|
|
45803
|
+
class FocusableElement {
|
|
45804
|
+
focusableElement = undefined;
|
|
45805
|
+
setFocusableElement(element) {
|
|
45806
|
+
this.focusableElement = element;
|
|
45807
|
+
}
|
|
45808
|
+
focus() {
|
|
45809
|
+
this.focusableElement?.focus();
|
|
45810
|
+
}
|
|
45811
|
+
}
|
|
45812
|
+
|
|
45723
45813
|
const RIPPLE_KEY_FRAMES = [
|
|
45724
45814
|
{ transform: "scale(0)" },
|
|
45725
45815
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -47762,6 +47852,7 @@ class Spreadsheet extends Component {
|
|
|
47762
47852
|
_t: Spreadsheet._t,
|
|
47763
47853
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
47764
47854
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
47855
|
+
focusableElement: new FocusableElement(),
|
|
47765
47856
|
});
|
|
47766
47857
|
useExternalListener(window, "resize", () => this.render(true));
|
|
47767
47858
|
useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
@@ -47868,17 +47959,18 @@ class Spreadsheet extends Component {
|
|
|
47868
47959
|
this.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
47869
47960
|
this.composer.topBarFocus = "contentFocus";
|
|
47870
47961
|
this.composer.gridFocusMode = "inactive";
|
|
47871
|
-
this.setComposerContent({ selection }
|
|
47962
|
+
this.setComposerContent({ selection });
|
|
47872
47963
|
}
|
|
47873
|
-
onGridComposerContentFocused() {
|
|
47964
|
+
onGridComposerContentFocused(selection) {
|
|
47874
47965
|
if (this.model.getters.isReadonly()) {
|
|
47875
47966
|
return;
|
|
47876
47967
|
}
|
|
47877
47968
|
this.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
47878
47969
|
this.composer.topBarFocus = "inactive";
|
|
47879
47970
|
this.composer.gridFocusMode = "contentFocus";
|
|
47880
|
-
this.setComposerContent({});
|
|
47971
|
+
this.setComposerContent({ selection });
|
|
47881
47972
|
}
|
|
47973
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
47882
47974
|
onGridComposerCellFocused(content, selection) {
|
|
47883
47975
|
if (this.model.getters.isReadonly()) {
|
|
47884
47976
|
return;
|
|
@@ -49290,11 +49382,10 @@ class SelectionStreamProcessorImpl {
|
|
|
49290
49382
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
49291
49383
|
*/
|
|
49292
49384
|
getEndOfCluster(startPosition, dim, dir) {
|
|
49293
|
-
const sheet = this.getters.getActiveSheet();
|
|
49294
49385
|
let currentPosition = startPosition;
|
|
49295
49386
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
49296
49387
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
49297
|
-
let mode = !this.
|
|
49388
|
+
let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
|
|
49298
49389
|
? "endOfCluster"
|
|
49299
49390
|
: "nextCluster";
|
|
49300
49391
|
while (true) {
|
|
@@ -49304,7 +49395,7 @@ class SelectionStreamProcessorImpl {
|
|
|
49304
49395
|
currentPosition.row === nextCellPosition.row) {
|
|
49305
49396
|
break;
|
|
49306
49397
|
}
|
|
49307
|
-
const isNextCellEmpty = this.
|
|
49398
|
+
const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
|
|
49308
49399
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
49309
49400
|
break;
|
|
49310
49401
|
}
|
|
@@ -49318,10 +49409,20 @@ class SelectionStreamProcessorImpl {
|
|
|
49318
49409
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
49319
49410
|
}
|
|
49320
49411
|
/**
|
|
49321
|
-
*
|
|
49322
|
-
* check
|
|
49412
|
+
* Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
|
|
49413
|
+
* the check applies to the main cell of the merge.
|
|
49323
49414
|
*/
|
|
49324
|
-
isCellEmpty({ col, row }
|
|
49415
|
+
isCellEmpty({ col, row }) {
|
|
49416
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
49417
|
+
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
49418
|
+
return !(this.getters.getCorrespondingFormulaCell(position) || this.getters.getCell(position)?.content);
|
|
49419
|
+
}
|
|
49420
|
+
/**
|
|
49421
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
49422
|
+
* the check applies to the main cell of the merge.
|
|
49423
|
+
*/
|
|
49424
|
+
isEvaluatedCellEmpty({ col, row }) {
|
|
49425
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
49325
49426
|
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
49326
49427
|
const cell = this.getters.getEvaluatedCell(position);
|
|
49327
49428
|
return cell.type === CellValueType.empty;
|
|
@@ -49799,12 +49900,7 @@ function addFormula(cell) {
|
|
|
49799
49900
|
attrs.push(["t", "str"]);
|
|
49800
49901
|
cycle = escapeXml /*xml*/ `<v>${cell.value}</v>`;
|
|
49801
49902
|
}
|
|
49802
|
-
node = escapeXml /*xml*/ `
|
|
49803
|
-
<f>
|
|
49804
|
-
${XlsxFormula}
|
|
49805
|
-
</f>
|
|
49806
|
-
${cycle}
|
|
49807
|
-
`;
|
|
49903
|
+
node = escapeXml /*xml*/ ` <f> ${XlsxFormula} </f> ${cycle} `;
|
|
49808
49904
|
return { attrs, node };
|
|
49809
49905
|
}
|
|
49810
49906
|
function addContent(content, sharedStrings, forceString = false) {
|
|
@@ -50623,11 +50719,10 @@ function addRows(construct, data, sheet) {
|
|
|
50623
50719
|
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader));
|
|
50624
50720
|
}
|
|
50625
50721
|
attributes.push(...additionalAttrs);
|
|
50626
|
-
|
|
50627
|
-
|
|
50628
|
-
|
|
50629
|
-
|
|
50630
|
-
`);
|
|
50722
|
+
// prettier-ignore
|
|
50723
|
+
cellNodes.push(escapeXml /*xml*/ `<c ${formatAttributes(attributes)}>
|
|
50724
|
+
${cellNode}
|
|
50725
|
+
</c>`);
|
|
50631
50726
|
}
|
|
50632
50727
|
}
|
|
50633
50728
|
if (cellNodes.length || row.size !== DEFAULT_CELL_HEIGHT || row.isHidden) {
|
|
@@ -51576,6 +51671,6 @@ const constants = {
|
|
|
51576
51671
|
export { AbstractChart, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
|
|
51577
51672
|
|
|
51578
51673
|
|
|
51579
|
-
__info__.version = '16.4.
|
|
51580
|
-
__info__.date = '2024-
|
|
51581
|
-
__info__.hash = '
|
|
51674
|
+
__info__.version = '16.4.23';
|
|
51675
|
+
__info__.date = '2024-02-16T14:23:29.521Z';
|
|
51676
|
+
__info__.hash = 'cb5db1a';
|