@odoo/o-spreadsheet 16.3.0-alpha.1 → 16.3.0-alpha.3
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 +891 -371
- package/dist/o-spreadsheet.d.ts +171 -125
- package/dist/o-spreadsheet.esm.js +891 -371
- package/dist/o-spreadsheet.iife.js +891 -371
- package/dist/o-spreadsheet.iife.min.js +267 -261
- package/package.json +3 -3
|
@@ -117,88 +117,88 @@ const FILTERS_COLOR = "#188038";
|
|
|
117
117
|
const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
|
|
118
118
|
const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
|
|
119
119
|
const SEPARATOR_COLOR = "#E0E2E4";
|
|
120
|
-
// Color picker
|
|
120
|
+
// Color picker defaults as upper case HEX to match `toHex`helper
|
|
121
121
|
const COLOR_PICKER_DEFAULTS = [
|
|
122
122
|
"#000000",
|
|
123
123
|
"#434343",
|
|
124
124
|
"#666666",
|
|
125
125
|
"#999999",
|
|
126
|
-
"#
|
|
127
|
-
"#
|
|
128
|
-
"#
|
|
129
|
-
"#
|
|
130
|
-
"#
|
|
131
|
-
"#
|
|
126
|
+
"#B7B7B7",
|
|
127
|
+
"#CCCCCC",
|
|
128
|
+
"#D9D9D9",
|
|
129
|
+
"#EFEFEF",
|
|
130
|
+
"#F3F3F3",
|
|
131
|
+
"#FFFFFF",
|
|
132
132
|
"#980000",
|
|
133
|
-
"#
|
|
134
|
-
"#
|
|
135
|
-
"#
|
|
136
|
-
"#
|
|
137
|
-
"#
|
|
138
|
-
"#
|
|
139
|
-
"#
|
|
140
|
-
"#
|
|
141
|
-
"#
|
|
142
|
-
"#
|
|
143
|
-
"#
|
|
144
|
-
"#
|
|
145
|
-
"#
|
|
146
|
-
"#
|
|
147
|
-
"#
|
|
148
|
-
"#
|
|
149
|
-
"#
|
|
150
|
-
"#
|
|
151
|
-
"#
|
|
152
|
-
"#
|
|
153
|
-
"#
|
|
154
|
-
"#
|
|
155
|
-
"#
|
|
156
|
-
"#
|
|
157
|
-
"#
|
|
158
|
-
"#
|
|
159
|
-
"#
|
|
160
|
-
"#
|
|
161
|
-
"#
|
|
162
|
-
"#
|
|
163
|
-
"#
|
|
164
|
-
"#
|
|
165
|
-
"#
|
|
166
|
-
"#
|
|
167
|
-
"#
|
|
168
|
-
"#
|
|
169
|
-
"#
|
|
170
|
-
"#
|
|
171
|
-
"#
|
|
172
|
-
"#
|
|
173
|
-
"#
|
|
174
|
-
"#
|
|
175
|
-
"#
|
|
176
|
-
"#
|
|
177
|
-
"#
|
|
178
|
-
"#
|
|
179
|
-
"#
|
|
180
|
-
"#
|
|
181
|
-
"#
|
|
182
|
-
"#
|
|
133
|
+
"#FF0000",
|
|
134
|
+
"#FF9900",
|
|
135
|
+
"#FFFF00",
|
|
136
|
+
"#00FF00",
|
|
137
|
+
"#00FFFF",
|
|
138
|
+
"#4A86E8",
|
|
139
|
+
"#0000FF",
|
|
140
|
+
"#9900FF",
|
|
141
|
+
"#FF00FF",
|
|
142
|
+
"#E6B8AF",
|
|
143
|
+
"#F4CCCC",
|
|
144
|
+
"#FCE5CD",
|
|
145
|
+
"#FFF2CC",
|
|
146
|
+
"#D9EAD3",
|
|
147
|
+
"#D0E0E3",
|
|
148
|
+
"#C9DAF8",
|
|
149
|
+
"#CFE2F3",
|
|
150
|
+
"#D9D2E9",
|
|
151
|
+
"#EAD1DC",
|
|
152
|
+
"#DD7E6B",
|
|
153
|
+
"#EA9999",
|
|
154
|
+
"#F9CB9C",
|
|
155
|
+
"#FFE599",
|
|
156
|
+
"#B6D7A8",
|
|
157
|
+
"#A2C4C9",
|
|
158
|
+
"#A4C2F4",
|
|
159
|
+
"#9FC5E8",
|
|
160
|
+
"#B4A7D6",
|
|
161
|
+
"#D5A6BD",
|
|
162
|
+
"#CC4125",
|
|
163
|
+
"#E06666",
|
|
164
|
+
"#F6B26B",
|
|
165
|
+
"#FFD966",
|
|
166
|
+
"#93C47D",
|
|
167
|
+
"#76A5AF",
|
|
168
|
+
"#6D9EEB",
|
|
169
|
+
"#6FA8DC",
|
|
170
|
+
"#8E7CC3",
|
|
171
|
+
"#C27BA0",
|
|
172
|
+
"#A61C00",
|
|
173
|
+
"#CC0000",
|
|
174
|
+
"#E69138",
|
|
175
|
+
"#F1C232",
|
|
176
|
+
"#6AA84F",
|
|
177
|
+
"#45818E",
|
|
178
|
+
"#3C78D8",
|
|
179
|
+
"#3D85C6",
|
|
180
|
+
"#674EA7",
|
|
181
|
+
"#A64D79",
|
|
182
|
+
"#85200C",
|
|
183
183
|
"#990000",
|
|
184
|
-
"#
|
|
185
|
-
"#
|
|
186
|
-
"#
|
|
187
|
-
"#
|
|
188
|
-
"#
|
|
189
|
-
"#
|
|
190
|
-
"#
|
|
191
|
-
"#
|
|
192
|
-
"#
|
|
184
|
+
"#B45F06",
|
|
185
|
+
"#BF9000",
|
|
186
|
+
"#38761D",
|
|
187
|
+
"#134F5C",
|
|
188
|
+
"#1155CC",
|
|
189
|
+
"#0B5394",
|
|
190
|
+
"#351C75",
|
|
191
|
+
"#741B47",
|
|
192
|
+
"#5B0F00",
|
|
193
193
|
"#660000",
|
|
194
|
-
"#
|
|
195
|
-
"#
|
|
196
|
-
"#
|
|
197
|
-
"#
|
|
198
|
-
"#
|
|
194
|
+
"#783F04",
|
|
195
|
+
"#7F6000",
|
|
196
|
+
"#274E13",
|
|
197
|
+
"#0C343D",
|
|
198
|
+
"#1C4587",
|
|
199
199
|
"#073763",
|
|
200
|
-
"#
|
|
201
|
-
"#
|
|
200
|
+
"#20124D",
|
|
201
|
+
"#4C1130",
|
|
202
202
|
];
|
|
203
203
|
// Dimensions
|
|
204
204
|
const MIN_ROW_HEIGHT = 10;
|
|
@@ -227,8 +227,6 @@ const MENU_VERTICAL_PADDING = 8;
|
|
|
227
227
|
const MENU_ITEM_HEIGHT = 28;
|
|
228
228
|
const MENU_SEPARATOR_BORDER_WIDTH = 1;
|
|
229
229
|
const MENU_SEPARATOR_PADDING = 5;
|
|
230
|
-
const MENU_SEPARATOR_HEIGHT = MENU_SEPARATOR_BORDER_WIDTH + 2 * MENU_SEPARATOR_PADDING;
|
|
231
|
-
const FIGURE_BORDER_SIZE = 1;
|
|
232
230
|
// Fonts
|
|
233
231
|
const DEFAULT_FONT_WEIGHT = "400";
|
|
234
232
|
const DEFAULT_FONT_SIZE = 10;
|
|
@@ -238,7 +236,7 @@ const DEFAULT_FONT = "'Roboto', arial";
|
|
|
238
236
|
const DEFAULT_BORDER_DESC = ["thin", "#000"];
|
|
239
237
|
const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
|
|
240
238
|
// DateTimeRegex
|
|
241
|
-
const DATETIME_FORMAT = /[
|
|
239
|
+
const DATETIME_FORMAT = /[ymdhs:]/;
|
|
242
240
|
// Ranges
|
|
243
241
|
const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
|
|
244
242
|
// Max Number of history steps kept in memory
|
|
@@ -248,6 +246,8 @@ const DEFAULT_REVISION_ID = "START_REVISION";
|
|
|
248
246
|
// Figure
|
|
249
247
|
const DEFAULT_FIGURE_HEIGHT = 335;
|
|
250
248
|
const DEFAULT_FIGURE_WIDTH = 536;
|
|
249
|
+
const FIGURE_BORDER_WIDTH = 1;
|
|
250
|
+
const MIN_FIG_SIZE = 80;
|
|
251
251
|
// Chart
|
|
252
252
|
const MAX_CHAR_LABEL = 20;
|
|
253
253
|
const FIGURE_ID_SPLITTER = "??";
|
|
@@ -258,7 +258,6 @@ const DEFAULT_SCORECARD_BASELINE_MODE = "difference";
|
|
|
258
258
|
const DEFAULT_SCORECARD_BASELINE_COLOR_UP = "#00A04A";
|
|
259
259
|
const DEFAULT_SCORECARD_BASELINE_COLOR_DOWN = "#DC6965";
|
|
260
260
|
const LINE_FILL_TRANSPARENCY = 0.4;
|
|
261
|
-
const MIN_FIG_SIZE = 80;
|
|
262
261
|
// session
|
|
263
262
|
const DEBOUNCE_TIME = 200;
|
|
264
263
|
const MESSAGE_VERSION = 1;
|
|
@@ -280,7 +279,8 @@ var ComponentsImportance;
|
|
|
280
279
|
ComponentsImportance[ComponentsImportance["TopBarComposer"] = 21] = "TopBarComposer";
|
|
281
280
|
ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
|
|
282
281
|
ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
|
|
283
|
-
ComponentsImportance[ComponentsImportance["
|
|
282
|
+
ComponentsImportance[ComponentsImportance["FigureAnchor"] = 1000] = "FigureAnchor";
|
|
283
|
+
ComponentsImportance[ComponentsImportance["FigureSnapLine"] = 1001] = "FigureSnapLine";
|
|
284
284
|
})(ComponentsImportance || (ComponentsImportance = {}));
|
|
285
285
|
const DEFAULT_SHEETVIEW_SIZE = 1000;
|
|
286
286
|
const MAXIMAL_FREEZABLE_RATIO = 0.85;
|
|
@@ -717,7 +717,7 @@ function getUnquotedSheetName(sheetName) {
|
|
|
717
717
|
* '\w' captures [0-9][a-z][A-Z] and _.
|
|
718
718
|
* @param sheetName Name of the sheet
|
|
719
719
|
*/
|
|
720
|
-
function
|
|
720
|
+
function getCanonicalSheetName(sheetName) {
|
|
721
721
|
var _a;
|
|
722
722
|
if (((_a = sheetName.match(/\w/g)) === null || _a === void 0 ? void 0 : _a.length) !== sheetName.length) {
|
|
723
723
|
sheetName = `'${sheetName}'`;
|
|
@@ -738,8 +738,9 @@ function getDefaultCellHeight(cell) {
|
|
|
738
738
|
return DEFAULT_CELL_HEIGHT;
|
|
739
739
|
}
|
|
740
740
|
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
741
|
-
|
|
742
|
-
|
|
741
|
+
// the number of lines should be computed from the formula result, but it's not evaluated at this point
|
|
742
|
+
const numberOfLines = cell.isFormula ? 1 : cell.content.split(NEWLINE).length;
|
|
743
|
+
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
743
744
|
}
|
|
744
745
|
function computeTextWidth(context, text, style) {
|
|
745
746
|
context.save();
|
|
@@ -1091,6 +1092,8 @@ function replaceSpecialSpaces(text) {
|
|
|
1091
1092
|
return text;
|
|
1092
1093
|
}
|
|
1093
1094
|
|
|
1095
|
+
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
1096
|
+
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
|
|
1094
1097
|
const colors$1 = [
|
|
1095
1098
|
"#eb6d00",
|
|
1096
1099
|
"#0074d9",
|
|
@@ -1116,7 +1119,10 @@ function colorNumberString(color) {
|
|
|
1116
1119
|
}
|
|
1117
1120
|
/**
|
|
1118
1121
|
* Converts any CSS color value to a standardized hex6 value.
|
|
1119
|
-
* Accepts: hex3, hex6, hex8 and
|
|
1122
|
+
* Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
|
|
1123
|
+
*
|
|
1124
|
+
* [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
|
|
1125
|
+
* with r,g,b ∈ [0, 255] and a ∈ [0, 1]
|
|
1120
1126
|
*
|
|
1121
1127
|
* toHex("#ABC")
|
|
1122
1128
|
* >> "#AABBCC"
|
|
@@ -1127,27 +1133,31 @@ function colorNumberString(color) {
|
|
|
1127
1133
|
* toHex("rgb(30, 80, 16)")
|
|
1128
1134
|
* >> "#1E5010"
|
|
1129
1135
|
*
|
|
1136
|
+
* * toHex("rgb(30, 80, 16, 0.5)")
|
|
1137
|
+
* >> "#1E501080"
|
|
1138
|
+
*
|
|
1130
1139
|
*/
|
|
1131
1140
|
function toHex(color) {
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
if (color.includes("rgb")) {
|
|
1136
|
-
return rgbToHex6(color);
|
|
1141
|
+
let hexColor = color;
|
|
1142
|
+
if (color.startsWith("rgb")) {
|
|
1143
|
+
hexColor = rgbaStringToHex(color);
|
|
1137
1144
|
}
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1145
|
+
else {
|
|
1146
|
+
hexColor = color.replace("#", "").toUpperCase();
|
|
1147
|
+
if (hexColor.length === 3 || hexColor.length === 4) {
|
|
1148
|
+
hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
|
|
1149
|
+
}
|
|
1150
|
+
hexColor = `#${hexColor}`;
|
|
1141
1151
|
}
|
|
1142
|
-
if (
|
|
1143
|
-
throw new Error(
|
|
1152
|
+
if (!hexColor.match(HEX_MATCH)) {
|
|
1153
|
+
throw new Error(`invalid color input: ${color}`);
|
|
1144
1154
|
}
|
|
1145
|
-
return
|
|
1155
|
+
return hexColor;
|
|
1146
1156
|
}
|
|
1147
1157
|
function isColorValid(color) {
|
|
1148
1158
|
try {
|
|
1149
|
-
|
|
1150
|
-
return
|
|
1159
|
+
toHex(color);
|
|
1160
|
+
return true;
|
|
1151
1161
|
}
|
|
1152
1162
|
catch (error) {
|
|
1153
1163
|
return false;
|
|
@@ -1180,15 +1190,29 @@ function relativeLuminance(color) {
|
|
|
1180
1190
|
/**
|
|
1181
1191
|
* Convert a CSS rgb color string to a standardized hex6 color value.
|
|
1182
1192
|
*
|
|
1183
|
-
*
|
|
1193
|
+
* rgbaStringToHex("rgb(30, 80, 16)")
|
|
1184
1194
|
* >> "#1E5010"
|
|
1195
|
+
*
|
|
1196
|
+
* rgbaStringToHex("rgba(30, 80, 16, 0.5)")
|
|
1197
|
+
* >> "#1E501080"
|
|
1198
|
+
*
|
|
1199
|
+
* DOES NOT SUPPORT NON INTEGER RGB VALUES
|
|
1185
1200
|
*/
|
|
1186
|
-
function
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1201
|
+
function rgbaStringToHex(color) {
|
|
1202
|
+
const stringVals = color.replace(RBA_REGEX, "").split(",");
|
|
1203
|
+
let alphaHex = 255;
|
|
1204
|
+
if (stringVals.length !== 3 && stringVals.length !== 4) {
|
|
1205
|
+
throw new Error("invalid color");
|
|
1206
|
+
}
|
|
1207
|
+
else if (stringVals.length === 4) {
|
|
1208
|
+
const alpha = parseFloat(stringVals.pop() || "1");
|
|
1209
|
+
alphaHex = Math.round((alpha || 1) * 255);
|
|
1210
|
+
}
|
|
1211
|
+
const vals = stringVals.map((val) => parseInt(val, 10));
|
|
1212
|
+
if (alphaHex !== 255) {
|
|
1213
|
+
vals.push(alphaHex);
|
|
1214
|
+
}
|
|
1215
|
+
return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
|
|
1192
1216
|
}
|
|
1193
1217
|
/**
|
|
1194
1218
|
* RGBA to HEX representation (#RRGGBBAA).
|
|
@@ -1210,7 +1234,7 @@ function rgbaToHex(rgba) {
|
|
|
1210
1234
|
a = "0" + a;
|
|
1211
1235
|
if (a === "ff")
|
|
1212
1236
|
a = "";
|
|
1213
|
-
return "#" + r + g + b + a;
|
|
1237
|
+
return ("#" + r + g + b + a).toUpperCase();
|
|
1214
1238
|
}
|
|
1215
1239
|
/**
|
|
1216
1240
|
* Color string to RGBA representation
|
|
@@ -1331,6 +1355,9 @@ function rgbaToHSLA(rgba) {
|
|
|
1331
1355
|
s = +(s * 100).toFixed(1);
|
|
1332
1356
|
l = +(l * 100).toFixed(1);
|
|
1333
1357
|
return { a: rgba.a, h, s, l };
|
|
1358
|
+
}
|
|
1359
|
+
function isSameColor(color1, color2) {
|
|
1360
|
+
return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
|
|
1334
1361
|
}
|
|
1335
1362
|
|
|
1336
1363
|
/** Reference of a cell (eg. A1, $B$5) */
|
|
@@ -1482,7 +1509,7 @@ function scrollDelay(value) {
|
|
|
1482
1509
|
* formula, commas are used to separate arguments
|
|
1483
1510
|
* - it does not support % symbol, in formulas % is an operator
|
|
1484
1511
|
*/
|
|
1485
|
-
const formulaNumberRegexp =
|
|
1512
|
+
const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
|
|
1486
1513
|
const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
|
|
1487
1514
|
const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
|
|
1488
1515
|
const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
|
|
@@ -3055,6 +3082,9 @@ function cellTextStyleToCss(style) {
|
|
|
3055
3082
|
}
|
|
3056
3083
|
return attributes;
|
|
3057
3084
|
}
|
|
3085
|
+
/**
|
|
3086
|
+
* Transform CSS properties into a CSS string.
|
|
3087
|
+
*/
|
|
3058
3088
|
function cssPropertiesToCss(attributes) {
|
|
3059
3089
|
const str = Object.entries(attributes)
|
|
3060
3090
|
.filter(([attName, attValue]) => attValue !== undefined)
|
|
@@ -3088,6 +3118,7 @@ const CHART_PADDING_RATIO = 0.02;
|
|
|
3088
3118
|
const LINE_HEIGHT = 1.2;
|
|
3089
3119
|
css /* scss */ `
|
|
3090
3120
|
div.o-scorecard {
|
|
3121
|
+
font-family: ${DEFAULT_FONT};
|
|
3091
3122
|
user-select: none;
|
|
3092
3123
|
background-color: white;
|
|
3093
3124
|
display: flex;
|
|
@@ -5075,6 +5106,10 @@ function usePopoverContainer() {
|
|
|
5075
5106
|
function rectIntersection(rect1, rect2) {
|
|
5076
5107
|
return zoneToRect(intersection(rectToZone(rect1), rectToZone(rect2)));
|
|
5077
5108
|
}
|
|
5109
|
+
/** Compute the union of the rectangles, ie. the smallest rectangle that contain them all */
|
|
5110
|
+
function rectUnion(...rects) {
|
|
5111
|
+
return zoneToRect(union(...rects.map(rectToZone)));
|
|
5112
|
+
}
|
|
5078
5113
|
function rectToZone(rect) {
|
|
5079
5114
|
return {
|
|
5080
5115
|
left: rect.x,
|
|
@@ -5371,24 +5406,30 @@ class Menu extends owl.Component {
|
|
|
5371
5406
|
}
|
|
5372
5407
|
});
|
|
5373
5408
|
}
|
|
5374
|
-
get
|
|
5375
|
-
|
|
5409
|
+
get menuItemsAndSeparators() {
|
|
5410
|
+
const menuItemsAndSeparators = [];
|
|
5411
|
+
for (let i = 0; i < this.props.menuItems.length; i++) {
|
|
5412
|
+
const menuItem = this.props.menuItems[i];
|
|
5413
|
+
if (menuItem.isVisible(this.env)) {
|
|
5414
|
+
menuItemsAndSeparators.push(menuItem);
|
|
5415
|
+
}
|
|
5416
|
+
if (menuItem.separator &&
|
|
5417
|
+
i !== this.props.menuItems.length - 1 && // no separator at the end
|
|
5418
|
+
menuItemsAndSeparators[menuItemsAndSeparators.length - 1] !== "separator" // no double separator
|
|
5419
|
+
) {
|
|
5420
|
+
menuItemsAndSeparators.push("separator");
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
5423
|
+
if (menuItemsAndSeparators.length === 1 && menuItemsAndSeparators[0] === "separator") {
|
|
5424
|
+
return [];
|
|
5425
|
+
}
|
|
5426
|
+
return menuItemsAndSeparators;
|
|
5376
5427
|
}
|
|
5377
5428
|
get subMenuPosition() {
|
|
5378
5429
|
const position = Object.assign({}, this.subMenu.position);
|
|
5379
5430
|
position.y -= this.subMenu.scrollOffset || 0;
|
|
5380
5431
|
return position;
|
|
5381
5432
|
}
|
|
5382
|
-
get menuHeight() {
|
|
5383
|
-
const menuItems = this.visibleMenuItems;
|
|
5384
|
-
let menuItemsHeight = this.getMenuItemsHeight(menuItems);
|
|
5385
|
-
// We don't display separator at the end of a menu
|
|
5386
|
-
if (menuItems[menuItems.length - 1].separator) {
|
|
5387
|
-
menuItemsHeight -= MENU_SEPARATOR_HEIGHT;
|
|
5388
|
-
}
|
|
5389
|
-
const menuHeight = 2 * MENU_VERTICAL_PADDING + menuItemsHeight;
|
|
5390
|
-
return this.props.maxHeight ? Math.min(menuHeight, this.props.maxHeight) : menuHeight;
|
|
5391
|
-
}
|
|
5392
5433
|
get popoverProps() {
|
|
5393
5434
|
const isRoot = this.props.depth === 1;
|
|
5394
5435
|
return {
|
|
@@ -5402,7 +5443,6 @@ class Menu extends owl.Component {
|
|
|
5402
5443
|
verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
|
|
5403
5444
|
onPopoverHidden: () => this.closeSubMenu(),
|
|
5404
5445
|
onPopoverMoved: () => this.closeSubMenu(),
|
|
5405
|
-
maxHeight: this.menuHeight,
|
|
5406
5446
|
};
|
|
5407
5447
|
}
|
|
5408
5448
|
getColor(menu) {
|
|
@@ -5418,14 +5458,6 @@ class Menu extends owl.Component {
|
|
|
5418
5458
|
this.closeSubMenu();
|
|
5419
5459
|
this.props.onClose();
|
|
5420
5460
|
}
|
|
5421
|
-
/**
|
|
5422
|
-
* Return the number of pixels between the top of the menu
|
|
5423
|
-
* and the menu item at a given index.
|
|
5424
|
-
*/
|
|
5425
|
-
subMenuVerticalPosition(menuIndex) {
|
|
5426
|
-
const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
|
|
5427
|
-
return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
|
|
5428
|
-
}
|
|
5429
5461
|
onExternalClick(ev) {
|
|
5430
5462
|
// Don't close a root menu when clicked to open the submenus.
|
|
5431
5463
|
const el = this.menuRef.el;
|
|
@@ -5435,10 +5467,6 @@ class Menu extends owl.Component {
|
|
|
5435
5467
|
ev.closedMenuId = this.props.menuId;
|
|
5436
5468
|
this.close();
|
|
5437
5469
|
}
|
|
5438
|
-
getMenuItemsHeight(menuItems) {
|
|
5439
|
-
const numberOfSeparators = menuItems.filter((m) => m.separator).length;
|
|
5440
|
-
return MENU_ITEM_HEIGHT * menuItems.length + MENU_SEPARATOR_HEIGHT * numberOfSeparators;
|
|
5441
|
-
}
|
|
5442
5470
|
getName(menu) {
|
|
5443
5471
|
return menu.name(this.env);
|
|
5444
5472
|
}
|
|
@@ -5458,8 +5486,11 @@ class Menu extends owl.Component {
|
|
|
5458
5486
|
* If the given menu is not disabled, open it's submenu at the
|
|
5459
5487
|
* correct position according to available surrounding space.
|
|
5460
5488
|
*/
|
|
5461
|
-
openSubMenu(menu, menuIndex) {
|
|
5462
|
-
const
|
|
5489
|
+
openSubMenu(menu, menuIndex, ev) {
|
|
5490
|
+
const parentMenuEl = ev.currentTarget;
|
|
5491
|
+
if (!parentMenuEl)
|
|
5492
|
+
return;
|
|
5493
|
+
const y = parentMenuEl.getBoundingClientRect().top;
|
|
5463
5494
|
this.subMenu.position = {
|
|
5464
5495
|
x: this.position.x + this.props.depth * MENU_WIDTH,
|
|
5465
5496
|
y: y - (this.subMenu.scrollOffset || 0),
|
|
@@ -5476,20 +5507,20 @@ class Menu extends owl.Component {
|
|
|
5476
5507
|
this.subMenu.isOpen = false;
|
|
5477
5508
|
this.subMenu.parentMenu = undefined;
|
|
5478
5509
|
}
|
|
5479
|
-
onClickMenu(menu, menuIndex) {
|
|
5510
|
+
onClickMenu(menu, menuIndex, ev) {
|
|
5480
5511
|
if (this.isEnabled(menu)) {
|
|
5481
5512
|
if (this.isRoot(menu)) {
|
|
5482
|
-
this.openSubMenu(menu, menuIndex);
|
|
5513
|
+
this.openSubMenu(menu, menuIndex, ev);
|
|
5483
5514
|
}
|
|
5484
5515
|
else {
|
|
5485
5516
|
this.activateMenu(menu);
|
|
5486
5517
|
}
|
|
5487
5518
|
}
|
|
5488
5519
|
}
|
|
5489
|
-
onMouseOver(menu, position) {
|
|
5520
|
+
onMouseOver(menu, position, ev) {
|
|
5490
5521
|
if (menu.isEnabled(this.env)) {
|
|
5491
5522
|
if (this.isRoot(menu)) {
|
|
5492
|
-
this.openSubMenu(menu, position);
|
|
5523
|
+
this.openSubMenu(menu, position, ev);
|
|
5493
5524
|
}
|
|
5494
5525
|
else {
|
|
5495
5526
|
this.closeSubMenu();
|
|
@@ -6066,8 +6097,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6066
6097
|
const dataSets = [];
|
|
6067
6098
|
for (const sheetXC of dataSetsString) {
|
|
6068
6099
|
const dataRange = getters.getRangeFromSheetXC(sheetId, sheetXC);
|
|
6069
|
-
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName } = dataRange;
|
|
6070
|
-
if (invalidSheetName) {
|
|
6100
|
+
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName, invalidXc } = dataRange;
|
|
6101
|
+
if (invalidSheetName || invalidXc) {
|
|
6071
6102
|
continue;
|
|
6072
6103
|
}
|
|
6073
6104
|
// It's a rectangle. We treat all columns (arbitrary) as different data series.
|
|
@@ -6092,14 +6123,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6092
6123
|
: undefined));
|
|
6093
6124
|
}
|
|
6094
6125
|
}
|
|
6095
|
-
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
6096
|
-
// A single cell. If it's only the title, the dataset is not added.
|
|
6097
|
-
if (!dataSetsHaveTitle) {
|
|
6098
|
-
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
6099
|
-
}
|
|
6100
|
-
}
|
|
6101
6126
|
else {
|
|
6102
|
-
/* 1 row or 1 column */
|
|
6127
|
+
/* 1 cell, 1 row or 1 column */
|
|
6103
6128
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
6104
6129
|
? {
|
|
6105
6130
|
top: zone.top,
|
|
@@ -6153,6 +6178,18 @@ function toExcelDataset(getters, ds) {
|
|
|
6153
6178
|
range: getters.getRangeString(dataRange, "forceSheetReference"),
|
|
6154
6179
|
};
|
|
6155
6180
|
}
|
|
6181
|
+
function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
6182
|
+
if (!labelRange)
|
|
6183
|
+
return undefined;
|
|
6184
|
+
let zone = {
|
|
6185
|
+
...labelRange.zone,
|
|
6186
|
+
};
|
|
6187
|
+
if (shouldRemoveFirstLabel && labelRange.zone.bottom > labelRange.zone.top) {
|
|
6188
|
+
zone.top = zone.top + 1;
|
|
6189
|
+
}
|
|
6190
|
+
const range = labelRange.clone({ zone });
|
|
6191
|
+
return getters.getRangeString(range, "forceSheetReference");
|
|
6192
|
+
}
|
|
6156
6193
|
/**
|
|
6157
6194
|
* Transform a chart definition which supports dataSets (dataSets and LabelRange)
|
|
6158
6195
|
* with an executed command
|
|
@@ -6237,6 +6274,20 @@ function checkLabelRange(definition) {
|
|
|
6237
6274
|
}
|
|
6238
6275
|
return 0 /* CommandResult.Success */;
|
|
6239
6276
|
}
|
|
6277
|
+
function shouldRemoveFirstLabel(labelRange, dataset, dataSetsHaveTitle) {
|
|
6278
|
+
if (!dataSetsHaveTitle)
|
|
6279
|
+
return false;
|
|
6280
|
+
if (!labelRange)
|
|
6281
|
+
return false;
|
|
6282
|
+
if (!dataset)
|
|
6283
|
+
return true;
|
|
6284
|
+
const datasetLength = getZoneArea(dataset.dataRange.zone);
|
|
6285
|
+
const labelLength = getZoneArea(labelRange.zone);
|
|
6286
|
+
if (labelLength < datasetLength) {
|
|
6287
|
+
return false;
|
|
6288
|
+
}
|
|
6289
|
+
return true;
|
|
6290
|
+
}
|
|
6240
6291
|
// ---------------------------------------------------------------------------
|
|
6241
6292
|
// Scorecard
|
|
6242
6293
|
// ---------------------------------------------------------------------------
|
|
@@ -6606,6 +6657,7 @@ class BarChart extends AbstractChart {
|
|
|
6606
6657
|
this.legendPosition = definition.legendPosition;
|
|
6607
6658
|
this.stacked = definition.stacked;
|
|
6608
6659
|
this.aggregated = definition.aggregated;
|
|
6660
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
6609
6661
|
}
|
|
6610
6662
|
static transformDefinition(definition, executed) {
|
|
6611
6663
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -6673,11 +6725,13 @@ class BarChart extends AbstractChart {
|
|
|
6673
6725
|
const dataSets = this.dataSets
|
|
6674
6726
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
6675
6727
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
6728
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
6676
6729
|
return {
|
|
6677
6730
|
...this.getDefinition(),
|
|
6678
6731
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
6679
6732
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
6680
6733
|
dataSets,
|
|
6734
|
+
labelRange,
|
|
6681
6735
|
};
|
|
6682
6736
|
}
|
|
6683
6737
|
updateRanges(applyChange) {
|
|
@@ -6745,6 +6799,11 @@ function createBarChartRuntime(chart, getters) {
|
|
|
6745
6799
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
6746
6800
|
let labels = labelValues.formattedValues;
|
|
6747
6801
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
6802
|
+
if (chart.dataSetsHaveTitle &&
|
|
6803
|
+
dataSetsValues[0] &&
|
|
6804
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
6805
|
+
labels.shift();
|
|
6806
|
+
}
|
|
6748
6807
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
6749
6808
|
if (chart.aggregated) {
|
|
6750
6809
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
@@ -7167,6 +7226,7 @@ class LineChart extends AbstractChart {
|
|
|
7167
7226
|
this.labelsAsText = definition.labelsAsText;
|
|
7168
7227
|
this.stacked = definition.stacked;
|
|
7169
7228
|
this.aggregated = definition.aggregated;
|
|
7229
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
7170
7230
|
}
|
|
7171
7231
|
static validateChartDefinition(validator, definition) {
|
|
7172
7232
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -7234,11 +7294,13 @@ class LineChart extends AbstractChart {
|
|
|
7234
7294
|
const dataSets = this.dataSets
|
|
7235
7295
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
7236
7296
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
7297
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
7237
7298
|
return {
|
|
7238
7299
|
...this.getDefinition(),
|
|
7239
7300
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
7240
7301
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
7241
7302
|
dataSets,
|
|
7303
|
+
labelRange,
|
|
7242
7304
|
};
|
|
7243
7305
|
}
|
|
7244
7306
|
copyForSheetId(sheetId) {
|
|
@@ -7376,6 +7438,11 @@ function createLineChartRuntime(chart, getters) {
|
|
|
7376
7438
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
7377
7439
|
let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
|
|
7378
7440
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
7441
|
+
if (chart.dataSetsHaveTitle &&
|
|
7442
|
+
dataSetsValues[0] &&
|
|
7443
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
7444
|
+
labels.shift();
|
|
7445
|
+
}
|
|
7379
7446
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
7380
7447
|
if (axisType === "time") {
|
|
7381
7448
|
({ labels, dataSetsValues } = fixEmptyLabelsForDateCharts(labels, dataSetsValues));
|
|
@@ -7434,6 +7501,7 @@ class PieChart extends AbstractChart {
|
|
|
7434
7501
|
this.background = definition.background;
|
|
7435
7502
|
this.legendPosition = definition.legendPosition;
|
|
7436
7503
|
this.aggregated = definition.aggregated;
|
|
7504
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
7437
7505
|
}
|
|
7438
7506
|
static transformDefinition(definition, executed) {
|
|
7439
7507
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -7497,12 +7565,14 @@ class PieChart extends AbstractChart {
|
|
|
7497
7565
|
const dataSets = this.dataSets
|
|
7498
7566
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
7499
7567
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
7568
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
7500
7569
|
return {
|
|
7501
7570
|
...this.getDefinition(),
|
|
7502
7571
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
7503
7572
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
7504
7573
|
verticalAxisPosition: "left",
|
|
7505
7574
|
dataSets,
|
|
7575
|
+
labelRange,
|
|
7506
7576
|
};
|
|
7507
7577
|
}
|
|
7508
7578
|
updateRanges(applyChange) {
|
|
@@ -7548,6 +7618,11 @@ function createPieChartRuntime(chart, getters) {
|
|
|
7548
7618
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
7549
7619
|
let labels = labelValues.formattedValues;
|
|
7550
7620
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
7621
|
+
if (chart.dataSetsHaveTitle &&
|
|
7622
|
+
dataSetsValues[0] &&
|
|
7623
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
7624
|
+
labels.shift();
|
|
7625
|
+
}
|
|
7551
7626
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
7552
7627
|
if (chart.aggregated) {
|
|
7553
7628
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
@@ -7804,6 +7879,10 @@ css /* scss */ `
|
|
|
7804
7879
|
}
|
|
7805
7880
|
`;
|
|
7806
7881
|
class ChartFigure extends owl.Component {
|
|
7882
|
+
onDoubleClick() {
|
|
7883
|
+
this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
|
|
7884
|
+
this.env.openSidePanel("ChartPanel");
|
|
7885
|
+
}
|
|
7807
7886
|
get chartType() {
|
|
7808
7887
|
return this.env.model.getters.getChartType(this.props.figure.id);
|
|
7809
7888
|
}
|
|
@@ -8179,7 +8258,6 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
8179
8258
|
labelRangeXc = zoneToXc({
|
|
8180
8259
|
...zone,
|
|
8181
8260
|
right: zone.left,
|
|
8182
|
-
top: dataSetsHaveTitle ? zone.top + 1 : zone.top,
|
|
8183
8261
|
});
|
|
8184
8262
|
}
|
|
8185
8263
|
// Only display legend for several datasets.
|
|
@@ -15097,7 +15175,7 @@ const ADDRESS = {
|
|
|
15097
15175
|
cellReference = rowPart + colPart;
|
|
15098
15176
|
}
|
|
15099
15177
|
if (sheet !== undefined) {
|
|
15100
|
-
return `${
|
|
15178
|
+
return `${getCanonicalSheetName(toString(sheet))}!${cellReference}`;
|
|
15101
15179
|
}
|
|
15102
15180
|
return cellReference;
|
|
15103
15181
|
},
|
|
@@ -16922,6 +17000,22 @@ class LineBarPieConfigPanel extends owl.Component {
|
|
|
16922
17000
|
aggregated: ev.target.checked,
|
|
16923
17001
|
});
|
|
16924
17002
|
}
|
|
17003
|
+
calculateHeaderPosition() {
|
|
17004
|
+
if (this.isDatasetInvalid || this.isLabelInvalid) {
|
|
17005
|
+
return undefined;
|
|
17006
|
+
}
|
|
17007
|
+
const getters = this.env.model.getters;
|
|
17008
|
+
const sheetId = getters.getActiveSheetId();
|
|
17009
|
+
const labelRange = createRange(getters, sheetId, this.labelRange);
|
|
17010
|
+
const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
|
|
17011
|
+
if (dataSets.length) {
|
|
17012
|
+
return dataSets[0].dataRange.zone.top + 1;
|
|
17013
|
+
}
|
|
17014
|
+
else if (labelRange) {
|
|
17015
|
+
return labelRange.zone.top + 1;
|
|
17016
|
+
}
|
|
17017
|
+
return undefined;
|
|
17018
|
+
}
|
|
16925
17019
|
}
|
|
16926
17020
|
LineBarPieConfigPanel.template = "o-spreadsheet-LineBarPieConfigPanel";
|
|
16927
17021
|
LineBarPieConfigPanel.components = { SelectionInput };
|
|
@@ -17169,6 +17263,9 @@ class ColorPicker extends owl.Component {
|
|
|
17169
17263
|
top,
|
|
17170
17264
|
});
|
|
17171
17265
|
}
|
|
17266
|
+
isSameColor(color1, color2) {
|
|
17267
|
+
return isSameColor(color1, color2);
|
|
17268
|
+
}
|
|
17172
17269
|
}
|
|
17173
17270
|
ColorPicker.template = "o-spreadsheet-ColorPicker";
|
|
17174
17271
|
ColorPicker.defaultProps = {
|
|
@@ -18841,7 +18938,7 @@ css /*SCSS*/ `
|
|
|
18841
18938
|
box-sizing: content-box;
|
|
18842
18939
|
|
|
18843
18940
|
.o-fig-anchor {
|
|
18844
|
-
z-index: ${ComponentsImportance.
|
|
18941
|
+
z-index: ${ComponentsImportance.FigureAnchor};
|
|
18845
18942
|
position: absolute;
|
|
18846
18943
|
width: ${ANCHOR_SIZE}px;
|
|
18847
18944
|
height: ${ANCHOR_SIZE}px;
|
|
@@ -19410,6 +19507,8 @@ class ContentEditableHelper {
|
|
|
19410
19507
|
start = 0;
|
|
19411
19508
|
if (end > textLength)
|
|
19412
19509
|
end = textLength;
|
|
19510
|
+
if (start > textLength)
|
|
19511
|
+
start = textLength;
|
|
19413
19512
|
}
|
|
19414
19513
|
let startNode = this.findChildAtCharacterIndex(start);
|
|
19415
19514
|
let endNode = this.findChildAtCharacterIndex(end);
|
|
@@ -19679,6 +19778,7 @@ css /* scss */ `
|
|
|
19679
19778
|
padding-right: 2px;
|
|
19680
19779
|
|
|
19681
19780
|
box-sizing: border-box;
|
|
19781
|
+
font-family: ${DEFAULT_FONT};
|
|
19682
19782
|
|
|
19683
19783
|
caret-color: black;
|
|
19684
19784
|
padding-left: 3px;
|
|
@@ -19708,13 +19808,6 @@ css /* scss */ `
|
|
|
19708
19808
|
pointer-events: none;
|
|
19709
19809
|
}
|
|
19710
19810
|
}
|
|
19711
|
-
|
|
19712
|
-
.o-topbar-composer .o-composer:empty:not(:focus)::before {
|
|
19713
|
-
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
19714
|
-
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 121.8 122.9' width='16' height='16' focusable='false'%3E%3Cpath d='m28 34-4 5v2h10l-6 40c-4 22-6 28-7 30-2 2-3 3-5 3-3 0-7-2-9-4H4c-2 2-4 4-4 7s4 6 8 6 9-2 15-8c8-7 13-17 18-39l7-35 13-1 3-6H49c4-23 7-27 11-27 2 0 5 2 8 6h4c1-1 4-4 4-7 0-2-3-6-9-6-5 0-13 4-20 10-6 7-9 14-11 24h-8zm41 16c4-5 7-7 8-7s2 1 5 9l3 12c-7 11-12 17-16 17l-3-1-2-1c-3 0-6 3-6 7s3 7 7 7c6 0 12-6 22-23l3 10c3 9 6 13 10 13 5 0 11-4 18-15l-3-4c-4 6-7 8-8 8-2 0-4-3-6-10l-5-15 8-10 6-4 3 1 3 2c2 0 6-3 6-7s-2-7-6-7c-6 0-11 5-21 20l-2-6c-3-9-5-14-9-14-5 0-12 6-18 15l3 3z' fill='%23BDBDBD' /%3E%3C/svg%3E");
|
|
19715
|
-
position: relative;
|
|
19716
|
-
top: 20%;
|
|
19717
|
-
}
|
|
19718
19811
|
`;
|
|
19719
19812
|
class Composer extends owl.Component {
|
|
19720
19813
|
constructor() {
|
|
@@ -20128,7 +20221,7 @@ class Composer extends owl.Component {
|
|
|
20128
20221
|
const highlights = this.env.model.getters.getHighlights();
|
|
20129
20222
|
const refSheet = sheetName
|
|
20130
20223
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
20131
|
-
: this.env.model.getters.
|
|
20224
|
+
: this.env.model.getters.getCurrentEditedCell().sheetId;
|
|
20132
20225
|
const highlight = highlights.find((highlight) => {
|
|
20133
20226
|
if (highlight.sheetId !== refSheet)
|
|
20134
20227
|
return false;
|
|
@@ -20289,7 +20382,7 @@ class GridComposer extends owl.Component {
|
|
|
20289
20382
|
get cellReference() {
|
|
20290
20383
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
20291
20384
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
20292
|
-
return `${prefixSheet ?
|
|
20385
|
+
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
20293
20386
|
}
|
|
20294
20387
|
get cellReferenceStyle() {
|
|
20295
20388
|
const { x: left, y: top } = this.rect;
|
|
@@ -20442,6 +20535,269 @@ FilterIconsOverlay.props = {
|
|
|
20442
20535
|
gridPosition: { type: Object, optional: true },
|
|
20443
20536
|
};
|
|
20444
20537
|
|
|
20538
|
+
/**
|
|
20539
|
+
* Transform a figure with coordinates from the model, to coordinates as they are shown on the screen,
|
|
20540
|
+
* taking into account the scroll position of the active sheet and the frozen panes.
|
|
20541
|
+
*/
|
|
20542
|
+
function internalFigureToScreen(getters, fig) {
|
|
20543
|
+
return { ...fig, ...internalToScreenCoordinates(getters, { x: fig.x, y: fig.y }) };
|
|
20544
|
+
}
|
|
20545
|
+
/**
|
|
20546
|
+
* Transform a figure with coordinates as they are shown on the screen, to coordinates as they are in the model,
|
|
20547
|
+
* taking into account the scroll position of the active sheet and the frozen panes.
|
|
20548
|
+
*
|
|
20549
|
+
* Note that this isn't exactly the reverse operation as internalFigureToScreen, because the figure will always be on top
|
|
20550
|
+
* of the frozen panes.
|
|
20551
|
+
*/
|
|
20552
|
+
function screenFigureToInternal(getters, fig) {
|
|
20553
|
+
return { ...fig, ...screenCoordinatesToInternal(getters, { x: fig.x, y: fig.y }) };
|
|
20554
|
+
}
|
|
20555
|
+
function internalToScreenCoordinates(getters, { x, y }) {
|
|
20556
|
+
const { x: viewportX, y: viewportY } = getters.getMainViewportCoordinates();
|
|
20557
|
+
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
20558
|
+
x = x < viewportX ? x : x - scrollX;
|
|
20559
|
+
y = y < viewportY ? y : y - scrollY;
|
|
20560
|
+
return { x, y };
|
|
20561
|
+
}
|
|
20562
|
+
function screenCoordinatesToInternal(getters, { x, y }) {
|
|
20563
|
+
const { x: viewportX, y: viewportY } = getters.getMainViewportCoordinates();
|
|
20564
|
+
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
20565
|
+
x = viewportX && x < viewportX ? x : x + scrollX;
|
|
20566
|
+
y = viewportY && y < viewportY ? y : y + scrollY;
|
|
20567
|
+
return { x, y };
|
|
20568
|
+
}
|
|
20569
|
+
|
|
20570
|
+
function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { maxX, maxY }, { scrollX, scrollY }) {
|
|
20571
|
+
const minX = viewportX ? 0 : -scrollX;
|
|
20572
|
+
const minY = viewportY ? 0 : -scrollY;
|
|
20573
|
+
const deltaX = mouseX - mouseInitialX;
|
|
20574
|
+
const newX = clamp(initialFigure.x + deltaX, minX, maxX - initialFigure.width - scrollX);
|
|
20575
|
+
const deltaY = mouseY - mouseInitialY;
|
|
20576
|
+
const newY = clamp(initialFigure.y + deltaY, minY, maxY - initialFigure.height - scrollY);
|
|
20577
|
+
return { ...initialFigure, x: newX, y: newY };
|
|
20578
|
+
}
|
|
20579
|
+
function clamp(value, min, max) {
|
|
20580
|
+
return Math.min(Math.max(value, min), max);
|
|
20581
|
+
}
|
|
20582
|
+
function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, keepRatio, minFigSize) {
|
|
20583
|
+
let { x, y, width, height } = initialFigure;
|
|
20584
|
+
if (keepRatio && dirX != 0 && dirY != 0) {
|
|
20585
|
+
const deltaX = Math.min(dirX * (mouseInitialX - mouseX), initialFigure.width - minFigSize);
|
|
20586
|
+
const deltaY = Math.min(dirY * (mouseInitialY - mouseY), initialFigure.height - minFigSize);
|
|
20587
|
+
const fraction = Math.min(deltaX / initialFigure.width, deltaY / initialFigure.height);
|
|
20588
|
+
width = initialFigure.width * (1 - fraction);
|
|
20589
|
+
height = initialFigure.height * (1 - fraction);
|
|
20590
|
+
if (dirX < 0) {
|
|
20591
|
+
x = initialFigure.x + initialFigure.width * fraction;
|
|
20592
|
+
}
|
|
20593
|
+
if (dirY < 0) {
|
|
20594
|
+
y = initialFigure.y + initialFigure.height * fraction;
|
|
20595
|
+
}
|
|
20596
|
+
}
|
|
20597
|
+
else {
|
|
20598
|
+
const deltaX = Math.max(dirX * (mouseX - mouseInitialX), minFigSize - initialFigure.width);
|
|
20599
|
+
const deltaY = Math.max(dirY * (mouseY - mouseInitialY), minFigSize - initialFigure.height);
|
|
20600
|
+
width = initialFigure.width + deltaX;
|
|
20601
|
+
height = initialFigure.height + deltaY;
|
|
20602
|
+
if (dirX < 0) {
|
|
20603
|
+
x = initialFigure.x - deltaX;
|
|
20604
|
+
}
|
|
20605
|
+
if (dirY < 0) {
|
|
20606
|
+
y = initialFigure.y - deltaY;
|
|
20607
|
+
}
|
|
20608
|
+
}
|
|
20609
|
+
return { ...initialFigure, x, y, width, height };
|
|
20610
|
+
}
|
|
20611
|
+
|
|
20612
|
+
const SNAP_MARGIN = 5;
|
|
20613
|
+
/**
|
|
20614
|
+
* Try to snap the given figure to other figures when moving the figure, and return the snapped
|
|
20615
|
+
* figure and the possible snap lines, if any were found
|
|
20616
|
+
*/
|
|
20617
|
+
function snapForMove(getters, figureToSnap, otherFigures) {
|
|
20618
|
+
const snappedFigure = { ...figureToSnap };
|
|
20619
|
+
const verticalSnapLine = getSnapLine(getters, snappedFigure, ["hCenter", "right", "left"], otherFigures, ["hCenter", "right", "left"]);
|
|
20620
|
+
const horizontalSnapLine = getSnapLine(getters, snappedFigure, ["vCenter", "bottom", "top"], otherFigures, ["vCenter", "bottom", "top"]);
|
|
20621
|
+
const { y: viewportY, x: viewportX } = getters.getMainViewportCoordinates();
|
|
20622
|
+
const { scrollY, scrollX } = getters.getActiveSheetScrollInfo();
|
|
20623
|
+
// If the snap cause the figure to change pane, we need to also apply the scroll as an offset
|
|
20624
|
+
if (horizontalSnapLine) {
|
|
20625
|
+
snappedFigure.y -= horizontalSnapLine.snapOffset;
|
|
20626
|
+
const isBaseFigFrozenY = figureToSnap.y < viewportY;
|
|
20627
|
+
const isSnappedFrozenY = snappedFigure.y < viewportY;
|
|
20628
|
+
if (isBaseFigFrozenY && !isSnappedFrozenY)
|
|
20629
|
+
snappedFigure.y += scrollY;
|
|
20630
|
+
else if (!isBaseFigFrozenY && isSnappedFrozenY)
|
|
20631
|
+
snappedFigure.y -= scrollY;
|
|
20632
|
+
}
|
|
20633
|
+
if (verticalSnapLine) {
|
|
20634
|
+
snappedFigure.x -= verticalSnapLine.snapOffset;
|
|
20635
|
+
const isBaseFigFrozenX = figureToSnap.x < viewportX;
|
|
20636
|
+
const isSnappedFrozenX = snappedFigure.x < viewportX;
|
|
20637
|
+
if (isBaseFigFrozenX && !isSnappedFrozenX)
|
|
20638
|
+
snappedFigure.x += scrollX;
|
|
20639
|
+
else if (!isBaseFigFrozenX && isSnappedFrozenX)
|
|
20640
|
+
snappedFigure.x -= scrollX;
|
|
20641
|
+
}
|
|
20642
|
+
return { snappedFigure, verticalSnapLine, horizontalSnapLine };
|
|
20643
|
+
}
|
|
20644
|
+
/**
|
|
20645
|
+
* Try to snap the given figure to the other figures when resizing the figure, and return the snapped
|
|
20646
|
+
* figure and the possible snap lines, if any were found
|
|
20647
|
+
*/
|
|
20648
|
+
function snapForResize(getters, resizeDirX, resizeDirY, figureToSnap, otherFigures) {
|
|
20649
|
+
const snappedFigure = { ...figureToSnap };
|
|
20650
|
+
// Vertical snap line
|
|
20651
|
+
const verticalSnapLine = getSnapLine(getters, snappedFigure, [resizeDirX === -1 ? "left" : "right"], otherFigures, ["right", "left"]);
|
|
20652
|
+
if (verticalSnapLine) {
|
|
20653
|
+
if (resizeDirX === 1) {
|
|
20654
|
+
snappedFigure.width -= verticalSnapLine.snapOffset;
|
|
20655
|
+
}
|
|
20656
|
+
else if (resizeDirX === -1) {
|
|
20657
|
+
snappedFigure.x -= verticalSnapLine.snapOffset;
|
|
20658
|
+
snappedFigure.width += verticalSnapLine.snapOffset;
|
|
20659
|
+
}
|
|
20660
|
+
}
|
|
20661
|
+
// Horizontal snap line
|
|
20662
|
+
const horizontalSnapLine = getSnapLine(getters, snappedFigure, [resizeDirY === -1 ? "top" : "bottom"], otherFigures, ["bottom", "top"]);
|
|
20663
|
+
if (horizontalSnapLine) {
|
|
20664
|
+
if (resizeDirY === 1) {
|
|
20665
|
+
snappedFigure.height -= horizontalSnapLine.snapOffset;
|
|
20666
|
+
}
|
|
20667
|
+
else if (resizeDirY === -1) {
|
|
20668
|
+
snappedFigure.y -= horizontalSnapLine.snapOffset;
|
|
20669
|
+
snappedFigure.height += horizontalSnapLine.snapOffset;
|
|
20670
|
+
}
|
|
20671
|
+
}
|
|
20672
|
+
snappedFigure.x = Math.round(snappedFigure.x);
|
|
20673
|
+
snappedFigure.y = Math.round(snappedFigure.y);
|
|
20674
|
+
snappedFigure.height = Math.round(snappedFigure.height);
|
|
20675
|
+
snappedFigure.width = Math.round(snappedFigure.width);
|
|
20676
|
+
return { snappedFigure, verticalSnapLine, horizontalSnapLine };
|
|
20677
|
+
}
|
|
20678
|
+
/**
|
|
20679
|
+
* Get the position of snap axes for the given figure
|
|
20680
|
+
*
|
|
20681
|
+
* @param figure the figure
|
|
20682
|
+
* @param axesTypes the list of axis types to return the positions of
|
|
20683
|
+
*/
|
|
20684
|
+
function getVisibleAxes(getters, figure, axesTypes) {
|
|
20685
|
+
const axes = axesTypes.map((axisType) => getAxis(figure, axisType));
|
|
20686
|
+
return axes
|
|
20687
|
+
.filter((axis) => isAxisVisible(getters, figure, axis))
|
|
20688
|
+
.map((axis) => getAxisScreenPosition(getters, figure, axis));
|
|
20689
|
+
}
|
|
20690
|
+
/**
|
|
20691
|
+
* We need two positions for the figure axis :
|
|
20692
|
+
* - the position (core) of the axis in the figure. This is used to know whether or not the axis is
|
|
20693
|
+
* displayed, or is hidden by the scroll/the frozen panes
|
|
20694
|
+
* - the position in the screen, which is used to find snap matches. We cannot use the core position for this,
|
|
20695
|
+
* because figures partially in frozen panes aren't displayed at their actual coordinates
|
|
20696
|
+
*/
|
|
20697
|
+
function getAxisScreenPosition(getters, figure, figureAxis) {
|
|
20698
|
+
const screenFigure = internalFigureToScreen(getters, figure);
|
|
20699
|
+
return getAxis(screenFigure, figureAxis.axisType);
|
|
20700
|
+
}
|
|
20701
|
+
function isAxisVisible(getters, figure, axis) {
|
|
20702
|
+
const { x: mainViewportX, y: mainViewportY } = getters.getMainViewportCoordinates();
|
|
20703
|
+
const axisStartEndPositions = [];
|
|
20704
|
+
switch (axis.axisType) {
|
|
20705
|
+
case "top":
|
|
20706
|
+
case "bottom":
|
|
20707
|
+
case "vCenter":
|
|
20708
|
+
if (figure.y < mainViewportY)
|
|
20709
|
+
return true;
|
|
20710
|
+
axisStartEndPositions.push({ x: figure.x, y: axis.position });
|
|
20711
|
+
axisStartEndPositions.push({ x: figure.x + figure.width, y: axis.position });
|
|
20712
|
+
break;
|
|
20713
|
+
case "left":
|
|
20714
|
+
case "right":
|
|
20715
|
+
case "hCenter":
|
|
20716
|
+
if (figure.x < mainViewportX)
|
|
20717
|
+
return true;
|
|
20718
|
+
axisStartEndPositions.push({ x: axis.position, y: figure.y });
|
|
20719
|
+
axisStartEndPositions.push({ x: axis.position, y: figure.y + figure.height });
|
|
20720
|
+
break;
|
|
20721
|
+
}
|
|
20722
|
+
return axisStartEndPositions.some(getters.isPositionVisible);
|
|
20723
|
+
}
|
|
20724
|
+
/**
|
|
20725
|
+
* Get a snap line for the given figure, if the figure can snap to any other figure
|
|
20726
|
+
*
|
|
20727
|
+
* @param figureToSnap figure to get the snap line for
|
|
20728
|
+
* @param figAxesTypes figure axes of the given figure to be considered to find a snap line
|
|
20729
|
+
* @param otherFigures figures to match against the snapped figure to find a snap line
|
|
20730
|
+
* @param otherAxesTypes figure axes of the other figures to be considered to find a snap line
|
|
20731
|
+
*/
|
|
20732
|
+
function getSnapLine(getters, figureToSnap, figAxesTypes, otherFigures, otherAxesTypes) {
|
|
20733
|
+
const axesOfFigure = getVisibleAxes(getters, figureToSnap, figAxesTypes);
|
|
20734
|
+
let closestMatch = undefined;
|
|
20735
|
+
for (const otherFigure of otherFigures) {
|
|
20736
|
+
const axesOfOtherFig = getVisibleAxes(getters, otherFigure, otherAxesTypes);
|
|
20737
|
+
for (const axisOfFigure of axesOfFigure) {
|
|
20738
|
+
for (const axisOfOtherFig of axesOfOtherFig) {
|
|
20739
|
+
if (!canSnap(axisOfFigure.position, axisOfOtherFig.position))
|
|
20740
|
+
continue;
|
|
20741
|
+
const snapOffset = axisOfFigure.position - axisOfOtherFig.position;
|
|
20742
|
+
if (closestMatch && snapOffset === closestMatch.snapOffset) {
|
|
20743
|
+
closestMatch.matchedFigIds.push(otherFigure.id);
|
|
20744
|
+
}
|
|
20745
|
+
else if (!closestMatch || Math.abs(snapOffset) <= Math.abs(closestMatch.snapOffset)) {
|
|
20746
|
+
closestMatch = {
|
|
20747
|
+
matchedFigIds: [otherFigure.id],
|
|
20748
|
+
snapOffset,
|
|
20749
|
+
snappedAxisType: axisOfFigure.axisType,
|
|
20750
|
+
position: axisOfOtherFig.position,
|
|
20751
|
+
};
|
|
20752
|
+
}
|
|
20753
|
+
}
|
|
20754
|
+
}
|
|
20755
|
+
}
|
|
20756
|
+
return closestMatch;
|
|
20757
|
+
}
|
|
20758
|
+
/** Check if two axes are close enough to snap */
|
|
20759
|
+
function canSnap(axisPosition1, axisPosition2) {
|
|
20760
|
+
return Math.abs(axisPosition1 - axisPosition2) <= SNAP_MARGIN;
|
|
20761
|
+
}
|
|
20762
|
+
function getAxis(fig, axisType) {
|
|
20763
|
+
let position = 0;
|
|
20764
|
+
switch (axisType) {
|
|
20765
|
+
case "top":
|
|
20766
|
+
position = fig.y;
|
|
20767
|
+
break;
|
|
20768
|
+
case "bottom":
|
|
20769
|
+
position = fig.y + fig.height - FIGURE_BORDER_WIDTH;
|
|
20770
|
+
break;
|
|
20771
|
+
case "vCenter":
|
|
20772
|
+
position = fig.y + Math.floor(fig.height / 2) - FIGURE_BORDER_WIDTH;
|
|
20773
|
+
break;
|
|
20774
|
+
case "left":
|
|
20775
|
+
position = fig.x;
|
|
20776
|
+
break;
|
|
20777
|
+
case "right":
|
|
20778
|
+
position = fig.x + fig.width - FIGURE_BORDER_WIDTH;
|
|
20779
|
+
break;
|
|
20780
|
+
case "hCenter":
|
|
20781
|
+
position = fig.x + Math.floor(fig.width / 2) - FIGURE_BORDER_WIDTH;
|
|
20782
|
+
break;
|
|
20783
|
+
}
|
|
20784
|
+
return { position, axisType: axisType };
|
|
20785
|
+
}
|
|
20786
|
+
|
|
20787
|
+
css /*SCSS*/ `
|
|
20788
|
+
.o-figure-snap-line {
|
|
20789
|
+
position: relative;
|
|
20790
|
+
z-index: ${ComponentsImportance.FigureSnapLine};
|
|
20791
|
+
&.vertical {
|
|
20792
|
+
width: 0px;
|
|
20793
|
+
border-left: 1px dashed black;
|
|
20794
|
+
}
|
|
20795
|
+
&.horizontal {
|
|
20796
|
+
border-top: 1px dashed black;
|
|
20797
|
+
height: 0px;
|
|
20798
|
+
}
|
|
20799
|
+
}
|
|
20800
|
+
`;
|
|
20445
20801
|
/**
|
|
20446
20802
|
* Each figure ⭐ is positioned inside a container `div` placed and sized
|
|
20447
20803
|
* according to the split pane the figure is part of, or a separate container for the figure
|
|
@@ -20506,11 +20862,9 @@ class FiguresContainer extends owl.Component {
|
|
|
20506
20862
|
constructor() {
|
|
20507
20863
|
super(...arguments);
|
|
20508
20864
|
this.dnd = owl.useState({
|
|
20509
|
-
|
|
20510
|
-
|
|
20511
|
-
|
|
20512
|
-
width: 0,
|
|
20513
|
-
height: 0,
|
|
20865
|
+
draggedFigure: undefined,
|
|
20866
|
+
horizontalSnap: undefined,
|
|
20867
|
+
verticalSnap: undefined,
|
|
20514
20868
|
});
|
|
20515
20869
|
}
|
|
20516
20870
|
setup() {
|
|
@@ -20526,9 +20880,11 @@ class FiguresContainer extends owl.Component {
|
|
|
20526
20880
|
});
|
|
20527
20881
|
}
|
|
20528
20882
|
getVisibleFigures() {
|
|
20883
|
+
var _a;
|
|
20529
20884
|
const visibleFigures = this.env.model.getters.getVisibleFigures();
|
|
20530
|
-
if (this.dnd.
|
|
20531
|
-
visibleFigures.
|
|
20885
|
+
if (this.dnd.draggedFigure &&
|
|
20886
|
+
!visibleFigures.some((figure) => { var _a; return figure.id === ((_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id); })) {
|
|
20887
|
+
visibleFigures.push(this.env.model.getters.getFigure(this.env.model.getters.getActiveSheetId(), (_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id));
|
|
20532
20888
|
}
|
|
20533
20889
|
return visibleFigures;
|
|
20534
20890
|
}
|
|
@@ -20551,7 +20907,7 @@ class FiguresContainer extends owl.Component {
|
|
|
20551
20907
|
});
|
|
20552
20908
|
}
|
|
20553
20909
|
}
|
|
20554
|
-
if (this.dnd.
|
|
20910
|
+
if (this.dnd.draggedFigure) {
|
|
20555
20911
|
containers.push({
|
|
20556
20912
|
type: "dnd",
|
|
20557
20913
|
figures: [this.getDndFigure()],
|
|
@@ -20562,19 +20918,25 @@ class FiguresContainer extends owl.Component {
|
|
|
20562
20918
|
return containers;
|
|
20563
20919
|
}
|
|
20564
20920
|
getContainerStyle(container) {
|
|
20565
|
-
|
|
20566
|
-
|
|
20567
|
-
|
|
20568
|
-
const width = viewWidth - left;
|
|
20569
|
-
const top = ["bottomRight", "bottomLeft"].includes(container) ? viewportY : 0;
|
|
20570
|
-
const height = viewHeight - top;
|
|
20921
|
+
return this.rectToCss(this.getContainerRect(container));
|
|
20922
|
+
}
|
|
20923
|
+
rectToCss(rect) {
|
|
20571
20924
|
return cssPropertiesToCss({
|
|
20572
|
-
left: `${
|
|
20573
|
-
top: `${
|
|
20574
|
-
width: `${width}px`,
|
|
20575
|
-
height: `${height}px`,
|
|
20925
|
+
left: `${rect.x}px`,
|
|
20926
|
+
top: `${rect.y}px`,
|
|
20927
|
+
width: `${rect.width}px`,
|
|
20928
|
+
height: `${rect.height}px`,
|
|
20576
20929
|
});
|
|
20577
20930
|
}
|
|
20931
|
+
getContainerRect(container) {
|
|
20932
|
+
const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
|
|
20933
|
+
const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
|
|
20934
|
+
const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
|
|
20935
|
+
const width = viewWidth - x;
|
|
20936
|
+
const y = ["bottomRight", "bottomLeft"].includes(container) ? viewportY : 0;
|
|
20937
|
+
const height = viewHeight - y;
|
|
20938
|
+
return { x, y, width, height };
|
|
20939
|
+
}
|
|
20578
20940
|
getInverseViewportPositionStyle(container) {
|
|
20579
20941
|
const { scrollX, scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
20580
20942
|
const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
|
|
@@ -20586,8 +20948,9 @@ class FiguresContainer extends owl.Component {
|
|
|
20586
20948
|
});
|
|
20587
20949
|
}
|
|
20588
20950
|
getFigureContainer(figure) {
|
|
20951
|
+
var _a;
|
|
20589
20952
|
const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
|
|
20590
|
-
if (figure.id === this.dnd.
|
|
20953
|
+
if (figure.id === ((_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
20591
20954
|
return "dnd";
|
|
20592
20955
|
}
|
|
20593
20956
|
else if (figure.x < viewportX && figure.y < viewportY) {
|
|
@@ -20613,133 +20976,141 @@ class FiguresContainer extends owl.Component {
|
|
|
20613
20976
|
return;
|
|
20614
20977
|
}
|
|
20615
20978
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
20616
|
-
const
|
|
20617
|
-
const
|
|
20618
|
-
|
|
20619
|
-
|
|
20620
|
-
|
|
20621
|
-
this.
|
|
20622
|
-
|
|
20979
|
+
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
20980
|
+
const maxDimensions = {
|
|
20981
|
+
maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
|
|
20982
|
+
maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
|
|
20983
|
+
};
|
|
20984
|
+
const { x, y } = internalFigureToScreen(this.env.model.getters, figure);
|
|
20985
|
+
const initialFig = { ...figure, x, y };
|
|
20623
20986
|
const onMouseMove = (ev) => {
|
|
20624
|
-
const
|
|
20625
|
-
const {
|
|
20626
|
-
const
|
|
20627
|
-
const
|
|
20628
|
-
|
|
20629
|
-
const
|
|
20630
|
-
|
|
20631
|
-
this.dnd.
|
|
20632
|
-
|
|
20633
|
-
let deltaY = newY - mouseInitialY;
|
|
20634
|
-
this.dnd.y = Math.max(dndInitialY + deltaY, minY);
|
|
20987
|
+
const getters = this.env.model.getters;
|
|
20988
|
+
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
20989
|
+
const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), maxDimensions, getters.getActiveSheetScrollInfo());
|
|
20990
|
+
const otherFigures = this.getOtherFigures(figure.id);
|
|
20991
|
+
const internalDragged = screenFigureToInternal(getters, draggedFigure);
|
|
20992
|
+
const snapResult = snapForMove(getters, internalDragged, otherFigures);
|
|
20993
|
+
this.dnd.draggedFigure = internalFigureToScreen(getters, snapResult.snappedFigure);
|
|
20994
|
+
this.dnd.horizontalSnap = this.getSnap(snapResult.horizontalSnapLine);
|
|
20995
|
+
this.dnd.verticalSnap = this.getSnap(snapResult.verticalSnapLine);
|
|
20635
20996
|
};
|
|
20636
20997
|
const onMouseUp = (ev) => {
|
|
20637
|
-
if (!this.dnd.
|
|
20998
|
+
if (!this.dnd.draggedFigure) {
|
|
20638
20999
|
return;
|
|
20639
21000
|
}
|
|
20640
|
-
let { x, y } = this.
|
|
20641
|
-
this.dnd.
|
|
21001
|
+
let { x, y } = screenFigureToInternal(this.env.model.getters, this.dnd.draggedFigure);
|
|
21002
|
+
this.dnd.draggedFigure = undefined;
|
|
21003
|
+
this.dnd.horizontalSnap = undefined;
|
|
21004
|
+
this.dnd.verticalSnap = undefined;
|
|
20642
21005
|
this.env.model.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x, y });
|
|
20643
21006
|
};
|
|
20644
21007
|
startDnd(onMouseMove, onMouseUp);
|
|
20645
21008
|
}
|
|
21009
|
+
/**
|
|
21010
|
+
* Initialize the resize of a figure with mouse movements
|
|
21011
|
+
*
|
|
21012
|
+
* @param dirX X direction of the resize. -1 : resize from the left border of the figure, 0 : no resize in X, 1 :
|
|
21013
|
+
* resize from the right border of the figure
|
|
21014
|
+
* @param dirY Y direction of the resize. -1 : resize from the top border of the figure, 0 : no resize in Y, 1 :
|
|
21015
|
+
* resize from the bottom border of the figure
|
|
21016
|
+
* @param ev Mouse Event
|
|
21017
|
+
*/
|
|
20646
21018
|
startResize(figure, dirX, dirY, ev) {
|
|
20647
21019
|
ev.stopPropagation();
|
|
20648
|
-
const
|
|
20649
|
-
const
|
|
20650
|
-
const { x
|
|
20651
|
-
this.dnd.x = dndInitialX;
|
|
20652
|
-
this.dnd.y = dndInitialY;
|
|
20653
|
-
this.dnd.width = figure.width;
|
|
20654
|
-
this.dnd.height = figure.height;
|
|
21020
|
+
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
21021
|
+
const { x, y } = internalFigureToScreen(this.env.model.getters, figure);
|
|
21022
|
+
const initialFig = { ...figure, x, y };
|
|
20655
21023
|
const keepRatio = figureRegistry.get(figure.tag).keepRatio || false;
|
|
20656
21024
|
const minFigSize = figureRegistry.get(figure.tag).minFigSize || MIN_FIG_SIZE;
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
|
|
20661
|
-
|
|
20662
|
-
|
|
20663
|
-
|
|
20664
|
-
|
|
20665
|
-
|
|
20666
|
-
if (dirX < 0) {
|
|
20667
|
-
this.dnd.x = dndInitialX + figure.width * fraction;
|
|
20668
|
-
}
|
|
20669
|
-
if (dirY < 0) {
|
|
20670
|
-
this.dnd.y = dndInitialY + figure.height * fraction;
|
|
20671
|
-
}
|
|
20672
|
-
};
|
|
20673
|
-
}
|
|
20674
|
-
else {
|
|
20675
|
-
onMouseMove = (ev) => {
|
|
20676
|
-
this.dnd.figId = figure.id;
|
|
20677
|
-
const deltaX = Math.max(dirX * (ev.clientX - initialX), minFigSize - figure.width);
|
|
20678
|
-
const deltaY = Math.max(dirY * (ev.clientY - initialY), minFigSize - figure.height);
|
|
20679
|
-
this.dnd.width = figure.width + deltaX;
|
|
20680
|
-
this.dnd.height = figure.height + deltaY;
|
|
20681
|
-
if (dirX < 0) {
|
|
20682
|
-
this.dnd.x = dndInitialX - deltaX;
|
|
20683
|
-
}
|
|
20684
|
-
if (dirY < 0) {
|
|
20685
|
-
this.dnd.y = dndInitialY - deltaY;
|
|
20686
|
-
}
|
|
20687
|
-
};
|
|
20688
|
-
}
|
|
21025
|
+
const onMouseMove = (ev) => {
|
|
21026
|
+
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
21027
|
+
const draggedFigure = dragFigureForResize(initialFig, dirX, dirY, currentMousePosition, initialMousePosition, keepRatio, minFigSize);
|
|
21028
|
+
const otherFigures = this.getOtherFigures(figure.id);
|
|
21029
|
+
const snapResult = snapForResize(this.env.model.getters, dirX, dirY, draggedFigure, otherFigures);
|
|
21030
|
+
this.dnd.draggedFigure = snapResult.snappedFigure;
|
|
21031
|
+
this.dnd.horizontalSnap = this.getSnap(snapResult.horizontalSnapLine);
|
|
21032
|
+
this.dnd.verticalSnap = this.getSnap(snapResult.verticalSnapLine);
|
|
21033
|
+
};
|
|
20689
21034
|
const onMouseUp = (ev) => {
|
|
20690
|
-
if (!this.dnd.
|
|
21035
|
+
if (!this.dnd.draggedFigure) {
|
|
20691
21036
|
return;
|
|
20692
21037
|
}
|
|
20693
|
-
this.dnd.
|
|
20694
|
-
let { x, y } = this.screenCoordinatesToInternal(this.dnd);
|
|
21038
|
+
let { x, y } = screenFigureToInternal(this.env.model.getters, this.dnd.draggedFigure);
|
|
20695
21039
|
const update = { x, y };
|
|
20696
21040
|
if (dirX) {
|
|
20697
|
-
update.width = this.dnd.width;
|
|
21041
|
+
update.width = this.dnd.draggedFigure.width;
|
|
20698
21042
|
}
|
|
20699
21043
|
if (dirY) {
|
|
20700
|
-
update.height = this.dnd.height;
|
|
21044
|
+
update.height = this.dnd.draggedFigure.height;
|
|
20701
21045
|
}
|
|
20702
21046
|
this.env.model.dispatch("UPDATE_FIGURE", {
|
|
20703
21047
|
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
20704
21048
|
id: figure.id,
|
|
20705
21049
|
...update,
|
|
20706
21050
|
});
|
|
21051
|
+
this.dnd.draggedFigure = undefined;
|
|
21052
|
+
this.dnd.horizontalSnap = undefined;
|
|
21053
|
+
this.dnd.verticalSnap = undefined;
|
|
20707
21054
|
};
|
|
20708
21055
|
startDnd(onMouseMove, onMouseUp);
|
|
20709
21056
|
}
|
|
21057
|
+
getOtherFigures(figId) {
|
|
21058
|
+
return this.getVisibleFigures().filter((f) => f.id !== figId);
|
|
21059
|
+
}
|
|
20710
21060
|
getDndFigure() {
|
|
20711
|
-
const figure = this.getVisibleFigures().find((fig) => fig.id === this.dnd.
|
|
21061
|
+
const figure = this.getVisibleFigures().find((fig) => { var _a; return fig.id === ((_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id); });
|
|
20712
21062
|
if (!figure)
|
|
20713
21063
|
throw new Error("Dnd figure not found");
|
|
20714
21064
|
return {
|
|
20715
21065
|
...figure,
|
|
20716
|
-
|
|
20717
|
-
y: this.dnd.y,
|
|
20718
|
-
width: this.dnd.width,
|
|
20719
|
-
height: this.dnd.height,
|
|
21066
|
+
...this.dnd.draggedFigure,
|
|
20720
21067
|
};
|
|
20721
21068
|
}
|
|
20722
21069
|
getFigureStyle(figure) {
|
|
20723
|
-
|
|
21070
|
+
var _a;
|
|
21071
|
+
if (figure.id !== ((_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id))
|
|
20724
21072
|
return "";
|
|
20725
21073
|
return cssPropertiesToCss({
|
|
20726
21074
|
opacity: "0.9",
|
|
20727
21075
|
cursor: "grabbing",
|
|
20728
21076
|
});
|
|
20729
21077
|
}
|
|
20730
|
-
|
|
20731
|
-
|
|
20732
|
-
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
|
|
21078
|
+
getSnap(snapLine) {
|
|
21079
|
+
if (!snapLine || !this.dnd.draggedFigure)
|
|
21080
|
+
return undefined;
|
|
21081
|
+
const figureVisibleRects = snapLine.matchedFigIds
|
|
21082
|
+
.map((id) => this.getVisibleFigures().find((fig) => fig.id === id))
|
|
21083
|
+
.filter(isDefined$1)
|
|
21084
|
+
.map((fig) => {
|
|
21085
|
+
const figOnSCreen = internalFigureToScreen(this.env.model.getters, fig);
|
|
21086
|
+
const container = this.getFigureContainer(fig);
|
|
21087
|
+
return rectIntersection(figOnSCreen, this.getContainerRect(container));
|
|
21088
|
+
})
|
|
21089
|
+
.filter(isDefined$1);
|
|
21090
|
+
const containerRect = rectUnion(this.dnd.draggedFigure, ...figureVisibleRects);
|
|
21091
|
+
return {
|
|
21092
|
+
line: snapLine,
|
|
21093
|
+
containerStyle: this.rectToCss(containerRect),
|
|
21094
|
+
lineStyle: this.getSnapLineStyle(snapLine, containerRect),
|
|
21095
|
+
};
|
|
20736
21096
|
}
|
|
20737
|
-
|
|
20738
|
-
|
|
20739
|
-
|
|
20740
|
-
|
|
20741
|
-
|
|
20742
|
-
|
|
21097
|
+
getSnapLineStyle(snapLine, containerRect) {
|
|
21098
|
+
if (!snapLine)
|
|
21099
|
+
return "";
|
|
21100
|
+
if (["top", "vCenter", "bottom"].includes(snapLine.snappedAxisType)) {
|
|
21101
|
+
return cssPropertiesToCss({
|
|
21102
|
+
top: `${snapLine.position - containerRect.y}px`,
|
|
21103
|
+
left: `0px`,
|
|
21104
|
+
width: `100%`,
|
|
21105
|
+
});
|
|
21106
|
+
}
|
|
21107
|
+
else {
|
|
21108
|
+
return cssPropertiesToCss({
|
|
21109
|
+
top: `0px`,
|
|
21110
|
+
left: `${snapLine.position - containerRect.x}px`,
|
|
21111
|
+
height: `100%`,
|
|
21112
|
+
});
|
|
21113
|
+
}
|
|
20743
21114
|
}
|
|
20744
21115
|
}
|
|
20745
21116
|
FiguresContainer.template = "o-spreadsheet-FiguresContainer";
|
|
@@ -20886,6 +21257,9 @@ class GridOverlay extends owl.Component {
|
|
|
20886
21257
|
owl.onMounted(() => {
|
|
20887
21258
|
resizeObserver.observe(this.gridOverlayEl);
|
|
20888
21259
|
});
|
|
21260
|
+
owl.onWillUnmount(() => {
|
|
21261
|
+
resizeObserver.disconnect();
|
|
21262
|
+
});
|
|
20889
21263
|
useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
|
|
20890
21264
|
const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
|
|
20891
21265
|
return scrollY > 0;
|
|
@@ -22306,6 +22680,10 @@ class Grid extends owl.Component {
|
|
|
22306
22680
|
}
|
|
22307
22681
|
}
|
|
22308
22682
|
onInput(ev) {
|
|
22683
|
+
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
22684
|
+
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
22685
|
+
return;
|
|
22686
|
+
}
|
|
22309
22687
|
if (ev.data) {
|
|
22310
22688
|
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
22311
22689
|
// character
|
|
@@ -23154,6 +23532,70 @@ function fixXlsxUnicode(str) {
|
|
|
23154
23532
|
});
|
|
23155
23533
|
}
|
|
23156
23534
|
|
|
23535
|
+
const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
|
|
23536
|
+
/**
|
|
23537
|
+
* Convert excel format to o_spreadsheet format
|
|
23538
|
+
*
|
|
23539
|
+
* Excel format are defined in openXML §18.8.31
|
|
23540
|
+
*/
|
|
23541
|
+
function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
23542
|
+
var _a, _b, _c;
|
|
23543
|
+
if (numFmtId === 0) {
|
|
23544
|
+
return undefined;
|
|
23545
|
+
}
|
|
23546
|
+
// Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
|
|
23547
|
+
let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
|
|
23548
|
+
if (format) {
|
|
23549
|
+
try {
|
|
23550
|
+
let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
|
|
23551
|
+
convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
|
|
23552
|
+
convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
|
|
23553
|
+
// Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
|
|
23554
|
+
const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
23555
|
+
const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
|
|
23556
|
+
if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
|
|
23557
|
+
throw new Error("Multiple escaped blocks in format");
|
|
23558
|
+
}
|
|
23559
|
+
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
23560
|
+
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
|
|
23561
|
+
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
|
|
23562
|
+
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
23563
|
+
convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
|
|
23564
|
+
if (isXlsxDateFormat(convertedFormat)) {
|
|
23565
|
+
convertedFormat = convertDateFormat$1(convertedFormat);
|
|
23566
|
+
}
|
|
23567
|
+
if (isFormatSupported(convertedFormat)) {
|
|
23568
|
+
return convertedFormat;
|
|
23569
|
+
}
|
|
23570
|
+
}
|
|
23571
|
+
catch (e) { }
|
|
23572
|
+
}
|
|
23573
|
+
warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
|
|
23574
|
+
return undefined;
|
|
23575
|
+
}
|
|
23576
|
+
function isFormatSupported(format) {
|
|
23577
|
+
try {
|
|
23578
|
+
formatValue(0, format);
|
|
23579
|
+
return true;
|
|
23580
|
+
}
|
|
23581
|
+
catch (e) {
|
|
23582
|
+
return false;
|
|
23583
|
+
}
|
|
23584
|
+
}
|
|
23585
|
+
function isXlsxDateFormat(format) {
|
|
23586
|
+
return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
|
|
23587
|
+
}
|
|
23588
|
+
function convertDateFormat$1(format) {
|
|
23589
|
+
// Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
|
|
23590
|
+
// but can still occur and are supported by Excel/Google sheets
|
|
23591
|
+
format = format.toLowerCase();
|
|
23592
|
+
format = format.replace(/mmmmm/g, "mmm");
|
|
23593
|
+
format = format.replace(/am\/pm|a\/m/g, "a");
|
|
23594
|
+
format = format.replace(/hhhh/g, "hh");
|
|
23595
|
+
format = format.replace(/\bh\b/g, "hh");
|
|
23596
|
+
return format;
|
|
23597
|
+
}
|
|
23598
|
+
|
|
23157
23599
|
function convertBorders(data, warningManager) {
|
|
23158
23600
|
const borderArray = data.borders.map((border) => {
|
|
23159
23601
|
addBorderWarnings(border, warningManager);
|
|
@@ -23216,41 +23658,6 @@ function convertFormats(data, warningManager) {
|
|
|
23216
23658
|
}
|
|
23217
23659
|
return arrayToObject(formats, 1);
|
|
23218
23660
|
}
|
|
23219
|
-
/**
|
|
23220
|
-
* Convert excel format to o_spreadsheet format
|
|
23221
|
-
*
|
|
23222
|
-
* Excel format are defined in openXML §18.8.31
|
|
23223
|
-
*/
|
|
23224
|
-
function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
23225
|
-
var _a, _b, _c;
|
|
23226
|
-
if (numFmtId === 0) {
|
|
23227
|
-
return undefined;
|
|
23228
|
-
}
|
|
23229
|
-
// Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
|
|
23230
|
-
let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
|
|
23231
|
-
if (format) {
|
|
23232
|
-
try {
|
|
23233
|
-
let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
|
|
23234
|
-
convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
|
|
23235
|
-
convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
|
|
23236
|
-
// Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
|
|
23237
|
-
const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
23238
|
-
const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
|
|
23239
|
-
if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
|
|
23240
|
-
throw new Error("Multiple escaped blocks in format");
|
|
23241
|
-
}
|
|
23242
|
-
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
23243
|
-
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
|
|
23244
|
-
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
|
|
23245
|
-
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
23246
|
-
formatValue(0, convertedFormat);
|
|
23247
|
-
return convertedFormat;
|
|
23248
|
-
}
|
|
23249
|
-
catch (e) { }
|
|
23250
|
-
}
|
|
23251
|
-
warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
|
|
23252
|
-
return undefined;
|
|
23253
|
-
}
|
|
23254
23661
|
// ---------------------------------------------------------------------------
|
|
23255
23662
|
// Warnings
|
|
23256
23663
|
// ---------------------------------------------------------------------------
|
|
@@ -23805,16 +24212,18 @@ function convertFigure(figure, id, sheetData) {
|
|
|
23805
24212
|
};
|
|
23806
24213
|
}
|
|
23807
24214
|
function convertChartData(chartData) {
|
|
23808
|
-
|
|
23809
|
-
const labelRange =
|
|
23810
|
-
|
|
24215
|
+
const dataSetsHaveTitle = chartData.dataSets[0].label !== undefined;
|
|
24216
|
+
const labelRange = chartData.labelRange
|
|
24217
|
+
? convertExcelRangeToSheetXC(chartData.labelRange, dataSetsHaveTitle)
|
|
24218
|
+
: undefined;
|
|
24219
|
+
let dataSets = chartData.dataSets.map((data) => convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle));
|
|
23811
24220
|
// For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
|
|
23812
24221
|
if (chartData.type === "pie") {
|
|
23813
24222
|
dataSets.reverse();
|
|
23814
24223
|
}
|
|
23815
24224
|
return {
|
|
23816
24225
|
dataSets,
|
|
23817
|
-
dataSetsHaveTitle
|
|
24226
|
+
dataSetsHaveTitle,
|
|
23818
24227
|
labelRange,
|
|
23819
24228
|
title: chartData.title || "",
|
|
23820
24229
|
type: chartData.type,
|
|
@@ -23825,6 +24234,28 @@ function convertChartData(chartData) {
|
|
|
23825
24234
|
aggregated: false,
|
|
23826
24235
|
labelsAsText: false,
|
|
23827
24236
|
};
|
|
24237
|
+
}
|
|
24238
|
+
function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
|
|
24239
|
+
let { sheetName, xc } = splitReference(range);
|
|
24240
|
+
if (sheetName) {
|
|
24241
|
+
sheetName = getCanonicalSheetName(sheetName) + "!";
|
|
24242
|
+
}
|
|
24243
|
+
else {
|
|
24244
|
+
sheetName = "";
|
|
24245
|
+
}
|
|
24246
|
+
let zone = toUnboundedZone(xc);
|
|
24247
|
+
if (dataSetsHaveTitle && zone.bottom !== undefined && zone.right !== undefined) {
|
|
24248
|
+
const height = zone.bottom - zone.top + 1;
|
|
24249
|
+
const width = zone.right - zone.left + 1;
|
|
24250
|
+
if (height === 1) {
|
|
24251
|
+
zone = { ...zone, left: zone.left - 1 };
|
|
24252
|
+
}
|
|
24253
|
+
else if (width === 1) {
|
|
24254
|
+
zone = { ...zone, top: zone.top - 1 };
|
|
24255
|
+
}
|
|
24256
|
+
}
|
|
24257
|
+
const dataXC = zoneToXc(zone);
|
|
24258
|
+
return sheetName + dataXC;
|
|
23828
24259
|
}
|
|
23829
24260
|
|
|
23830
24261
|
/**
|
|
@@ -24892,6 +25323,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
24892
25323
|
title: chartTitle,
|
|
24893
25324
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
24894
25325
|
dataSets: this.extractChartDatasets(this.querySelector(rootChartElement, `c:${chartType}`)),
|
|
25326
|
+
labelRange: this.extractChildTextContent(rootChartElement, "c:ser c:cat c:f"),
|
|
24895
25327
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
24896
25328
|
default: "ffffff",
|
|
24897
25329
|
}).asString(),
|
|
@@ -24911,7 +25343,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
24911
25343
|
extractChartDatasets(chartElement) {
|
|
24912
25344
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
24913
25345
|
return {
|
|
24914
|
-
label: this.extractChildTextContent(chartDataElement, "c:
|
|
25346
|
+
label: this.extractChildTextContent(chartDataElement, "c:tx c:f"),
|
|
24915
25347
|
range: this.extractChildTextContent(chartDataElement, "c:val c:f", { required: true }),
|
|
24916
25348
|
};
|
|
24917
25349
|
});
|
|
@@ -28828,6 +29260,39 @@ class FigurePlugin extends CorePlugin {
|
|
|
28828
29260
|
case "DELETE_FIGURE":
|
|
28829
29261
|
this.removeFigure(cmd.id, cmd.sheetId);
|
|
28830
29262
|
break;
|
|
29263
|
+
case "REMOVE_COLUMNS_ROWS":
|
|
29264
|
+
this.onRowColDelete(cmd.sheetId, cmd.dimension);
|
|
29265
|
+
}
|
|
29266
|
+
}
|
|
29267
|
+
onRowColDelete(sheetId, dimension) {
|
|
29268
|
+
dimension === "ROW" ? this.onRowDeletion(sheetId) : this.onColDeletion(sheetId);
|
|
29269
|
+
}
|
|
29270
|
+
onRowDeletion(sheetId) {
|
|
29271
|
+
const numHeader = this.getters.getNumberRows(sheetId);
|
|
29272
|
+
let gridHeight = 0;
|
|
29273
|
+
for (let i = 0; i < numHeader; i++) {
|
|
29274
|
+
gridHeight += this.getters.getRowSize(sheetId, i);
|
|
29275
|
+
}
|
|
29276
|
+
const figures = this.getters.getFigures(sheetId);
|
|
29277
|
+
for (const figure of figures) {
|
|
29278
|
+
const newY = Math.min(figure.y, gridHeight - figure.height);
|
|
29279
|
+
if (newY !== figure.y) {
|
|
29280
|
+
this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, y: newY });
|
|
29281
|
+
}
|
|
29282
|
+
}
|
|
29283
|
+
}
|
|
29284
|
+
onColDeletion(sheetId) {
|
|
29285
|
+
const numHeader = this.getters.getNumberCols(sheetId);
|
|
29286
|
+
let gridWidth = 0;
|
|
29287
|
+
for (let i = 0; i < numHeader; i++) {
|
|
29288
|
+
gridWidth += this.getters.getColSize(sheetId, i);
|
|
29289
|
+
}
|
|
29290
|
+
const figures = this.getters.getFigures(sheetId);
|
|
29291
|
+
for (const figure of figures) {
|
|
29292
|
+
const newX = Math.min(figure.x, gridWidth - figure.width);
|
|
29293
|
+
if (newX !== figure.x) {
|
|
29294
|
+
this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x: newX });
|
|
29295
|
+
}
|
|
28831
29296
|
}
|
|
28832
29297
|
}
|
|
28833
29298
|
updateFigure(sheetId, figure) {
|
|
@@ -30242,6 +30707,7 @@ class RangeAdapter {
|
|
|
30242
30707
|
}
|
|
30243
30708
|
else if (range.zone[start] >= min && range.zone[end] <= max) {
|
|
30244
30709
|
changeType = "REMOVE";
|
|
30710
|
+
newRange = range.clone({ ...this.getInvalidRange() });
|
|
30245
30711
|
}
|
|
30246
30712
|
else if (range.zone[start] <= max && range.zone[end] >= max) {
|
|
30247
30713
|
const toRemove = max - range.zone[start] + 1;
|
|
@@ -30307,8 +30773,10 @@ class RangeAdapter {
|
|
|
30307
30773
|
return { changeType: "NONE" };
|
|
30308
30774
|
}
|
|
30309
30775
|
const invalidSheetName = this.getters.getSheetName(cmd.sheetId);
|
|
30310
|
-
|
|
30311
|
-
|
|
30776
|
+
range = range.clone({
|
|
30777
|
+
...this.getInvalidRange(),
|
|
30778
|
+
invalidSheetName,
|
|
30779
|
+
});
|
|
30312
30780
|
return { changeType: "REMOVE", range };
|
|
30313
30781
|
}, cmd.sheetId);
|
|
30314
30782
|
break;
|
|
@@ -30495,7 +30963,7 @@ class RangeAdapter {
|
|
|
30495
30963
|
sheetName = rangeImpl.invalidSheetName;
|
|
30496
30964
|
}
|
|
30497
30965
|
else {
|
|
30498
|
-
sheetName =
|
|
30966
|
+
sheetName = getCanonicalSheetName(this.getters.getSheetName(rangeImpl.sheetId));
|
|
30499
30967
|
}
|
|
30500
30968
|
}
|
|
30501
30969
|
if (prefixSheet && !sheetName) {
|
|
@@ -30568,6 +31036,15 @@ class RangeAdapter {
|
|
|
30568
31036
|
}
|
|
30569
31037
|
return str;
|
|
30570
31038
|
}
|
|
31039
|
+
getInvalidRange() {
|
|
31040
|
+
return {
|
|
31041
|
+
parts: [],
|
|
31042
|
+
prefixSheet: false,
|
|
31043
|
+
zone: { left: -1, top: -1, right: -1, bottom: -1 },
|
|
31044
|
+
sheetId: "",
|
|
31045
|
+
invalidXc: INCORRECT_RANGE_STRING,
|
|
31046
|
+
};
|
|
31047
|
+
}
|
|
30571
31048
|
}
|
|
30572
31049
|
RangeAdapter.getters = [
|
|
30573
31050
|
"getRangeString",
|
|
@@ -31537,9 +32014,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
31537
32014
|
// remove duplicates first to check validity on a reduced
|
|
31538
32015
|
// set of colors, then normalize to HEX and remove duplicates
|
|
31539
32016
|
// again
|
|
31540
|
-
[...new Set([...usedColors, ...this.customColors])]
|
|
31541
|
-
.filter(isColorValid)
|
|
31542
|
-
.map((c) => toHex(c).toLowerCase())),
|
|
32017
|
+
[...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
|
|
31543
32018
|
]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
|
|
31544
32019
|
}
|
|
31545
32020
|
getColorsFromCells(cells) {
|
|
@@ -31600,7 +32075,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
31600
32075
|
return [...chartsColors];
|
|
31601
32076
|
}
|
|
31602
32077
|
tryToAddColor(color) {
|
|
31603
|
-
const formattedColor = toHex(color)
|
|
32078
|
+
const formattedColor = toHex(color);
|
|
31604
32079
|
if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
|
|
31605
32080
|
this.customColors.add(formattedColor);
|
|
31606
32081
|
}
|
|
@@ -32615,8 +33090,8 @@ class InternalViewport {
|
|
|
32615
33090
|
this.getters = getters;
|
|
32616
33091
|
this.sheetId = sheetId;
|
|
32617
33092
|
this.boundaries = boundaries;
|
|
32618
|
-
this.
|
|
32619
|
-
this.
|
|
33093
|
+
this.viewportWidth = sizeInGrid.width;
|
|
33094
|
+
this.viewportHeight = sizeInGrid.height;
|
|
32620
33095
|
this.offsetScrollbarX = offsets.x;
|
|
32621
33096
|
this.offsetScrollbarY = offsets.y;
|
|
32622
33097
|
this.canScrollVertically = options.canScrollVertically;
|
|
@@ -32627,6 +33102,10 @@ class InternalViewport {
|
|
|
32627
33102
|
this.adjustViewportOffsetY();
|
|
32628
33103
|
}
|
|
32629
33104
|
// PUBLIC
|
|
33105
|
+
/** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
|
|
33106
|
+
* When the viewport grid size is smaller than its client width (resp. height), it will return
|
|
33107
|
+
* the client width (resp. height).
|
|
33108
|
+
*/
|
|
32630
33109
|
getMaxSize() {
|
|
32631
33110
|
const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
|
|
32632
33111
|
first: this.boundaries.left,
|
|
@@ -32638,20 +33117,24 @@ class InternalViewport {
|
|
|
32638
33117
|
});
|
|
32639
33118
|
const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
|
|
32640
33119
|
const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
|
|
32641
|
-
const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.
|
|
33120
|
+
const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
|
|
32642
33121
|
const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
|
|
32643
|
-
const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.
|
|
33122
|
+
const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
|
|
32644
33123
|
const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
|
|
32645
|
-
|
|
32646
|
-
|
|
32647
|
-
(
|
|
32648
|
-
|
|
32649
|
-
|
|
32650
|
-
|
|
32651
|
-
|
|
32652
|
-
|
|
32653
|
-
|
|
32654
|
-
|
|
33124
|
+
let width = lastColEnd - this.offsetCorrectionX;
|
|
33125
|
+
if (this.canScrollHorizontally) {
|
|
33126
|
+
width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
|
|
33127
|
+
Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
|
|
33128
|
+
);
|
|
33129
|
+
width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
|
|
33130
|
+
}
|
|
33131
|
+
let height = lastRowEnd - this.offsetCorrectionY;
|
|
33132
|
+
if (this.canScrollVertically) {
|
|
33133
|
+
height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
|
|
33134
|
+
Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
|
|
33135
|
+
);
|
|
33136
|
+
height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
|
|
33137
|
+
}
|
|
32655
33138
|
return { width, height };
|
|
32656
33139
|
}
|
|
32657
33140
|
/**
|
|
@@ -32660,7 +33143,7 @@ class InternalViewport {
|
|
|
32660
33143
|
* It returns -1 if no column is found.
|
|
32661
33144
|
*/
|
|
32662
33145
|
getColIndex(x, absolute = false) {
|
|
32663
|
-
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.
|
|
33146
|
+
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
|
|
32664
33147
|
return -1;
|
|
32665
33148
|
}
|
|
32666
33149
|
return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
|
|
@@ -32671,7 +33154,7 @@ class InternalViewport {
|
|
|
32671
33154
|
* It returns -1 if no row is found.
|
|
32672
33155
|
*/
|
|
32673
33156
|
getRowIndex(y, absolute = false) {
|
|
32674
|
-
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.
|
|
33157
|
+
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
|
|
32675
33158
|
return -1;
|
|
32676
33159
|
}
|
|
32677
33160
|
return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
|
|
@@ -32698,7 +33181,7 @@ class InternalViewport {
|
|
|
32698
33181
|
adjustPositionX(col) {
|
|
32699
33182
|
const sheetId = this.sheetId;
|
|
32700
33183
|
const { start, end } = this.getters.getColDimensions(sheetId, col);
|
|
32701
|
-
while (end > this.offsetX + this.offsetCorrectionX + this.
|
|
33184
|
+
while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
|
|
32702
33185
|
this.offsetX + this.offsetCorrectionX < start) {
|
|
32703
33186
|
this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
|
|
32704
33187
|
this.offsetScrollbarX = this.offsetX;
|
|
@@ -32720,7 +33203,7 @@ class InternalViewport {
|
|
|
32720
33203
|
adjustPositionY(row) {
|
|
32721
33204
|
const sheetId = this.sheetId;
|
|
32722
33205
|
while (this.getters.getRowDimensions(sheetId, row).end >
|
|
32723
|
-
this.offsetY + this.
|
|
33206
|
+
this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
|
|
32724
33207
|
this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
|
|
32725
33208
|
this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
|
|
32726
33209
|
this.offsetScrollbarY = this.offsetY;
|
|
@@ -32758,8 +33241,8 @@ class InternalViewport {
|
|
|
32758
33241
|
const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
|
|
32759
33242
|
this.offsetCorrectionX;
|
|
32760
33243
|
const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
|
|
32761
|
-
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.
|
|
32762
|
-
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.
|
|
33244
|
+
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
|
|
33245
|
+
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
|
|
32763
33246
|
return {
|
|
32764
33247
|
x,
|
|
32765
33248
|
y,
|
|
@@ -32822,12 +33305,12 @@ class InternalViewport {
|
|
|
32822
33305
|
adjustViewportOffsetX() {
|
|
32823
33306
|
if (this.canScrollHorizontally) {
|
|
32824
33307
|
const { width: viewportWidth } = this.getMaxSize();
|
|
32825
|
-
if (this.
|
|
32826
|
-
this.offsetScrollbarX = Math.max(0, viewportWidth - this.
|
|
33308
|
+
if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
|
|
33309
|
+
this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
|
|
32827
33310
|
}
|
|
32828
33311
|
}
|
|
32829
33312
|
this.left = this.getColIndex(this.offsetScrollbarX, true);
|
|
32830
|
-
this.right = this.getColIndex(this.offsetScrollbarX + this.
|
|
33313
|
+
this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
|
|
32831
33314
|
if (this.right === -1) {
|
|
32832
33315
|
this.right = this.boundaries.right;
|
|
32833
33316
|
}
|
|
@@ -32839,12 +33322,12 @@ class InternalViewport {
|
|
|
32839
33322
|
adjustViewportOffsetY() {
|
|
32840
33323
|
if (this.canScrollVertically) {
|
|
32841
33324
|
const { height: paneHeight } = this.getMaxSize();
|
|
32842
|
-
if (this.
|
|
32843
|
-
this.offsetScrollbarY = Math.max(0, paneHeight - this.
|
|
33325
|
+
if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
|
|
33326
|
+
this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
|
|
32844
33327
|
}
|
|
32845
33328
|
}
|
|
32846
33329
|
this.top = this.getRowIndex(this.offsetScrollbarY, true);
|
|
32847
|
-
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.
|
|
33330
|
+
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
|
|
32848
33331
|
if (this.bottom === -1) {
|
|
32849
33332
|
this.bottom = this.boundaries.bottom;
|
|
32850
33333
|
}
|
|
@@ -32855,7 +33338,7 @@ class InternalViewport {
|
|
|
32855
33338
|
adjustViewportZoneX() {
|
|
32856
33339
|
const sheetId = this.sheetId;
|
|
32857
33340
|
this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
|
|
32858
|
-
this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.
|
|
33341
|
+
this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
|
|
32859
33342
|
if (this.right === -1) {
|
|
32860
33343
|
this.right = this.getters.getNumberCols(sheetId) - 1;
|
|
32861
33344
|
}
|
|
@@ -32868,7 +33351,7 @@ class InternalViewport {
|
|
|
32868
33351
|
adjustViewportZoneY() {
|
|
32869
33352
|
const sheetId = this.sheetId;
|
|
32870
33353
|
this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
|
|
32871
|
-
this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.
|
|
33354
|
+
this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
|
|
32872
33355
|
if (this.bottom === -1) {
|
|
32873
33356
|
this.bottom = this.getters.getNumberRows(sheetId) - 1;
|
|
32874
33357
|
}
|
|
@@ -33131,8 +33614,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33131
33614
|
return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
|
|
33132
33615
|
}
|
|
33133
33616
|
/**
|
|
33134
|
-
* Return the main viewport maximum size
|
|
33135
|
-
* with some bottom and right padding.
|
|
33617
|
+
* Return the main viewport maximum size relative to the client size.
|
|
33136
33618
|
*/
|
|
33137
33619
|
getMainViewportRect() {
|
|
33138
33620
|
const sheetId = this.getters.getActiveSheetId();
|
|
@@ -33148,8 +33630,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33148
33630
|
const { width, height } = this.getMainViewportRect();
|
|
33149
33631
|
const viewport = this.getMainInternalViewport(sheetId);
|
|
33150
33632
|
return {
|
|
33151
|
-
maxOffsetX: Math.max(0, width - viewport.
|
|
33152
|
-
maxOffsetY: Math.max(0, height - viewport.
|
|
33633
|
+
maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
|
|
33634
|
+
maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
|
|
33153
33635
|
};
|
|
33154
33636
|
}
|
|
33155
33637
|
getColRowOffsetInViewport(dimension, referenceIndex, index) {
|
|
@@ -33464,6 +33946,20 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33464
33946
|
}
|
|
33465
33947
|
return result;
|
|
33466
33948
|
}
|
|
33949
|
+
isPositionVisible(position) {
|
|
33950
|
+
const { scrollX, scrollY } = this.getters.getActiveSheetScrollInfo();
|
|
33951
|
+
const { x: mainViewportX, y: mainViewportY } = this.getters.getMainViewportCoordinates();
|
|
33952
|
+
const { width, height } = this.getters.getSheetViewDimension();
|
|
33953
|
+
if (position.x >= mainViewportX &&
|
|
33954
|
+
(position.x < mainViewportX + scrollX || position.x > width + scrollX + mainViewportX)) {
|
|
33955
|
+
return false;
|
|
33956
|
+
}
|
|
33957
|
+
if (position.y >= mainViewportY &&
|
|
33958
|
+
(position.y < mainViewportY + scrollY || position.y > height + scrollY + mainViewportY)) {
|
|
33959
|
+
return false;
|
|
33960
|
+
}
|
|
33961
|
+
return true;
|
|
33962
|
+
}
|
|
33467
33963
|
getFrozenSheetViewRatio(sheetId) {
|
|
33468
33964
|
const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
|
|
33469
33965
|
const offsetCorrectionX = this.getters.getColDimensions(sheetId, xSplit).start;
|
|
@@ -33492,6 +33988,7 @@ SheetViewPlugin.getters = [
|
|
|
33492
33988
|
"getSheetViewVisibleCols",
|
|
33493
33989
|
"getSheetViewVisibleRows",
|
|
33494
33990
|
"getFrozenSheetViewRatio",
|
|
33991
|
+
"isPositionVisible",
|
|
33495
33992
|
];
|
|
33496
33993
|
|
|
33497
33994
|
/**
|
|
@@ -35354,7 +35851,7 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
35354
35851
|
const inputSheetId = this.activeSheet;
|
|
35355
35852
|
const sheetId = this.getters.getActiveSheetId();
|
|
35356
35853
|
const sheetName = this.getters.getSheetName(sheetId);
|
|
35357
|
-
this.add([sheetId === inputSheetId ? xc : `${
|
|
35854
|
+
this.add([sheetId === inputSheetId ? xc : `${getCanonicalSheetName(sheetName)}!${xc}`]);
|
|
35358
35855
|
}
|
|
35359
35856
|
handle(cmd) {
|
|
35360
35857
|
switch (cmd.type) {
|
|
@@ -37601,13 +38098,19 @@ class ClipboardFigureState {
|
|
|
37601
38098
|
*/
|
|
37602
38099
|
paste(target) {
|
|
37603
38100
|
const sheetId = this.getters.getActiveSheetId();
|
|
38101
|
+
const { width, height } = this.copiedFigure;
|
|
38102
|
+
const numCols = this.getters.getNumberCols(sheetId);
|
|
38103
|
+
const numRows = this.getters.getNumberRows(sheetId);
|
|
38104
|
+
const targetX = this.getters.getColDimensions(sheetId, target[0].left).start;
|
|
38105
|
+
const targetY = this.getters.getRowDimensions(sheetId, target[0].top).start;
|
|
38106
|
+
const maxX = this.getters.getColDimensions(sheetId, numCols - 1).end;
|
|
38107
|
+
const maxY = this.getters.getRowDimensions(sheetId, numRows - 1).end;
|
|
37604
38108
|
const position = {
|
|
37605
|
-
x:
|
|
37606
|
-
y:
|
|
38109
|
+
x: maxX < width ? 0 : Math.min(targetX, maxX - width),
|
|
38110
|
+
y: maxY < height ? 0 : Math.min(targetY, maxY - height),
|
|
37607
38111
|
};
|
|
37608
|
-
const size = { height: this.copiedFigure.height, width: this.copiedFigure.width };
|
|
37609
38112
|
const newId = new UuidGenerator().uuidv4();
|
|
37610
|
-
this.copiedFigureContent.paste(sheetId, newId, position,
|
|
38113
|
+
this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
|
|
37611
38114
|
if (this.operation === "CUT") {
|
|
37612
38115
|
this.dispatch("DELETE_FIGURE", {
|
|
37613
38116
|
sheetId: this.copiedFigureContent.sheetId,
|
|
@@ -37973,7 +38476,7 @@ function loopThroughReferenceType(token) {
|
|
|
37973
38476
|
return token;
|
|
37974
38477
|
const { xc, sheetName } = splitReference(token.value);
|
|
37975
38478
|
const [left, right] = xc.split(":");
|
|
37976
|
-
const sheetRef = sheetName ? `${
|
|
38479
|
+
const sheetRef = sheetName ? `${getCanonicalSheetName(sheetName)}!` : "";
|
|
37977
38480
|
const updatedLeft = getTokenNextReferenceType(left);
|
|
37978
38481
|
const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
|
|
37979
38482
|
return { ...token, value: sheetRef + updatedLeft + updatedRight };
|
|
@@ -38232,9 +38735,6 @@ class EditionPlugin extends UIPlugin {
|
|
|
38232
38735
|
}
|
|
38233
38736
|
return this.currentContent;
|
|
38234
38737
|
}
|
|
38235
|
-
getEditionSheet() {
|
|
38236
|
-
return this.sheetId;
|
|
38237
|
-
}
|
|
38238
38738
|
getComposerSelection() {
|
|
38239
38739
|
return {
|
|
38240
38740
|
start: this.selectionStart,
|
|
@@ -38518,8 +39018,8 @@ class EditionPlugin extends UIPlugin {
|
|
|
38518
39018
|
getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
|
|
38519
39019
|
const sheetId = this.getters.getActiveSheetId();
|
|
38520
39020
|
let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
|
|
38521
|
-
if (this.getters.
|
|
38522
|
-
const sheetName =
|
|
39021
|
+
if (this.getters.getCurrentEditedCell().sheetId !== this.getters.getActiveSheetId()) {
|
|
39022
|
+
const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
|
|
38523
39023
|
selectedXc = `${sheetName}!${selectedXc}`;
|
|
38524
39024
|
}
|
|
38525
39025
|
return selectedXc;
|
|
@@ -38533,7 +39033,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38533
39033
|
_fixedParts.pop();
|
|
38534
39034
|
}
|
|
38535
39035
|
const newRange = range.clone({ parts: _fixedParts });
|
|
38536
|
-
return this.getters.getSelectionRangeString(newRange, this.getters.
|
|
39036
|
+
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().sheetId);
|
|
38537
39037
|
}
|
|
38538
39038
|
/**
|
|
38539
39039
|
* Replace the current selection by a new text.
|
|
@@ -38566,7 +39066,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38566
39066
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
38567
39067
|
return;
|
|
38568
39068
|
}
|
|
38569
|
-
const editionSheetId = this.getters.
|
|
39069
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38570
39070
|
const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
|
|
38571
39071
|
const colorsToKeep = {};
|
|
38572
39072
|
for (const xc of XCs) {
|
|
@@ -38595,7 +39095,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38595
39095
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
38596
39096
|
return [];
|
|
38597
39097
|
}
|
|
38598
|
-
const editionSheetId = this.getters.
|
|
39098
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38599
39099
|
const rangeColor = (rangeString) => {
|
|
38600
39100
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
38601
39101
|
return colors$1[colorIndex % colors$1.length];
|
|
@@ -38613,7 +39113,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38613
39113
|
* Return ranges currently referenced in the composer
|
|
38614
39114
|
*/
|
|
38615
39115
|
getReferencedRanges() {
|
|
38616
|
-
const editionSheetId = this.getters.
|
|
39116
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38617
39117
|
return this.currentTokens
|
|
38618
39118
|
.filter((token) => token.type === "REFERENCE")
|
|
38619
39119
|
.map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
|
|
@@ -38672,7 +39172,6 @@ EditionPlugin.getters = [
|
|
|
38672
39172
|
"isSelectingForComposer",
|
|
38673
39173
|
"showSelectionIndicator",
|
|
38674
39174
|
"getCurrentContent",
|
|
38675
|
-
"getEditionSheet",
|
|
38676
39175
|
"getComposerSelection",
|
|
38677
39176
|
"getCurrentTokens",
|
|
38678
39177
|
"getTokenAtCursor",
|
|
@@ -39995,10 +40494,6 @@ css /* scss */ `
|
|
|
39995
40494
|
.o-bottom-bar-arrows {
|
|
39996
40495
|
.o-bottom-bar-arrow {
|
|
39997
40496
|
cursor: pointer;
|
|
39998
|
-
&.o-disabled {
|
|
39999
|
-
opacity: 0.4;
|
|
40000
|
-
cursor: default;
|
|
40001
|
-
}
|
|
40002
40497
|
&:hover:not([class*="o-disabled"]) {
|
|
40003
40498
|
.o-icon {
|
|
40004
40499
|
opacity: 0.9;
|
|
@@ -40591,6 +41086,11 @@ css /* scss */ `
|
|
|
40591
41086
|
margin-top: -1px;
|
|
40592
41087
|
border: 1px solid;
|
|
40593
41088
|
z-index: ${ComponentsImportance.TopBarComposer};
|
|
41089
|
+
|
|
41090
|
+
.o-composer:empty:not(:focus)::before {
|
|
41091
|
+
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
41092
|
+
content: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -10 121.8 142.9' width='24' height='24' focusable='false'%3E%3Cpath d='m28 34-4 5v2h10l-6 40c-4 22-6 28-7 30-2 2-3 3-5 3-3 0-7-2-9-4H4c-2 2-4 4-4 7s4 6 8 6 9-2 15-8c8-7 13-17 18-39l7-35 13-1 3-6H49c4-23 7-27 11-27 2 0 5 2 8 6h4c1-1 4-4 4-7 0-2-3-6-9-6-5 0-13 4-20 10-6 7-9 14-11 24h-8zm41 16c4-5 7-7 8-7s2 1 5 9l3 12c-7 11-12 17-16 17l-3-1-2-1c-3 0-6 3-6 7s3 7 7 7c6 0 12-6 22-23l3 10c3 9 6 13 10 13 5 0 11-4 18-15l-3-4c-4 6-7 8-8 8-2 0-4-3-6-10l-5-15 8-10 6-4 3 1 3 2c2 0 6-3 6-7s-2-7-6-7c-6 0-11 5-21 20l-2-6c-3-9-5-14-9-14-5 0-12 6-18 15l3 3z' fill='%23BDBDBD' /%3E%3C/svg%3E");
|
|
41093
|
+
}
|
|
40594
41094
|
}
|
|
40595
41095
|
`;
|
|
40596
41096
|
class TopBarComposer extends owl.Component {
|
|
@@ -40831,11 +41331,6 @@ css /* scss */ `
|
|
|
40831
41331
|
margin: 0 6px;
|
|
40832
41332
|
}
|
|
40833
41333
|
|
|
40834
|
-
.o-disabled {
|
|
40835
|
-
opacity: 0.6;
|
|
40836
|
-
cursor: default;
|
|
40837
|
-
}
|
|
40838
|
-
|
|
40839
41334
|
.o-dropdown {
|
|
40840
41335
|
position: relative;
|
|
40841
41336
|
display: flex;
|
|
@@ -40997,6 +41492,7 @@ class TopBar extends owl.Component {
|
|
|
40997
41492
|
this.state.menuState.parentMenu = menu;
|
|
40998
41493
|
this.isSelectingMenu = true;
|
|
40999
41494
|
this.openedEl = ev.target;
|
|
41495
|
+
this.env.model.dispatch("STOP_EDITION");
|
|
41000
41496
|
}
|
|
41001
41497
|
closeMenus() {
|
|
41002
41498
|
this.state.activeTool = "";
|
|
@@ -41209,10 +41705,12 @@ css /* scss */ `
|
|
|
41209
41705
|
button {
|
|
41210
41706
|
color: #333;
|
|
41211
41707
|
}
|
|
41212
|
-
|
|
41213
|
-
|
|
41214
|
-
|
|
41708
|
+
.o-disabled {
|
|
41709
|
+
opacity: 0.4;
|
|
41710
|
+
pointer: default;
|
|
41711
|
+
pointer-events: none;
|
|
41215
41712
|
}
|
|
41713
|
+
|
|
41216
41714
|
&,
|
|
41217
41715
|
*,
|
|
41218
41716
|
*:before,
|
|
@@ -41370,8 +41868,10 @@ class Spreadsheet extends owl.Component {
|
|
|
41370
41868
|
this.sidePanel.isOpen = true;
|
|
41371
41869
|
}
|
|
41372
41870
|
closeSidePanel() {
|
|
41871
|
+
var _a, _b;
|
|
41373
41872
|
this.sidePanel.isOpen = false;
|
|
41374
41873
|
this.focusGrid();
|
|
41874
|
+
(_b = (_a = this.sidePanel.panelProps) === null || _a === void 0 ? void 0 : _a.onCloseSidePanel) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
41375
41875
|
}
|
|
41376
41876
|
toggleSidePanel(panel, panelProps) {
|
|
41377
41877
|
if (this.sidePanel.isOpen && panel === this.sidePanel.component) {
|
|
@@ -43810,7 +44310,7 @@ function figureCoordinates(headers, position) {
|
|
|
43810
44310
|
if (currentPosition <= position && position < currentPosition + header.size) {
|
|
43811
44311
|
return {
|
|
43812
44312
|
index: parseInt(headerIndex),
|
|
43813
|
-
offset: convertDotValueToEMU(position - currentPosition +
|
|
44313
|
+
offset: convertDotValueToEMU(position - currentPosition + FIGURE_BORDER_WIDTH),
|
|
43814
44314
|
};
|
|
43815
44315
|
}
|
|
43816
44316
|
else {
|
|
@@ -43819,7 +44319,7 @@ function figureCoordinates(headers, position) {
|
|
|
43819
44319
|
}
|
|
43820
44320
|
return {
|
|
43821
44321
|
index: headers.length - 1,
|
|
43822
|
-
offset: convertDotValueToEMU(position - currentPosition +
|
|
44322
|
+
offset: convertDotValueToEMU(position - currentPosition + FIGURE_BORDER_WIDTH),
|
|
43823
44323
|
};
|
|
43824
44324
|
}
|
|
43825
44325
|
function createChartDrawing(figure, sheet, chartRelId) {
|
|
@@ -44579,6 +45079,13 @@ class Model extends EventBus {
|
|
|
44579
45079
|
* Internal status of the model. Important for command handling coordination
|
|
44580
45080
|
*/
|
|
44581
45081
|
this.status = 0 /* Status.Ready */;
|
|
45082
|
+
/**
|
|
45083
|
+
* Check if a command can be dispatched, and returns a DispatchResult object with the possible
|
|
45084
|
+
* reasons the dispatch failed.
|
|
45085
|
+
*/
|
|
45086
|
+
this.canDispatch = (type, payload) => {
|
|
45087
|
+
return this.checkDispatchAllowed({ ...payload, type });
|
|
45088
|
+
};
|
|
44582
45089
|
/**
|
|
44583
45090
|
* The dispatch method is the only entry point to manipulate data in the model.
|
|
44584
45091
|
* This is through this method that commands are dispatched most of the time
|
|
@@ -44722,7 +45229,10 @@ class Model extends EventBus {
|
|
|
44722
45229
|
owl.markRaw(this);
|
|
44723
45230
|
}
|
|
44724
45231
|
get handlers() {
|
|
44725
|
-
return [
|
|
45232
|
+
return [...this.coreHandlers, ...this.allUIPlugins, this.history];
|
|
45233
|
+
}
|
|
45234
|
+
get coreHandlers() {
|
|
45235
|
+
return [this.range, ...this.corePlugins];
|
|
44726
45236
|
}
|
|
44727
45237
|
get allUIPlugins() {
|
|
44728
45238
|
return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
|
|
@@ -44850,6 +45360,16 @@ class Model extends EventBus {
|
|
|
44850
45360
|
* Check if the given command is allowed by all the plugins and the history.
|
|
44851
45361
|
*/
|
|
44852
45362
|
checkDispatchAllowed(command) {
|
|
45363
|
+
if (isCoreCommand(command)) {
|
|
45364
|
+
return this.checkDispatchAllowedCoreCommand(command);
|
|
45365
|
+
}
|
|
45366
|
+
return this.checkDispatchAllowedLocalCommand(command);
|
|
45367
|
+
}
|
|
45368
|
+
checkDispatchAllowedCoreCommand(command) {
|
|
45369
|
+
const results = this.coreHandlers.map((handler) => handler.allowDispatch(command));
|
|
45370
|
+
return new DispatchResult(results.flat());
|
|
45371
|
+
}
|
|
45372
|
+
checkDispatchAllowedLocalCommand(command) {
|
|
44853
45373
|
const results = this.handlers.map((handler) => handler.allowDispatch(command));
|
|
44854
45374
|
return new DispatchResult(results.flat());
|
|
44855
45375
|
}
|
|
@@ -45078,6 +45598,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
45078
45598
|
exports.tokenize = tokenize;
|
|
45079
45599
|
|
|
45080
45600
|
|
|
45081
|
-
__info__.version = '16.3.0-alpha.
|
|
45082
|
-
__info__.date = '2023-
|
|
45083
|
-
__info__.hash = '
|
|
45601
|
+
__info__.version = '16.3.0-alpha.3';
|
|
45602
|
+
__info__.date = '2023-04-13T08:30:41.165Z';
|
|
45603
|
+
__info__.hash = '573e679';
|