@odoo/o-spreadsheet 16.3.24 → 16.3.26
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 +219 -124
- package/dist/o-spreadsheet.d.ts +29 -14
- package/dist/o-spreadsheet.esm.js +219 -124
- package/dist/o-spreadsheet.iife.js +219 -124
- package/dist/o-spreadsheet.iife.min.js +141 -141
- package/dist/o_spreadsheet.xml +15 -33
- package/package.json +1 -1
|
@@ -1746,6 +1746,9 @@ function parseFormat(formatString) {
|
|
|
1746
1746
|
function formatValue(value, format) {
|
|
1747
1747
|
switch (typeof value) {
|
|
1748
1748
|
case "string":
|
|
1749
|
+
if (value.includes('\\"')) {
|
|
1750
|
+
return value.replace(/\\"/g, '"');
|
|
1751
|
+
}
|
|
1749
1752
|
return value;
|
|
1750
1753
|
case "boolean":
|
|
1751
1754
|
return value ? "TRUE" : "FALSE";
|
|
@@ -9433,6 +9436,12 @@ const INSERT_LINK = (env) => {
|
|
|
9433
9436
|
let { col, row } = env.model.getters.getActivePosition();
|
|
9434
9437
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
9435
9438
|
};
|
|
9439
|
+
const INSERT_LINK_NAME = (env) => {
|
|
9440
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
9441
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
9442
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
9443
|
+
return cell && cell.link ? _lt("Edit link") : _lt("Insert link");
|
|
9444
|
+
};
|
|
9436
9445
|
//------------------------------------------------------------------------------
|
|
9437
9446
|
// Filters action
|
|
9438
9447
|
//------------------------------------------------------------------------------
|
|
@@ -16657,7 +16666,7 @@ cellMenuRegistry
|
|
|
16657
16666
|
})
|
|
16658
16667
|
.add("insert_link", {
|
|
16659
16668
|
...insertLink,
|
|
16660
|
-
name:
|
|
16669
|
+
name: INSERT_LINK_NAME,
|
|
16661
16670
|
sequence: 150,
|
|
16662
16671
|
separator: true,
|
|
16663
16672
|
});
|
|
@@ -20984,6 +20993,7 @@ class Composer extends owl.Component {
|
|
|
20984
20993
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
20985
20994
|
static defaultProps = {
|
|
20986
20995
|
inputStyle: "",
|
|
20996
|
+
isDefaultFocus: false,
|
|
20987
20997
|
};
|
|
20988
20998
|
composerRef = owl.useRef("o_composer");
|
|
20989
20999
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -21041,13 +21051,13 @@ class Composer extends owl.Component {
|
|
|
21041
21051
|
setup() {
|
|
21042
21052
|
owl.onMounted(() => {
|
|
21043
21053
|
const el = this.composerRef.el;
|
|
21054
|
+
if (this.props.isDefaultFocus) {
|
|
21055
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
21056
|
+
}
|
|
21044
21057
|
this.contentHelper.updateEl(el);
|
|
21045
21058
|
this.processContent();
|
|
21046
21059
|
this.contentHelper.scrollSelectionIntoView();
|
|
21047
21060
|
});
|
|
21048
|
-
owl.onWillUnmount(() => {
|
|
21049
|
-
this.props.onComposerUnmounted?.();
|
|
21050
|
-
});
|
|
21051
21061
|
owl.onPatched(() => {
|
|
21052
21062
|
if (!this.isKeyStillDown) {
|
|
21053
21063
|
this.processContent();
|
|
@@ -21058,7 +21068,8 @@ class Composer extends owl.Component {
|
|
|
21058
21068
|
// Handlers
|
|
21059
21069
|
// ---------------------------------------------------------------------------
|
|
21060
21070
|
processArrowKeys(ev) {
|
|
21061
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
21071
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
21072
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
21062
21073
|
this.functionDescriptionState.showDescription = false;
|
|
21063
21074
|
// Prevent the default content editable behavior which moves the cursor
|
|
21064
21075
|
ev.preventDefault();
|
|
@@ -21098,21 +21109,23 @@ class Composer extends owl.Component {
|
|
|
21098
21109
|
processTabKey(ev) {
|
|
21099
21110
|
ev.preventDefault();
|
|
21100
21111
|
ev.stopPropagation();
|
|
21101
|
-
if (this.
|
|
21102
|
-
|
|
21103
|
-
|
|
21104
|
-
|
|
21105
|
-
|
|
21112
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
21113
|
+
if (this.autoCompleteState.showProvider) {
|
|
21114
|
+
const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
|
|
21115
|
+
if (autoCompleteValue) {
|
|
21116
|
+
this.autoComplete(autoCompleteValue);
|
|
21117
|
+
return;
|
|
21118
|
+
}
|
|
21106
21119
|
}
|
|
21107
|
-
|
|
21108
|
-
|
|
21109
|
-
|
|
21110
|
-
|
|
21111
|
-
|
|
21112
|
-
|
|
21120
|
+
else {
|
|
21121
|
+
// when completing with tab, if there is no value to complete, the active cell will be moved to the right.
|
|
21122
|
+
// we can't let the model think that it is for a ref selection.
|
|
21123
|
+
// todo: check if this can be removed someday
|
|
21124
|
+
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21125
|
+
}
|
|
21126
|
+
this.env.model.dispatch("STOP_EDITION");
|
|
21113
21127
|
}
|
|
21114
21128
|
const direction = ev.shiftKey ? "left" : "right";
|
|
21115
|
-
this.env.model.dispatch("STOP_EDITION");
|
|
21116
21129
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
21117
21130
|
}
|
|
21118
21131
|
processEnterKey(ev) {
|
|
@@ -21156,6 +21169,9 @@ class Composer extends owl.Component {
|
|
|
21156
21169
|
this.compositionActive = false;
|
|
21157
21170
|
}
|
|
21158
21171
|
onKeydown(ev) {
|
|
21172
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
21173
|
+
return;
|
|
21174
|
+
}
|
|
21159
21175
|
let handler = this.keyMapping[ev.key];
|
|
21160
21176
|
if (handler) {
|
|
21161
21177
|
handler.call(this, ev);
|
|
@@ -21166,22 +21182,44 @@ class Composer extends owl.Component {
|
|
|
21166
21182
|
}
|
|
21167
21183
|
}
|
|
21168
21184
|
updateCursorIfNeeded() {
|
|
21169
|
-
|
|
21185
|
+
const moveCursor = !this.env.model.getters.isSelectingForComposer() &&
|
|
21186
|
+
!(this.env.model.getters.getEditionMode() === "inactive");
|
|
21187
|
+
if (moveCursor) {
|
|
21170
21188
|
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
21171
21189
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
|
|
21172
21190
|
this.isKeyStillDown = true;
|
|
21173
21191
|
}
|
|
21174
21192
|
}
|
|
21193
|
+
onPaste(ev) {
|
|
21194
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
21195
|
+
ev.stopPropagation();
|
|
21196
|
+
}
|
|
21197
|
+
}
|
|
21175
21198
|
/*
|
|
21176
21199
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
21177
21200
|
* */
|
|
21178
|
-
onInput() {
|
|
21179
|
-
if (
|
|
21201
|
+
onInput(ev) {
|
|
21202
|
+
if (!this.shouldProcessInputEvents) {
|
|
21180
21203
|
return;
|
|
21181
21204
|
}
|
|
21205
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
21206
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
21207
|
+
return;
|
|
21208
|
+
}
|
|
21209
|
+
ev.stopPropagation();
|
|
21210
|
+
let content;
|
|
21211
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
21212
|
+
content = ev.data || "";
|
|
21213
|
+
}
|
|
21214
|
+
else {
|
|
21215
|
+
content = this.contentHelper.getText();
|
|
21216
|
+
}
|
|
21217
|
+
if (this.props.focus === "inactive") {
|
|
21218
|
+
return this.props.onComposerCellFocused?.(content);
|
|
21219
|
+
}
|
|
21182
21220
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21183
21221
|
this.env.model.dispatch("SET_CURRENT_CONTENT", {
|
|
21184
|
-
content
|
|
21222
|
+
content,
|
|
21185
21223
|
selection: this.contentHelper.getCurrentSelection(),
|
|
21186
21224
|
});
|
|
21187
21225
|
}
|
|
@@ -21252,9 +21290,8 @@ class Composer extends owl.Component {
|
|
|
21252
21290
|
}
|
|
21253
21291
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
21254
21292
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21255
|
-
|
|
21256
|
-
|
|
21257
|
-
}
|
|
21293
|
+
this.props.onComposerContentFocused();
|
|
21294
|
+
if (this.props.focus === "inactive") ;
|
|
21258
21295
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
21259
21296
|
this.processTokenAtCursor();
|
|
21260
21297
|
}
|
|
@@ -21398,7 +21435,7 @@ class Composer extends owl.Component {
|
|
|
21398
21435
|
const highlights = this.env.model.getters.getHighlights();
|
|
21399
21436
|
const refSheet = sheetName
|
|
21400
21437
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
21401
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
21438
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
21402
21439
|
const highlight = highlights.find((highlight) => {
|
|
21403
21440
|
if (highlight.sheetId !== refSheet)
|
|
21404
21441
|
return false;
|
|
@@ -21475,12 +21512,13 @@ class Composer extends owl.Component {
|
|
|
21475
21512
|
}
|
|
21476
21513
|
}
|
|
21477
21514
|
Composer.props = {
|
|
21478
|
-
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
21479
|
-
onComposerContentFocused: Function,
|
|
21480
21515
|
inputStyle: { type: String, optional: true },
|
|
21481
21516
|
rect: { type: Object, optional: true },
|
|
21482
21517
|
delimitation: { type: Object, optional: true },
|
|
21483
|
-
|
|
21518
|
+
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
21519
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
21520
|
+
onComposerContentFocused: Function,
|
|
21521
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
21484
21522
|
};
|
|
21485
21523
|
|
|
21486
21524
|
const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
|
|
@@ -21514,51 +21552,26 @@ css /* scss */ `
|
|
|
21514
21552
|
class GridComposer extends owl.Component {
|
|
21515
21553
|
static template = "o-spreadsheet-GridComposer";
|
|
21516
21554
|
static components = { Composer };
|
|
21517
|
-
|
|
21518
|
-
|
|
21519
|
-
|
|
21555
|
+
// TODORAR see if we can keep it undefined
|
|
21556
|
+
rect = this.defaultRect;
|
|
21557
|
+
isEditing = false;
|
|
21520
21558
|
isCellReferenceVisible;
|
|
21521
|
-
|
|
21559
|
+
get defaultRect() {
|
|
21560
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
21561
|
+
}
|
|
21522
21562
|
setup() {
|
|
21523
|
-
this.gridComposerRef = owl.useRef("gridComposer");
|
|
21524
|
-
this.composerState = owl.useState({
|
|
21525
|
-
rect: undefined,
|
|
21526
|
-
delimitation: undefined,
|
|
21527
|
-
});
|
|
21528
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
21529
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
21530
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
21531
|
-
this.isCellReferenceVisible = false;
|
|
21532
|
-
owl.onMounted(() => {
|
|
21533
|
-
const el = this.gridComposerRef.el;
|
|
21534
|
-
this.composerState.rect = {
|
|
21535
|
-
x: this.rect.x,
|
|
21536
|
-
y: this.rect.y,
|
|
21537
|
-
width: el.clientWidth,
|
|
21538
|
-
height: el.clientHeight,
|
|
21539
|
-
};
|
|
21540
|
-
this.composerState.delimitation = {
|
|
21541
|
-
width: el.parentElement.clientWidth,
|
|
21542
|
-
height: el.parentElement.clientHeight,
|
|
21543
|
-
};
|
|
21544
|
-
});
|
|
21545
21563
|
owl.onWillUpdateProps(() => {
|
|
21546
|
-
|
|
21547
|
-
|
|
21548
|
-
}
|
|
21549
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
21550
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
21551
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
21552
|
-
if (!deepEquals(rect, this.rect) ||
|
|
21553
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
21554
|
-
this.isCellReferenceVisible = true;
|
|
21555
|
-
}
|
|
21564
|
+
this.updateComponentPosition();
|
|
21565
|
+
this.updateCellReferenceVisibility();
|
|
21556
21566
|
});
|
|
21557
21567
|
}
|
|
21558
21568
|
get shouldDisplayCellReference() {
|
|
21559
21569
|
return this.isCellReferenceVisible;
|
|
21560
21570
|
}
|
|
21561
21571
|
get cellReference() {
|
|
21572
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
21573
|
+
return "";
|
|
21574
|
+
}
|
|
21562
21575
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
21563
21576
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
21564
21577
|
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
@@ -21570,7 +21583,27 @@ class GridComposer extends owl.Component {
|
|
|
21570
21583
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
21571
21584
|
});
|
|
21572
21585
|
}
|
|
21586
|
+
get composerProps() {
|
|
21587
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
21588
|
+
return {
|
|
21589
|
+
rect: { ...this.rect },
|
|
21590
|
+
delimitation: {
|
|
21591
|
+
width,
|
|
21592
|
+
height,
|
|
21593
|
+
},
|
|
21594
|
+
focus: this.props.focus,
|
|
21595
|
+
isDefaultFocus: true,
|
|
21596
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
21597
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
21598
|
+
};
|
|
21599
|
+
}
|
|
21573
21600
|
get containerStyle() {
|
|
21601
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
21602
|
+
return `
|
|
21603
|
+
position: absolute;
|
|
21604
|
+
z-index: -1000;
|
|
21605
|
+
`;
|
|
21606
|
+
}
|
|
21574
21607
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
21575
21608
|
const cell = this.env.model.getters.getActiveCell();
|
|
21576
21609
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -21590,6 +21623,8 @@ class GridComposer extends owl.Component {
|
|
|
21590
21623
|
if (!isFormula) {
|
|
21591
21624
|
textAlign = style.align || cell.defaultAlign;
|
|
21592
21625
|
}
|
|
21626
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
21627
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
21593
21628
|
/**
|
|
21594
21629
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
21595
21630
|
* including all the paddings/margins of the composer
|
|
@@ -21601,6 +21636,8 @@ class GridComposer extends owl.Component {
|
|
|
21601
21636
|
top: `${top}px`,
|
|
21602
21637
|
"min-width": `${width + 1}px`,
|
|
21603
21638
|
"min-height": `${height + 1}px`,
|
|
21639
|
+
"max-width": `${maxWidth}px`,
|
|
21640
|
+
"max-height": `${maxHeight}px`,
|
|
21604
21641
|
background,
|
|
21605
21642
|
color,
|
|
21606
21643
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -21610,20 +21647,38 @@ class GridComposer extends owl.Component {
|
|
|
21610
21647
|
"text-align": textAlign,
|
|
21611
21648
|
});
|
|
21612
21649
|
}
|
|
21613
|
-
|
|
21614
|
-
const
|
|
21615
|
-
|
|
21616
|
-
|
|
21617
|
-
|
|
21618
|
-
|
|
21619
|
-
|
|
21650
|
+
updateComponentPosition() {
|
|
21651
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
21652
|
+
if (this.isEditing !== isEditing) {
|
|
21653
|
+
this.isEditing = isEditing;
|
|
21654
|
+
if (!isEditing) {
|
|
21655
|
+
this.rect = this.defaultRect;
|
|
21656
|
+
this.env.focusableElement.focus();
|
|
21657
|
+
return;
|
|
21658
|
+
}
|
|
21659
|
+
const position = this.env.model.getters.getActivePosition();
|
|
21660
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
21661
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
21662
|
+
}
|
|
21663
|
+
}
|
|
21664
|
+
updateCellReferenceVisibility() {
|
|
21665
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
21666
|
+
return;
|
|
21667
|
+
}
|
|
21668
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
21669
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
21670
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
21671
|
+
if (!deepEquals(rect, this.rect) ||
|
|
21672
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
21673
|
+
this.isCellReferenceVisible = true;
|
|
21674
|
+
}
|
|
21620
21675
|
}
|
|
21621
21676
|
}
|
|
21622
21677
|
GridComposer.props = {
|
|
21623
21678
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
21624
|
-
onComposerUnmounted: Function,
|
|
21625
21679
|
onComposerContentFocused: Function,
|
|
21626
21680
|
gridDims: Object,
|
|
21681
|
+
onComposerCellFocused: Function,
|
|
21627
21682
|
};
|
|
21628
21683
|
|
|
21629
21684
|
const CSS$1 = css /* scss */ `
|
|
@@ -22492,7 +22547,6 @@ class GridOverlay extends owl.Component {
|
|
|
22492
22547
|
this.props.onCellDoubleClicked(col, row);
|
|
22493
22548
|
}
|
|
22494
22549
|
onContextMenu(ev) {
|
|
22495
|
-
ev.preventDefault();
|
|
22496
22550
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
22497
22551
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
22498
22552
|
}
|
|
@@ -23586,7 +23640,6 @@ class Grid extends owl.Component {
|
|
|
23586
23640
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
23587
23641
|
menuState;
|
|
23588
23642
|
gridRef;
|
|
23589
|
-
hiddenInput;
|
|
23590
23643
|
onMouseWheel;
|
|
23591
23644
|
canvasPosition;
|
|
23592
23645
|
hoveredCell;
|
|
@@ -23597,17 +23650,16 @@ class Grid extends owl.Component {
|
|
|
23597
23650
|
menuItems: [],
|
|
23598
23651
|
});
|
|
23599
23652
|
this.gridRef = owl.useRef("grid");
|
|
23600
|
-
this.hiddenInput = owl.useRef("hiddenInput");
|
|
23601
23653
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
23602
23654
|
this.hoveredCell = owl.useState({ col: undefined, row: undefined });
|
|
23603
23655
|
owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
23604
23656
|
owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
23605
23657
|
owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
23606
23658
|
owl.useExternalListener(document.body, "paste", this.paste);
|
|
23607
|
-
owl.onMounted(() => this.
|
|
23608
|
-
this.props.exposeFocus(() => this.
|
|
23659
|
+
owl.onMounted(() => this.focusDefaultElement());
|
|
23660
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
23609
23661
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
23610
|
-
owl.useEffect(() => this.
|
|
23662
|
+
owl.useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
23611
23663
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
23612
23664
|
this.moveCanvas(deltaX, deltaY);
|
|
23613
23665
|
this.hoveredCell.col = undefined;
|
|
@@ -23630,7 +23682,7 @@ class Grid extends owl.Component {
|
|
|
23630
23682
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
23631
23683
|
this.closeOpenedPopover();
|
|
23632
23684
|
}
|
|
23633
|
-
this.
|
|
23685
|
+
this.focusDefaultElement();
|
|
23634
23686
|
}
|
|
23635
23687
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
23636
23688
|
// down itself
|
|
@@ -23800,10 +23852,10 @@ class Grid extends owl.Component {
|
|
|
23800
23852
|
PAGEUP: () => this.env.model.dispatch("SHIFT_VIEWPORT_UP"),
|
|
23801
23853
|
"CTRL+K": () => INSERT_LINK(this.env),
|
|
23802
23854
|
};
|
|
23803
|
-
|
|
23855
|
+
focusDefaultElement() {
|
|
23804
23856
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
23805
23857
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
23806
|
-
this.
|
|
23858
|
+
this.env.focusableElement.focus();
|
|
23807
23859
|
}
|
|
23808
23860
|
}
|
|
23809
23861
|
get gridEl() {
|
|
@@ -23947,19 +23999,6 @@ class Grid extends owl.Component {
|
|
|
23947
23999
|
return;
|
|
23948
24000
|
}
|
|
23949
24001
|
}
|
|
23950
|
-
onInput(ev) {
|
|
23951
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
23952
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
23953
|
-
return;
|
|
23954
|
-
}
|
|
23955
|
-
if (ev.data) {
|
|
23956
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
23957
|
-
// character
|
|
23958
|
-
ev.preventDefault();
|
|
23959
|
-
ev.stopPropagation();
|
|
23960
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
23961
|
-
}
|
|
23962
|
-
}
|
|
23963
24002
|
// ---------------------------------------------------------------------------
|
|
23964
24003
|
// Context Menu
|
|
23965
24004
|
// ---------------------------------------------------------------------------
|
|
@@ -24069,7 +24108,7 @@ class Grid extends owl.Component {
|
|
|
24069
24108
|
}
|
|
24070
24109
|
closeMenu() {
|
|
24071
24110
|
this.menuState.isOpen = false;
|
|
24072
|
-
this.
|
|
24111
|
+
this.focusDefaultElement();
|
|
24073
24112
|
}
|
|
24074
24113
|
}
|
|
24075
24114
|
Grid.props = {
|
|
@@ -28729,6 +28768,31 @@ const MIGRATIONS = [
|
|
|
28729
28768
|
return data;
|
|
28730
28769
|
},
|
|
28731
28770
|
},
|
|
28771
|
+
{
|
|
28772
|
+
description: "Fix datafilter duplication",
|
|
28773
|
+
from: 12,
|
|
28774
|
+
to: 12.5,
|
|
28775
|
+
applyMigration(data) {
|
|
28776
|
+
for (let sheet of data.sheets || []) {
|
|
28777
|
+
let knownDataFilterZones = [];
|
|
28778
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
28779
|
+
const zone = toZone(filterTable.range);
|
|
28780
|
+
// See commit message for the details
|
|
28781
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
28782
|
+
if (intersectZoneIndex !== -1) {
|
|
28783
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
28784
|
+
}
|
|
28785
|
+
else {
|
|
28786
|
+
knownDataFilterZones.push(zone);
|
|
28787
|
+
}
|
|
28788
|
+
}
|
|
28789
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
28790
|
+
range: zoneToXc(zone),
|
|
28791
|
+
}));
|
|
28792
|
+
}
|
|
28793
|
+
return data;
|
|
28794
|
+
},
|
|
28795
|
+
},
|
|
28732
28796
|
{
|
|
28733
28797
|
description: "Change Border description structure",
|
|
28734
28798
|
from: 12,
|
|
@@ -29630,9 +29694,9 @@ class CellPlugin extends CorePlugin {
|
|
|
29630
29694
|
allowDispatch(cmd) {
|
|
29631
29695
|
switch (cmd.type) {
|
|
29632
29696
|
case "UPDATE_CELL":
|
|
29633
|
-
return this.
|
|
29697
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
29634
29698
|
case "CLEAR_CELL":
|
|
29635
|
-
return this.checkValidations(cmd, this.
|
|
29699
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
29636
29700
|
default:
|
|
29637
29701
|
return 0 /* CommandResult.Success */;
|
|
29638
29702
|
}
|
|
@@ -29764,10 +29828,6 @@ class CellPlugin extends CorePlugin {
|
|
|
29764
29828
|
format: cell.format ? getItemId(cell.format, formats) : undefined,
|
|
29765
29829
|
content: cell.content || undefined,
|
|
29766
29830
|
};
|
|
29767
|
-
// if there is a formula but no dependencies (maybe because the cell is in error), no need to recompute the formula text
|
|
29768
|
-
if (cell.isFormula && cell.dependencies.length) {
|
|
29769
|
-
cells[xc].content = this.buildFormulaContent(_sheet.id, cell, cell.dependencies, true);
|
|
29770
|
-
}
|
|
29771
29831
|
}
|
|
29772
29832
|
_sheet.cells = cells;
|
|
29773
29833
|
}
|
|
@@ -29930,7 +29990,7 @@ class CellPlugin extends CorePlugin {
|
|
|
29930
29990
|
else {
|
|
29931
29991
|
style = before ? before.style : undefined;
|
|
29932
29992
|
}
|
|
29933
|
-
|
|
29993
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
29934
29994
|
/* Read the following IF as:
|
|
29935
29995
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
29936
29996
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -29974,7 +30034,7 @@ class CellPlugin extends CorePlugin {
|
|
|
29974
30034
|
id,
|
|
29975
30035
|
content,
|
|
29976
30036
|
style,
|
|
29977
|
-
format,
|
|
30037
|
+
format: format || detectFormat(content),
|
|
29978
30038
|
isFormula: false,
|
|
29979
30039
|
};
|
|
29980
30040
|
}
|
|
@@ -30051,6 +30111,18 @@ class CellPlugin extends CorePlugin {
|
|
|
30051
30111
|
}
|
|
30052
30112
|
return 0 /* CommandResult.Success */;
|
|
30053
30113
|
}
|
|
30114
|
+
checkUselessUpdateCell(cmd) {
|
|
30115
|
+
const cell = this.getters.getCell(cmd);
|
|
30116
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
30117
|
+
const hasStyle = "style" in cmd;
|
|
30118
|
+
const hasFormat = "format" in cmd;
|
|
30119
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
30120
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
30121
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
30122
|
+
return 94 /* CommandResult.NoChanges */;
|
|
30123
|
+
}
|
|
30124
|
+
return 0 /* CommandResult.Success */;
|
|
30125
|
+
}
|
|
30054
30126
|
}
|
|
30055
30127
|
|
|
30056
30128
|
class ChartPlugin extends CorePlugin {
|
|
@@ -33842,6 +33914,10 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
33842
33914
|
if (cell.format !== evaluatedCell.format) {
|
|
33843
33915
|
exportedCellData.computedFormat = evaluatedCell.format;
|
|
33844
33916
|
}
|
|
33917
|
+
// if there is a formula but no dependencies (maybe because the cell is in error), no need to recompute the formula text
|
|
33918
|
+
if (cell.isFormula && cell.dependencies.length) {
|
|
33919
|
+
exportedCellData.content = this.getters.buildFormulaContent(sheet.id, cell, cell.dependencies, true);
|
|
33920
|
+
}
|
|
33845
33921
|
}
|
|
33846
33922
|
}
|
|
33847
33923
|
}
|
|
@@ -35710,8 +35786,7 @@ class AutofillPlugin extends UIPlugin {
|
|
|
35710
35786
|
let row = zone.bottom;
|
|
35711
35787
|
if (col > 0) {
|
|
35712
35788
|
let leftPosition = { sheetId, col: col - 1, row };
|
|
35713
|
-
while (this.getters.
|
|
35714
|
-
this.getters.getCell(leftPosition)?.content) {
|
|
35789
|
+
while (this.getters.getCell(leftPosition)?.content) {
|
|
35715
35790
|
row += 1;
|
|
35716
35791
|
leftPosition = { sheetId, col: col - 1, row };
|
|
35717
35792
|
}
|
|
@@ -35720,8 +35795,7 @@ class AutofillPlugin extends UIPlugin {
|
|
|
35720
35795
|
col = zone.right;
|
|
35721
35796
|
if (col <= this.getters.getNumberCols(sheetId)) {
|
|
35722
35797
|
let rightPosition = { sheetId, col: col + 1, row };
|
|
35723
|
-
while (this.getters.
|
|
35724
|
-
this.getters.getCell(rightPosition)?.content) {
|
|
35798
|
+
while (this.getters.getCell(rightPosition)?.content) {
|
|
35725
35799
|
row += 1;
|
|
35726
35800
|
rightPosition = { sheetId, col: col + 1, row };
|
|
35727
35801
|
}
|
|
@@ -41186,7 +41260,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
41186
41260
|
getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
|
|
41187
41261
|
const sheetId = this.getters.getActiveSheetId();
|
|
41188
41262
|
let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
|
|
41189
|
-
if (this.getters.getCurrentEditedCell()
|
|
41263
|
+
if (this.getters.getCurrentEditedCell()?.sheetId !== this.getters.getActiveSheetId()) {
|
|
41190
41264
|
const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
|
|
41191
41265
|
selectedXc = `${sheetName}!${selectedXc}`;
|
|
41192
41266
|
}
|
|
@@ -41201,7 +41275,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
41201
41275
|
_fixedParts.pop();
|
|
41202
41276
|
}
|
|
41203
41277
|
const newRange = range.clone({ parts: _fixedParts });
|
|
41204
|
-
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().
|
|
41278
|
+
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId());
|
|
41205
41279
|
}
|
|
41206
41280
|
/**
|
|
41207
41281
|
* Replace the current selection by a new text.
|
|
@@ -41234,7 +41308,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
41234
41308
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
41235
41309
|
return;
|
|
41236
41310
|
}
|
|
41237
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
41311
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
41238
41312
|
const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
|
|
41239
41313
|
const colorsToKeep = {};
|
|
41240
41314
|
for (const xc of XCs) {
|
|
@@ -41263,7 +41337,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
41263
41337
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
41264
41338
|
return [];
|
|
41265
41339
|
}
|
|
41266
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
41340
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
41267
41341
|
const rangeColor = (rangeString) => {
|
|
41268
41342
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
41269
41343
|
return colors$1[colorIndex % colors$1.length];
|
|
@@ -41281,7 +41355,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
41281
41355
|
* Return ranges currently referenced in the composer
|
|
41282
41356
|
*/
|
|
41283
41357
|
getReferencedRanges() {
|
|
41284
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
41358
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
41285
41359
|
const referenceRanges = this.currentTokens
|
|
41286
41360
|
.filter((token) => token.type === "REFERENCE")
|
|
41287
41361
|
.map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
|
|
@@ -42092,6 +42166,16 @@ class ImageProvider {
|
|
|
42092
42166
|
}
|
|
42093
42167
|
}
|
|
42094
42168
|
|
|
42169
|
+
class FocusableElement {
|
|
42170
|
+
focusableElement = undefined;
|
|
42171
|
+
setFocusableElement(element) {
|
|
42172
|
+
this.focusableElement = element;
|
|
42173
|
+
}
|
|
42174
|
+
focus() {
|
|
42175
|
+
this.focusableElement?.focus();
|
|
42176
|
+
}
|
|
42177
|
+
}
|
|
42178
|
+
|
|
42095
42179
|
const RIPPLE_KEY_FRAMES = [
|
|
42096
42180
|
{ transform: "scale(0)" },
|
|
42097
42181
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -44120,6 +44204,7 @@ class Spreadsheet extends owl.Component {
|
|
|
44120
44204
|
_t: Spreadsheet._t,
|
|
44121
44205
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
44122
44206
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
44207
|
+
focusableElement: new FocusableElement(),
|
|
44123
44208
|
});
|
|
44124
44209
|
owl.useExternalListener(window, "resize", () => this.render(true));
|
|
44125
44210
|
owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
@@ -44226,17 +44311,18 @@ class Spreadsheet extends owl.Component {
|
|
|
44226
44311
|
this.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
44227
44312
|
this.composer.topBarFocus = "contentFocus";
|
|
44228
44313
|
this.composer.gridFocusMode = "inactive";
|
|
44229
|
-
this.setComposerContent({ selection }
|
|
44314
|
+
this.setComposerContent({ selection });
|
|
44230
44315
|
}
|
|
44231
|
-
onGridComposerContentFocused() {
|
|
44316
|
+
onGridComposerContentFocused(selection) {
|
|
44232
44317
|
if (this.model.getters.isReadonly()) {
|
|
44233
44318
|
return;
|
|
44234
44319
|
}
|
|
44235
44320
|
this.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
44236
44321
|
this.composer.topBarFocus = "inactive";
|
|
44237
44322
|
this.composer.gridFocusMode = "contentFocus";
|
|
44238
|
-
this.setComposerContent({});
|
|
44323
|
+
this.setComposerContent({ selection });
|
|
44239
44324
|
}
|
|
44325
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
44240
44326
|
onGridComposerCellFocused(content, selection) {
|
|
44241
44327
|
if (this.model.getters.isReadonly()) {
|
|
44242
44328
|
return;
|
|
@@ -45634,11 +45720,10 @@ class SelectionStreamProcessorImpl {
|
|
|
45634
45720
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
45635
45721
|
*/
|
|
45636
45722
|
getEndOfCluster(startPosition, dim, dir) {
|
|
45637
|
-
const sheet = this.getters.getActiveSheet();
|
|
45638
45723
|
let currentPosition = startPosition;
|
|
45639
45724
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
45640
45725
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
45641
|
-
let mode = !this.
|
|
45726
|
+
let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
|
|
45642
45727
|
? "endOfCluster"
|
|
45643
45728
|
: "nextCluster";
|
|
45644
45729
|
while (true) {
|
|
@@ -45648,7 +45733,7 @@ class SelectionStreamProcessorImpl {
|
|
|
45648
45733
|
currentPosition.row === nextCellPosition.row) {
|
|
45649
45734
|
break;
|
|
45650
45735
|
}
|
|
45651
|
-
const isNextCellEmpty = this.
|
|
45736
|
+
const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
|
|
45652
45737
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
45653
45738
|
break;
|
|
45654
45739
|
}
|
|
@@ -45662,14 +45747,24 @@ class SelectionStreamProcessorImpl {
|
|
|
45662
45747
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
45663
45748
|
}
|
|
45664
45749
|
/**
|
|
45665
|
-
* Check if a cell is empty
|
|
45666
|
-
* check
|
|
45750
|
+
* Check if a cell evaluated value is empty. If the cell is part of a merge,
|
|
45751
|
+
* the check applies to the main cell of the merge.
|
|
45667
45752
|
*/
|
|
45668
|
-
|
|
45753
|
+
isEvaluatedCellEmpty({ col, row }) {
|
|
45754
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
45669
45755
|
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
45670
45756
|
const cell = this.getters.getEvaluatedCell(position);
|
|
45671
45757
|
return cell.type === CellValueType.empty;
|
|
45672
45758
|
}
|
|
45759
|
+
/**
|
|
45760
|
+
* Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
|
|
45761
|
+
* the check applies to the main cell of the merge.
|
|
45762
|
+
*/
|
|
45763
|
+
isCellEmpty({ col, row }) {
|
|
45764
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
45765
|
+
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
45766
|
+
return !this.getters.getCell(position)?.content;
|
|
45767
|
+
}
|
|
45673
45768
|
/** Computes the next cell position in the given direction by crossing through merges and skipping hidden cells.
|
|
45674
45769
|
*
|
|
45675
45770
|
* This has the same behaviour as getNextAvailablePosition() for certain arguments, but use this method instead
|
|
@@ -47938,6 +48033,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
47938
48033
|
exports.tokenize = tokenize;
|
|
47939
48034
|
|
|
47940
48035
|
|
|
47941
|
-
__info__.version = '16.3.
|
|
47942
|
-
__info__.date = '2024-02-
|
|
47943
|
-
__info__.hash = '
|
|
48036
|
+
__info__.version = '16.3.26';
|
|
48037
|
+
__info__.date = '2024-02-16T14:22:11.270Z';
|
|
48038
|
+
__info__.hash = 'ab9abb6';
|