@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
|
@@ -1743,6 +1743,9 @@
|
|
|
1743
1743
|
function formatValue(value, format) {
|
|
1744
1744
|
switch (typeof value) {
|
|
1745
1745
|
case "string":
|
|
1746
|
+
if (value.includes('\\"')) {
|
|
1747
|
+
return value.replace(/\\"/g, '"');
|
|
1748
|
+
}
|
|
1746
1749
|
return value;
|
|
1747
1750
|
case "boolean":
|
|
1748
1751
|
return value ? "TRUE" : "FALSE";
|
|
@@ -9430,6 +9433,12 @@
|
|
|
9430
9433
|
let { col, row } = env.model.getters.getActivePosition();
|
|
9431
9434
|
env.model.dispatch("OPEN_CELL_POPOVER", { col, row, popoverType: "LinkEditor" });
|
|
9432
9435
|
};
|
|
9436
|
+
const INSERT_LINK_NAME = (env) => {
|
|
9437
|
+
const sheetId = env.model.getters.getActiveSheetId();
|
|
9438
|
+
const { col, row } = env.model.getters.getActivePosition();
|
|
9439
|
+
const cell = env.model.getters.getEvaluatedCell({ sheetId, col, row });
|
|
9440
|
+
return cell && cell.link ? _lt("Edit link") : _lt("Insert link");
|
|
9441
|
+
};
|
|
9433
9442
|
//------------------------------------------------------------------------------
|
|
9434
9443
|
// Filters action
|
|
9435
9444
|
//------------------------------------------------------------------------------
|
|
@@ -16654,7 +16663,7 @@
|
|
|
16654
16663
|
})
|
|
16655
16664
|
.add("insert_link", {
|
|
16656
16665
|
...insertLink,
|
|
16657
|
-
name:
|
|
16666
|
+
name: INSERT_LINK_NAME,
|
|
16658
16667
|
sequence: 150,
|
|
16659
16668
|
separator: true,
|
|
16660
16669
|
});
|
|
@@ -20981,6 +20990,7 @@
|
|
|
20981
20990
|
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
20982
20991
|
static defaultProps = {
|
|
20983
20992
|
inputStyle: "",
|
|
20993
|
+
isDefaultFocus: false,
|
|
20984
20994
|
};
|
|
20985
20995
|
composerRef = owl.useRef("o_composer");
|
|
20986
20996
|
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
@@ -21038,13 +21048,13 @@
|
|
|
21038
21048
|
setup() {
|
|
21039
21049
|
owl.onMounted(() => {
|
|
21040
21050
|
const el = this.composerRef.el;
|
|
21051
|
+
if (this.props.isDefaultFocus) {
|
|
21052
|
+
this.env.focusableElement.setFocusableElement(el);
|
|
21053
|
+
}
|
|
21041
21054
|
this.contentHelper.updateEl(el);
|
|
21042
21055
|
this.processContent();
|
|
21043
21056
|
this.contentHelper.scrollSelectionIntoView();
|
|
21044
21057
|
});
|
|
21045
|
-
owl.onWillUnmount(() => {
|
|
21046
|
-
this.props.onComposerUnmounted?.();
|
|
21047
|
-
});
|
|
21048
21058
|
owl.onPatched(() => {
|
|
21049
21059
|
if (!this.isKeyStillDown) {
|
|
21050
21060
|
this.processContent();
|
|
@@ -21055,7 +21065,8 @@
|
|
|
21055
21065
|
// Handlers
|
|
21056
21066
|
// ---------------------------------------------------------------------------
|
|
21057
21067
|
processArrowKeys(ev) {
|
|
21058
|
-
if (this.env.model.getters.isSelectingForComposer()
|
|
21068
|
+
if (this.env.model.getters.isSelectingForComposer() ||
|
|
21069
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
21059
21070
|
this.functionDescriptionState.showDescription = false;
|
|
21060
21071
|
// Prevent the default content editable behavior which moves the cursor
|
|
21061
21072
|
ev.preventDefault();
|
|
@@ -21095,21 +21106,23 @@
|
|
|
21095
21106
|
processTabKey(ev) {
|
|
21096
21107
|
ev.preventDefault();
|
|
21097
21108
|
ev.stopPropagation();
|
|
21098
|
-
if (this.
|
|
21099
|
-
|
|
21100
|
-
|
|
21101
|
-
|
|
21102
|
-
|
|
21109
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
21110
|
+
if (this.autoCompleteState.showProvider) {
|
|
21111
|
+
const autoCompleteValue = this.autoCompleteState.values[this.autoCompleteState.selectedIndex]?.text;
|
|
21112
|
+
if (autoCompleteValue) {
|
|
21113
|
+
this.autoComplete(autoCompleteValue);
|
|
21114
|
+
return;
|
|
21115
|
+
}
|
|
21103
21116
|
}
|
|
21104
|
-
|
|
21105
|
-
|
|
21106
|
-
|
|
21107
|
-
|
|
21108
|
-
|
|
21109
|
-
|
|
21117
|
+
else {
|
|
21118
|
+
// when completing with tab, if there is no value to complete, the active cell will be moved to the right.
|
|
21119
|
+
// we can't let the model think that it is for a ref selection.
|
|
21120
|
+
// todo: check if this can be removed someday
|
|
21121
|
+
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21122
|
+
}
|
|
21123
|
+
this.env.model.dispatch("STOP_EDITION");
|
|
21110
21124
|
}
|
|
21111
21125
|
const direction = ev.shiftKey ? "left" : "right";
|
|
21112
|
-
this.env.model.dispatch("STOP_EDITION");
|
|
21113
21126
|
this.env.model.selection.moveAnchorCell(direction, 1);
|
|
21114
21127
|
}
|
|
21115
21128
|
processEnterKey(ev) {
|
|
@@ -21153,6 +21166,9 @@
|
|
|
21153
21166
|
this.compositionActive = false;
|
|
21154
21167
|
}
|
|
21155
21168
|
onKeydown(ev) {
|
|
21169
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
21170
|
+
return;
|
|
21171
|
+
}
|
|
21156
21172
|
let handler = this.keyMapping[ev.key];
|
|
21157
21173
|
if (handler) {
|
|
21158
21174
|
handler.call(this, ev);
|
|
@@ -21163,22 +21179,44 @@
|
|
|
21163
21179
|
}
|
|
21164
21180
|
}
|
|
21165
21181
|
updateCursorIfNeeded() {
|
|
21166
|
-
|
|
21182
|
+
const moveCursor = !this.env.model.getters.isSelectingForComposer() &&
|
|
21183
|
+
!(this.env.model.getters.getEditionMode() === "inactive");
|
|
21184
|
+
if (moveCursor) {
|
|
21167
21185
|
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
21168
21186
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", { start, end });
|
|
21169
21187
|
this.isKeyStillDown = true;
|
|
21170
21188
|
}
|
|
21171
21189
|
}
|
|
21190
|
+
onPaste(ev) {
|
|
21191
|
+
if (this.env.model.getters.getEditionMode() !== "inactive") {
|
|
21192
|
+
ev.stopPropagation();
|
|
21193
|
+
}
|
|
21194
|
+
}
|
|
21172
21195
|
/*
|
|
21173
21196
|
* Triggered automatically by the content-editable between the keydown and key up
|
|
21174
21197
|
* */
|
|
21175
|
-
onInput() {
|
|
21176
|
-
if (
|
|
21198
|
+
onInput(ev) {
|
|
21199
|
+
if (!this.shouldProcessInputEvents) {
|
|
21177
21200
|
return;
|
|
21178
21201
|
}
|
|
21202
|
+
if (ev.inputType === "insertFromPaste" &&
|
|
21203
|
+
this.env.model.getters.getEditionMode() === "inactive") {
|
|
21204
|
+
return;
|
|
21205
|
+
}
|
|
21206
|
+
ev.stopPropagation();
|
|
21207
|
+
let content;
|
|
21208
|
+
if (this.env.model.getters.getEditionMode() === "inactive") {
|
|
21209
|
+
content = ev.data || "";
|
|
21210
|
+
}
|
|
21211
|
+
else {
|
|
21212
|
+
content = this.contentHelper.getText();
|
|
21213
|
+
}
|
|
21214
|
+
if (this.props.focus === "inactive") {
|
|
21215
|
+
return this.props.onComposerCellFocused?.(content);
|
|
21216
|
+
}
|
|
21179
21217
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21180
21218
|
this.env.model.dispatch("SET_CURRENT_CONTENT", {
|
|
21181
|
-
content
|
|
21219
|
+
content,
|
|
21182
21220
|
selection: this.contentHelper.getCurrentSelection(),
|
|
21183
21221
|
});
|
|
21184
21222
|
}
|
|
@@ -21249,9 +21287,8 @@
|
|
|
21249
21287
|
}
|
|
21250
21288
|
const newSelection = this.contentHelper.getCurrentSelection();
|
|
21251
21289
|
this.env.model.dispatch("STOP_COMPOSER_RANGE_SELECTION");
|
|
21252
|
-
|
|
21253
|
-
|
|
21254
|
-
}
|
|
21290
|
+
this.props.onComposerContentFocused();
|
|
21291
|
+
if (this.props.focus === "inactive") ;
|
|
21255
21292
|
this.env.model.dispatch("CHANGE_COMPOSER_CURSOR_SELECTION", newSelection);
|
|
21256
21293
|
this.processTokenAtCursor();
|
|
21257
21294
|
}
|
|
@@ -21395,7 +21432,7 @@
|
|
|
21395
21432
|
const highlights = this.env.model.getters.getHighlights();
|
|
21396
21433
|
const refSheet = sheetName
|
|
21397
21434
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
21398
|
-
: this.env.model.getters.getCurrentEditedCell()
|
|
21435
|
+
: this.env.model.getters.getCurrentEditedCell()?.sheetId;
|
|
21399
21436
|
const highlight = highlights.find((highlight) => {
|
|
21400
21437
|
if (highlight.sheetId !== refSheet)
|
|
21401
21438
|
return false;
|
|
@@ -21472,12 +21509,13 @@
|
|
|
21472
21509
|
}
|
|
21473
21510
|
}
|
|
21474
21511
|
Composer.props = {
|
|
21475
|
-
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
21476
|
-
onComposerContentFocused: Function,
|
|
21477
21512
|
inputStyle: { type: String, optional: true },
|
|
21478
21513
|
rect: { type: Object, optional: true },
|
|
21479
21514
|
delimitation: { type: Object, optional: true },
|
|
21480
|
-
|
|
21515
|
+
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
21516
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
21517
|
+
onComposerContentFocused: Function,
|
|
21518
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
21481
21519
|
};
|
|
21482
21520
|
|
|
21483
21521
|
const COMPOSER_BORDER_WIDTH = 3 * 0.4 * window.devicePixelRatio || 1;
|
|
@@ -21511,51 +21549,26 @@
|
|
|
21511
21549
|
class GridComposer extends owl.Component {
|
|
21512
21550
|
static template = "o-spreadsheet-GridComposer";
|
|
21513
21551
|
static components = { Composer };
|
|
21514
|
-
|
|
21515
|
-
|
|
21516
|
-
|
|
21552
|
+
// TODORAR see if we can keep it undefined
|
|
21553
|
+
rect = this.defaultRect;
|
|
21554
|
+
isEditing = false;
|
|
21517
21555
|
isCellReferenceVisible;
|
|
21518
|
-
|
|
21556
|
+
get defaultRect() {
|
|
21557
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
21558
|
+
}
|
|
21519
21559
|
setup() {
|
|
21520
|
-
this.gridComposerRef = owl.useRef("gridComposer");
|
|
21521
|
-
this.composerState = owl.useState({
|
|
21522
|
-
rect: undefined,
|
|
21523
|
-
delimitation: undefined,
|
|
21524
|
-
});
|
|
21525
|
-
const { sheetId, col, row } = this.env.model.getters.getActivePosition();
|
|
21526
|
-
this.zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
|
|
21527
|
-
this.rect = this.env.model.getters.getVisibleRect(this.zone);
|
|
21528
|
-
this.isCellReferenceVisible = false;
|
|
21529
|
-
owl.onMounted(() => {
|
|
21530
|
-
const el = this.gridComposerRef.el;
|
|
21531
|
-
this.composerState.rect = {
|
|
21532
|
-
x: this.rect.x,
|
|
21533
|
-
y: this.rect.y,
|
|
21534
|
-
width: el.clientWidth,
|
|
21535
|
-
height: el.clientHeight,
|
|
21536
|
-
};
|
|
21537
|
-
this.composerState.delimitation = {
|
|
21538
|
-
width: el.parentElement.clientWidth,
|
|
21539
|
-
height: el.parentElement.clientHeight,
|
|
21540
|
-
};
|
|
21541
|
-
});
|
|
21542
21560
|
owl.onWillUpdateProps(() => {
|
|
21543
|
-
|
|
21544
|
-
|
|
21545
|
-
}
|
|
21546
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
21547
|
-
const zone = this.env.model.getters.getSelectedZone();
|
|
21548
|
-
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
21549
|
-
if (!deepEquals(rect, this.rect) ||
|
|
21550
|
-
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
21551
|
-
this.isCellReferenceVisible = true;
|
|
21552
|
-
}
|
|
21561
|
+
this.updateComponentPosition();
|
|
21562
|
+
this.updateCellReferenceVisibility();
|
|
21553
21563
|
});
|
|
21554
21564
|
}
|
|
21555
21565
|
get shouldDisplayCellReference() {
|
|
21556
21566
|
return this.isCellReferenceVisible;
|
|
21557
21567
|
}
|
|
21558
21568
|
get cellReference() {
|
|
21569
|
+
if (!this.env.model.getters.getCurrentEditedCell()) {
|
|
21570
|
+
return "";
|
|
21571
|
+
}
|
|
21559
21572
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
21560
21573
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
21561
21574
|
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
@@ -21567,7 +21580,27 @@
|
|
|
21567
21580
|
top: `${top - GRID_CELL_REFERENCE_TOP_OFFSET}px`,
|
|
21568
21581
|
});
|
|
21569
21582
|
}
|
|
21583
|
+
get composerProps() {
|
|
21584
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
21585
|
+
return {
|
|
21586
|
+
rect: { ...this.rect },
|
|
21587
|
+
delimitation: {
|
|
21588
|
+
width,
|
|
21589
|
+
height,
|
|
21590
|
+
},
|
|
21591
|
+
focus: this.props.focus,
|
|
21592
|
+
isDefaultFocus: true,
|
|
21593
|
+
onComposerContentFocused: this.props.onComposerContentFocused,
|
|
21594
|
+
onComposerCellFocused: this.props.onComposerCellFocused,
|
|
21595
|
+
};
|
|
21596
|
+
}
|
|
21570
21597
|
get containerStyle() {
|
|
21598
|
+
if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
|
|
21599
|
+
return `
|
|
21600
|
+
position: absolute;
|
|
21601
|
+
z-index: -1000;
|
|
21602
|
+
`;
|
|
21603
|
+
}
|
|
21571
21604
|
const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
|
|
21572
21605
|
const cell = this.env.model.getters.getActiveCell();
|
|
21573
21606
|
const position = this.env.model.getters.getActivePosition();
|
|
@@ -21587,6 +21620,8 @@
|
|
|
21587
21620
|
if (!isFormula) {
|
|
21588
21621
|
textAlign = style.align || cell.defaultAlign;
|
|
21589
21622
|
}
|
|
21623
|
+
const maxHeight = this.props.gridDims.height - this.rect.y;
|
|
21624
|
+
const maxWidth = this.props.gridDims.width - this.rect.x;
|
|
21590
21625
|
/**
|
|
21591
21626
|
* min-size is on the container, not the composer element, because we want to have the same size as the cell by default,
|
|
21592
21627
|
* including all the paddings/margins of the composer
|
|
@@ -21598,6 +21633,8 @@
|
|
|
21598
21633
|
top: `${top}px`,
|
|
21599
21634
|
"min-width": `${width + 1}px`,
|
|
21600
21635
|
"min-height": `${height + 1}px`,
|
|
21636
|
+
"max-width": `${maxWidth}px`,
|
|
21637
|
+
"max-height": `${maxHeight}px`,
|
|
21601
21638
|
background,
|
|
21602
21639
|
color,
|
|
21603
21640
|
"font-size": `${fontSizeInPixels(fontSize)}px`,
|
|
@@ -21607,20 +21644,38 @@
|
|
|
21607
21644
|
"text-align": textAlign,
|
|
21608
21645
|
});
|
|
21609
21646
|
}
|
|
21610
|
-
|
|
21611
|
-
const
|
|
21612
|
-
|
|
21613
|
-
|
|
21614
|
-
|
|
21615
|
-
|
|
21616
|
-
|
|
21647
|
+
updateComponentPosition() {
|
|
21648
|
+
const isEditing = this.env.model.getters.getEditionMode() !== "inactive";
|
|
21649
|
+
if (this.isEditing !== isEditing) {
|
|
21650
|
+
this.isEditing = isEditing;
|
|
21651
|
+
if (!isEditing) {
|
|
21652
|
+
this.rect = this.defaultRect;
|
|
21653
|
+
this.env.focusableElement.focus();
|
|
21654
|
+
return;
|
|
21655
|
+
}
|
|
21656
|
+
const position = this.env.model.getters.getActivePosition();
|
|
21657
|
+
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
21658
|
+
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
21659
|
+
}
|
|
21660
|
+
}
|
|
21661
|
+
updateCellReferenceVisibility() {
|
|
21662
|
+
if (this.isCellReferenceVisible || this.env.model.getters.getEditionMode() === "inactive") {
|
|
21663
|
+
return;
|
|
21664
|
+
}
|
|
21665
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
21666
|
+
const zone = this.env.model.getters.getSelectedZone();
|
|
21667
|
+
const rect = this.env.model.getters.getVisibleRect(zone);
|
|
21668
|
+
if (!deepEquals(rect, this.rect) ||
|
|
21669
|
+
sheetId !== this.env.model.getters.getCurrentEditedCell().sheetId) {
|
|
21670
|
+
this.isCellReferenceVisible = true;
|
|
21671
|
+
}
|
|
21617
21672
|
}
|
|
21618
21673
|
}
|
|
21619
21674
|
GridComposer.props = {
|
|
21620
21675
|
focus: { validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value) },
|
|
21621
|
-
onComposerUnmounted: Function,
|
|
21622
21676
|
onComposerContentFocused: Function,
|
|
21623
21677
|
gridDims: Object,
|
|
21678
|
+
onComposerCellFocused: Function,
|
|
21624
21679
|
};
|
|
21625
21680
|
|
|
21626
21681
|
const CSS$1 = css /* scss */ `
|
|
@@ -22489,7 +22544,6 @@
|
|
|
22489
22544
|
this.props.onCellDoubleClicked(col, row);
|
|
22490
22545
|
}
|
|
22491
22546
|
onContextMenu(ev) {
|
|
22492
|
-
ev.preventDefault();
|
|
22493
22547
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
22494
22548
|
this.props.onCellRightClicked(col, row, { x: ev.clientX, y: ev.clientY });
|
|
22495
22549
|
}
|
|
@@ -23583,7 +23637,6 @@
|
|
|
23583
23637
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
23584
23638
|
menuState;
|
|
23585
23639
|
gridRef;
|
|
23586
|
-
hiddenInput;
|
|
23587
23640
|
onMouseWheel;
|
|
23588
23641
|
canvasPosition;
|
|
23589
23642
|
hoveredCell;
|
|
@@ -23594,17 +23647,16 @@
|
|
|
23594
23647
|
menuItems: [],
|
|
23595
23648
|
});
|
|
23596
23649
|
this.gridRef = owl.useRef("grid");
|
|
23597
|
-
this.hiddenInput = owl.useRef("hiddenInput");
|
|
23598
23650
|
this.canvasPosition = useAbsoluteBoundingRect(this.gridRef);
|
|
23599
23651
|
this.hoveredCell = owl.useState({ col: undefined, row: undefined });
|
|
23600
23652
|
owl.useChildSubEnv({ getPopoverContainerRect: () => this.getGridRect() });
|
|
23601
23653
|
owl.useExternalListener(document.body, "cut", this.copy.bind(this, true));
|
|
23602
23654
|
owl.useExternalListener(document.body, "copy", this.copy.bind(this, false));
|
|
23603
23655
|
owl.useExternalListener(document.body, "paste", this.paste);
|
|
23604
|
-
owl.onMounted(() => this.
|
|
23605
|
-
this.props.exposeFocus(() => this.
|
|
23656
|
+
owl.onMounted(() => this.focusDefaultElement());
|
|
23657
|
+
this.props.exposeFocus(() => this.focusDefaultElement());
|
|
23606
23658
|
useGridDrawing("canvas", this.env.model, () => this.env.model.getters.getSheetViewDimensionWithHeaders());
|
|
23607
|
-
owl.useEffect(() => this.
|
|
23659
|
+
owl.useEffect(() => this.focusDefaultElement(), () => [this.env.model.getters.getActiveSheetId()]);
|
|
23608
23660
|
this.onMouseWheel = useWheelHandler((deltaX, deltaY) => {
|
|
23609
23661
|
this.moveCanvas(deltaX, deltaY);
|
|
23610
23662
|
this.hoveredCell.col = undefined;
|
|
@@ -23627,7 +23679,7 @@
|
|
|
23627
23679
|
if (this.env.model.getters.hasOpenedPopover()) {
|
|
23628
23680
|
this.closeOpenedPopover();
|
|
23629
23681
|
}
|
|
23630
|
-
this.
|
|
23682
|
+
this.focusDefaultElement();
|
|
23631
23683
|
}
|
|
23632
23684
|
// this map will handle most of the actions that should happen on key down. The arrow keys are managed in the key
|
|
23633
23685
|
// down itself
|
|
@@ -23797,10 +23849,10 @@
|
|
|
23797
23849
|
PAGEUP: () => this.env.model.dispatch("SHIFT_VIEWPORT_UP"),
|
|
23798
23850
|
"CTRL+K": () => INSERT_LINK(this.env),
|
|
23799
23851
|
};
|
|
23800
|
-
|
|
23852
|
+
focusDefaultElement() {
|
|
23801
23853
|
if (!this.env.model.getters.getSelectedFigureId() &&
|
|
23802
23854
|
this.env.model.getters.getEditionMode() === "inactive") {
|
|
23803
|
-
this.
|
|
23855
|
+
this.env.focusableElement.focus();
|
|
23804
23856
|
}
|
|
23805
23857
|
}
|
|
23806
23858
|
get gridEl() {
|
|
@@ -23944,19 +23996,6 @@
|
|
|
23944
23996
|
return;
|
|
23945
23997
|
}
|
|
23946
23998
|
}
|
|
23947
|
-
onInput(ev) {
|
|
23948
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
23949
|
-
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
23950
|
-
return;
|
|
23951
|
-
}
|
|
23952
|
-
if (ev.data) {
|
|
23953
|
-
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
23954
|
-
// character
|
|
23955
|
-
ev.preventDefault();
|
|
23956
|
-
ev.stopPropagation();
|
|
23957
|
-
this.props.onGridComposerCellFocused(ev.data);
|
|
23958
|
-
}
|
|
23959
|
-
}
|
|
23960
23999
|
// ---------------------------------------------------------------------------
|
|
23961
24000
|
// Context Menu
|
|
23962
24001
|
// ---------------------------------------------------------------------------
|
|
@@ -24066,7 +24105,7 @@
|
|
|
24066
24105
|
}
|
|
24067
24106
|
closeMenu() {
|
|
24068
24107
|
this.menuState.isOpen = false;
|
|
24069
|
-
this.
|
|
24108
|
+
this.focusDefaultElement();
|
|
24070
24109
|
}
|
|
24071
24110
|
}
|
|
24072
24111
|
Grid.props = {
|
|
@@ -28726,6 +28765,31 @@
|
|
|
28726
28765
|
return data;
|
|
28727
28766
|
},
|
|
28728
28767
|
},
|
|
28768
|
+
{
|
|
28769
|
+
description: "Fix datafilter duplication",
|
|
28770
|
+
from: 12,
|
|
28771
|
+
to: 12.5,
|
|
28772
|
+
applyMigration(data) {
|
|
28773
|
+
for (let sheet of data.sheets || []) {
|
|
28774
|
+
let knownDataFilterZones = [];
|
|
28775
|
+
for (let filterTable of sheet.filterTables || []) {
|
|
28776
|
+
const zone = toZone(filterTable.range);
|
|
28777
|
+
// See commit message for the details
|
|
28778
|
+
const intersectZoneIndex = knownDataFilterZones.findIndex((knownZone) => overlap(knownZone, zone));
|
|
28779
|
+
if (intersectZoneIndex !== -1) {
|
|
28780
|
+
knownDataFilterZones[intersectZoneIndex] = zone;
|
|
28781
|
+
}
|
|
28782
|
+
else {
|
|
28783
|
+
knownDataFilterZones.push(zone);
|
|
28784
|
+
}
|
|
28785
|
+
}
|
|
28786
|
+
sheet.filterTables = knownDataFilterZones.map((zone) => ({
|
|
28787
|
+
range: zoneToXc(zone),
|
|
28788
|
+
}));
|
|
28789
|
+
}
|
|
28790
|
+
return data;
|
|
28791
|
+
},
|
|
28792
|
+
},
|
|
28729
28793
|
{
|
|
28730
28794
|
description: "Change Border description structure",
|
|
28731
28795
|
from: 12,
|
|
@@ -29627,9 +29691,9 @@
|
|
|
29627
29691
|
allowDispatch(cmd) {
|
|
29628
29692
|
switch (cmd.type) {
|
|
29629
29693
|
case "UPDATE_CELL":
|
|
29630
|
-
return this.
|
|
29694
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessUpdateCell);
|
|
29631
29695
|
case "CLEAR_CELL":
|
|
29632
|
-
return this.checkValidations(cmd, this.
|
|
29696
|
+
return this.checkValidations(cmd, this.checkCellOutOfSheet, this.checkUselessClearCell);
|
|
29633
29697
|
default:
|
|
29634
29698
|
return 0 /* CommandResult.Success */;
|
|
29635
29699
|
}
|
|
@@ -29761,10 +29825,6 @@
|
|
|
29761
29825
|
format: cell.format ? getItemId(cell.format, formats) : undefined,
|
|
29762
29826
|
content: cell.content || undefined,
|
|
29763
29827
|
};
|
|
29764
|
-
// if there is a formula but no dependencies (maybe because the cell is in error), no need to recompute the formula text
|
|
29765
|
-
if (cell.isFormula && cell.dependencies.length) {
|
|
29766
|
-
cells[xc].content = this.buildFormulaContent(_sheet.id, cell, cell.dependencies, true);
|
|
29767
|
-
}
|
|
29768
29828
|
}
|
|
29769
29829
|
_sheet.cells = cells;
|
|
29770
29830
|
}
|
|
@@ -29927,7 +29987,7 @@
|
|
|
29927
29987
|
else {
|
|
29928
29988
|
style = before ? before.style : undefined;
|
|
29929
29989
|
}
|
|
29930
|
-
|
|
29990
|
+
const format = "format" in after ? after.format : before && before.format;
|
|
29931
29991
|
/* Read the following IF as:
|
|
29932
29992
|
* we need to remove the cell if it is completely empty, but we can know if it completely empty if:
|
|
29933
29993
|
* - the command says the new content is empty and has no border/format/style
|
|
@@ -29971,7 +30031,7 @@
|
|
|
29971
30031
|
id,
|
|
29972
30032
|
content,
|
|
29973
30033
|
style,
|
|
29974
|
-
format,
|
|
30034
|
+
format: format || detectFormat(content),
|
|
29975
30035
|
isFormula: false,
|
|
29976
30036
|
};
|
|
29977
30037
|
}
|
|
@@ -30048,6 +30108,18 @@
|
|
|
30048
30108
|
}
|
|
30049
30109
|
return 0 /* CommandResult.Success */;
|
|
30050
30110
|
}
|
|
30111
|
+
checkUselessUpdateCell(cmd) {
|
|
30112
|
+
const cell = this.getters.getCell(cmd);
|
|
30113
|
+
const hasContent = "content" in cmd || "formula" in cmd;
|
|
30114
|
+
const hasStyle = "style" in cmd;
|
|
30115
|
+
const hasFormat = "format" in cmd;
|
|
30116
|
+
if ((!hasContent || cell?.content === cmd.content) &&
|
|
30117
|
+
(!hasStyle || deepEquals(cell?.style, cmd.style)) &&
|
|
30118
|
+
(!hasFormat || cell?.format === cmd.format)) {
|
|
30119
|
+
return 94 /* CommandResult.NoChanges */;
|
|
30120
|
+
}
|
|
30121
|
+
return 0 /* CommandResult.Success */;
|
|
30122
|
+
}
|
|
30051
30123
|
}
|
|
30052
30124
|
|
|
30053
30125
|
class ChartPlugin extends CorePlugin {
|
|
@@ -33839,6 +33911,10 @@
|
|
|
33839
33911
|
if (cell.format !== evaluatedCell.format) {
|
|
33840
33912
|
exportedCellData.computedFormat = evaluatedCell.format;
|
|
33841
33913
|
}
|
|
33914
|
+
// if there is a formula but no dependencies (maybe because the cell is in error), no need to recompute the formula text
|
|
33915
|
+
if (cell.isFormula && cell.dependencies.length) {
|
|
33916
|
+
exportedCellData.content = this.getters.buildFormulaContent(sheet.id, cell, cell.dependencies, true);
|
|
33917
|
+
}
|
|
33842
33918
|
}
|
|
33843
33919
|
}
|
|
33844
33920
|
}
|
|
@@ -35707,8 +35783,7 @@
|
|
|
35707
35783
|
let row = zone.bottom;
|
|
35708
35784
|
if (col > 0) {
|
|
35709
35785
|
let leftPosition = { sheetId, col: col - 1, row };
|
|
35710
|
-
while (this.getters.
|
|
35711
|
-
this.getters.getCell(leftPosition)?.content) {
|
|
35786
|
+
while (this.getters.getCell(leftPosition)?.content) {
|
|
35712
35787
|
row += 1;
|
|
35713
35788
|
leftPosition = { sheetId, col: col - 1, row };
|
|
35714
35789
|
}
|
|
@@ -35717,8 +35792,7 @@
|
|
|
35717
35792
|
col = zone.right;
|
|
35718
35793
|
if (col <= this.getters.getNumberCols(sheetId)) {
|
|
35719
35794
|
let rightPosition = { sheetId, col: col + 1, row };
|
|
35720
|
-
while (this.getters.
|
|
35721
|
-
this.getters.getCell(rightPosition)?.content) {
|
|
35795
|
+
while (this.getters.getCell(rightPosition)?.content) {
|
|
35722
35796
|
row += 1;
|
|
35723
35797
|
rightPosition = { sheetId, col: col + 1, row };
|
|
35724
35798
|
}
|
|
@@ -41183,7 +41257,7 @@
|
|
|
41183
41257
|
getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
|
|
41184
41258
|
const sheetId = this.getters.getActiveSheetId();
|
|
41185
41259
|
let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
|
|
41186
|
-
if (this.getters.getCurrentEditedCell()
|
|
41260
|
+
if (this.getters.getCurrentEditedCell()?.sheetId !== this.getters.getActiveSheetId()) {
|
|
41187
41261
|
const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
|
|
41188
41262
|
selectedXc = `${sheetName}!${selectedXc}`;
|
|
41189
41263
|
}
|
|
@@ -41198,7 +41272,7 @@
|
|
|
41198
41272
|
_fixedParts.pop();
|
|
41199
41273
|
}
|
|
41200
41274
|
const newRange = range.clone({ parts: _fixedParts });
|
|
41201
|
-
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().
|
|
41275
|
+
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId());
|
|
41202
41276
|
}
|
|
41203
41277
|
/**
|
|
41204
41278
|
* Replace the current selection by a new text.
|
|
@@ -41231,7 +41305,7 @@
|
|
|
41231
41305
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
41232
41306
|
return;
|
|
41233
41307
|
}
|
|
41234
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
41308
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
41235
41309
|
const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
|
|
41236
41310
|
const colorsToKeep = {};
|
|
41237
41311
|
for (const xc of XCs) {
|
|
@@ -41260,7 +41334,7 @@
|
|
|
41260
41334
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
41261
41335
|
return [];
|
|
41262
41336
|
}
|
|
41263
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
41337
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
41264
41338
|
const rangeColor = (rangeString) => {
|
|
41265
41339
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
41266
41340
|
return colors$1[colorIndex % colors$1.length];
|
|
@@ -41278,7 +41352,7 @@
|
|
|
41278
41352
|
* Return ranges currently referenced in the composer
|
|
41279
41353
|
*/
|
|
41280
41354
|
getReferencedRanges() {
|
|
41281
|
-
const editionSheetId = this.getters.getCurrentEditedCell().
|
|
41355
|
+
const editionSheetId = this.getters.getCurrentEditedCell()?.sheetId || this.getters.getActiveSheetId();
|
|
41282
41356
|
const referenceRanges = this.currentTokens
|
|
41283
41357
|
.filter((token) => token.type === "REFERENCE")
|
|
41284
41358
|
.map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
|
|
@@ -42089,6 +42163,16 @@
|
|
|
42089
42163
|
}
|
|
42090
42164
|
}
|
|
42091
42165
|
|
|
42166
|
+
class FocusableElement {
|
|
42167
|
+
focusableElement = undefined;
|
|
42168
|
+
setFocusableElement(element) {
|
|
42169
|
+
this.focusableElement = element;
|
|
42170
|
+
}
|
|
42171
|
+
focus() {
|
|
42172
|
+
this.focusableElement?.focus();
|
|
42173
|
+
}
|
|
42174
|
+
}
|
|
42175
|
+
|
|
42092
42176
|
const RIPPLE_KEY_FRAMES = [
|
|
42093
42177
|
{ transform: "scale(0)" },
|
|
42094
42178
|
{ transform: "scale(0.8)", offset: 0.33 },
|
|
@@ -44117,6 +44201,7 @@
|
|
|
44117
44201
|
_t: Spreadsheet._t,
|
|
44118
44202
|
clipboard: this.env.clipboard || instantiateClipboard(),
|
|
44119
44203
|
startCellEdition: (content) => this.onGridComposerCellFocused(content),
|
|
44204
|
+
focusableElement: new FocusableElement(),
|
|
44120
44205
|
});
|
|
44121
44206
|
owl.useExternalListener(window, "resize", () => this.render(true));
|
|
44122
44207
|
owl.useExternalListener(window, "beforeunload", this.unbindModelEvents.bind(this));
|
|
@@ -44223,17 +44308,18 @@
|
|
|
44223
44308
|
this.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
44224
44309
|
this.composer.topBarFocus = "contentFocus";
|
|
44225
44310
|
this.composer.gridFocusMode = "inactive";
|
|
44226
|
-
this.setComposerContent({ selection }
|
|
44311
|
+
this.setComposerContent({ selection });
|
|
44227
44312
|
}
|
|
44228
|
-
onGridComposerContentFocused() {
|
|
44313
|
+
onGridComposerContentFocused(selection) {
|
|
44229
44314
|
if (this.model.getters.isReadonly()) {
|
|
44230
44315
|
return;
|
|
44231
44316
|
}
|
|
44232
44317
|
this.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
44233
44318
|
this.composer.topBarFocus = "inactive";
|
|
44234
44319
|
this.composer.gridFocusMode = "contentFocus";
|
|
44235
|
-
this.setComposerContent({});
|
|
44320
|
+
this.setComposerContent({ selection });
|
|
44236
44321
|
}
|
|
44322
|
+
// TODO: either both are defined or none of them. change those args to an object
|
|
44237
44323
|
onGridComposerCellFocused(content, selection) {
|
|
44238
44324
|
if (this.model.getters.isReadonly()) {
|
|
44239
44325
|
return;
|
|
@@ -45631,11 +45717,10 @@
|
|
|
45631
45717
|
* next cluster if the given cell is outside a cluster or at the border of a cluster in the given direction.
|
|
45632
45718
|
*/
|
|
45633
45719
|
getEndOfCluster(startPosition, dim, dir) {
|
|
45634
|
-
const sheet = this.getters.getActiveSheet();
|
|
45635
45720
|
let currentPosition = startPosition;
|
|
45636
45721
|
// If both the current cell and the next cell are not empty, we want to go to the end of the cluster
|
|
45637
45722
|
const nextCellPosition = this.getNextCellPosition(startPosition, dim, dir);
|
|
45638
|
-
let mode = !this.
|
|
45723
|
+
let mode = !this.isEvaluatedCellEmpty(currentPosition) && !this.isEvaluatedCellEmpty(nextCellPosition)
|
|
45639
45724
|
? "endOfCluster"
|
|
45640
45725
|
: "nextCluster";
|
|
45641
45726
|
while (true) {
|
|
@@ -45645,7 +45730,7 @@
|
|
|
45645
45730
|
currentPosition.row === nextCellPosition.row) {
|
|
45646
45731
|
break;
|
|
45647
45732
|
}
|
|
45648
|
-
const isNextCellEmpty = this.
|
|
45733
|
+
const isNextCellEmpty = this.isEvaluatedCellEmpty(nextCellPosition);
|
|
45649
45734
|
if (mode === "endOfCluster" && isNextCellEmpty) {
|
|
45650
45735
|
break;
|
|
45651
45736
|
}
|
|
@@ -45659,14 +45744,24 @@
|
|
|
45659
45744
|
return dim === "cols" ? currentPosition.col : currentPosition.row;
|
|
45660
45745
|
}
|
|
45661
45746
|
/**
|
|
45662
|
-
* Check if a cell is empty
|
|
45663
|
-
* check
|
|
45747
|
+
* Check if a cell evaluated value is empty. If the cell is part of a merge,
|
|
45748
|
+
* the check applies to the main cell of the merge.
|
|
45664
45749
|
*/
|
|
45665
|
-
|
|
45750
|
+
isEvaluatedCellEmpty({ col, row }) {
|
|
45751
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
45666
45752
|
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
45667
45753
|
const cell = this.getters.getEvaluatedCell(position);
|
|
45668
45754
|
return cell.type === CellValueType.empty;
|
|
45669
45755
|
}
|
|
45756
|
+
/**
|
|
45757
|
+
* Checks if a cell is empty (i.e. does not have a content). If the cell is part of a merge,
|
|
45758
|
+
* the check applies to the main cell of the merge.
|
|
45759
|
+
*/
|
|
45760
|
+
isCellEmpty({ col, row }) {
|
|
45761
|
+
const sheetId = this.getters.getActiveSheetId();
|
|
45762
|
+
const position = this.getters.getMainCellPosition({ sheetId, col, row });
|
|
45763
|
+
return !this.getters.getCell(position)?.content;
|
|
45764
|
+
}
|
|
45670
45765
|
/** Computes the next cell position in the given direction by crossing through merges and skipping hidden cells.
|
|
45671
45766
|
*
|
|
45672
45767
|
* This has the same behaviour as getNextAvailablePosition() for certain arguments, but use this method instead
|
|
@@ -47937,9 +48032,9 @@
|
|
|
47937
48032
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
47938
48033
|
|
|
47939
48034
|
|
|
47940
|
-
__info__.version = '16.3.
|
|
47941
|
-
__info__.date = '2024-02-
|
|
47942
|
-
__info__.hash = '
|
|
48035
|
+
__info__.version = '16.3.26';
|
|
48036
|
+
__info__.date = '2024-02-16T14:22:11.270Z';
|
|
48037
|
+
__info__.hash = 'ab9abb6';
|
|
47943
48038
|
|
|
47944
48039
|
|
|
47945
48040
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|