@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
|
@@ -705,18 +705,18 @@ function isConsecutive(iterable) {
|
|
|
705
705
|
return true;
|
|
706
706
|
}
|
|
707
707
|
class JetSet extends Set {
|
|
708
|
-
|
|
708
|
+
addMany(iterable) {
|
|
709
709
|
for (const element of iterable) {
|
|
710
710
|
super.add(element);
|
|
711
711
|
}
|
|
712
712
|
return this;
|
|
713
713
|
}
|
|
714
|
-
|
|
715
|
-
let
|
|
714
|
+
deleteMany(iterable) {
|
|
715
|
+
let wasDeleted = false;
|
|
716
716
|
for (const element of iterable) {
|
|
717
|
-
|
|
717
|
+
wasDeleted ||= super.delete(element);
|
|
718
718
|
}
|
|
719
|
-
return
|
|
719
|
+
return wasDeleted;
|
|
720
720
|
}
|
|
721
721
|
}
|
|
722
722
|
/**
|
|
@@ -1842,6 +1842,9 @@ function parseFormat(formatString) {
|
|
|
1842
1842
|
function formatValue(value, { format, locale }) {
|
|
1843
1843
|
switch (typeof value) {
|
|
1844
1844
|
case "string":
|
|
1845
|
+
if (value.includes('\\"')) {
|
|
1846
|
+
return value.replace(/\\"/g, '"');
|
|
1847
|
+
}
|
|
1845
1848
|
return value;
|
|
1846
1849
|
case "boolean":
|
|
1847
1850
|
return value ? "TRUE" : "FALSE";
|
|
@@ -15239,6 +15242,9 @@ function isValidLocale(locale) {
|
|
|
15239
15242
|
if (locale.formulaArgSeparator === locale.decimalSeparator) {
|
|
15240
15243
|
return false;
|
|
15241
15244
|
}
|
|
15245
|
+
if (locale.thousandsSeparator === locale.decimalSeparator) {
|
|
15246
|
+
return false;
|
|
15247
|
+
}
|
|
15242
15248
|
try {
|
|
15243
15249
|
formatValue(1, { locale, format: "#,##0.00" });
|
|
15244
15250
|
formatValue(1, { locale, format: locale.dateFormat });
|
|
@@ -15329,7 +15335,7 @@ function canonicalizeNumberLiteral(content, locale) {
|
|
|
15329
15335
|
if (locale.decimalSeparator === "." || !isNumber(content, locale)) {
|
|
15330
15336
|
return content;
|
|
15331
15337
|
}
|
|
15332
|
-
return content.replace(locale.decimalSeparator, ".");
|
|
15338
|
+
return content.replace(locale.thousandsSeparator, "").replace(locale.decimalSeparator, ".");
|
|
15333
15339
|
}
|
|
15334
15340
|
/**
|
|
15335
15341
|
* Change a content string from the given locale to its canonical form (en_US locale). Also convert date string.
|
|
@@ -15975,14 +15981,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
15975
15981
|
: undefined));
|
|
15976
15982
|
}
|
|
15977
15983
|
}
|
|
15978
|
-
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
15979
|
-
// A single cell. If it's only the title, the dataset is not added.
|
|
15980
|
-
if (!dataSetsHaveTitle) {
|
|
15981
|
-
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
15982
|
-
}
|
|
15983
|
-
}
|
|
15984
15984
|
else {
|
|
15985
|
-
/* 1 row or 1 column */
|
|
15985
|
+
/* 1 cell, 1 row or 1 column */
|
|
15986
15986
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
15987
15987
|
? {
|
|
15988
15988
|
top: zone.top,
|
|
@@ -16031,8 +16031,10 @@ function toExcelDataset(getters, ds) {
|
|
|
16031
16031
|
}
|
|
16032
16032
|
const dataRange = ds.dataRange.clone({ zone: dataZone });
|
|
16033
16033
|
return {
|
|
16034
|
-
label: ds.labelCell
|
|
16035
|
-
|
|
16034
|
+
label: ds.labelCell
|
|
16035
|
+
? getters.getRangeString(ds.labelCell, "forceSheetReference", true)
|
|
16036
|
+
: undefined,
|
|
16037
|
+
range: getters.getRangeString(dataRange, "forceSheetReference", true),
|
|
16036
16038
|
};
|
|
16037
16039
|
}
|
|
16038
16040
|
function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
@@ -16045,7 +16047,7 @@ function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
|
16045
16047
|
zone.top = zone.top + 1;
|
|
16046
16048
|
}
|
|
16047
16049
|
const range = labelRange.clone({ zone });
|
|
16048
|
-
return getters.getRangeString(range, "forceSheetReference");
|
|
16050
|
+
return getters.getRangeString(range, "forceSheetReference", true);
|
|
16049
16051
|
}
|
|
16050
16052
|
/**
|
|
16051
16053
|
* Transform a chart definition which supports dataSets (dataSets and LabelRange)
|
|
@@ -16582,7 +16584,7 @@ class BarChart extends AbstractChart {
|
|
|
16582
16584
|
return undefined;
|
|
16583
16585
|
const dataSets = this.dataSets
|
|
16584
16586
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
16585
|
-
.filter((ds) => ds.range !== ""
|
|
16587
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
16586
16588
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
16587
16589
|
return {
|
|
16588
16590
|
...this.getDefinition(),
|
|
@@ -17170,7 +17172,7 @@ class LineChart extends AbstractChart {
|
|
|
17170
17172
|
return undefined;
|
|
17171
17173
|
const dataSets = this.dataSets
|
|
17172
17174
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
17173
|
-
.filter((ds) => ds.range !== ""
|
|
17175
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
17174
17176
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
17175
17177
|
return {
|
|
17176
17178
|
...this.getDefinition(),
|
|
@@ -17457,7 +17459,7 @@ class PieChart extends AbstractChart {
|
|
|
17457
17459
|
return undefined;
|
|
17458
17460
|
const dataSets = this.dataSets
|
|
17459
17461
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
17460
|
-
.filter((ds) => ds.range !== ""
|
|
17462
|
+
.filter((ds) => ds.range !== "" && ds.range !== INCORRECT_RANGE_STRING);
|
|
17461
17463
|
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
17462
17464
|
return {
|
|
17463
17465
|
...this.getDefinition(),
|
|
@@ -18635,6 +18637,12 @@ const INSERT_LINK = (env) => {
|
|
|
18635
18637
|
let { col, row } = env.model.getters.getActivePosition();
|
|
18636
18638
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
18637
18639
|
};
|
|
18640
|
+
const INSERT_LINK_NAME = (env) => {
|
|
18641
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
18642
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
18643
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
18644
|
+
return cell && cell.link ? _lt("Edit link") : _lt("Insert link");
|
|
18645
|
+
};
|
|
18638
18646
|
//------------------------------------------------------------------------------
|
|
18639
18647
|
// Filters action
|
|
18640
18648
|
//------------------------------------------------------------------------------
|
|
@@ -19175,7 +19183,7 @@ cellMenuRegistry
|
|
|
19175
19183
|
})
|
|
19176
19184
|
.add("insert_link", {
|
|
19177
19185
|
...insertLink,
|
|
19178
|
-
name:
|
|
19186
|
+
name: INSERT_LINK_NAME,
|
|
19179
19187
|
sequence: 150,
|
|
19180
19188
|
separator: true,
|
|
19181
19189
|
});
|
|
@@ -24086,6 +24094,7 @@ class Composer extends owl.Component {
|
|
|
24086
24094
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
24087
24095
|
static defaultProps = {
|
|
24088
24096
|
inputStyle: "",
|
|
24097
|
+
isDefaultFocus: false,
|
|
24089
24098
|
};
|
|
24090
24099
|
composerRef = owl.useRef("o_composer");
|
|
24091
24100
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -24138,7 +24147,6 @@ class Composer extends owl.Component {
|
|
|
24138
24147
|
F2: () => console.warn("Not implemented"),
|
|
24139
24148
|
F4: this.processF4Key,
|
|
24140
24149
|
Tab: (ev) => this.processTabKey(ev),
|
|
24141
|
-
" ": (ev) => this.processSpaceKey(ev),
|
|
24142
24150
|
};
|
|
24143
24151
|
keyCodeMapping = {
|
|
24144
24152
|
NumpadDecimal: this.processNumpadDecimal,
|
|
@@ -24146,11 +24154,11 @@ class Composer extends owl.Component {
|
|
|
24146
24154
|
setup() {
|
|
24147
24155
|
owl.onMounted(() => {
|
|
24148
24156
|
const el = this.composerRef.el;
|
|
24157
|
+
if (this.props.isDefaultFocus) {
|
|
24158
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
24159
|
+
}
|
|
24149
24160
|
this.contentHelper.updateEl(el);
|
|
24150
24161
|
});
|
|
24151
|
-
owl.onWillUnmount(() => {
|
|
24152
|
-
this.props.onComposerUnmounted?.();
|
|
24153
|
-
});
|
|
24154
24162
|
owl.useEffect(() => {
|
|
24155
24163
|
this.processContent();
|
|
24156
24164
|
});
|
|
@@ -24159,7 +24167,8 @@ class Composer extends owl.Component {
|
|
|
24159
24167
|
// Handlers
|
|
24160
24168
|
// ---------------------------------------------------------------------------
|
|
24161
24169
|
processArrowKeys(ev) {
|
|
24162
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
24170
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
24171
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
24163
24172
|
this.functionDescriptionState.showDescription = false;
|
|
24164
24173
|
// Prevent the default content editable behavior which moves the cursor
|
|
24165
24174
|
ev.preventDefault();
|
|
@@ -24198,25 +24207,19 @@ class Composer extends owl.Component {
|
|
|
24198
24207
|
processTabKey(ev) {
|
|
24199
24208
|
ev.preventDefault();
|
|
24200
24209
|
ev.stopPropagation();
|
|
24201
|
-
if (this.
|
|
24202
|
-
|
|
24203
|
-
|
|
24204
|
-
|
|
24205
|
-
|
|
24210
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
24211
|
+
if (this.autoCompleteState.showProvider) {
|
|
24212
|
+
const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
|
|
24213
|
+
if (autoCompleteValue) {
|
|
24214
|
+
this.autoComplete(autoCompleteValue);
|
|
24215
|
+
return;
|
|
24216
|
+
}
|
|
24206
24217
|
}
|
|
24218
|
+
this.env.model.dispatch("STOP_EDITION");
|
|
24207
24219
|
}
|
|
24208
24220
|
const direction = ev.shiftKey ? "left" : "right";
|
|
24209
|
-
this.env.model.dispatch("STOP_EDITION");
|
|
24210
24221
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
24211
24222
|
}
|
|
24212
|
-
processSpaceKey(ev) {
|
|
24213
|
-
if (ev.ctrlKey) {
|
|
24214
|
-
ev.preventDefault();
|
|
24215
|
-
ev.stopPropagation();
|
|
24216
|
-
this.showAutocomplete("");
|
|
24217
|
-
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
24218
|
-
}
|
|
24219
|
-
}
|
|
24220
24223
|
processEnterKey(ev) {
|
|
24221
24224
|
ev.preventDefault();
|
|
24222
24225
|
ev.stopPropagation();
|
|
@@ -24268,6 +24271,9 @@ class Composer extends owl.Component {
|
|
|
24268
24271
|
this.compositionActive = false;
|
|
24269
24272
|
}
|
|
24270
24273
|
onKeydown(ev) {
|
|
24274
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
24275
|
+
return;
|
|
24276
|
+
}
|
|
24271
24277
|
let handler = this.keyMapping[ev.key] || this.keyCodeMapping[ev.code];
|
|
24272
24278
|
if (handler) {
|
|
24273
24279
|
handler.call(this, ev);
|
|
@@ -24276,14 +24282,33 @@ class Composer extends owl.Component {
|
|
|
24276
24282
|
ev.stopPropagation();
|
|
24277
24283
|
}
|
|
24278
24284
|
}
|
|
24285
|
+
onPaste(ev) {
|
|
24286
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
24287
|
+
ev.stopPropagation();
|
|
24288
|
+
}
|
|
24289
|
+
}
|
|
24279
24290
|
/*
|
|
24280
24291
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
24281
24292
|
* */
|
|
24282
24293
|
onInput(ev) {
|
|
24283
|
-
if (
|
|
24294
|
+
if (!this.shouldProcessInputEvents) {
|
|
24295
|
+
return;
|
|
24296
|
+
}
|
|
24297
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
24298
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
24284
24299
|
return;
|
|
24285
24300
|
}
|
|
24286
|
-
|
|
24301
|
+
ev.stopPropagation();
|
|
24302
|
+
let content;
|
|
24303
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
24304
|
+
content = ev.data || "";
|
|
24305
|
+
}
|
|
24306
|
+
else {
|
|
24307
|
+
content = this.contentHelper.getText();
|
|
24308
|
+
}
|
|
24309
|
+
if (this.props.focus === "inactive") {
|
|
24310
|
+
return this.props.onComposerCellFocused?.(content);
|
|
24311
|
+
}
|
|
24287
24312
|
let selection = this.contentHelper.getCurrentSelection();
|
|
24288
24313
|
if (ev.inputType === "insertParagraph") {
|
|
24289
24314
|
const start = Math.min(selection.start, selection.end);
|
|
@@ -24361,9 +24386,8 @@ class Composer extends owl.Component {
|
|
|
24361
24386
|
}
|
|
24362
24387
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
24363
24388
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
24364
|
-
|
|
24365
|
-
|
|
24366
|
-
}
|
|
24389
|
+
this.props.onComposerContentFocused();
|
|
24390
|
+
if (this.props.focus === "inactive") ;
|
|
24367
24391
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
24368
24392
|
this.processTokenAtCursor();
|
|
24369
24393
|
}
|
|
@@ -24530,7 +24554,7 @@ class Composer extends owl.Component {
|
|
|
24530
24554
|
const highlights = this.env.model.getters.getHighlights();
|
|
24531
24555
|
const refSheet = sheetName
|
|
24532
24556
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
24533
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
24557
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
24534
24558
|
const highlight = highlights.find((highlight) => {
|
|
24535
24559
|
if (highlight.sheetId !== refSheet)
|
|
24536
24560
|
return false;
|
|
@@ -24610,12 +24634,13 @@ class Composer extends owl.Component {
|
|
|
24610
24634
|
}
|
|
24611
24635
|
}
|
|
24612
24636
|
Composer.props = {
|
|
24613
|
-
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
24614
|
-
onComposerContentFocused: Function,
|
|
24615
24637
|
inputStyle: { type: String, optional: true },
|
|
24616
24638
|
rect: { type: Object, optional: true },
|
|
24617
24639
|
delimitation: { type: Object, optional: true },
|
|
24618
|
-
|
|
24640
|
+
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
24641
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
24642
|
+
onComposerContentFocused: Function,
|
|
24643
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
24619
24644
|
};
|
|
24620
24645
|
|
|
24621
24646
|
const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
|
|
@@ -24649,51 +24674,26 @@ css /* scss */ `
|
|
|
24649
24674
|
class GridComposer extends owl.Component {
|
|
24650
24675
|
static template = "o-spreadsheet-GridComposer";
|
|
24651
24676
|
static components = { Composer };
|
|
24652
|
-
|
|
24653
|
-
|
|
24654
|
-
|
|
24677
|
+
// TODORAR see if we can keep it undefined
|
|
24678
|
+
rect = this.defaultRect;
|
|
24679
|
+
isEditing = false;
|
|
24655
24680
|
isCellReferenceVisible;
|
|
24656
|
-
|
|
24681
|
+
get defaultRect() {
|
|
24682
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
24683
|
+
}
|
|
24657
24684
|
setup() {
|
|
24658
|
-
this.gridComposerRef = owl.useRef("gridComposer");
|
|
24659
|
-
this.composerState = owl.useState({
|
|
24660
|
-
rect: undefined,
|
|
24661
|
-
delimitation: undefined,
|
|
24662
|
-
});
|
|
24663
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
24664
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
24665
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
24666
|
-
this.isCellReferenceVisible = false;
|
|
24667
|
-
owl.onMounted(() => {
|
|
24668
|
-
const el = this.gridComposerRef.el;
|
|
24669
|
-
this.composerState.rect = {
|
|
24670
|
-
x: this.rect.x,
|
|
24671
|
-
y: this.rect.y,
|
|
24672
|
-
width: el.clientWidth,
|
|
24673
|
-
height: el.clientHeight,
|
|
24674
|
-
};
|
|
24675
|
-
this.composerState.delimitation = {
|
|
24676
|
-
width: this.props.gridDims.width,
|
|
24677
|
-
height: this.props.gridDims.height,
|
|
24678
|
-
};
|
|
24679
|
-
});
|
|
24680
24685
|
owl.onWillUpdateProps(() => {
|
|
24681
|
-
|
|
24682
|
-
|
|
24683
|
-
}
|
|
24684
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
24685
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
24686
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
24687
|
-
if (!deepEquals(rect, this.rect) ||
|
|
24688
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
24689
|
-
this.isCellReferenceVisible = true;
|
|
24690
|
-
}
|
|
24686
|
+
this.updateComponentPosition();
|
|
24687
|
+
this.updateCellReferenceVisibility();
|
|
24691
24688
|
});
|
|
24692
24689
|
}
|
|
24693
24690
|
get shouldDisplayCellReference() {
|
|
24694
24691
|
return this.isCellReferenceVisible;
|
|
24695
24692
|
}
|
|
24696
24693
|
get cellReference() {
|
|
24694
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
24695
|
+
return "";
|
|
24696
|
+
}
|
|
24697
24697
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
24698
24698
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
24699
24699
|
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
@@ -24705,7 +24705,27 @@ class GridComposer extends owl.Component {
|
|
|
24705
24705
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
24706
24706
|
});
|
|
24707
24707
|
}
|
|
24708
|
+
get composerProps() {
|
|
24709
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
24710
|
+
return {
|
|
24711
|
+
rect: { ...this.rect },
|
|
24712
|
+
delimitation: {
|
|
24713
|
+
width,
|
|
24714
|
+
height,
|
|
24715
|
+
},
|
|
24716
|
+
focus: this.props.focus,
|
|
24717
|
+
isDefaultFocus: true,
|
|
24718
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
24719
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
24720
|
+
};
|
|
24721
|
+
}
|
|
24708
24722
|
get containerStyle() {
|
|
24723
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
24724
|
+
return `
|
|
24725
|
+
position: absolute;
|
|
24726
|
+
z-index: -1000;
|
|
24727
|
+
`;
|
|
24728
|
+
}
|
|
24709
24729
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
24710
24730
|
const cell = this.env.model.getters.getActiveCell();
|
|
24711
24731
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -24725,6 +24745,8 @@ class GridComposer extends owl.Component {
|
|
|
24725
24745
|
if (!isFormula) {
|
|
24726
24746
|
textAlign = style.align || cell.defaultAlign;
|
|
24727
24747
|
}
|
|
24748
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
24749
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
24728
24750
|
/**
|
|
24729
24751
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
24730
24752
|
* including all the paddings/margins of the composer
|
|
@@ -24736,6 +24758,8 @@ class GridComposer extends owl.Component {
|
|
|
24736
24758
|
top: `${top}px`,
|
|
24737
24759
|
"min-width": `${width + 1}px`,
|
|
24738
24760
|
"min-height": `${height + 1}px`,
|
|
24761
|
+
"max-width": `${maxWidth}px`,
|
|
24762
|
+
"max-height": `${maxHeight}px`,
|
|
24739
24763
|
background,
|
|
24740
24764
|
color,
|
|
24741
24765
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -24745,20 +24769,38 @@ class GridComposer extends owl.Component {
|
|
|
24745
24769
|
"text-align": textAlign,
|
|
24746
24770
|
});
|
|
24747
24771
|
}
|
|
24748
|
-
|
|
24749
|
-
const
|
|
24750
|
-
|
|
24751
|
-
|
|
24752
|
-
|
|
24753
|
-
|
|
24754
|
-
|
|
24772
|
+
updateComponentPosition() {
|
|
24773
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
24774
|
+
if (this.isEditing !== isEditing) {
|
|
24775
|
+
this.isEditing = isEditing;
|
|
24776
|
+
if (!isEditing) {
|
|
24777
|
+
this.rect = this.defaultRect;
|
|
24778
|
+
this.env.focusableElement.focus();
|
|
24779
|
+
return;
|
|
24780
|
+
}
|
|
24781
|
+
const position = this.env.model.getters.getActivePosition();
|
|
24782
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
24783
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
24784
|
+
}
|
|
24785
|
+
}
|
|
24786
|
+
updateCellReferenceVisibility() {
|
|
24787
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
24788
|
+
return;
|
|
24789
|
+
}
|
|
24790
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
24791
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
24792
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
24793
|
+
if (!deepEquals(rect, this.rect) ||
|
|
24794
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
24795
|
+
this.isCellReferenceVisible = true;
|
|
24796
|
+
}
|
|
24755
24797
|
}
|
|
24756
24798
|
}
|
|
24757
24799
|
GridComposer.props = {
|
|
24758
24800
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
24759
|
-
onComposerUnmounted: Function,
|
|
24760
24801
|
onComposerContentFocused: Function,
|
|
24761
24802
|
gridDims: Object,
|
|
24803
|
+
onComposerCellFocused: Function,
|
|
24762
24804
|
};
|
|
24763
24805
|
|
|
24764
24806
|
const CSS$1 = css /* scss */ `
|
|
@@ -25639,7 +25681,6 @@ class GridOverlay extends owl.Component {
|
|
|
25639
25681
|
this.props.onCellDoubleClicked(col, row);
|
|
25640
25682
|
}
|
|
25641
25683
|
onContextMenu(ev) {
|
|
25642
|
-
ev.preventDefault();
|
|
25643
25684
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
25644
25685
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
25645
25686
|
}
|
|
@@ -26732,7 +26773,6 @@ class Grid extends owl.Component {
|
|
|
26732
26773
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
26733
26774
|
menuState;
|
|
26734
26775
|
gridRef;
|
|
26735
|
-
hiddenInput;
|
|
26736
26776
|
onMouseWheel;
|
|
26737
26777
|
canvasPosition;
|
|
26738
26778
|
hoveredCell;
|
|
@@ -26743,17 +26783,16 @@ class Grid extends owl.Component {
|
|
|
26743
26783
|
menuItems: [],
|
|
26744
26784
|
});
|
|
26745
26785
|
this.gridRef = owl.useRef("grid");
|
|
26746
|
-
this.hiddenInput = owl.useRef("hiddenInput");
|
|
26747
26786
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
26748
26787
|
this.hoveredCell = owl.useState({ col: undefined, row: undefined });
|
|
26749
26788
|
owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
26750
26789
|
owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
26751
26790
|
owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
26752
26791
|
owl.useExternalListener(document.body, "paste", this.paste);
|
|
26753
|
-
owl.onMounted(() => this.
|
|
26754
|
-
this.props.exposeFocus(() => this.
|
|
26792
|
+
owl.onMounted(() => this.focusDefaultElement());
|
|
26793
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
26755
26794
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
26756
|
-
owl.useEffect(() => this.
|
|
26795
|
+
owl.useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
26757
26796
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
26758
26797
|
this.moveCanvas(deltaX, deltaY);
|
|
26759
26798
|
this.hoveredCell.col = undefined;
|
|
@@ -26776,7 +26815,7 @@ class Grid extends owl.Component {
|
|
|
26776
26815
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
26777
26816
|
this.closeOpenedPopover();
|
|
26778
26817
|
}
|
|
26779
|
-
this.
|
|
26818
|
+
this.focusDefaultElement();
|
|
26780
26819
|
}
|
|
26781
26820
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
26782
26821
|
// down itself
|
|
@@ -26949,10 +26988,10 @@ class Grid extends owl.Component {
|
|
|
26949
26988
|
PAGEUP: () => this.env.model.dispatch("SHIFT_VIEWPORT_UP"),
|
|
26950
26989
|
"CTRL+K": () => INSERT_LINK(this.env),
|
|
26951
26990
|
};
|
|
26952
|
-
|
|
26991
|
+
focusDefaultElement() {
|
|
26953
26992
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
26954
26993
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
26955
|
-
this.
|
|
26994
|
+
this.env.focusableElement.focus();
|
|
26956
26995
|
}
|
|
26957
26996
|
}
|
|
26958
26997
|
get gridEl() {
|
|
@@ -27096,19 +27135,6 @@ class Grid extends owl.Component {
|
|
|
27096
27135
|
return;
|
|
27097
27136
|
}
|
|
27098
27137
|
}
|
|
27099
|
-
onInput(ev) {
|
|
27100
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
27101
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
27102
|
-
return;
|
|
27103
|
-
}
|
|
27104
|
-
if (ev.data) {
|
|
27105
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
27106
|
-
// character
|
|
27107
|
-
ev.preventDefault();
|
|
27108
|
-
ev.stopPropagation();
|
|
27109
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
27110
|
-
}
|
|
27111
|
-
}
|
|
27112
27138
|
// ---------------------------------------------------------------------------
|
|
27113
27139
|
// Context Menu
|
|
27114
27140
|
// ---------------------------------------------------------------------------
|
|
@@ -27221,7 +27247,7 @@ class Grid extends owl.Component {
|
|
|
27221
27247
|
}
|
|
27222
27248
|
closeMenu() {
|
|
27223
27249
|
this.menuState.isOpen = false;
|
|
27224
|
-
this.
|
|
27250
|
+
this.focusDefaultElement();
|
|
27225
27251
|
}
|
|
27226
27252
|
}
|
|
27227
27253
|
Grid.props = {
|
|
@@ -30881,6 +30907,31 @@ const MIGRATIONS = [
|
|
|
30881
30907
|
return data;
|
|
30882
30908
|
},
|
|
30883
30909
|
},
|
|
30910
|
+
{
|
|
30911
|
+
description: "Fix datafilter duplication",
|
|
30912
|
+
from: 12,
|
|
30913
|
+
to: 12.5,
|
|
30914
|
+
applyMigration(data) {
|
|
30915
|
+
for (let sheet of data.sheets || []) {
|
|
30916
|
+
let knownDataFilterZones = [];
|
|
30917
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
30918
|
+
const zone = toZone(filterTable.range);
|
|
30919
|
+
// See commit message for the details
|
|
30920
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
30921
|
+
if (intersectZoneIndex !== -1) {
|
|
30922
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
30923
|
+
}
|
|
30924
|
+
else {
|
|
30925
|
+
knownDataFilterZones.push(zone);
|
|
30926
|
+
}
|
|
30927
|
+
}
|
|
30928
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
30929
|
+
range: zoneToXc(zone),
|
|
30930
|
+
}));
|
|
30931
|
+
}
|
|
30932
|
+
return data;
|
|
30933
|
+
},
|
|
30934
|
+
},
|
|
30884
30935
|
{
|
|
30885
30936
|
description: "Change Border description structure",
|
|
30886
30937
|
from: 12,
|
|
@@ -31800,9 +31851,9 @@ class CellPlugin extends CorePlugin {
|
|
|
31800
31851
|
allowDispatch(cmd) {
|
|
31801
31852
|
switch (cmd.type) {
|
|
31802
31853
|
case "UPDATE_CELL":
|
|
31803
|
-
return this.
|
|
31854
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
31804
31855
|
case "CLEAR_CELL":
|
|
31805
|
-
return this.checkValidations(cmd, this.
|
|
31856
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
31806
31857
|
default:
|
|
31807
31858
|
return 0 /* CommandResult.Success */;
|
|
31808
31859
|
}
|
|
@@ -31968,13 +32019,13 @@ class CellPlugin extends CorePlugin {
|
|
|
31968
32019
|
/*
|
|
31969
32020
|
* Reconstructs the original formula string based on a normalized form and its dependencies
|
|
31970
32021
|
*/
|
|
31971
|
-
buildFormulaContent(sheetId, cell, dependencies) {
|
|
32022
|
+
buildFormulaContent(sheetId, cell, dependencies, useFixedZone = false) {
|
|
31972
32023
|
const ranges = dependencies || cell.dependencies;
|
|
31973
32024
|
let rangeIndex = 0;
|
|
31974
32025
|
return concat(cell.compiledFormula.tokens.map((token) => {
|
|
31975
32026
|
if (token.type === "REFERENCE") {
|
|
31976
32027
|
const range = ranges[rangeIndex++];
|
|
31977
|
-
return this.getters.getRangeString(range, sheetId);
|
|
32028
|
+
return this.getters.getRangeString(range, sheetId, useFixedZone);
|
|
31978
32029
|
}
|
|
31979
32030
|
return token.value;
|
|
31980
32031
|
}));
|
|
@@ -32096,10 +32147,7 @@ class CellPlugin extends CorePlugin {
|
|
|
32096
32147
|
else {
|
|
32097
32148
|
style = before ? before.style : undefined;
|
|
32098
32149
|
}
|
|
32099
|
-
const
|
|
32100
|
-
let format = ("format" in after ? after.format : before && before.format) ||
|
|
32101
|
-
detectDateFormat(afterContent, locale) ||
|
|
32102
|
-
detectNumberFormat(afterContent);
|
|
32150
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
32103
32151
|
/* Read the following IF as:
|
|
32104
32152
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
32105
32153
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -32140,12 +32188,11 @@ class CellPlugin extends CorePlugin {
|
|
|
32140
32188
|
}
|
|
32141
32189
|
createLiteralCell(id, content, format, style) {
|
|
32142
32190
|
const locale = this.getters.getLocale();
|
|
32143
|
-
content = parseLiteral(content, locale).toString();
|
|
32144
32191
|
return {
|
|
32145
32192
|
id,
|
|
32146
|
-
content,
|
|
32193
|
+
content: parseLiteral(content, locale).toString(),
|
|
32147
32194
|
style,
|
|
32148
|
-
format,
|
|
32195
|
+
format: format || detectDateFormat(content, locale) || detectNumberFormat(content),
|
|
32149
32196
|
isFormula: false,
|
|
32150
32197
|
};
|
|
32151
32198
|
}
|
|
@@ -32206,6 +32253,18 @@ class CellPlugin extends CorePlugin {
|
|
|
32206
32253
|
}
|
|
32207
32254
|
return 0 /* CommandResult.Success */;
|
|
32208
32255
|
}
|
|
32256
|
+
checkUselessUpdateCell(cmd) {
|
|
32257
|
+
const cell = this.getters.getCell(cmd);
|
|
32258
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
32259
|
+
const hasStyle = "style" in cmd;
|
|
32260
|
+
const hasFormat = "format" in cmd;
|
|
32261
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
32262
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
32263
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
32264
|
+
return 98 /* CommandResult.NoChanges */;
|
|
32265
|
+
}
|
|
32266
|
+
return 0 /* CommandResult.Success */;
|
|
32267
|
+
}
|
|
32209
32268
|
}
|
|
32210
32269
|
class FormulaCellWithDependencies {
|
|
32211
32270
|
id;
|
|
@@ -32543,7 +32602,13 @@ class ConditionalFormatPlugin extends CorePlugin {
|
|
|
32543
32602
|
}
|
|
32544
32603
|
}
|
|
32545
32604
|
exportForExcel(data) {
|
|
32546
|
-
|
|
32605
|
+
if (data.sheets) {
|
|
32606
|
+
for (let sheet of data.sheets) {
|
|
32607
|
+
if (this.cfRules[sheet.id]) {
|
|
32608
|
+
sheet.conditionalFormats = this.cfRules[sheet.id].map((rule) => this.mapToConditionalFormat(sheet.id, rule, { useFixedReference: true }));
|
|
32609
|
+
}
|
|
32610
|
+
}
|
|
32611
|
+
}
|
|
32547
32612
|
}
|
|
32548
32613
|
// ---------------------------------------------------------------------------
|
|
32549
32614
|
// Getters
|
|
@@ -32608,11 +32673,11 @@ class ConditionalFormatPlugin extends CorePlugin {
|
|
|
32608
32673
|
// ---------------------------------------------------------------------------
|
|
32609
32674
|
// Private
|
|
32610
32675
|
// ---------------------------------------------------------------------------
|
|
32611
|
-
mapToConditionalFormat(sheetId, cf) {
|
|
32676
|
+
mapToConditionalFormat(sheetId, cf, options = { useFixedReference: false }) {
|
|
32612
32677
|
return {
|
|
32613
32678
|
...cf,
|
|
32614
32679
|
ranges: cf.ranges.map((range) => {
|
|
32615
|
-
return this.getters.getRangeString(range, sheetId);
|
|
32680
|
+
return this.getters.getRangeString(range, sheetId, options.useFixedReference);
|
|
32616
32681
|
}),
|
|
32617
32682
|
};
|
|
32618
32683
|
}
|
|
@@ -34449,8 +34514,9 @@ class RangeAdapter {
|
|
|
34449
34514
|
*
|
|
34450
34515
|
* @param range the range (received from getRangeFromXC or getRangeFromZone)
|
|
34451
34516
|
* @param forSheetId the id of the sheet where the range string is supposed to be used.
|
|
34517
|
+
* @param [useFixedZone=false] if true, the range will be returned with fixed row and column
|
|
34452
34518
|
*/
|
|
34453
|
-
getRangeString(range, forSheetId) {
|
|
34519
|
+
getRangeString(range, forSheetId, useFixedZone = false) {
|
|
34454
34520
|
if (!range) {
|
|
34455
34521
|
return INCORRECT_RANGE_STRING;
|
|
34456
34522
|
}
|
|
@@ -34477,7 +34543,7 @@ class RangeAdapter {
|
|
|
34477
34543
|
if (prefixSheet && !sheetName) {
|
|
34478
34544
|
return INCORRECT_RANGE_STRING;
|
|
34479
34545
|
}
|
|
34480
|
-
let rangeString = this.getRangePartString(rangeImpl, 0);
|
|
34546
|
+
let rangeString = this.getRangePartString(rangeImpl, 0, useFixedZone);
|
|
34481
34547
|
if (rangeImpl.parts && rangeImpl.parts.length === 2) {
|
|
34482
34548
|
// this if converts A2:A2 into A2 except if any part of the original range had fixed row or column (with $)
|
|
34483
34549
|
if (rangeImpl.zone.top !== rangeImpl.zone.bottom ||
|
|
@@ -34487,7 +34553,7 @@ class RangeAdapter {
|
|
|
34487
34553
|
rangeImpl.parts[1].rowFixed ||
|
|
34488
34554
|
rangeImpl.parts[1].colFixed) {
|
|
34489
34555
|
rangeString += ":";
|
|
34490
|
-
rangeString += this.getRangePartString(rangeImpl, 1);
|
|
34556
|
+
rangeString += this.getRangePartString(rangeImpl, 1, useFixedZone);
|
|
34491
34557
|
}
|
|
34492
34558
|
}
|
|
34493
34559
|
return `${prefixSheet ? sheetName + "!" : ""}${rangeString}`;
|
|
@@ -34528,13 +34594,13 @@ class RangeAdapter {
|
|
|
34528
34594
|
/**
|
|
34529
34595
|
* Get a Xc string that represent a part of a range
|
|
34530
34596
|
*/
|
|
34531
|
-
getRangePartString(range, part) {
|
|
34597
|
+
getRangePartString(range, part, useFixedZone = false) {
|
|
34532
34598
|
const colFixed = range.parts && range.parts[part]?.colFixed ? "$" : "";
|
|
34533
34599
|
const col = part === 0 ? numberToLetters(range.zone.left) : numberToLetters(range.zone.right);
|
|
34534
34600
|
const rowFixed = range.parts && range.parts[part]?.rowFixed ? "$" : "";
|
|
34535
34601
|
const row = part === 0 ? String(range.zone.top + 1) : String(range.zone.bottom + 1);
|
|
34536
34602
|
let str = "";
|
|
34537
|
-
if (range.isFullCol) {
|
|
34603
|
+
if (range.isFullCol && !useFixedZone) {
|
|
34538
34604
|
if (part === 0 && range.unboundedZone.hasHeader) {
|
|
34539
34605
|
str = colFixed + col + rowFixed + row;
|
|
34540
34606
|
}
|
|
@@ -34542,7 +34608,7 @@ class RangeAdapter {
|
|
|
34542
34608
|
str = colFixed + col;
|
|
34543
34609
|
}
|
|
34544
34610
|
}
|
|
34545
|
-
else if (range.isFullRow) {
|
|
34611
|
+
else if (range.isFullRow && !useFixedZone) {
|
|
34546
34612
|
if (part === 0 && range.unboundedZone.hasHeader) {
|
|
34547
34613
|
str = colFixed + col + rowFixed + row;
|
|
34548
34614
|
}
|
|
@@ -36339,7 +36405,15 @@ class SpreadsheetRTree {
|
|
|
36339
36405
|
if (!this.rTrees[sheetId]) {
|
|
36340
36406
|
return;
|
|
36341
36407
|
}
|
|
36342
|
-
this.rTrees[sheetId].remove(item,
|
|
36408
|
+
this.rTrees[sheetId].remove(item, this.rtreeItemComparer);
|
|
36409
|
+
}
|
|
36410
|
+
rtreeItemComparer(left, right) {
|
|
36411
|
+
return (left.data == right.data &&
|
|
36412
|
+
left.boundingBox.sheetId === right.boundingBox.sheetId &&
|
|
36413
|
+
left.boundingBox?.zone.left === right.boundingBox.zone.left &&
|
|
36414
|
+
left.boundingBox?.zone.top === right.boundingBox.zone.top &&
|
|
36415
|
+
left.boundingBox?.zone.right === right.boundingBox.zone.right &&
|
|
36416
|
+
left.boundingBox?.zone.bottom === right.boundingBox.zone.bottom);
|
|
36343
36417
|
}
|
|
36344
36418
|
}
|
|
36345
36419
|
/**
|
|
@@ -36417,7 +36491,7 @@ class FormulaDependencyGraph {
|
|
|
36417
36491
|
const queue = Array.from(ranges).reverse();
|
|
36418
36492
|
while (queue.length > 0) {
|
|
36419
36493
|
const range = queue.pop();
|
|
36420
|
-
visited.
|
|
36494
|
+
visited.addMany(this.encoder.encodeBoundingBox(range));
|
|
36421
36495
|
const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
|
|
36422
36496
|
for (const positionId of impactedPositionIds) {
|
|
36423
36497
|
if (!visited.has(positionId)) {
|
|
@@ -36425,7 +36499,7 @@ class FormulaDependencyGraph {
|
|
|
36425
36499
|
}
|
|
36426
36500
|
}
|
|
36427
36501
|
}
|
|
36428
|
-
visited.
|
|
36502
|
+
visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
|
|
36429
36503
|
return visited;
|
|
36430
36504
|
}
|
|
36431
36505
|
}
|
|
@@ -36556,9 +36630,9 @@ class Evaluator {
|
|
|
36556
36630
|
const cells = positions.map((p) => this.encoder.encode(p));
|
|
36557
36631
|
const cellsToCompute = new JetSet(cells);
|
|
36558
36632
|
const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
|
|
36559
|
-
cellsToCompute.
|
|
36560
|
-
cellsToCompute.
|
|
36561
|
-
cellsToCompute.
|
|
36633
|
+
cellsToCompute.addMany(this.getCellsDependingOn(cells));
|
|
36634
|
+
cellsToCompute.addMany(arrayFormulasPositionIds);
|
|
36635
|
+
cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
|
|
36562
36636
|
this.evaluate(cellsToCompute);
|
|
36563
36637
|
}
|
|
36564
36638
|
getArrayFormulasImpactedByChangesOf(positionIds) {
|
|
@@ -36572,7 +36646,7 @@ class Evaluator {
|
|
|
36572
36646
|
}
|
|
36573
36647
|
if (!content) {
|
|
36574
36648
|
// The previous content could have blocked some array formulas
|
|
36575
|
-
impactedPositionIds.
|
|
36649
|
+
impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
|
|
36576
36650
|
}
|
|
36577
36651
|
}
|
|
36578
36652
|
return impactedPositionIds;
|
|
@@ -36620,7 +36694,7 @@ class Evaluator {
|
|
|
36620
36694
|
}
|
|
36621
36695
|
const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
|
|
36622
36696
|
const cells = new JetSet(arrayFormulas);
|
|
36623
|
-
cells.
|
|
36697
|
+
cells.addMany(this.getCellsDependingOn(arrayFormulas));
|
|
36624
36698
|
return cells;
|
|
36625
36699
|
}
|
|
36626
36700
|
nextPositionsToUpdate = new JetSet();
|
|
@@ -36771,7 +36845,7 @@ class Evaluator {
|
|
|
36771
36845
|
this.setEvaluatedCell(positionId, evaluatedCell);
|
|
36772
36846
|
// check if formula dependencies present in the spread zone
|
|
36773
36847
|
// if so, they need to be recomputed
|
|
36774
|
-
this.nextPositionsToUpdate.
|
|
36848
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
|
|
36775
36849
|
};
|
|
36776
36850
|
}
|
|
36777
36851
|
invalidateSpreading(positionId) {
|
|
@@ -36786,8 +36860,8 @@ class Evaluator {
|
|
|
36786
36860
|
continue;
|
|
36787
36861
|
}
|
|
36788
36862
|
this.evaluatedCells.delete(child);
|
|
36789
|
-
this.nextPositionsToUpdate.
|
|
36790
|
-
this.nextPositionsToUpdate.
|
|
36863
|
+
this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
|
|
36864
|
+
this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
|
|
36791
36865
|
}
|
|
36792
36866
|
this.spreadingRelations.removeNode(positionId);
|
|
36793
36867
|
}
|
|
@@ -37147,7 +37221,13 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
37147
37221
|
const format = newFormat
|
|
37148
37222
|
? getItemId(newFormat, data.formats)
|
|
37149
37223
|
: exportedCellData.format;
|
|
37150
|
-
|
|
37224
|
+
let content;
|
|
37225
|
+
if (formulaCell instanceof FormulaCellWithDependencies) {
|
|
37226
|
+
content = this.getters.buildFormulaContent(exportedSheetData.id, formulaCell, formulaCell.dependencies, true);
|
|
37227
|
+
}
|
|
37228
|
+
else {
|
|
37229
|
+
content = !isExported ? newContent : exportedCellData.content;
|
|
37230
|
+
}
|
|
37151
37231
|
exportedSheetData.cells[xc] = { ...exportedCellData, value, isFormula, content, format };
|
|
37152
37232
|
}
|
|
37153
37233
|
}
|
|
@@ -43666,7 +43746,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43666
43746
|
this.replaceText(ref, this.selectionInitialStart, this.selectionEnd);
|
|
43667
43747
|
}
|
|
43668
43748
|
getZoneReference(zone) {
|
|
43669
|
-
const inputSheetId = this.getters.getCurrentEditedCell().
|
|
43749
|
+
const inputSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
43670
43750
|
const sheetId = this.getters.getActiveSheetId();
|
|
43671
43751
|
const range = this.getters.getRangeFromZone(sheetId, zone);
|
|
43672
43752
|
return this.getters.getSelectionRangeString(range, inputSheetId);
|
|
@@ -43680,7 +43760,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43680
43760
|
_fixedParts.pop();
|
|
43681
43761
|
}
|
|
43682
43762
|
const newRange = range.clone({ parts: _fixedParts });
|
|
43683
|
-
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().
|
|
43763
|
+
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId());
|
|
43684
43764
|
}
|
|
43685
43765
|
/**
|
|
43686
43766
|
* Replace the current selection by a new text.
|
|
@@ -43713,7 +43793,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43713
43793
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
43714
43794
|
return;
|
|
43715
43795
|
}
|
|
43716
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
43796
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
43717
43797
|
const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
|
|
43718
43798
|
const colorsToKeep = {};
|
|
43719
43799
|
for (const xc of XCs) {
|
|
@@ -43742,7 +43822,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43742
43822
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
43743
43823
|
return [];
|
|
43744
43824
|
}
|
|
43745
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
43825
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
43746
43826
|
const rangeColor = (rangeString) => {
|
|
43747
43827
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
43748
43828
|
return colors$1[colorIndex % colors$1.length];
|
|
@@ -43760,7 +43840,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
43760
43840
|
* Return ranges currently referenced in the composer
|
|
43761
43841
|
*/
|
|
43762
43842
|
getReferencedRanges() {
|
|
43763
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
43843
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
43764
43844
|
const referenceRanges = this.currentTokens
|
|
43765
43845
|
.filter((token) => token.type === "REFERENCE")
|
|
43766
43846
|
.map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
|
|
@@ -45724,6 +45804,16 @@ class ImageProvider {
|
|
|
45724
45804
|
}
|
|
45725
45805
|
}
|
|
45726
45806
|
|
|
45807
|
+
class FocusableElement {
|
|
45808
|
+
focusableElement = undefined;
|
|
45809
|
+
setFocusableElement(element) {
|
|
45810
|
+
this.focusableElement = element;
|
|
45811
|
+
}
|
|
45812
|
+
focus() {
|
|
45813
|
+
this.focusableElement?.focus();
|
|
45814
|
+
}
|
|
45815
|
+
}
|
|
45816
|
+
|
|
45727
45817
|
const RIPPLE_KEY_FRAMES = [
|
|
45728
45818
|
{ transform: "scale(0)" },
|
|
45729
45819
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -47766,6 +47856,7 @@ class Spreadsheet extends owl.Component {
|
|
|
47766
47856
|
_t: Spreadsheet._t,
|
|
47767
47857
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
47768
47858
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
47859
|
+
focusableElement: new FocusableElement(),
|
|
47769
47860
|
});
|
|
47770
47861
|
owl.useExternalListener(window, "resize", () => this.render(true));
|
|
47771
47862
|
owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
@@ -47872,17 +47963,18 @@ class Spreadsheet extends owl.Component {
|
|
|
47872
47963
|
this.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
47873
47964
|
this.composer.topBarFocus = "contentFocus";
|
|
47874
47965
|
this.composer.gridFocusMode = "inactive";
|
|
47875
|
-
this.setComposerContent({ selection }
|
|
47966
|
+
this.setComposerContent({ selection });
|
|
47876
47967
|
}
|
|
47877
|
-
onGridComposerContentFocused() {
|
|
47968
|
+
onGridComposerContentFocused(selection) {
|
|
47878
47969
|
if (this.model.getters.isReadonly()) {
|
|
47879
47970
|
return;
|
|
47880
47971
|
}
|
|
47881
47972
|
this.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
47882
47973
|
this.composer.topBarFocus = "inactive";
|
|
47883
47974
|
this.composer.gridFocusMode = "contentFocus";
|
|
47884
|
-
this.setComposerContent({});
|
|
47975
|
+
this.setComposerContent({ selection });
|
|
47885
47976
|
}
|
|
47977
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
47886
47978
|
onGridComposerCellFocused(content, selection) {
|
|
47887
47979
|
if (this.model.getters.isReadonly()) {
|
|
47888
47980
|
return;
|
|
@@ -49294,11 +49386,10 @@ class SelectionStreamProcessorImpl {
|
|
|
49294
49386
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
49295
49387
|
*/
|
|
49296
49388
|
getEndOfCluster(startPosition, dim, dir) {
|
|
49297
|
-
const sheet = this.getters.getActiveSheet();
|
|
49298
49389
|
let currentPosition = startPosition;
|
|
49299
49390
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
49300
49391
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
49301
|
-
let mode = !this.
|
|
49392
|
+
let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
|
|
49302
49393
|
? "endOfCluster"
|
|
49303
49394
|
: "nextCluster";
|
|
49304
49395
|
while (true) {
|
|
@@ -49308,7 +49399,7 @@ class SelectionStreamProcessorImpl {
|
|
|
49308
49399
|
currentPosition.row === nextCellPosition.row) {
|
|
49309
49400
|
break;
|
|
49310
49401
|
}
|
|
49311
|
-
const isNextCellEmpty = this.
|
|
49402
|
+
const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
|
|
49312
49403
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
49313
49404
|
break;
|
|
49314
49405
|
}
|
|
@@ -49322,10 +49413,20 @@ class SelectionStreamProcessorImpl {
|
|
|
49322
49413
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
49323
49414
|
}
|
|
49324
49415
|
/**
|
|
49325
|
-
*
|
|
49326
|
-
* check
|
|
49416
|
+
* Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
|
|
49417
|
+
* the check applies to the main cell of the merge.
|
|
49327
49418
|
*/
|
|
49328
|
-
isCellEmpty({ col, row }
|
|
49419
|
+
isCellEmpty({ col, row }) {
|
|
49420
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
49421
|
+
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
49422
|
+
return !(this.getters.getCorrespondingFormulaCell(position) || this.getters.getCell(position)?.content);
|
|
49423
|
+
}
|
|
49424
|
+
/**
|
|
49425
|
+
* Checks if a cell evaluated value is empty. If the cell is part of a merge,
|
|
49426
|
+
* the check applies to the main cell of the merge.
|
|
49427
|
+
*/
|
|
49428
|
+
isEvaluatedCellEmpty({ col, row }) {
|
|
49429
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
49329
49430
|
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
49330
49431
|
const cell = this.getters.getEvaluatedCell(position);
|
|
49331
49432
|
return cell.type === CellValueType.empty;
|
|
@@ -49803,12 +49904,7 @@ function addFormula(cell) {
|
|
|
49803
49904
|
attrs.push(["t", "str"]);
|
|
49804
49905
|
cycle = escapeXml /*xml*/ `<v>${cell.value}</v>`;
|
|
49805
49906
|
}
|
|
49806
|
-
node = escapeXml /*xml*/ `
|
|
49807
|
-
<f>
|
|
49808
|
-
${XlsxFormula}
|
|
49809
|
-
</f>
|
|
49810
|
-
${cycle}
|
|
49811
|
-
`;
|
|
49907
|
+
node = escapeXml /*xml*/ ` <f> ${XlsxFormula} </f> ${cycle} `;
|
|
49812
49908
|
return { attrs, node };
|
|
49813
49909
|
}
|
|
49814
49910
|
function addContent(content, sharedStrings, forceString = false) {
|
|
@@ -50627,11 +50723,10 @@ function addRows(construct, data, sheet) {
|
|
|
50627
50723
|
({ attrs: additionalAttrs, node: cellNode } = addContent(cell.content, construct.sharedStrings, isTableHeader));
|
|
50628
50724
|
}
|
|
50629
50725
|
attributes.push(...additionalAttrs);
|
|
50630
|
-
|
|
50631
|
-
|
|
50632
|
-
|
|
50633
|
-
|
|
50634
|
-
`);
|
|
50726
|
+
// prettier-ignore
|
|
50727
|
+
cellNodes.push(escapeXml /*xml*/ `<c ${formatAttributes(attributes)}>
|
|
50728
|
+
${cellNode}
|
|
50729
|
+
</c>`);
|
|
50635
50730
|
}
|
|
50636
50731
|
}
|
|
50637
50732
|
if (cellNodes.length || row.size !== DEFAULT_CELL_HEIGHT || row.isHidden) {
|
|
@@ -51612,6 +51707,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
51612
51707
|
exports.tokenize = tokenize;
|
|
51613
51708
|
|
|
51614
51709
|
|
|
51615
|
-
__info__.version = '16.4.
|
|
51616
|
-
__info__.date = '2024-
|
|
51617
|
-
__info__.hash = '
|
|
51710
|
+
__info__.version = '16.4.23';
|
|
51711
|
+
__info__.date = '2024-02-16T14:23:29.521Z';
|
|
51712
|
+
__info__.hash = 'cb5db1a';
|