@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
|
@@ -113,88 +113,88 @@ const FILTERS_COLOR = "#188038";
|
|
|
113
113
|
const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
|
|
114
114
|
const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
|
|
115
115
|
const SEPARATOR_COLOR = "#E0E2E4";
|
|
116
|
-
// Color picker
|
|
116
|
+
// Color picker defaults as upper case HEX to match `toHex`helper
|
|
117
117
|
const COLOR_PICKER_DEFAULTS = [
|
|
118
118
|
"#000000",
|
|
119
119
|
"#434343",
|
|
120
120
|
"#666666",
|
|
121
121
|
"#999999",
|
|
122
|
-
"#
|
|
123
|
-
"#
|
|
124
|
-
"#
|
|
125
|
-
"#
|
|
126
|
-
"#
|
|
127
|
-
"#
|
|
122
|
+
"#B7B7B7",
|
|
123
|
+
"#CCCCCC",
|
|
124
|
+
"#D9D9D9",
|
|
125
|
+
"#EFEFEF",
|
|
126
|
+
"#F3F3F3",
|
|
127
|
+
"#FFFFFF",
|
|
128
128
|
"#980000",
|
|
129
|
-
"#
|
|
130
|
-
"#
|
|
131
|
-
"#
|
|
132
|
-
"#
|
|
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
|
-
"#
|
|
129
|
+
"#FF0000",
|
|
130
|
+
"#FF9900",
|
|
131
|
+
"#FFFF00",
|
|
132
|
+
"#00FF00",
|
|
133
|
+
"#00FFFF",
|
|
134
|
+
"#4A86E8",
|
|
135
|
+
"#0000FF",
|
|
136
|
+
"#9900FF",
|
|
137
|
+
"#FF00FF",
|
|
138
|
+
"#E6B8AF",
|
|
139
|
+
"#F4CCCC",
|
|
140
|
+
"#FCE5CD",
|
|
141
|
+
"#FFF2CC",
|
|
142
|
+
"#D9EAD3",
|
|
143
|
+
"#D0E0E3",
|
|
144
|
+
"#C9DAF8",
|
|
145
|
+
"#CFE2F3",
|
|
146
|
+
"#D9D2E9",
|
|
147
|
+
"#EAD1DC",
|
|
148
|
+
"#DD7E6B",
|
|
149
|
+
"#EA9999",
|
|
150
|
+
"#F9CB9C",
|
|
151
|
+
"#FFE599",
|
|
152
|
+
"#B6D7A8",
|
|
153
|
+
"#A2C4C9",
|
|
154
|
+
"#A4C2F4",
|
|
155
|
+
"#9FC5E8",
|
|
156
|
+
"#B4A7D6",
|
|
157
|
+
"#D5A6BD",
|
|
158
|
+
"#CC4125",
|
|
159
|
+
"#E06666",
|
|
160
|
+
"#F6B26B",
|
|
161
|
+
"#FFD966",
|
|
162
|
+
"#93C47D",
|
|
163
|
+
"#76A5AF",
|
|
164
|
+
"#6D9EEB",
|
|
165
|
+
"#6FA8DC",
|
|
166
|
+
"#8E7CC3",
|
|
167
|
+
"#C27BA0",
|
|
168
|
+
"#A61C00",
|
|
169
|
+
"#CC0000",
|
|
170
|
+
"#E69138",
|
|
171
|
+
"#F1C232",
|
|
172
|
+
"#6AA84F",
|
|
173
|
+
"#45818E",
|
|
174
|
+
"#3C78D8",
|
|
175
|
+
"#3D85C6",
|
|
176
|
+
"#674EA7",
|
|
177
|
+
"#A64D79",
|
|
178
|
+
"#85200C",
|
|
179
179
|
"#990000",
|
|
180
|
-
"#
|
|
181
|
-
"#
|
|
182
|
-
"#
|
|
183
|
-
"#
|
|
184
|
-
"#
|
|
185
|
-
"#
|
|
186
|
-
"#
|
|
187
|
-
"#
|
|
188
|
-
"#
|
|
180
|
+
"#B45F06",
|
|
181
|
+
"#BF9000",
|
|
182
|
+
"#38761D",
|
|
183
|
+
"#134F5C",
|
|
184
|
+
"#1155CC",
|
|
185
|
+
"#0B5394",
|
|
186
|
+
"#351C75",
|
|
187
|
+
"#741B47",
|
|
188
|
+
"#5B0F00",
|
|
189
189
|
"#660000",
|
|
190
|
-
"#
|
|
191
|
-
"#
|
|
192
|
-
"#
|
|
193
|
-
"#
|
|
194
|
-
"#
|
|
190
|
+
"#783F04",
|
|
191
|
+
"#7F6000",
|
|
192
|
+
"#274E13",
|
|
193
|
+
"#0C343D",
|
|
194
|
+
"#1C4587",
|
|
195
195
|
"#073763",
|
|
196
|
-
"#
|
|
197
|
-
"#
|
|
196
|
+
"#20124D",
|
|
197
|
+
"#4C1130",
|
|
198
198
|
];
|
|
199
199
|
// Dimensions
|
|
200
200
|
const MIN_ROW_HEIGHT = 10;
|
|
@@ -223,8 +223,6 @@ const MENU_VERTICAL_PADDING = 8;
|
|
|
223
223
|
const MENU_ITEM_HEIGHT = 28;
|
|
224
224
|
const MENU_SEPARATOR_BORDER_WIDTH = 1;
|
|
225
225
|
const MENU_SEPARATOR_PADDING = 5;
|
|
226
|
-
const MENU_SEPARATOR_HEIGHT = MENU_SEPARATOR_BORDER_WIDTH + 2 * MENU_SEPARATOR_PADDING;
|
|
227
|
-
const FIGURE_BORDER_SIZE = 1;
|
|
228
226
|
// Fonts
|
|
229
227
|
const DEFAULT_FONT_WEIGHT = "400";
|
|
230
228
|
const DEFAULT_FONT_SIZE = 10;
|
|
@@ -234,7 +232,7 @@ const DEFAULT_FONT = "'Roboto', arial";
|
|
|
234
232
|
const DEFAULT_BORDER_DESC = ["thin", "#000"];
|
|
235
233
|
const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
|
|
236
234
|
// DateTimeRegex
|
|
237
|
-
const DATETIME_FORMAT = /[
|
|
235
|
+
const DATETIME_FORMAT = /[ymdhs:]/;
|
|
238
236
|
// Ranges
|
|
239
237
|
const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
|
|
240
238
|
// Max Number of history steps kept in memory
|
|
@@ -244,6 +242,8 @@ const DEFAULT_REVISION_ID = "START_REVISION";
|
|
|
244
242
|
// Figure
|
|
245
243
|
const DEFAULT_FIGURE_HEIGHT = 335;
|
|
246
244
|
const DEFAULT_FIGURE_WIDTH = 536;
|
|
245
|
+
const FIGURE_BORDER_WIDTH = 1;
|
|
246
|
+
const MIN_FIG_SIZE = 80;
|
|
247
247
|
// Chart
|
|
248
248
|
const MAX_CHAR_LABEL = 20;
|
|
249
249
|
const FIGURE_ID_SPLITTER = "??";
|
|
@@ -254,7 +254,6 @@ const DEFAULT_SCORECARD_BASELINE_MODE = "difference";
|
|
|
254
254
|
const DEFAULT_SCORECARD_BASELINE_COLOR_UP = "#00A04A";
|
|
255
255
|
const DEFAULT_SCORECARD_BASELINE_COLOR_DOWN = "#DC6965";
|
|
256
256
|
const LINE_FILL_TRANSPARENCY = 0.4;
|
|
257
|
-
const MIN_FIG_SIZE = 80;
|
|
258
257
|
// session
|
|
259
258
|
const DEBOUNCE_TIME = 200;
|
|
260
259
|
const MESSAGE_VERSION = 1;
|
|
@@ -276,7 +275,8 @@ var ComponentsImportance;
|
|
|
276
275
|
ComponentsImportance[ComponentsImportance["TopBarComposer"] = 21] = "TopBarComposer";
|
|
277
276
|
ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
|
|
278
277
|
ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
|
|
279
|
-
ComponentsImportance[ComponentsImportance["
|
|
278
|
+
ComponentsImportance[ComponentsImportance["FigureAnchor"] = 1000] = "FigureAnchor";
|
|
279
|
+
ComponentsImportance[ComponentsImportance["FigureSnapLine"] = 1001] = "FigureSnapLine";
|
|
280
280
|
})(ComponentsImportance || (ComponentsImportance = {}));
|
|
281
281
|
const DEFAULT_SHEETVIEW_SIZE = 1000;
|
|
282
282
|
const MAXIMAL_FREEZABLE_RATIO = 0.85;
|
|
@@ -713,7 +713,7 @@ function getUnquotedSheetName(sheetName) {
|
|
|
713
713
|
* '\w' captures [0-9][a-z][A-Z] and _.
|
|
714
714
|
* @param sheetName Name of the sheet
|
|
715
715
|
*/
|
|
716
|
-
function
|
|
716
|
+
function getCanonicalSheetName(sheetName) {
|
|
717
717
|
var _a;
|
|
718
718
|
if (((_a = sheetName.match(/\w/g)) === null || _a === void 0 ? void 0 : _a.length) !== sheetName.length) {
|
|
719
719
|
sheetName = `'${sheetName}'`;
|
|
@@ -734,8 +734,9 @@ function getDefaultCellHeight(cell) {
|
|
|
734
734
|
return DEFAULT_CELL_HEIGHT;
|
|
735
735
|
}
|
|
736
736
|
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
737
|
-
|
|
738
|
-
|
|
737
|
+
// the number of lines should be computed from the formula result, but it's not evaluated at this point
|
|
738
|
+
const numberOfLines = cell.isFormula ? 1 : cell.content.split(NEWLINE).length;
|
|
739
|
+
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
739
740
|
}
|
|
740
741
|
function computeTextWidth(context, text, style) {
|
|
741
742
|
context.save();
|
|
@@ -1087,6 +1088,8 @@ function replaceSpecialSpaces(text) {
|
|
|
1087
1088
|
return text;
|
|
1088
1089
|
}
|
|
1089
1090
|
|
|
1091
|
+
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
1092
|
+
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
|
|
1090
1093
|
const colors$1 = [
|
|
1091
1094
|
"#eb6d00",
|
|
1092
1095
|
"#0074d9",
|
|
@@ -1112,7 +1115,10 @@ function colorNumberString(color) {
|
|
|
1112
1115
|
}
|
|
1113
1116
|
/**
|
|
1114
1117
|
* Converts any CSS color value to a standardized hex6 value.
|
|
1115
|
-
* Accepts: hex3, hex6, hex8 and
|
|
1118
|
+
* Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
|
|
1119
|
+
*
|
|
1120
|
+
* [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
|
|
1121
|
+
* with r,g,b ∈ [0, 255] and a ∈ [0, 1]
|
|
1116
1122
|
*
|
|
1117
1123
|
* toHex("#ABC")
|
|
1118
1124
|
* >> "#AABBCC"
|
|
@@ -1123,27 +1129,31 @@ function colorNumberString(color) {
|
|
|
1123
1129
|
* toHex("rgb(30, 80, 16)")
|
|
1124
1130
|
* >> "#1E5010"
|
|
1125
1131
|
*
|
|
1132
|
+
* * toHex("rgb(30, 80, 16, 0.5)")
|
|
1133
|
+
* >> "#1E501080"
|
|
1134
|
+
*
|
|
1126
1135
|
*/
|
|
1127
1136
|
function toHex(color) {
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
if (color.includes("rgb")) {
|
|
1132
|
-
return rgbToHex6(color);
|
|
1137
|
+
let hexColor = color;
|
|
1138
|
+
if (color.startsWith("rgb")) {
|
|
1139
|
+
hexColor = rgbaStringToHex(color);
|
|
1133
1140
|
}
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1141
|
+
else {
|
|
1142
|
+
hexColor = color.replace("#", "").toUpperCase();
|
|
1143
|
+
if (hexColor.length === 3 || hexColor.length === 4) {
|
|
1144
|
+
hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
|
|
1145
|
+
}
|
|
1146
|
+
hexColor = `#${hexColor}`;
|
|
1137
1147
|
}
|
|
1138
|
-
if (
|
|
1139
|
-
throw new Error(
|
|
1148
|
+
if (!hexColor.match(HEX_MATCH)) {
|
|
1149
|
+
throw new Error(`invalid color input: ${color}`);
|
|
1140
1150
|
}
|
|
1141
|
-
return
|
|
1151
|
+
return hexColor;
|
|
1142
1152
|
}
|
|
1143
1153
|
function isColorValid(color) {
|
|
1144
1154
|
try {
|
|
1145
|
-
|
|
1146
|
-
return
|
|
1155
|
+
toHex(color);
|
|
1156
|
+
return true;
|
|
1147
1157
|
}
|
|
1148
1158
|
catch (error) {
|
|
1149
1159
|
return false;
|
|
@@ -1176,15 +1186,29 @@ function relativeLuminance(color) {
|
|
|
1176
1186
|
/**
|
|
1177
1187
|
* Convert a CSS rgb color string to a standardized hex6 color value.
|
|
1178
1188
|
*
|
|
1179
|
-
*
|
|
1189
|
+
* rgbaStringToHex("rgb(30, 80, 16)")
|
|
1180
1190
|
* >> "#1E5010"
|
|
1191
|
+
*
|
|
1192
|
+
* rgbaStringToHex("rgba(30, 80, 16, 0.5)")
|
|
1193
|
+
* >> "#1E501080"
|
|
1194
|
+
*
|
|
1195
|
+
* DOES NOT SUPPORT NON INTEGER RGB VALUES
|
|
1181
1196
|
*/
|
|
1182
|
-
function
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1197
|
+
function rgbaStringToHex(color) {
|
|
1198
|
+
const stringVals = color.replace(RBA_REGEX, "").split(",");
|
|
1199
|
+
let alphaHex = 255;
|
|
1200
|
+
if (stringVals.length !== 3 && stringVals.length !== 4) {
|
|
1201
|
+
throw new Error("invalid color");
|
|
1202
|
+
}
|
|
1203
|
+
else if (stringVals.length === 4) {
|
|
1204
|
+
const alpha = parseFloat(stringVals.pop() || "1");
|
|
1205
|
+
alphaHex = Math.round((alpha || 1) * 255);
|
|
1206
|
+
}
|
|
1207
|
+
const vals = stringVals.map((val) => parseInt(val, 10));
|
|
1208
|
+
if (alphaHex !== 255) {
|
|
1209
|
+
vals.push(alphaHex);
|
|
1210
|
+
}
|
|
1211
|
+
return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
|
|
1188
1212
|
}
|
|
1189
1213
|
/**
|
|
1190
1214
|
* RGBA to HEX representation (#RRGGBBAA).
|
|
@@ -1206,7 +1230,7 @@ function rgbaToHex(rgba) {
|
|
|
1206
1230
|
a = "0" + a;
|
|
1207
1231
|
if (a === "ff")
|
|
1208
1232
|
a = "";
|
|
1209
|
-
return "#" + r + g + b + a;
|
|
1233
|
+
return ("#" + r + g + b + a).toUpperCase();
|
|
1210
1234
|
}
|
|
1211
1235
|
/**
|
|
1212
1236
|
* Color string to RGBA representation
|
|
@@ -1327,6 +1351,9 @@ function rgbaToHSLA(rgba) {
|
|
|
1327
1351
|
s = +(s * 100).toFixed(1);
|
|
1328
1352
|
l = +(l * 100).toFixed(1);
|
|
1329
1353
|
return { a: rgba.a, h, s, l };
|
|
1354
|
+
}
|
|
1355
|
+
function isSameColor(color1, color2) {
|
|
1356
|
+
return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
|
|
1330
1357
|
}
|
|
1331
1358
|
|
|
1332
1359
|
/** Reference of a cell (eg. A1, $B$5) */
|
|
@@ -1478,7 +1505,7 @@ function scrollDelay(value) {
|
|
|
1478
1505
|
* formula, commas are used to separate arguments
|
|
1479
1506
|
* - it does not support % symbol, in formulas % is an operator
|
|
1480
1507
|
*/
|
|
1481
|
-
const formulaNumberRegexp =
|
|
1508
|
+
const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
|
|
1482
1509
|
const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
|
|
1483
1510
|
const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
|
|
1484
1511
|
const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
|
|
@@ -3051,6 +3078,9 @@ function cellTextStyleToCss(style) {
|
|
|
3051
3078
|
}
|
|
3052
3079
|
return attributes;
|
|
3053
3080
|
}
|
|
3081
|
+
/**
|
|
3082
|
+
* Transform CSS properties into a CSS string.
|
|
3083
|
+
*/
|
|
3054
3084
|
function cssPropertiesToCss(attributes) {
|
|
3055
3085
|
const str = Object.entries(attributes)
|
|
3056
3086
|
.filter(([attName, attValue]) => attValue !== undefined)
|
|
@@ -3084,6 +3114,7 @@ const CHART_PADDING_RATIO = 0.02;
|
|
|
3084
3114
|
const LINE_HEIGHT = 1.2;
|
|
3085
3115
|
css /* scss */ `
|
|
3086
3116
|
div.o-scorecard {
|
|
3117
|
+
font-family: ${DEFAULT_FONT};
|
|
3087
3118
|
user-select: none;
|
|
3088
3119
|
background-color: white;
|
|
3089
3120
|
display: flex;
|
|
@@ -5071,6 +5102,10 @@ function usePopoverContainer() {
|
|
|
5071
5102
|
function rectIntersection(rect1, rect2) {
|
|
5072
5103
|
return zoneToRect(intersection(rectToZone(rect1), rectToZone(rect2)));
|
|
5073
5104
|
}
|
|
5105
|
+
/** Compute the union of the rectangles, ie. the smallest rectangle that contain them all */
|
|
5106
|
+
function rectUnion(...rects) {
|
|
5107
|
+
return zoneToRect(union(...rects.map(rectToZone)));
|
|
5108
|
+
}
|
|
5074
5109
|
function rectToZone(rect) {
|
|
5075
5110
|
return {
|
|
5076
5111
|
left: rect.x,
|
|
@@ -5367,24 +5402,30 @@ class Menu extends Component {
|
|
|
5367
5402
|
}
|
|
5368
5403
|
});
|
|
5369
5404
|
}
|
|
5370
|
-
get
|
|
5371
|
-
|
|
5405
|
+
get menuItemsAndSeparators() {
|
|
5406
|
+
const menuItemsAndSeparators = [];
|
|
5407
|
+
for (let i = 0; i < this.props.menuItems.length; i++) {
|
|
5408
|
+
const menuItem = this.props.menuItems[i];
|
|
5409
|
+
if (menuItem.isVisible(this.env)) {
|
|
5410
|
+
menuItemsAndSeparators.push(menuItem);
|
|
5411
|
+
}
|
|
5412
|
+
if (menuItem.separator &&
|
|
5413
|
+
i !== this.props.menuItems.length - 1 && // no separator at the end
|
|
5414
|
+
menuItemsAndSeparators[menuItemsAndSeparators.length - 1] !== "separator" // no double separator
|
|
5415
|
+
) {
|
|
5416
|
+
menuItemsAndSeparators.push("separator");
|
|
5417
|
+
}
|
|
5418
|
+
}
|
|
5419
|
+
if (menuItemsAndSeparators.length === 1 && menuItemsAndSeparators[0] === "separator") {
|
|
5420
|
+
return [];
|
|
5421
|
+
}
|
|
5422
|
+
return menuItemsAndSeparators;
|
|
5372
5423
|
}
|
|
5373
5424
|
get subMenuPosition() {
|
|
5374
5425
|
const position = Object.assign({}, this.subMenu.position);
|
|
5375
5426
|
position.y -= this.subMenu.scrollOffset || 0;
|
|
5376
5427
|
return position;
|
|
5377
5428
|
}
|
|
5378
|
-
get menuHeight() {
|
|
5379
|
-
const menuItems = this.visibleMenuItems;
|
|
5380
|
-
let menuItemsHeight = this.getMenuItemsHeight(menuItems);
|
|
5381
|
-
// We don't display separator at the end of a menu
|
|
5382
|
-
if (menuItems[menuItems.length - 1].separator) {
|
|
5383
|
-
menuItemsHeight -= MENU_SEPARATOR_HEIGHT;
|
|
5384
|
-
}
|
|
5385
|
-
const menuHeight = 2 * MENU_VERTICAL_PADDING + menuItemsHeight;
|
|
5386
|
-
return this.props.maxHeight ? Math.min(menuHeight, this.props.maxHeight) : menuHeight;
|
|
5387
|
-
}
|
|
5388
5429
|
get popoverProps() {
|
|
5389
5430
|
const isRoot = this.props.depth === 1;
|
|
5390
5431
|
return {
|
|
@@ -5398,7 +5439,6 @@ class Menu extends Component {
|
|
|
5398
5439
|
verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
|
|
5399
5440
|
onPopoverHidden: () => this.closeSubMenu(),
|
|
5400
5441
|
onPopoverMoved: () => this.closeSubMenu(),
|
|
5401
|
-
maxHeight: this.menuHeight,
|
|
5402
5442
|
};
|
|
5403
5443
|
}
|
|
5404
5444
|
getColor(menu) {
|
|
@@ -5414,14 +5454,6 @@ class Menu extends Component {
|
|
|
5414
5454
|
this.closeSubMenu();
|
|
5415
5455
|
this.props.onClose();
|
|
5416
5456
|
}
|
|
5417
|
-
/**
|
|
5418
|
-
* Return the number of pixels between the top of the menu
|
|
5419
|
-
* and the menu item at a given index.
|
|
5420
|
-
*/
|
|
5421
|
-
subMenuVerticalPosition(menuIndex) {
|
|
5422
|
-
const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
|
|
5423
|
-
return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
|
|
5424
|
-
}
|
|
5425
5457
|
onExternalClick(ev) {
|
|
5426
5458
|
// Don't close a root menu when clicked to open the submenus.
|
|
5427
5459
|
const el = this.menuRef.el;
|
|
@@ -5431,10 +5463,6 @@ class Menu extends Component {
|
|
|
5431
5463
|
ev.closedMenuId = this.props.menuId;
|
|
5432
5464
|
this.close();
|
|
5433
5465
|
}
|
|
5434
|
-
getMenuItemsHeight(menuItems) {
|
|
5435
|
-
const numberOfSeparators = menuItems.filter((m) => m.separator).length;
|
|
5436
|
-
return MENU_ITEM_HEIGHT * menuItems.length + MENU_SEPARATOR_HEIGHT * numberOfSeparators;
|
|
5437
|
-
}
|
|
5438
5466
|
getName(menu) {
|
|
5439
5467
|
return menu.name(this.env);
|
|
5440
5468
|
}
|
|
@@ -5454,8 +5482,11 @@ class Menu extends Component {
|
|
|
5454
5482
|
* If the given menu is not disabled, open it's submenu at the
|
|
5455
5483
|
* correct position according to available surrounding space.
|
|
5456
5484
|
*/
|
|
5457
|
-
openSubMenu(menu, menuIndex) {
|
|
5458
|
-
const
|
|
5485
|
+
openSubMenu(menu, menuIndex, ev) {
|
|
5486
|
+
const parentMenuEl = ev.currentTarget;
|
|
5487
|
+
if (!parentMenuEl)
|
|
5488
|
+
return;
|
|
5489
|
+
const y = parentMenuEl.getBoundingClientRect().top;
|
|
5459
5490
|
this.subMenu.position = {
|
|
5460
5491
|
x: this.position.x + this.props.depth * MENU_WIDTH,
|
|
5461
5492
|
y: y - (this.subMenu.scrollOffset || 0),
|
|
@@ -5472,20 +5503,20 @@ class Menu extends Component {
|
|
|
5472
5503
|
this.subMenu.isOpen = false;
|
|
5473
5504
|
this.subMenu.parentMenu = undefined;
|
|
5474
5505
|
}
|
|
5475
|
-
onClickMenu(menu, menuIndex) {
|
|
5506
|
+
onClickMenu(menu, menuIndex, ev) {
|
|
5476
5507
|
if (this.isEnabled(menu)) {
|
|
5477
5508
|
if (this.isRoot(menu)) {
|
|
5478
|
-
this.openSubMenu(menu, menuIndex);
|
|
5509
|
+
this.openSubMenu(menu, menuIndex, ev);
|
|
5479
5510
|
}
|
|
5480
5511
|
else {
|
|
5481
5512
|
this.activateMenu(menu);
|
|
5482
5513
|
}
|
|
5483
5514
|
}
|
|
5484
5515
|
}
|
|
5485
|
-
onMouseOver(menu, position) {
|
|
5516
|
+
onMouseOver(menu, position, ev) {
|
|
5486
5517
|
if (menu.isEnabled(this.env)) {
|
|
5487
5518
|
if (this.isRoot(menu)) {
|
|
5488
|
-
this.openSubMenu(menu, position);
|
|
5519
|
+
this.openSubMenu(menu, position, ev);
|
|
5489
5520
|
}
|
|
5490
5521
|
else {
|
|
5491
5522
|
this.closeSubMenu();
|
|
@@ -6062,8 +6093,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6062
6093
|
const dataSets = [];
|
|
6063
6094
|
for (const sheetXC of dataSetsString) {
|
|
6064
6095
|
const dataRange = getters.getRangeFromSheetXC(sheetId, sheetXC);
|
|
6065
|
-
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName } = dataRange;
|
|
6066
|
-
if (invalidSheetName) {
|
|
6096
|
+
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName, invalidXc } = dataRange;
|
|
6097
|
+
if (invalidSheetName || invalidXc) {
|
|
6067
6098
|
continue;
|
|
6068
6099
|
}
|
|
6069
6100
|
// It's a rectangle. We treat all columns (arbitrary) as different data series.
|
|
@@ -6088,14 +6119,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6088
6119
|
: undefined));
|
|
6089
6120
|
}
|
|
6090
6121
|
}
|
|
6091
|
-
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
6092
|
-
// A single cell. If it's only the title, the dataset is not added.
|
|
6093
|
-
if (!dataSetsHaveTitle) {
|
|
6094
|
-
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
6095
|
-
}
|
|
6096
|
-
}
|
|
6097
6122
|
else {
|
|
6098
|
-
/* 1 row or 1 column */
|
|
6123
|
+
/* 1 cell, 1 row or 1 column */
|
|
6099
6124
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
6100
6125
|
? {
|
|
6101
6126
|
top: zone.top,
|
|
@@ -6149,6 +6174,18 @@ function toExcelDataset(getters, ds) {
|
|
|
6149
6174
|
range: getters.getRangeString(dataRange, "forceSheetReference"),
|
|
6150
6175
|
};
|
|
6151
6176
|
}
|
|
6177
|
+
function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
6178
|
+
if (!labelRange)
|
|
6179
|
+
return undefined;
|
|
6180
|
+
let zone = {
|
|
6181
|
+
...labelRange.zone,
|
|
6182
|
+
};
|
|
6183
|
+
if (shouldRemoveFirstLabel && labelRange.zone.bottom > labelRange.zone.top) {
|
|
6184
|
+
zone.top = zone.top + 1;
|
|
6185
|
+
}
|
|
6186
|
+
const range = labelRange.clone({ zone });
|
|
6187
|
+
return getters.getRangeString(range, "forceSheetReference");
|
|
6188
|
+
}
|
|
6152
6189
|
/**
|
|
6153
6190
|
* Transform a chart definition which supports dataSets (dataSets and LabelRange)
|
|
6154
6191
|
* with an executed command
|
|
@@ -6233,6 +6270,20 @@ function checkLabelRange(definition) {
|
|
|
6233
6270
|
}
|
|
6234
6271
|
return 0 /* CommandResult.Success */;
|
|
6235
6272
|
}
|
|
6273
|
+
function shouldRemoveFirstLabel(labelRange, dataset, dataSetsHaveTitle) {
|
|
6274
|
+
if (!dataSetsHaveTitle)
|
|
6275
|
+
return false;
|
|
6276
|
+
if (!labelRange)
|
|
6277
|
+
return false;
|
|
6278
|
+
if (!dataset)
|
|
6279
|
+
return true;
|
|
6280
|
+
const datasetLength = getZoneArea(dataset.dataRange.zone);
|
|
6281
|
+
const labelLength = getZoneArea(labelRange.zone);
|
|
6282
|
+
if (labelLength < datasetLength) {
|
|
6283
|
+
return false;
|
|
6284
|
+
}
|
|
6285
|
+
return true;
|
|
6286
|
+
}
|
|
6236
6287
|
// ---------------------------------------------------------------------------
|
|
6237
6288
|
// Scorecard
|
|
6238
6289
|
// ---------------------------------------------------------------------------
|
|
@@ -6602,6 +6653,7 @@ class BarChart extends AbstractChart {
|
|
|
6602
6653
|
this.legendPosition = definition.legendPosition;
|
|
6603
6654
|
this.stacked = definition.stacked;
|
|
6604
6655
|
this.aggregated = definition.aggregated;
|
|
6656
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
6605
6657
|
}
|
|
6606
6658
|
static transformDefinition(definition, executed) {
|
|
6607
6659
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -6669,11 +6721,13 @@ class BarChart extends AbstractChart {
|
|
|
6669
6721
|
const dataSets = this.dataSets
|
|
6670
6722
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
6671
6723
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
6724
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
6672
6725
|
return {
|
|
6673
6726
|
...this.getDefinition(),
|
|
6674
6727
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
6675
6728
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
6676
6729
|
dataSets,
|
|
6730
|
+
labelRange,
|
|
6677
6731
|
};
|
|
6678
6732
|
}
|
|
6679
6733
|
updateRanges(applyChange) {
|
|
@@ -6741,6 +6795,11 @@ function createBarChartRuntime(chart, getters) {
|
|
|
6741
6795
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
6742
6796
|
let labels = labelValues.formattedValues;
|
|
6743
6797
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
6798
|
+
if (chart.dataSetsHaveTitle &&
|
|
6799
|
+
dataSetsValues[0] &&
|
|
6800
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
6801
|
+
labels.shift();
|
|
6802
|
+
}
|
|
6744
6803
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
6745
6804
|
if (chart.aggregated) {
|
|
6746
6805
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
@@ -7163,6 +7222,7 @@ class LineChart extends AbstractChart {
|
|
|
7163
7222
|
this.labelsAsText = definition.labelsAsText;
|
|
7164
7223
|
this.stacked = definition.stacked;
|
|
7165
7224
|
this.aggregated = definition.aggregated;
|
|
7225
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
7166
7226
|
}
|
|
7167
7227
|
static validateChartDefinition(validator, definition) {
|
|
7168
7228
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -7230,11 +7290,13 @@ class LineChart extends AbstractChart {
|
|
|
7230
7290
|
const dataSets = this.dataSets
|
|
7231
7291
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
7232
7292
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
7293
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
7233
7294
|
return {
|
|
7234
7295
|
...this.getDefinition(),
|
|
7235
7296
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
7236
7297
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
7237
7298
|
dataSets,
|
|
7299
|
+
labelRange,
|
|
7238
7300
|
};
|
|
7239
7301
|
}
|
|
7240
7302
|
copyForSheetId(sheetId) {
|
|
@@ -7372,6 +7434,11 @@ function createLineChartRuntime(chart, getters) {
|
|
|
7372
7434
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
7373
7435
|
let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
|
|
7374
7436
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
7437
|
+
if (chart.dataSetsHaveTitle &&
|
|
7438
|
+
dataSetsValues[0] &&
|
|
7439
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
7440
|
+
labels.shift();
|
|
7441
|
+
}
|
|
7375
7442
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
7376
7443
|
if (axisType === "time") {
|
|
7377
7444
|
({ labels, dataSetsValues } = fixEmptyLabelsForDateCharts(labels, dataSetsValues));
|
|
@@ -7430,6 +7497,7 @@ class PieChart extends AbstractChart {
|
|
|
7430
7497
|
this.background = definition.background;
|
|
7431
7498
|
this.legendPosition = definition.legendPosition;
|
|
7432
7499
|
this.aggregated = definition.aggregated;
|
|
7500
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
7433
7501
|
}
|
|
7434
7502
|
static transformDefinition(definition, executed) {
|
|
7435
7503
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -7493,12 +7561,14 @@ class PieChart extends AbstractChart {
|
|
|
7493
7561
|
const dataSets = this.dataSets
|
|
7494
7562
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
7495
7563
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
7564
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
7496
7565
|
return {
|
|
7497
7566
|
...this.getDefinition(),
|
|
7498
7567
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
7499
7568
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
7500
7569
|
verticalAxisPosition: "left",
|
|
7501
7570
|
dataSets,
|
|
7571
|
+
labelRange,
|
|
7502
7572
|
};
|
|
7503
7573
|
}
|
|
7504
7574
|
updateRanges(applyChange) {
|
|
@@ -7544,6 +7614,11 @@ function createPieChartRuntime(chart, getters) {
|
|
|
7544
7614
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
7545
7615
|
let labels = labelValues.formattedValues;
|
|
7546
7616
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
7617
|
+
if (chart.dataSetsHaveTitle &&
|
|
7618
|
+
dataSetsValues[0] &&
|
|
7619
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
7620
|
+
labels.shift();
|
|
7621
|
+
}
|
|
7547
7622
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
7548
7623
|
if (chart.aggregated) {
|
|
7549
7624
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
@@ -7800,6 +7875,10 @@ css /* scss */ `
|
|
|
7800
7875
|
}
|
|
7801
7876
|
`;
|
|
7802
7877
|
class ChartFigure extends Component {
|
|
7878
|
+
onDoubleClick() {
|
|
7879
|
+
this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
|
|
7880
|
+
this.env.openSidePanel("ChartPanel");
|
|
7881
|
+
}
|
|
7803
7882
|
get chartType() {
|
|
7804
7883
|
return this.env.model.getters.getChartType(this.props.figure.id);
|
|
7805
7884
|
}
|
|
@@ -8175,7 +8254,6 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
8175
8254
|
labelRangeXc = zoneToXc({
|
|
8176
8255
|
...zone,
|
|
8177
8256
|
right: zone.left,
|
|
8178
|
-
top: dataSetsHaveTitle ? zone.top + 1 : zone.top,
|
|
8179
8257
|
});
|
|
8180
8258
|
}
|
|
8181
8259
|
// Only display legend for several datasets.
|
|
@@ -15093,7 +15171,7 @@ const ADDRESS = {
|
|
|
15093
15171
|
cellReference = rowPart + colPart;
|
|
15094
15172
|
}
|
|
15095
15173
|
if (sheet !== undefined) {
|
|
15096
|
-
return `${
|
|
15174
|
+
return `${getCanonicalSheetName(toString(sheet))}!${cellReference}`;
|
|
15097
15175
|
}
|
|
15098
15176
|
return cellReference;
|
|
15099
15177
|
},
|
|
@@ -16918,6 +16996,22 @@ class LineBarPieConfigPanel extends Component {
|
|
|
16918
16996
|
aggregated: ev.target.checked,
|
|
16919
16997
|
});
|
|
16920
16998
|
}
|
|
16999
|
+
calculateHeaderPosition() {
|
|
17000
|
+
if (this.isDatasetInvalid || this.isLabelInvalid) {
|
|
17001
|
+
return undefined;
|
|
17002
|
+
}
|
|
17003
|
+
const getters = this.env.model.getters;
|
|
17004
|
+
const sheetId = getters.getActiveSheetId();
|
|
17005
|
+
const labelRange = createRange(getters, sheetId, this.labelRange);
|
|
17006
|
+
const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
|
|
17007
|
+
if (dataSets.length) {
|
|
17008
|
+
return dataSets[0].dataRange.zone.top + 1;
|
|
17009
|
+
}
|
|
17010
|
+
else if (labelRange) {
|
|
17011
|
+
return labelRange.zone.top + 1;
|
|
17012
|
+
}
|
|
17013
|
+
return undefined;
|
|
17014
|
+
}
|
|
16921
17015
|
}
|
|
16922
17016
|
LineBarPieConfigPanel.template = "o-spreadsheet-LineBarPieConfigPanel";
|
|
16923
17017
|
LineBarPieConfigPanel.components = { SelectionInput };
|
|
@@ -17165,6 +17259,9 @@ class ColorPicker extends Component {
|
|
|
17165
17259
|
top,
|
|
17166
17260
|
});
|
|
17167
17261
|
}
|
|
17262
|
+
isSameColor(color1, color2) {
|
|
17263
|
+
return isSameColor(color1, color2);
|
|
17264
|
+
}
|
|
17168
17265
|
}
|
|
17169
17266
|
ColorPicker.template = "o-spreadsheet-ColorPicker";
|
|
17170
17267
|
ColorPicker.defaultProps = {
|
|
@@ -18837,7 +18934,7 @@ css /*SCSS*/ `
|
|
|
18837
18934
|
box-sizing: content-box;
|
|
18838
18935
|
|
|
18839
18936
|
.o-fig-anchor {
|
|
18840
|
-
z-index: ${ComponentsImportance.
|
|
18937
|
+
z-index: ${ComponentsImportance.FigureAnchor};
|
|
18841
18938
|
position: absolute;
|
|
18842
18939
|
width: ${ANCHOR_SIZE}px;
|
|
18843
18940
|
height: ${ANCHOR_SIZE}px;
|
|
@@ -19406,6 +19503,8 @@ class ContentEditableHelper {
|
|
|
19406
19503
|
start = 0;
|
|
19407
19504
|
if (end > textLength)
|
|
19408
19505
|
end = textLength;
|
|
19506
|
+
if (start > textLength)
|
|
19507
|
+
start = textLength;
|
|
19409
19508
|
}
|
|
19410
19509
|
let startNode = this.findChildAtCharacterIndex(start);
|
|
19411
19510
|
let endNode = this.findChildAtCharacterIndex(end);
|
|
@@ -19675,6 +19774,7 @@ css /* scss */ `
|
|
|
19675
19774
|
padding-right: 2px;
|
|
19676
19775
|
|
|
19677
19776
|
box-sizing: border-box;
|
|
19777
|
+
font-family: ${DEFAULT_FONT};
|
|
19678
19778
|
|
|
19679
19779
|
caret-color: black;
|
|
19680
19780
|
padding-left: 3px;
|
|
@@ -19704,13 +19804,6 @@ css /* scss */ `
|
|
|
19704
19804
|
pointer-events: none;
|
|
19705
19805
|
}
|
|
19706
19806
|
}
|
|
19707
|
-
|
|
19708
|
-
.o-topbar-composer .o-composer:empty:not(:focus)::before {
|
|
19709
|
-
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
19710
|
-
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");
|
|
19711
|
-
position: relative;
|
|
19712
|
-
top: 20%;
|
|
19713
|
-
}
|
|
19714
19807
|
`;
|
|
19715
19808
|
class Composer extends Component {
|
|
19716
19809
|
constructor() {
|
|
@@ -20124,7 +20217,7 @@ class Composer extends Component {
|
|
|
20124
20217
|
const highlights = this.env.model.getters.getHighlights();
|
|
20125
20218
|
const refSheet = sheetName
|
|
20126
20219
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
20127
|
-
: this.env.model.getters.
|
|
20220
|
+
: this.env.model.getters.getCurrentEditedCell().sheetId;
|
|
20128
20221
|
const highlight = highlights.find((highlight) => {
|
|
20129
20222
|
if (highlight.sheetId !== refSheet)
|
|
20130
20223
|
return false;
|
|
@@ -20285,7 +20378,7 @@ class GridComposer extends Component {
|
|
|
20285
20378
|
get cellReference() {
|
|
20286
20379
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
20287
20380
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
20288
|
-
return `${prefixSheet ?
|
|
20381
|
+
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
20289
20382
|
}
|
|
20290
20383
|
get cellReferenceStyle() {
|
|
20291
20384
|
const { x: left, y: top } = this.rect;
|
|
@@ -20438,6 +20531,269 @@ FilterIconsOverlay.props = {
|
|
|
20438
20531
|
gridPosition: { type: Object, optional: true },
|
|
20439
20532
|
};
|
|
20440
20533
|
|
|
20534
|
+
/**
|
|
20535
|
+
* Transform a figure with coordinates from the model, to coordinates as they are shown on the screen,
|
|
20536
|
+
* taking into account the scroll position of the active sheet and the frozen panes.
|
|
20537
|
+
*/
|
|
20538
|
+
function internalFigureToScreen(getters, fig) {
|
|
20539
|
+
return { ...fig, ...internalToScreenCoordinates(getters, { x: fig.x, y: fig.y }) };
|
|
20540
|
+
}
|
|
20541
|
+
/**
|
|
20542
|
+
* Transform a figure with coordinates as they are shown on the screen, to coordinates as they are in the model,
|
|
20543
|
+
* taking into account the scroll position of the active sheet and the frozen panes.
|
|
20544
|
+
*
|
|
20545
|
+
* Note that this isn't exactly the reverse operation as internalFigureToScreen, because the figure will always be on top
|
|
20546
|
+
* of the frozen panes.
|
|
20547
|
+
*/
|
|
20548
|
+
function screenFigureToInternal(getters, fig) {
|
|
20549
|
+
return { ...fig, ...screenCoordinatesToInternal(getters, { x: fig.x, y: fig.y }) };
|
|
20550
|
+
}
|
|
20551
|
+
function internalToScreenCoordinates(getters, { x, y }) {
|
|
20552
|
+
const { x: viewportX, y: viewportY } = getters.getMainViewportCoordinates();
|
|
20553
|
+
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
20554
|
+
x = x < viewportX ? x : x - scrollX;
|
|
20555
|
+
y = y < viewportY ? y : y - scrollY;
|
|
20556
|
+
return { x, y };
|
|
20557
|
+
}
|
|
20558
|
+
function screenCoordinatesToInternal(getters, { x, y }) {
|
|
20559
|
+
const { x: viewportX, y: viewportY } = getters.getMainViewportCoordinates();
|
|
20560
|
+
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
20561
|
+
x = viewportX && x < viewportX ? x : x + scrollX;
|
|
20562
|
+
y = viewportY && y < viewportY ? y : y + scrollY;
|
|
20563
|
+
return { x, y };
|
|
20564
|
+
}
|
|
20565
|
+
|
|
20566
|
+
function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { maxX, maxY }, { scrollX, scrollY }) {
|
|
20567
|
+
const minX = viewportX ? 0 : -scrollX;
|
|
20568
|
+
const minY = viewportY ? 0 : -scrollY;
|
|
20569
|
+
const deltaX = mouseX - mouseInitialX;
|
|
20570
|
+
const newX = clamp(initialFigure.x + deltaX, minX, maxX - initialFigure.width - scrollX);
|
|
20571
|
+
const deltaY = mouseY - mouseInitialY;
|
|
20572
|
+
const newY = clamp(initialFigure.y + deltaY, minY, maxY - initialFigure.height - scrollY);
|
|
20573
|
+
return { ...initialFigure, x: newX, y: newY };
|
|
20574
|
+
}
|
|
20575
|
+
function clamp(value, min, max) {
|
|
20576
|
+
return Math.min(Math.max(value, min), max);
|
|
20577
|
+
}
|
|
20578
|
+
function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, keepRatio, minFigSize) {
|
|
20579
|
+
let { x, y, width, height } = initialFigure;
|
|
20580
|
+
if (keepRatio && dirX != 0 && dirY != 0) {
|
|
20581
|
+
const deltaX = Math.min(dirX * (mouseInitialX - mouseX), initialFigure.width - minFigSize);
|
|
20582
|
+
const deltaY = Math.min(dirY * (mouseInitialY - mouseY), initialFigure.height - minFigSize);
|
|
20583
|
+
const fraction = Math.min(deltaX / initialFigure.width, deltaY / initialFigure.height);
|
|
20584
|
+
width = initialFigure.width * (1 - fraction);
|
|
20585
|
+
height = initialFigure.height * (1 - fraction);
|
|
20586
|
+
if (dirX < 0) {
|
|
20587
|
+
x = initialFigure.x + initialFigure.width * fraction;
|
|
20588
|
+
}
|
|
20589
|
+
if (dirY < 0) {
|
|
20590
|
+
y = initialFigure.y + initialFigure.height * fraction;
|
|
20591
|
+
}
|
|
20592
|
+
}
|
|
20593
|
+
else {
|
|
20594
|
+
const deltaX = Math.max(dirX * (mouseX - mouseInitialX), minFigSize - initialFigure.width);
|
|
20595
|
+
const deltaY = Math.max(dirY * (mouseY - mouseInitialY), minFigSize - initialFigure.height);
|
|
20596
|
+
width = initialFigure.width + deltaX;
|
|
20597
|
+
height = initialFigure.height + deltaY;
|
|
20598
|
+
if (dirX < 0) {
|
|
20599
|
+
x = initialFigure.x - deltaX;
|
|
20600
|
+
}
|
|
20601
|
+
if (dirY < 0) {
|
|
20602
|
+
y = initialFigure.y - deltaY;
|
|
20603
|
+
}
|
|
20604
|
+
}
|
|
20605
|
+
return { ...initialFigure, x, y, width, height };
|
|
20606
|
+
}
|
|
20607
|
+
|
|
20608
|
+
const SNAP_MARGIN = 5;
|
|
20609
|
+
/**
|
|
20610
|
+
* Try to snap the given figure to other figures when moving the figure, and return the snapped
|
|
20611
|
+
* figure and the possible snap lines, if any were found
|
|
20612
|
+
*/
|
|
20613
|
+
function snapForMove(getters, figureToSnap, otherFigures) {
|
|
20614
|
+
const snappedFigure = { ...figureToSnap };
|
|
20615
|
+
const verticalSnapLine = getSnapLine(getters, snappedFigure, ["hCenter", "right", "left"], otherFigures, ["hCenter", "right", "left"]);
|
|
20616
|
+
const horizontalSnapLine = getSnapLine(getters, snappedFigure, ["vCenter", "bottom", "top"], otherFigures, ["vCenter", "bottom", "top"]);
|
|
20617
|
+
const { y: viewportY, x: viewportX } = getters.getMainViewportCoordinates();
|
|
20618
|
+
const { scrollY, scrollX } = getters.getActiveSheetScrollInfo();
|
|
20619
|
+
// If the snap cause the figure to change pane, we need to also apply the scroll as an offset
|
|
20620
|
+
if (horizontalSnapLine) {
|
|
20621
|
+
snappedFigure.y -= horizontalSnapLine.snapOffset;
|
|
20622
|
+
const isBaseFigFrozenY = figureToSnap.y < viewportY;
|
|
20623
|
+
const isSnappedFrozenY = snappedFigure.y < viewportY;
|
|
20624
|
+
if (isBaseFigFrozenY && !isSnappedFrozenY)
|
|
20625
|
+
snappedFigure.y += scrollY;
|
|
20626
|
+
else if (!isBaseFigFrozenY && isSnappedFrozenY)
|
|
20627
|
+
snappedFigure.y -= scrollY;
|
|
20628
|
+
}
|
|
20629
|
+
if (verticalSnapLine) {
|
|
20630
|
+
snappedFigure.x -= verticalSnapLine.snapOffset;
|
|
20631
|
+
const isBaseFigFrozenX = figureToSnap.x < viewportX;
|
|
20632
|
+
const isSnappedFrozenX = snappedFigure.x < viewportX;
|
|
20633
|
+
if (isBaseFigFrozenX && !isSnappedFrozenX)
|
|
20634
|
+
snappedFigure.x += scrollX;
|
|
20635
|
+
else if (!isBaseFigFrozenX && isSnappedFrozenX)
|
|
20636
|
+
snappedFigure.x -= scrollX;
|
|
20637
|
+
}
|
|
20638
|
+
return { snappedFigure, verticalSnapLine, horizontalSnapLine };
|
|
20639
|
+
}
|
|
20640
|
+
/**
|
|
20641
|
+
* Try to snap the given figure to the other figures when resizing the figure, and return the snapped
|
|
20642
|
+
* figure and the possible snap lines, if any were found
|
|
20643
|
+
*/
|
|
20644
|
+
function snapForResize(getters, resizeDirX, resizeDirY, figureToSnap, otherFigures) {
|
|
20645
|
+
const snappedFigure = { ...figureToSnap };
|
|
20646
|
+
// Vertical snap line
|
|
20647
|
+
const verticalSnapLine = getSnapLine(getters, snappedFigure, [resizeDirX === -1 ? "left" : "right"], otherFigures, ["right", "left"]);
|
|
20648
|
+
if (verticalSnapLine) {
|
|
20649
|
+
if (resizeDirX === 1) {
|
|
20650
|
+
snappedFigure.width -= verticalSnapLine.snapOffset;
|
|
20651
|
+
}
|
|
20652
|
+
else if (resizeDirX === -1) {
|
|
20653
|
+
snappedFigure.x -= verticalSnapLine.snapOffset;
|
|
20654
|
+
snappedFigure.width += verticalSnapLine.snapOffset;
|
|
20655
|
+
}
|
|
20656
|
+
}
|
|
20657
|
+
// Horizontal snap line
|
|
20658
|
+
const horizontalSnapLine = getSnapLine(getters, snappedFigure, [resizeDirY === -1 ? "top" : "bottom"], otherFigures, ["bottom", "top"]);
|
|
20659
|
+
if (horizontalSnapLine) {
|
|
20660
|
+
if (resizeDirY === 1) {
|
|
20661
|
+
snappedFigure.height -= horizontalSnapLine.snapOffset;
|
|
20662
|
+
}
|
|
20663
|
+
else if (resizeDirY === -1) {
|
|
20664
|
+
snappedFigure.y -= horizontalSnapLine.snapOffset;
|
|
20665
|
+
snappedFigure.height += horizontalSnapLine.snapOffset;
|
|
20666
|
+
}
|
|
20667
|
+
}
|
|
20668
|
+
snappedFigure.x = Math.round(snappedFigure.x);
|
|
20669
|
+
snappedFigure.y = Math.round(snappedFigure.y);
|
|
20670
|
+
snappedFigure.height = Math.round(snappedFigure.height);
|
|
20671
|
+
snappedFigure.width = Math.round(snappedFigure.width);
|
|
20672
|
+
return { snappedFigure, verticalSnapLine, horizontalSnapLine };
|
|
20673
|
+
}
|
|
20674
|
+
/**
|
|
20675
|
+
* Get the position of snap axes for the given figure
|
|
20676
|
+
*
|
|
20677
|
+
* @param figure the figure
|
|
20678
|
+
* @param axesTypes the list of axis types to return the positions of
|
|
20679
|
+
*/
|
|
20680
|
+
function getVisibleAxes(getters, figure, axesTypes) {
|
|
20681
|
+
const axes = axesTypes.map((axisType) => getAxis(figure, axisType));
|
|
20682
|
+
return axes
|
|
20683
|
+
.filter((axis) => isAxisVisible(getters, figure, axis))
|
|
20684
|
+
.map((axis) => getAxisScreenPosition(getters, figure, axis));
|
|
20685
|
+
}
|
|
20686
|
+
/**
|
|
20687
|
+
* We need two positions for the figure axis :
|
|
20688
|
+
* - the position (core) of the axis in the figure. This is used to know whether or not the axis is
|
|
20689
|
+
* displayed, or is hidden by the scroll/the frozen panes
|
|
20690
|
+
* - the position in the screen, which is used to find snap matches. We cannot use the core position for this,
|
|
20691
|
+
* because figures partially in frozen panes aren't displayed at their actual coordinates
|
|
20692
|
+
*/
|
|
20693
|
+
function getAxisScreenPosition(getters, figure, figureAxis) {
|
|
20694
|
+
const screenFigure = internalFigureToScreen(getters, figure);
|
|
20695
|
+
return getAxis(screenFigure, figureAxis.axisType);
|
|
20696
|
+
}
|
|
20697
|
+
function isAxisVisible(getters, figure, axis) {
|
|
20698
|
+
const { x: mainViewportX, y: mainViewportY } = getters.getMainViewportCoordinates();
|
|
20699
|
+
const axisStartEndPositions = [];
|
|
20700
|
+
switch (axis.axisType) {
|
|
20701
|
+
case "top":
|
|
20702
|
+
case "bottom":
|
|
20703
|
+
case "vCenter":
|
|
20704
|
+
if (figure.y < mainViewportY)
|
|
20705
|
+
return true;
|
|
20706
|
+
axisStartEndPositions.push({ x: figure.x, y: axis.position });
|
|
20707
|
+
axisStartEndPositions.push({ x: figure.x + figure.width, y: axis.position });
|
|
20708
|
+
break;
|
|
20709
|
+
case "left":
|
|
20710
|
+
case "right":
|
|
20711
|
+
case "hCenter":
|
|
20712
|
+
if (figure.x < mainViewportX)
|
|
20713
|
+
return true;
|
|
20714
|
+
axisStartEndPositions.push({ x: axis.position, y: figure.y });
|
|
20715
|
+
axisStartEndPositions.push({ x: axis.position, y: figure.y + figure.height });
|
|
20716
|
+
break;
|
|
20717
|
+
}
|
|
20718
|
+
return axisStartEndPositions.some(getters.isPositionVisible);
|
|
20719
|
+
}
|
|
20720
|
+
/**
|
|
20721
|
+
* Get a snap line for the given figure, if the figure can snap to any other figure
|
|
20722
|
+
*
|
|
20723
|
+
* @param figureToSnap figure to get the snap line for
|
|
20724
|
+
* @param figAxesTypes figure axes of the given figure to be considered to find a snap line
|
|
20725
|
+
* @param otherFigures figures to match against the snapped figure to find a snap line
|
|
20726
|
+
* @param otherAxesTypes figure axes of the other figures to be considered to find a snap line
|
|
20727
|
+
*/
|
|
20728
|
+
function getSnapLine(getters, figureToSnap, figAxesTypes, otherFigures, otherAxesTypes) {
|
|
20729
|
+
const axesOfFigure = getVisibleAxes(getters, figureToSnap, figAxesTypes);
|
|
20730
|
+
let closestMatch = undefined;
|
|
20731
|
+
for (const otherFigure of otherFigures) {
|
|
20732
|
+
const axesOfOtherFig = getVisibleAxes(getters, otherFigure, otherAxesTypes);
|
|
20733
|
+
for (const axisOfFigure of axesOfFigure) {
|
|
20734
|
+
for (const axisOfOtherFig of axesOfOtherFig) {
|
|
20735
|
+
if (!canSnap(axisOfFigure.position, axisOfOtherFig.position))
|
|
20736
|
+
continue;
|
|
20737
|
+
const snapOffset = axisOfFigure.position - axisOfOtherFig.position;
|
|
20738
|
+
if (closestMatch && snapOffset === closestMatch.snapOffset) {
|
|
20739
|
+
closestMatch.matchedFigIds.push(otherFigure.id);
|
|
20740
|
+
}
|
|
20741
|
+
else if (!closestMatch || Math.abs(snapOffset) <= Math.abs(closestMatch.snapOffset)) {
|
|
20742
|
+
closestMatch = {
|
|
20743
|
+
matchedFigIds: [otherFigure.id],
|
|
20744
|
+
snapOffset,
|
|
20745
|
+
snappedAxisType: axisOfFigure.axisType,
|
|
20746
|
+
position: axisOfOtherFig.position,
|
|
20747
|
+
};
|
|
20748
|
+
}
|
|
20749
|
+
}
|
|
20750
|
+
}
|
|
20751
|
+
}
|
|
20752
|
+
return closestMatch;
|
|
20753
|
+
}
|
|
20754
|
+
/** Check if two axes are close enough to snap */
|
|
20755
|
+
function canSnap(axisPosition1, axisPosition2) {
|
|
20756
|
+
return Math.abs(axisPosition1 - axisPosition2) <= SNAP_MARGIN;
|
|
20757
|
+
}
|
|
20758
|
+
function getAxis(fig, axisType) {
|
|
20759
|
+
let position = 0;
|
|
20760
|
+
switch (axisType) {
|
|
20761
|
+
case "top":
|
|
20762
|
+
position = fig.y;
|
|
20763
|
+
break;
|
|
20764
|
+
case "bottom":
|
|
20765
|
+
position = fig.y + fig.height - FIGURE_BORDER_WIDTH;
|
|
20766
|
+
break;
|
|
20767
|
+
case "vCenter":
|
|
20768
|
+
position = fig.y + Math.floor(fig.height / 2) - FIGURE_BORDER_WIDTH;
|
|
20769
|
+
break;
|
|
20770
|
+
case "left":
|
|
20771
|
+
position = fig.x;
|
|
20772
|
+
break;
|
|
20773
|
+
case "right":
|
|
20774
|
+
position = fig.x + fig.width - FIGURE_BORDER_WIDTH;
|
|
20775
|
+
break;
|
|
20776
|
+
case "hCenter":
|
|
20777
|
+
position = fig.x + Math.floor(fig.width / 2) - FIGURE_BORDER_WIDTH;
|
|
20778
|
+
break;
|
|
20779
|
+
}
|
|
20780
|
+
return { position, axisType: axisType };
|
|
20781
|
+
}
|
|
20782
|
+
|
|
20783
|
+
css /*SCSS*/ `
|
|
20784
|
+
.o-figure-snap-line {
|
|
20785
|
+
position: relative;
|
|
20786
|
+
z-index: ${ComponentsImportance.FigureSnapLine};
|
|
20787
|
+
&.vertical {
|
|
20788
|
+
width: 0px;
|
|
20789
|
+
border-left: 1px dashed black;
|
|
20790
|
+
}
|
|
20791
|
+
&.horizontal {
|
|
20792
|
+
border-top: 1px dashed black;
|
|
20793
|
+
height: 0px;
|
|
20794
|
+
}
|
|
20795
|
+
}
|
|
20796
|
+
`;
|
|
20441
20797
|
/**
|
|
20442
20798
|
* Each figure ⭐ is positioned inside a container `div` placed and sized
|
|
20443
20799
|
* according to the split pane the figure is part of, or a separate container for the figure
|
|
@@ -20502,11 +20858,9 @@ class FiguresContainer extends Component {
|
|
|
20502
20858
|
constructor() {
|
|
20503
20859
|
super(...arguments);
|
|
20504
20860
|
this.dnd = useState({
|
|
20505
|
-
|
|
20506
|
-
|
|
20507
|
-
|
|
20508
|
-
width: 0,
|
|
20509
|
-
height: 0,
|
|
20861
|
+
draggedFigure: undefined,
|
|
20862
|
+
horizontalSnap: undefined,
|
|
20863
|
+
verticalSnap: undefined,
|
|
20510
20864
|
});
|
|
20511
20865
|
}
|
|
20512
20866
|
setup() {
|
|
@@ -20522,9 +20876,11 @@ class FiguresContainer extends Component {
|
|
|
20522
20876
|
});
|
|
20523
20877
|
}
|
|
20524
20878
|
getVisibleFigures() {
|
|
20879
|
+
var _a;
|
|
20525
20880
|
const visibleFigures = this.env.model.getters.getVisibleFigures();
|
|
20526
|
-
if (this.dnd.
|
|
20527
|
-
visibleFigures.
|
|
20881
|
+
if (this.dnd.draggedFigure &&
|
|
20882
|
+
!visibleFigures.some((figure) => { var _a; return figure.id === ((_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id); })) {
|
|
20883
|
+
visibleFigures.push(this.env.model.getters.getFigure(this.env.model.getters.getActiveSheetId(), (_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id));
|
|
20528
20884
|
}
|
|
20529
20885
|
return visibleFigures;
|
|
20530
20886
|
}
|
|
@@ -20547,7 +20903,7 @@ class FiguresContainer extends Component {
|
|
|
20547
20903
|
});
|
|
20548
20904
|
}
|
|
20549
20905
|
}
|
|
20550
|
-
if (this.dnd.
|
|
20906
|
+
if (this.dnd.draggedFigure) {
|
|
20551
20907
|
containers.push({
|
|
20552
20908
|
type: "dnd",
|
|
20553
20909
|
figures: [this.getDndFigure()],
|
|
@@ -20558,19 +20914,25 @@ class FiguresContainer extends Component {
|
|
|
20558
20914
|
return containers;
|
|
20559
20915
|
}
|
|
20560
20916
|
getContainerStyle(container) {
|
|
20561
|
-
|
|
20562
|
-
|
|
20563
|
-
|
|
20564
|
-
const width = viewWidth - left;
|
|
20565
|
-
const top = ["bottomRight", "bottomLeft"].includes(container) ? viewportY : 0;
|
|
20566
|
-
const height = viewHeight - top;
|
|
20917
|
+
return this.rectToCss(this.getContainerRect(container));
|
|
20918
|
+
}
|
|
20919
|
+
rectToCss(rect) {
|
|
20567
20920
|
return cssPropertiesToCss({
|
|
20568
|
-
left: `${
|
|
20569
|
-
top: `${
|
|
20570
|
-
width: `${width}px`,
|
|
20571
|
-
height: `${height}px`,
|
|
20921
|
+
left: `${rect.x}px`,
|
|
20922
|
+
top: `${rect.y}px`,
|
|
20923
|
+
width: `${rect.width}px`,
|
|
20924
|
+
height: `${rect.height}px`,
|
|
20572
20925
|
});
|
|
20573
20926
|
}
|
|
20927
|
+
getContainerRect(container) {
|
|
20928
|
+
const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
|
|
20929
|
+
const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
|
|
20930
|
+
const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
|
|
20931
|
+
const width = viewWidth - x;
|
|
20932
|
+
const y = ["bottomRight", "bottomLeft"].includes(container) ? viewportY : 0;
|
|
20933
|
+
const height = viewHeight - y;
|
|
20934
|
+
return { x, y, width, height };
|
|
20935
|
+
}
|
|
20574
20936
|
getInverseViewportPositionStyle(container) {
|
|
20575
20937
|
const { scrollX, scrollY } = this.env.model.getters.getActiveSheetScrollInfo();
|
|
20576
20938
|
const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
|
|
@@ -20582,8 +20944,9 @@ class FiguresContainer extends Component {
|
|
|
20582
20944
|
});
|
|
20583
20945
|
}
|
|
20584
20946
|
getFigureContainer(figure) {
|
|
20947
|
+
var _a;
|
|
20585
20948
|
const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
|
|
20586
|
-
if (figure.id === this.dnd.
|
|
20949
|
+
if (figure.id === ((_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id)) {
|
|
20587
20950
|
return "dnd";
|
|
20588
20951
|
}
|
|
20589
20952
|
else if (figure.x < viewportX && figure.y < viewportY) {
|
|
@@ -20609,133 +20972,141 @@ class FiguresContainer extends Component {
|
|
|
20609
20972
|
return;
|
|
20610
20973
|
}
|
|
20611
20974
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
20612
|
-
const
|
|
20613
|
-
const
|
|
20614
|
-
|
|
20615
|
-
|
|
20616
|
-
|
|
20617
|
-
this.
|
|
20618
|
-
|
|
20975
|
+
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
20976
|
+
const maxDimensions = {
|
|
20977
|
+
maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
|
|
20978
|
+
maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
|
|
20979
|
+
};
|
|
20980
|
+
const { x, y } = internalFigureToScreen(this.env.model.getters, figure);
|
|
20981
|
+
const initialFig = { ...figure, x, y };
|
|
20619
20982
|
const onMouseMove = (ev) => {
|
|
20620
|
-
const
|
|
20621
|
-
const {
|
|
20622
|
-
const
|
|
20623
|
-
const
|
|
20624
|
-
|
|
20625
|
-
const
|
|
20626
|
-
|
|
20627
|
-
this.dnd.
|
|
20628
|
-
|
|
20629
|
-
let deltaY = newY - mouseInitialY;
|
|
20630
|
-
this.dnd.y = Math.max(dndInitialY + deltaY, minY);
|
|
20983
|
+
const getters = this.env.model.getters;
|
|
20984
|
+
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
20985
|
+
const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), maxDimensions, getters.getActiveSheetScrollInfo());
|
|
20986
|
+
const otherFigures = this.getOtherFigures(figure.id);
|
|
20987
|
+
const internalDragged = screenFigureToInternal(getters, draggedFigure);
|
|
20988
|
+
const snapResult = snapForMove(getters, internalDragged, otherFigures);
|
|
20989
|
+
this.dnd.draggedFigure = internalFigureToScreen(getters, snapResult.snappedFigure);
|
|
20990
|
+
this.dnd.horizontalSnap = this.getSnap(snapResult.horizontalSnapLine);
|
|
20991
|
+
this.dnd.verticalSnap = this.getSnap(snapResult.verticalSnapLine);
|
|
20631
20992
|
};
|
|
20632
20993
|
const onMouseUp = (ev) => {
|
|
20633
|
-
if (!this.dnd.
|
|
20994
|
+
if (!this.dnd.draggedFigure) {
|
|
20634
20995
|
return;
|
|
20635
20996
|
}
|
|
20636
|
-
let { x, y } = this.
|
|
20637
|
-
this.dnd.
|
|
20997
|
+
let { x, y } = screenFigureToInternal(this.env.model.getters, this.dnd.draggedFigure);
|
|
20998
|
+
this.dnd.draggedFigure = undefined;
|
|
20999
|
+
this.dnd.horizontalSnap = undefined;
|
|
21000
|
+
this.dnd.verticalSnap = undefined;
|
|
20638
21001
|
this.env.model.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x, y });
|
|
20639
21002
|
};
|
|
20640
21003
|
startDnd(onMouseMove, onMouseUp);
|
|
20641
21004
|
}
|
|
21005
|
+
/**
|
|
21006
|
+
* Initialize the resize of a figure with mouse movements
|
|
21007
|
+
*
|
|
21008
|
+
* @param dirX X direction of the resize. -1 : resize from the left border of the figure, 0 : no resize in X, 1 :
|
|
21009
|
+
* resize from the right border of the figure
|
|
21010
|
+
* @param dirY Y direction of the resize. -1 : resize from the top border of the figure, 0 : no resize in Y, 1 :
|
|
21011
|
+
* resize from the bottom border of the figure
|
|
21012
|
+
* @param ev Mouse Event
|
|
21013
|
+
*/
|
|
20642
21014
|
startResize(figure, dirX, dirY, ev) {
|
|
20643
21015
|
ev.stopPropagation();
|
|
20644
|
-
const
|
|
20645
|
-
const
|
|
20646
|
-
const { x
|
|
20647
|
-
this.dnd.x = dndInitialX;
|
|
20648
|
-
this.dnd.y = dndInitialY;
|
|
20649
|
-
this.dnd.width = figure.width;
|
|
20650
|
-
this.dnd.height = figure.height;
|
|
21016
|
+
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
21017
|
+
const { x, y } = internalFigureToScreen(this.env.model.getters, figure);
|
|
21018
|
+
const initialFig = { ...figure, x, y };
|
|
20651
21019
|
const keepRatio = figureRegistry.get(figure.tag).keepRatio || false;
|
|
20652
21020
|
const minFigSize = figureRegistry.get(figure.tag).minFigSize || MIN_FIG_SIZE;
|
|
20653
|
-
|
|
20654
|
-
|
|
20655
|
-
|
|
20656
|
-
|
|
20657
|
-
|
|
20658
|
-
|
|
20659
|
-
|
|
20660
|
-
|
|
20661
|
-
|
|
20662
|
-
if (dirX < 0) {
|
|
20663
|
-
this.dnd.x = dndInitialX + figure.width * fraction;
|
|
20664
|
-
}
|
|
20665
|
-
if (dirY < 0) {
|
|
20666
|
-
this.dnd.y = dndInitialY + figure.height * fraction;
|
|
20667
|
-
}
|
|
20668
|
-
};
|
|
20669
|
-
}
|
|
20670
|
-
else {
|
|
20671
|
-
onMouseMove = (ev) => {
|
|
20672
|
-
this.dnd.figId = figure.id;
|
|
20673
|
-
const deltaX = Math.max(dirX * (ev.clientX - initialX), minFigSize - figure.width);
|
|
20674
|
-
const deltaY = Math.max(dirY * (ev.clientY - initialY), minFigSize - figure.height);
|
|
20675
|
-
this.dnd.width = figure.width + deltaX;
|
|
20676
|
-
this.dnd.height = figure.height + deltaY;
|
|
20677
|
-
if (dirX < 0) {
|
|
20678
|
-
this.dnd.x = dndInitialX - deltaX;
|
|
20679
|
-
}
|
|
20680
|
-
if (dirY < 0) {
|
|
20681
|
-
this.dnd.y = dndInitialY - deltaY;
|
|
20682
|
-
}
|
|
20683
|
-
};
|
|
20684
|
-
}
|
|
21021
|
+
const onMouseMove = (ev) => {
|
|
21022
|
+
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
21023
|
+
const draggedFigure = dragFigureForResize(initialFig, dirX, dirY, currentMousePosition, initialMousePosition, keepRatio, minFigSize);
|
|
21024
|
+
const otherFigures = this.getOtherFigures(figure.id);
|
|
21025
|
+
const snapResult = snapForResize(this.env.model.getters, dirX, dirY, draggedFigure, otherFigures);
|
|
21026
|
+
this.dnd.draggedFigure = snapResult.snappedFigure;
|
|
21027
|
+
this.dnd.horizontalSnap = this.getSnap(snapResult.horizontalSnapLine);
|
|
21028
|
+
this.dnd.verticalSnap = this.getSnap(snapResult.verticalSnapLine);
|
|
21029
|
+
};
|
|
20685
21030
|
const onMouseUp = (ev) => {
|
|
20686
|
-
if (!this.dnd.
|
|
21031
|
+
if (!this.dnd.draggedFigure) {
|
|
20687
21032
|
return;
|
|
20688
21033
|
}
|
|
20689
|
-
this.dnd.
|
|
20690
|
-
let { x, y } = this.screenCoordinatesToInternal(this.dnd);
|
|
21034
|
+
let { x, y } = screenFigureToInternal(this.env.model.getters, this.dnd.draggedFigure);
|
|
20691
21035
|
const update = { x, y };
|
|
20692
21036
|
if (dirX) {
|
|
20693
|
-
update.width = this.dnd.width;
|
|
21037
|
+
update.width = this.dnd.draggedFigure.width;
|
|
20694
21038
|
}
|
|
20695
21039
|
if (dirY) {
|
|
20696
|
-
update.height = this.dnd.height;
|
|
21040
|
+
update.height = this.dnd.draggedFigure.height;
|
|
20697
21041
|
}
|
|
20698
21042
|
this.env.model.dispatch("UPDATE_FIGURE", {
|
|
20699
21043
|
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
20700
21044
|
id: figure.id,
|
|
20701
21045
|
...update,
|
|
20702
21046
|
});
|
|
21047
|
+
this.dnd.draggedFigure = undefined;
|
|
21048
|
+
this.dnd.horizontalSnap = undefined;
|
|
21049
|
+
this.dnd.verticalSnap = undefined;
|
|
20703
21050
|
};
|
|
20704
21051
|
startDnd(onMouseMove, onMouseUp);
|
|
20705
21052
|
}
|
|
21053
|
+
getOtherFigures(figId) {
|
|
21054
|
+
return this.getVisibleFigures().filter((f) => f.id !== figId);
|
|
21055
|
+
}
|
|
20706
21056
|
getDndFigure() {
|
|
20707
|
-
const figure = this.getVisibleFigures().find((fig) => fig.id === this.dnd.
|
|
21057
|
+
const figure = this.getVisibleFigures().find((fig) => { var _a; return fig.id === ((_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id); });
|
|
20708
21058
|
if (!figure)
|
|
20709
21059
|
throw new Error("Dnd figure not found");
|
|
20710
21060
|
return {
|
|
20711
21061
|
...figure,
|
|
20712
|
-
|
|
20713
|
-
y: this.dnd.y,
|
|
20714
|
-
width: this.dnd.width,
|
|
20715
|
-
height: this.dnd.height,
|
|
21062
|
+
...this.dnd.draggedFigure,
|
|
20716
21063
|
};
|
|
20717
21064
|
}
|
|
20718
21065
|
getFigureStyle(figure) {
|
|
20719
|
-
|
|
21066
|
+
var _a;
|
|
21067
|
+
if (figure.id !== ((_a = this.dnd.draggedFigure) === null || _a === void 0 ? void 0 : _a.id))
|
|
20720
21068
|
return "";
|
|
20721
21069
|
return cssPropertiesToCss({
|
|
20722
21070
|
opacity: "0.9",
|
|
20723
21071
|
cursor: "grabbing",
|
|
20724
21072
|
});
|
|
20725
21073
|
}
|
|
20726
|
-
|
|
20727
|
-
|
|
20728
|
-
|
|
20729
|
-
|
|
20730
|
-
|
|
20731
|
-
|
|
21074
|
+
getSnap(snapLine) {
|
|
21075
|
+
if (!snapLine || !this.dnd.draggedFigure)
|
|
21076
|
+
return undefined;
|
|
21077
|
+
const figureVisibleRects = snapLine.matchedFigIds
|
|
21078
|
+
.map((id) => this.getVisibleFigures().find((fig) => fig.id === id))
|
|
21079
|
+
.filter(isDefined$1)
|
|
21080
|
+
.map((fig) => {
|
|
21081
|
+
const figOnSCreen = internalFigureToScreen(this.env.model.getters, fig);
|
|
21082
|
+
const container = this.getFigureContainer(fig);
|
|
21083
|
+
return rectIntersection(figOnSCreen, this.getContainerRect(container));
|
|
21084
|
+
})
|
|
21085
|
+
.filter(isDefined$1);
|
|
21086
|
+
const containerRect = rectUnion(this.dnd.draggedFigure, ...figureVisibleRects);
|
|
21087
|
+
return {
|
|
21088
|
+
line: snapLine,
|
|
21089
|
+
containerStyle: this.rectToCss(containerRect),
|
|
21090
|
+
lineStyle: this.getSnapLineStyle(snapLine, containerRect),
|
|
21091
|
+
};
|
|
20732
21092
|
}
|
|
20733
|
-
|
|
20734
|
-
|
|
20735
|
-
|
|
20736
|
-
|
|
20737
|
-
|
|
20738
|
-
|
|
21093
|
+
getSnapLineStyle(snapLine, containerRect) {
|
|
21094
|
+
if (!snapLine)
|
|
21095
|
+
return "";
|
|
21096
|
+
if (["top", "vCenter", "bottom"].includes(snapLine.snappedAxisType)) {
|
|
21097
|
+
return cssPropertiesToCss({
|
|
21098
|
+
top: `${snapLine.position - containerRect.y}px`,
|
|
21099
|
+
left: `0px`,
|
|
21100
|
+
width: `100%`,
|
|
21101
|
+
});
|
|
21102
|
+
}
|
|
21103
|
+
else {
|
|
21104
|
+
return cssPropertiesToCss({
|
|
21105
|
+
top: `0px`,
|
|
21106
|
+
left: `${snapLine.position - containerRect.x}px`,
|
|
21107
|
+
height: `100%`,
|
|
21108
|
+
});
|
|
21109
|
+
}
|
|
20739
21110
|
}
|
|
20740
21111
|
}
|
|
20741
21112
|
FiguresContainer.template = "o-spreadsheet-FiguresContainer";
|
|
@@ -20882,6 +21253,9 @@ class GridOverlay extends Component {
|
|
|
20882
21253
|
onMounted(() => {
|
|
20883
21254
|
resizeObserver.observe(this.gridOverlayEl);
|
|
20884
21255
|
});
|
|
21256
|
+
onWillUnmount(() => {
|
|
21257
|
+
resizeObserver.disconnect();
|
|
21258
|
+
});
|
|
20885
21259
|
useTouchMove(this.gridOverlay, this.props.onGridMoved, () => {
|
|
20886
21260
|
const { scrollY } = this.env.model.getters.getActiveSheetDOMScrollInfo();
|
|
20887
21261
|
return scrollY > 0;
|
|
@@ -22302,6 +22676,10 @@ class Grid extends Component {
|
|
|
22302
22676
|
}
|
|
22303
22677
|
}
|
|
22304
22678
|
onInput(ev) {
|
|
22679
|
+
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
22680
|
+
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
22681
|
+
return;
|
|
22682
|
+
}
|
|
22305
22683
|
if (ev.data) {
|
|
22306
22684
|
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
22307
22685
|
// character
|
|
@@ -23150,6 +23528,70 @@ function fixXlsxUnicode(str) {
|
|
|
23150
23528
|
});
|
|
23151
23529
|
}
|
|
23152
23530
|
|
|
23531
|
+
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;
|
|
23532
|
+
/**
|
|
23533
|
+
* Convert excel format to o_spreadsheet format
|
|
23534
|
+
*
|
|
23535
|
+
* Excel format are defined in openXML §18.8.31
|
|
23536
|
+
*/
|
|
23537
|
+
function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
23538
|
+
var _a, _b, _c;
|
|
23539
|
+
if (numFmtId === 0) {
|
|
23540
|
+
return undefined;
|
|
23541
|
+
}
|
|
23542
|
+
// Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
|
|
23543
|
+
let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
|
|
23544
|
+
if (format) {
|
|
23545
|
+
try {
|
|
23546
|
+
let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
|
|
23547
|
+
convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
|
|
23548
|
+
convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
|
|
23549
|
+
// Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
|
|
23550
|
+
const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
23551
|
+
const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
|
|
23552
|
+
if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
|
|
23553
|
+
throw new Error("Multiple escaped blocks in format");
|
|
23554
|
+
}
|
|
23555
|
+
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
23556
|
+
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
|
|
23557
|
+
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
|
|
23558
|
+
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
23559
|
+
convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
|
|
23560
|
+
if (isXlsxDateFormat(convertedFormat)) {
|
|
23561
|
+
convertedFormat = convertDateFormat$1(convertedFormat);
|
|
23562
|
+
}
|
|
23563
|
+
if (isFormatSupported(convertedFormat)) {
|
|
23564
|
+
return convertedFormat;
|
|
23565
|
+
}
|
|
23566
|
+
}
|
|
23567
|
+
catch (e) { }
|
|
23568
|
+
}
|
|
23569
|
+
warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
|
|
23570
|
+
return undefined;
|
|
23571
|
+
}
|
|
23572
|
+
function isFormatSupported(format) {
|
|
23573
|
+
try {
|
|
23574
|
+
formatValue(0, format);
|
|
23575
|
+
return true;
|
|
23576
|
+
}
|
|
23577
|
+
catch (e) {
|
|
23578
|
+
return false;
|
|
23579
|
+
}
|
|
23580
|
+
}
|
|
23581
|
+
function isXlsxDateFormat(format) {
|
|
23582
|
+
return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
|
|
23583
|
+
}
|
|
23584
|
+
function convertDateFormat$1(format) {
|
|
23585
|
+
// Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
|
|
23586
|
+
// but can still occur and are supported by Excel/Google sheets
|
|
23587
|
+
format = format.toLowerCase();
|
|
23588
|
+
format = format.replace(/mmmmm/g, "mmm");
|
|
23589
|
+
format = format.replace(/am\/pm|a\/m/g, "a");
|
|
23590
|
+
format = format.replace(/hhhh/g, "hh");
|
|
23591
|
+
format = format.replace(/\bh\b/g, "hh");
|
|
23592
|
+
return format;
|
|
23593
|
+
}
|
|
23594
|
+
|
|
23153
23595
|
function convertBorders(data, warningManager) {
|
|
23154
23596
|
const borderArray = data.borders.map((border) => {
|
|
23155
23597
|
addBorderWarnings(border, warningManager);
|
|
@@ -23212,41 +23654,6 @@ function convertFormats(data, warningManager) {
|
|
|
23212
23654
|
}
|
|
23213
23655
|
return arrayToObject(formats, 1);
|
|
23214
23656
|
}
|
|
23215
|
-
/**
|
|
23216
|
-
* Convert excel format to o_spreadsheet format
|
|
23217
|
-
*
|
|
23218
|
-
* Excel format are defined in openXML §18.8.31
|
|
23219
|
-
*/
|
|
23220
|
-
function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
23221
|
-
var _a, _b, _c;
|
|
23222
|
-
if (numFmtId === 0) {
|
|
23223
|
-
return undefined;
|
|
23224
|
-
}
|
|
23225
|
-
// Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
|
|
23226
|
-
let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
|
|
23227
|
-
if (format) {
|
|
23228
|
-
try {
|
|
23229
|
-
let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
|
|
23230
|
-
convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
|
|
23231
|
-
convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
|
|
23232
|
-
// Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
|
|
23233
|
-
const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
23234
|
-
const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
|
|
23235
|
-
if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
|
|
23236
|
-
throw new Error("Multiple escaped blocks in format");
|
|
23237
|
-
}
|
|
23238
|
-
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
23239
|
-
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
|
|
23240
|
-
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
|
|
23241
|
-
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
23242
|
-
formatValue(0, convertedFormat);
|
|
23243
|
-
return convertedFormat;
|
|
23244
|
-
}
|
|
23245
|
-
catch (e) { }
|
|
23246
|
-
}
|
|
23247
|
-
warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
|
|
23248
|
-
return undefined;
|
|
23249
|
-
}
|
|
23250
23657
|
// ---------------------------------------------------------------------------
|
|
23251
23658
|
// Warnings
|
|
23252
23659
|
// ---------------------------------------------------------------------------
|
|
@@ -23801,16 +24208,18 @@ function convertFigure(figure, id, sheetData) {
|
|
|
23801
24208
|
};
|
|
23802
24209
|
}
|
|
23803
24210
|
function convertChartData(chartData) {
|
|
23804
|
-
|
|
23805
|
-
const labelRange =
|
|
23806
|
-
|
|
24211
|
+
const dataSetsHaveTitle = chartData.dataSets[0].label !== undefined;
|
|
24212
|
+
const labelRange = chartData.labelRange
|
|
24213
|
+
? convertExcelRangeToSheetXC(chartData.labelRange, dataSetsHaveTitle)
|
|
24214
|
+
: undefined;
|
|
24215
|
+
let dataSets = chartData.dataSets.map((data) => convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle));
|
|
23807
24216
|
// For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
|
|
23808
24217
|
if (chartData.type === "pie") {
|
|
23809
24218
|
dataSets.reverse();
|
|
23810
24219
|
}
|
|
23811
24220
|
return {
|
|
23812
24221
|
dataSets,
|
|
23813
|
-
dataSetsHaveTitle
|
|
24222
|
+
dataSetsHaveTitle,
|
|
23814
24223
|
labelRange,
|
|
23815
24224
|
title: chartData.title || "",
|
|
23816
24225
|
type: chartData.type,
|
|
@@ -23821,6 +24230,28 @@ function convertChartData(chartData) {
|
|
|
23821
24230
|
aggregated: false,
|
|
23822
24231
|
labelsAsText: false,
|
|
23823
24232
|
};
|
|
24233
|
+
}
|
|
24234
|
+
function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
|
|
24235
|
+
let { sheetName, xc } = splitReference(range);
|
|
24236
|
+
if (sheetName) {
|
|
24237
|
+
sheetName = getCanonicalSheetName(sheetName) + "!";
|
|
24238
|
+
}
|
|
24239
|
+
else {
|
|
24240
|
+
sheetName = "";
|
|
24241
|
+
}
|
|
24242
|
+
let zone = toUnboundedZone(xc);
|
|
24243
|
+
if (dataSetsHaveTitle && zone.bottom !== undefined && zone.right !== undefined) {
|
|
24244
|
+
const height = zone.bottom - zone.top + 1;
|
|
24245
|
+
const width = zone.right - zone.left + 1;
|
|
24246
|
+
if (height === 1) {
|
|
24247
|
+
zone = { ...zone, left: zone.left - 1 };
|
|
24248
|
+
}
|
|
24249
|
+
else if (width === 1) {
|
|
24250
|
+
zone = { ...zone, top: zone.top - 1 };
|
|
24251
|
+
}
|
|
24252
|
+
}
|
|
24253
|
+
const dataXC = zoneToXc(zone);
|
|
24254
|
+
return sheetName + dataXC;
|
|
23824
24255
|
}
|
|
23825
24256
|
|
|
23826
24257
|
/**
|
|
@@ -24888,6 +25319,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
24888
25319
|
title: chartTitle,
|
|
24889
25320
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
24890
25321
|
dataSets: this.extractChartDatasets(this.querySelector(rootChartElement, `c:${chartType}`)),
|
|
25322
|
+
labelRange: this.extractChildTextContent(rootChartElement, "c:ser c:cat c:f"),
|
|
24891
25323
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
24892
25324
|
default: "ffffff",
|
|
24893
25325
|
}).asString(),
|
|
@@ -24907,7 +25339,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
24907
25339
|
extractChartDatasets(chartElement) {
|
|
24908
25340
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
24909
25341
|
return {
|
|
24910
|
-
label: this.extractChildTextContent(chartDataElement, "c:
|
|
25342
|
+
label: this.extractChildTextContent(chartDataElement, "c:tx c:f"),
|
|
24911
25343
|
range: this.extractChildTextContent(chartDataElement, "c:val c:f", { required: true }),
|
|
24912
25344
|
};
|
|
24913
25345
|
});
|
|
@@ -28824,6 +29256,39 @@ class FigurePlugin extends CorePlugin {
|
|
|
28824
29256
|
case "DELETE_FIGURE":
|
|
28825
29257
|
this.removeFigure(cmd.id, cmd.sheetId);
|
|
28826
29258
|
break;
|
|
29259
|
+
case "REMOVE_COLUMNS_ROWS":
|
|
29260
|
+
this.onRowColDelete(cmd.sheetId, cmd.dimension);
|
|
29261
|
+
}
|
|
29262
|
+
}
|
|
29263
|
+
onRowColDelete(sheetId, dimension) {
|
|
29264
|
+
dimension === "ROW" ? this.onRowDeletion(sheetId) : this.onColDeletion(sheetId);
|
|
29265
|
+
}
|
|
29266
|
+
onRowDeletion(sheetId) {
|
|
29267
|
+
const numHeader = this.getters.getNumberRows(sheetId);
|
|
29268
|
+
let gridHeight = 0;
|
|
29269
|
+
for (let i = 0; i < numHeader; i++) {
|
|
29270
|
+
gridHeight += this.getters.getRowSize(sheetId, i);
|
|
29271
|
+
}
|
|
29272
|
+
const figures = this.getters.getFigures(sheetId);
|
|
29273
|
+
for (const figure of figures) {
|
|
29274
|
+
const newY = Math.min(figure.y, gridHeight - figure.height);
|
|
29275
|
+
if (newY !== figure.y) {
|
|
29276
|
+
this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, y: newY });
|
|
29277
|
+
}
|
|
29278
|
+
}
|
|
29279
|
+
}
|
|
29280
|
+
onColDeletion(sheetId) {
|
|
29281
|
+
const numHeader = this.getters.getNumberCols(sheetId);
|
|
29282
|
+
let gridWidth = 0;
|
|
29283
|
+
for (let i = 0; i < numHeader; i++) {
|
|
29284
|
+
gridWidth += this.getters.getColSize(sheetId, i);
|
|
29285
|
+
}
|
|
29286
|
+
const figures = this.getters.getFigures(sheetId);
|
|
29287
|
+
for (const figure of figures) {
|
|
29288
|
+
const newX = Math.min(figure.x, gridWidth - figure.width);
|
|
29289
|
+
if (newX !== figure.x) {
|
|
29290
|
+
this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x: newX });
|
|
29291
|
+
}
|
|
28827
29292
|
}
|
|
28828
29293
|
}
|
|
28829
29294
|
updateFigure(sheetId, figure) {
|
|
@@ -30238,6 +30703,7 @@ class RangeAdapter {
|
|
|
30238
30703
|
}
|
|
30239
30704
|
else if (range.zone[start] >= min && range.zone[end] <= max) {
|
|
30240
30705
|
changeType = "REMOVE";
|
|
30706
|
+
newRange = range.clone({ ...this.getInvalidRange() });
|
|
30241
30707
|
}
|
|
30242
30708
|
else if (range.zone[start] <= max && range.zone[end] >= max) {
|
|
30243
30709
|
const toRemove = max - range.zone[start] + 1;
|
|
@@ -30303,8 +30769,10 @@ class RangeAdapter {
|
|
|
30303
30769
|
return { changeType: "NONE" };
|
|
30304
30770
|
}
|
|
30305
30771
|
const invalidSheetName = this.getters.getSheetName(cmd.sheetId);
|
|
30306
|
-
|
|
30307
|
-
|
|
30772
|
+
range = range.clone({
|
|
30773
|
+
...this.getInvalidRange(),
|
|
30774
|
+
invalidSheetName,
|
|
30775
|
+
});
|
|
30308
30776
|
return { changeType: "REMOVE", range };
|
|
30309
30777
|
}, cmd.sheetId);
|
|
30310
30778
|
break;
|
|
@@ -30491,7 +30959,7 @@ class RangeAdapter {
|
|
|
30491
30959
|
sheetName = rangeImpl.invalidSheetName;
|
|
30492
30960
|
}
|
|
30493
30961
|
else {
|
|
30494
|
-
sheetName =
|
|
30962
|
+
sheetName = getCanonicalSheetName(this.getters.getSheetName(rangeImpl.sheetId));
|
|
30495
30963
|
}
|
|
30496
30964
|
}
|
|
30497
30965
|
if (prefixSheet && !sheetName) {
|
|
@@ -30564,6 +31032,15 @@ class RangeAdapter {
|
|
|
30564
31032
|
}
|
|
30565
31033
|
return str;
|
|
30566
31034
|
}
|
|
31035
|
+
getInvalidRange() {
|
|
31036
|
+
return {
|
|
31037
|
+
parts: [],
|
|
31038
|
+
prefixSheet: false,
|
|
31039
|
+
zone: { left: -1, top: -1, right: -1, bottom: -1 },
|
|
31040
|
+
sheetId: "",
|
|
31041
|
+
invalidXc: INCORRECT_RANGE_STRING,
|
|
31042
|
+
};
|
|
31043
|
+
}
|
|
30567
31044
|
}
|
|
30568
31045
|
RangeAdapter.getters = [
|
|
30569
31046
|
"getRangeString",
|
|
@@ -31533,9 +32010,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
31533
32010
|
// remove duplicates first to check validity on a reduced
|
|
31534
32011
|
// set of colors, then normalize to HEX and remove duplicates
|
|
31535
32012
|
// again
|
|
31536
|
-
[...new Set([...usedColors, ...this.customColors])]
|
|
31537
|
-
.filter(isColorValid)
|
|
31538
|
-
.map((c) => toHex(c).toLowerCase())),
|
|
32013
|
+
[...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
|
|
31539
32014
|
]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
|
|
31540
32015
|
}
|
|
31541
32016
|
getColorsFromCells(cells) {
|
|
@@ -31596,7 +32071,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
31596
32071
|
return [...chartsColors];
|
|
31597
32072
|
}
|
|
31598
32073
|
tryToAddColor(color) {
|
|
31599
|
-
const formattedColor = toHex(color)
|
|
32074
|
+
const formattedColor = toHex(color);
|
|
31600
32075
|
if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
|
|
31601
32076
|
this.customColors.add(formattedColor);
|
|
31602
32077
|
}
|
|
@@ -32611,8 +33086,8 @@ class InternalViewport {
|
|
|
32611
33086
|
this.getters = getters;
|
|
32612
33087
|
this.sheetId = sheetId;
|
|
32613
33088
|
this.boundaries = boundaries;
|
|
32614
|
-
this.
|
|
32615
|
-
this.
|
|
33089
|
+
this.viewportWidth = sizeInGrid.width;
|
|
33090
|
+
this.viewportHeight = sizeInGrid.height;
|
|
32616
33091
|
this.offsetScrollbarX = offsets.x;
|
|
32617
33092
|
this.offsetScrollbarY = offsets.y;
|
|
32618
33093
|
this.canScrollVertically = options.canScrollVertically;
|
|
@@ -32623,6 +33098,10 @@ class InternalViewport {
|
|
|
32623
33098
|
this.adjustViewportOffsetY();
|
|
32624
33099
|
}
|
|
32625
33100
|
// PUBLIC
|
|
33101
|
+
/** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
|
|
33102
|
+
* When the viewport grid size is smaller than its client width (resp. height), it will return
|
|
33103
|
+
* the client width (resp. height).
|
|
33104
|
+
*/
|
|
32626
33105
|
getMaxSize() {
|
|
32627
33106
|
const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
|
|
32628
33107
|
first: this.boundaries.left,
|
|
@@ -32634,20 +33113,24 @@ class InternalViewport {
|
|
|
32634
33113
|
});
|
|
32635
33114
|
const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
|
|
32636
33115
|
const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
|
|
32637
|
-
const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.
|
|
33116
|
+
const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
|
|
32638
33117
|
const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
|
|
32639
|
-
const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.
|
|
33118
|
+
const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
|
|
32640
33119
|
const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
|
|
32641
|
-
|
|
32642
|
-
|
|
32643
|
-
(
|
|
32644
|
-
|
|
32645
|
-
|
|
32646
|
-
|
|
32647
|
-
|
|
32648
|
-
|
|
32649
|
-
|
|
32650
|
-
|
|
33120
|
+
let width = lastColEnd - this.offsetCorrectionX;
|
|
33121
|
+
if (this.canScrollHorizontally) {
|
|
33122
|
+
width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
|
|
33123
|
+
Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
|
|
33124
|
+
);
|
|
33125
|
+
width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
|
|
33126
|
+
}
|
|
33127
|
+
let height = lastRowEnd - this.offsetCorrectionY;
|
|
33128
|
+
if (this.canScrollVertically) {
|
|
33129
|
+
height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
|
|
33130
|
+
Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
|
|
33131
|
+
);
|
|
33132
|
+
height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
|
|
33133
|
+
}
|
|
32651
33134
|
return { width, height };
|
|
32652
33135
|
}
|
|
32653
33136
|
/**
|
|
@@ -32656,7 +33139,7 @@ class InternalViewport {
|
|
|
32656
33139
|
* It returns -1 if no column is found.
|
|
32657
33140
|
*/
|
|
32658
33141
|
getColIndex(x, absolute = false) {
|
|
32659
|
-
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.
|
|
33142
|
+
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
|
|
32660
33143
|
return -1;
|
|
32661
33144
|
}
|
|
32662
33145
|
return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
|
|
@@ -32667,7 +33150,7 @@ class InternalViewport {
|
|
|
32667
33150
|
* It returns -1 if no row is found.
|
|
32668
33151
|
*/
|
|
32669
33152
|
getRowIndex(y, absolute = false) {
|
|
32670
|
-
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.
|
|
33153
|
+
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
|
|
32671
33154
|
return -1;
|
|
32672
33155
|
}
|
|
32673
33156
|
return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
|
|
@@ -32694,7 +33177,7 @@ class InternalViewport {
|
|
|
32694
33177
|
adjustPositionX(col) {
|
|
32695
33178
|
const sheetId = this.sheetId;
|
|
32696
33179
|
const { start, end } = this.getters.getColDimensions(sheetId, col);
|
|
32697
|
-
while (end > this.offsetX + this.offsetCorrectionX + this.
|
|
33180
|
+
while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
|
|
32698
33181
|
this.offsetX + this.offsetCorrectionX < start) {
|
|
32699
33182
|
this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
|
|
32700
33183
|
this.offsetScrollbarX = this.offsetX;
|
|
@@ -32716,7 +33199,7 @@ class InternalViewport {
|
|
|
32716
33199
|
adjustPositionY(row) {
|
|
32717
33200
|
const sheetId = this.sheetId;
|
|
32718
33201
|
while (this.getters.getRowDimensions(sheetId, row).end >
|
|
32719
|
-
this.offsetY + this.
|
|
33202
|
+
this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
|
|
32720
33203
|
this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
|
|
32721
33204
|
this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
|
|
32722
33205
|
this.offsetScrollbarY = this.offsetY;
|
|
@@ -32754,8 +33237,8 @@ class InternalViewport {
|
|
|
32754
33237
|
const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
|
|
32755
33238
|
this.offsetCorrectionX;
|
|
32756
33239
|
const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
|
|
32757
|
-
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.
|
|
32758
|
-
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.
|
|
33240
|
+
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
|
|
33241
|
+
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
|
|
32759
33242
|
return {
|
|
32760
33243
|
x,
|
|
32761
33244
|
y,
|
|
@@ -32818,12 +33301,12 @@ class InternalViewport {
|
|
|
32818
33301
|
adjustViewportOffsetX() {
|
|
32819
33302
|
if (this.canScrollHorizontally) {
|
|
32820
33303
|
const { width: viewportWidth } = this.getMaxSize();
|
|
32821
|
-
if (this.
|
|
32822
|
-
this.offsetScrollbarX = Math.max(0, viewportWidth - this.
|
|
33304
|
+
if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
|
|
33305
|
+
this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
|
|
32823
33306
|
}
|
|
32824
33307
|
}
|
|
32825
33308
|
this.left = this.getColIndex(this.offsetScrollbarX, true);
|
|
32826
|
-
this.right = this.getColIndex(this.offsetScrollbarX + this.
|
|
33309
|
+
this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
|
|
32827
33310
|
if (this.right === -1) {
|
|
32828
33311
|
this.right = this.boundaries.right;
|
|
32829
33312
|
}
|
|
@@ -32835,12 +33318,12 @@ class InternalViewport {
|
|
|
32835
33318
|
adjustViewportOffsetY() {
|
|
32836
33319
|
if (this.canScrollVertically) {
|
|
32837
33320
|
const { height: paneHeight } = this.getMaxSize();
|
|
32838
|
-
if (this.
|
|
32839
|
-
this.offsetScrollbarY = Math.max(0, paneHeight - this.
|
|
33321
|
+
if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
|
|
33322
|
+
this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
|
|
32840
33323
|
}
|
|
32841
33324
|
}
|
|
32842
33325
|
this.top = this.getRowIndex(this.offsetScrollbarY, true);
|
|
32843
|
-
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.
|
|
33326
|
+
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
|
|
32844
33327
|
if (this.bottom === -1) {
|
|
32845
33328
|
this.bottom = this.boundaries.bottom;
|
|
32846
33329
|
}
|
|
@@ -32851,7 +33334,7 @@ class InternalViewport {
|
|
|
32851
33334
|
adjustViewportZoneX() {
|
|
32852
33335
|
const sheetId = this.sheetId;
|
|
32853
33336
|
this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
|
|
32854
|
-
this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.
|
|
33337
|
+
this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
|
|
32855
33338
|
if (this.right === -1) {
|
|
32856
33339
|
this.right = this.getters.getNumberCols(sheetId) - 1;
|
|
32857
33340
|
}
|
|
@@ -32864,7 +33347,7 @@ class InternalViewport {
|
|
|
32864
33347
|
adjustViewportZoneY() {
|
|
32865
33348
|
const sheetId = this.sheetId;
|
|
32866
33349
|
this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
|
|
32867
|
-
this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.
|
|
33350
|
+
this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
|
|
32868
33351
|
if (this.bottom === -1) {
|
|
32869
33352
|
this.bottom = this.getters.getNumberRows(sheetId) - 1;
|
|
32870
33353
|
}
|
|
@@ -33127,8 +33610,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33127
33610
|
return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
|
|
33128
33611
|
}
|
|
33129
33612
|
/**
|
|
33130
|
-
* Return the main viewport maximum size
|
|
33131
|
-
* with some bottom and right padding.
|
|
33613
|
+
* Return the main viewport maximum size relative to the client size.
|
|
33132
33614
|
*/
|
|
33133
33615
|
getMainViewportRect() {
|
|
33134
33616
|
const sheetId = this.getters.getActiveSheetId();
|
|
@@ -33144,8 +33626,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33144
33626
|
const { width, height } = this.getMainViewportRect();
|
|
33145
33627
|
const viewport = this.getMainInternalViewport(sheetId);
|
|
33146
33628
|
return {
|
|
33147
|
-
maxOffsetX: Math.max(0, width - viewport.
|
|
33148
|
-
maxOffsetY: Math.max(0, height - viewport.
|
|
33629
|
+
maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
|
|
33630
|
+
maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
|
|
33149
33631
|
};
|
|
33150
33632
|
}
|
|
33151
33633
|
getColRowOffsetInViewport(dimension, referenceIndex, index) {
|
|
@@ -33460,6 +33942,20 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33460
33942
|
}
|
|
33461
33943
|
return result;
|
|
33462
33944
|
}
|
|
33945
|
+
isPositionVisible(position) {
|
|
33946
|
+
const { scrollX, scrollY } = this.getters.getActiveSheetScrollInfo();
|
|
33947
|
+
const { x: mainViewportX, y: mainViewportY } = this.getters.getMainViewportCoordinates();
|
|
33948
|
+
const { width, height } = this.getters.getSheetViewDimension();
|
|
33949
|
+
if (position.x >= mainViewportX &&
|
|
33950
|
+
(position.x < mainViewportX + scrollX || position.x > width + scrollX + mainViewportX)) {
|
|
33951
|
+
return false;
|
|
33952
|
+
}
|
|
33953
|
+
if (position.y >= mainViewportY &&
|
|
33954
|
+
(position.y < mainViewportY + scrollY || position.y > height + scrollY + mainViewportY)) {
|
|
33955
|
+
return false;
|
|
33956
|
+
}
|
|
33957
|
+
return true;
|
|
33958
|
+
}
|
|
33463
33959
|
getFrozenSheetViewRatio(sheetId) {
|
|
33464
33960
|
const { xSplit, ySplit } = this.getters.getPaneDivisions(sheetId);
|
|
33465
33961
|
const offsetCorrectionX = this.getters.getColDimensions(sheetId, xSplit).start;
|
|
@@ -33488,6 +33984,7 @@ SheetViewPlugin.getters = [
|
|
|
33488
33984
|
"getSheetViewVisibleCols",
|
|
33489
33985
|
"getSheetViewVisibleRows",
|
|
33490
33986
|
"getFrozenSheetViewRatio",
|
|
33987
|
+
"isPositionVisible",
|
|
33491
33988
|
];
|
|
33492
33989
|
|
|
33493
33990
|
/**
|
|
@@ -35350,7 +35847,7 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
35350
35847
|
const inputSheetId = this.activeSheet;
|
|
35351
35848
|
const sheetId = this.getters.getActiveSheetId();
|
|
35352
35849
|
const sheetName = this.getters.getSheetName(sheetId);
|
|
35353
|
-
this.add([sheetId === inputSheetId ? xc : `${
|
|
35850
|
+
this.add([sheetId === inputSheetId ? xc : `${getCanonicalSheetName(sheetName)}!${xc}`]);
|
|
35354
35851
|
}
|
|
35355
35852
|
handle(cmd) {
|
|
35356
35853
|
switch (cmd.type) {
|
|
@@ -37597,13 +38094,19 @@ class ClipboardFigureState {
|
|
|
37597
38094
|
*/
|
|
37598
38095
|
paste(target) {
|
|
37599
38096
|
const sheetId = this.getters.getActiveSheetId();
|
|
38097
|
+
const { width, height } = this.copiedFigure;
|
|
38098
|
+
const numCols = this.getters.getNumberCols(sheetId);
|
|
38099
|
+
const numRows = this.getters.getNumberRows(sheetId);
|
|
38100
|
+
const targetX = this.getters.getColDimensions(sheetId, target[0].left).start;
|
|
38101
|
+
const targetY = this.getters.getRowDimensions(sheetId, target[0].top).start;
|
|
38102
|
+
const maxX = this.getters.getColDimensions(sheetId, numCols - 1).end;
|
|
38103
|
+
const maxY = this.getters.getRowDimensions(sheetId, numRows - 1).end;
|
|
37600
38104
|
const position = {
|
|
37601
|
-
x:
|
|
37602
|
-
y:
|
|
38105
|
+
x: maxX < width ? 0 : Math.min(targetX, maxX - width),
|
|
38106
|
+
y: maxY < height ? 0 : Math.min(targetY, maxY - height),
|
|
37603
38107
|
};
|
|
37604
|
-
const size = { height: this.copiedFigure.height, width: this.copiedFigure.width };
|
|
37605
38108
|
const newId = new UuidGenerator().uuidv4();
|
|
37606
|
-
this.copiedFigureContent.paste(sheetId, newId, position,
|
|
38109
|
+
this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
|
|
37607
38110
|
if (this.operation === "CUT") {
|
|
37608
38111
|
this.dispatch("DELETE_FIGURE", {
|
|
37609
38112
|
sheetId: this.copiedFigureContent.sheetId,
|
|
@@ -37969,7 +38472,7 @@ function loopThroughReferenceType(token) {
|
|
|
37969
38472
|
return token;
|
|
37970
38473
|
const { xc, sheetName } = splitReference(token.value);
|
|
37971
38474
|
const [left, right] = xc.split(":");
|
|
37972
|
-
const sheetRef = sheetName ? `${
|
|
38475
|
+
const sheetRef = sheetName ? `${getCanonicalSheetName(sheetName)}!` : "";
|
|
37973
38476
|
const updatedLeft = getTokenNextReferenceType(left);
|
|
37974
38477
|
const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
|
|
37975
38478
|
return { ...token, value: sheetRef + updatedLeft + updatedRight };
|
|
@@ -38228,9 +38731,6 @@ class EditionPlugin extends UIPlugin {
|
|
|
38228
38731
|
}
|
|
38229
38732
|
return this.currentContent;
|
|
38230
38733
|
}
|
|
38231
|
-
getEditionSheet() {
|
|
38232
|
-
return this.sheetId;
|
|
38233
|
-
}
|
|
38234
38734
|
getComposerSelection() {
|
|
38235
38735
|
return {
|
|
38236
38736
|
start: this.selectionStart,
|
|
@@ -38514,8 +39014,8 @@ class EditionPlugin extends UIPlugin {
|
|
|
38514
39014
|
getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
|
|
38515
39015
|
const sheetId = this.getters.getActiveSheetId();
|
|
38516
39016
|
let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
|
|
38517
|
-
if (this.getters.
|
|
38518
|
-
const sheetName =
|
|
39017
|
+
if (this.getters.getCurrentEditedCell().sheetId !== this.getters.getActiveSheetId()) {
|
|
39018
|
+
const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
|
|
38519
39019
|
selectedXc = `${sheetName}!${selectedXc}`;
|
|
38520
39020
|
}
|
|
38521
39021
|
return selectedXc;
|
|
@@ -38529,7 +39029,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38529
39029
|
_fixedParts.pop();
|
|
38530
39030
|
}
|
|
38531
39031
|
const newRange = range.clone({ parts: _fixedParts });
|
|
38532
|
-
return this.getters.getSelectionRangeString(newRange, this.getters.
|
|
39032
|
+
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().sheetId);
|
|
38533
39033
|
}
|
|
38534
39034
|
/**
|
|
38535
39035
|
* Replace the current selection by a new text.
|
|
@@ -38562,7 +39062,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38562
39062
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
38563
39063
|
return;
|
|
38564
39064
|
}
|
|
38565
|
-
const editionSheetId = this.getters.
|
|
39065
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38566
39066
|
const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
|
|
38567
39067
|
const colorsToKeep = {};
|
|
38568
39068
|
for (const xc of XCs) {
|
|
@@ -38591,7 +39091,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38591
39091
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
38592
39092
|
return [];
|
|
38593
39093
|
}
|
|
38594
|
-
const editionSheetId = this.getters.
|
|
39094
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38595
39095
|
const rangeColor = (rangeString) => {
|
|
38596
39096
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
38597
39097
|
return colors$1[colorIndex % colors$1.length];
|
|
@@ -38609,7 +39109,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38609
39109
|
* Return ranges currently referenced in the composer
|
|
38610
39110
|
*/
|
|
38611
39111
|
getReferencedRanges() {
|
|
38612
|
-
const editionSheetId = this.getters.
|
|
39112
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38613
39113
|
return this.currentTokens
|
|
38614
39114
|
.filter((token) => token.type === "REFERENCE")
|
|
38615
39115
|
.map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
|
|
@@ -38668,7 +39168,6 @@ EditionPlugin.getters = [
|
|
|
38668
39168
|
"isSelectingForComposer",
|
|
38669
39169
|
"showSelectionIndicator",
|
|
38670
39170
|
"getCurrentContent",
|
|
38671
|
-
"getEditionSheet",
|
|
38672
39171
|
"getComposerSelection",
|
|
38673
39172
|
"getCurrentTokens",
|
|
38674
39173
|
"getTokenAtCursor",
|
|
@@ -39991,10 +40490,6 @@ css /* scss */ `
|
|
|
39991
40490
|
.o-bottom-bar-arrows {
|
|
39992
40491
|
.o-bottom-bar-arrow {
|
|
39993
40492
|
cursor: pointer;
|
|
39994
|
-
&.o-disabled {
|
|
39995
|
-
opacity: 0.4;
|
|
39996
|
-
cursor: default;
|
|
39997
|
-
}
|
|
39998
40493
|
&:hover:not([class*="o-disabled"]) {
|
|
39999
40494
|
.o-icon {
|
|
40000
40495
|
opacity: 0.9;
|
|
@@ -40587,6 +41082,11 @@ css /* scss */ `
|
|
|
40587
41082
|
margin-top: -1px;
|
|
40588
41083
|
border: 1px solid;
|
|
40589
41084
|
z-index: ${ComponentsImportance.TopBarComposer};
|
|
41085
|
+
|
|
41086
|
+
.o-composer:empty:not(:focus)::before {
|
|
41087
|
+
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
41088
|
+
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");
|
|
41089
|
+
}
|
|
40590
41090
|
}
|
|
40591
41091
|
`;
|
|
40592
41092
|
class TopBarComposer extends Component {
|
|
@@ -40827,11 +41327,6 @@ css /* scss */ `
|
|
|
40827
41327
|
margin: 0 6px;
|
|
40828
41328
|
}
|
|
40829
41329
|
|
|
40830
|
-
.o-disabled {
|
|
40831
|
-
opacity: 0.6;
|
|
40832
|
-
cursor: default;
|
|
40833
|
-
}
|
|
40834
|
-
|
|
40835
41330
|
.o-dropdown {
|
|
40836
41331
|
position: relative;
|
|
40837
41332
|
display: flex;
|
|
@@ -40993,6 +41488,7 @@ class TopBar extends Component {
|
|
|
40993
41488
|
this.state.menuState.parentMenu = menu;
|
|
40994
41489
|
this.isSelectingMenu = true;
|
|
40995
41490
|
this.openedEl = ev.target;
|
|
41491
|
+
this.env.model.dispatch("STOP_EDITION");
|
|
40996
41492
|
}
|
|
40997
41493
|
closeMenus() {
|
|
40998
41494
|
this.state.activeTool = "";
|
|
@@ -41205,10 +41701,12 @@ css /* scss */ `
|
|
|
41205
41701
|
button {
|
|
41206
41702
|
color: #333;
|
|
41207
41703
|
}
|
|
41208
|
-
|
|
41209
|
-
|
|
41210
|
-
|
|
41704
|
+
.o-disabled {
|
|
41705
|
+
opacity: 0.4;
|
|
41706
|
+
pointer: default;
|
|
41707
|
+
pointer-events: none;
|
|
41211
41708
|
}
|
|
41709
|
+
|
|
41212
41710
|
&,
|
|
41213
41711
|
*,
|
|
41214
41712
|
*:before,
|
|
@@ -41366,8 +41864,10 @@ class Spreadsheet extends Component {
|
|
|
41366
41864
|
this.sidePanel.isOpen = true;
|
|
41367
41865
|
}
|
|
41368
41866
|
closeSidePanel() {
|
|
41867
|
+
var _a, _b;
|
|
41369
41868
|
this.sidePanel.isOpen = false;
|
|
41370
41869
|
this.focusGrid();
|
|
41870
|
+
(_b = (_a = this.sidePanel.panelProps) === null || _a === void 0 ? void 0 : _a.onCloseSidePanel) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
41371
41871
|
}
|
|
41372
41872
|
toggleSidePanel(panel, panelProps) {
|
|
41373
41873
|
if (this.sidePanel.isOpen && panel === this.sidePanel.component) {
|
|
@@ -43806,7 +44306,7 @@ function figureCoordinates(headers, position) {
|
|
|
43806
44306
|
if (currentPosition <= position && position < currentPosition + header.size) {
|
|
43807
44307
|
return {
|
|
43808
44308
|
index: parseInt(headerIndex),
|
|
43809
|
-
offset: convertDotValueToEMU(position - currentPosition +
|
|
44309
|
+
offset: convertDotValueToEMU(position - currentPosition + FIGURE_BORDER_WIDTH),
|
|
43810
44310
|
};
|
|
43811
44311
|
}
|
|
43812
44312
|
else {
|
|
@@ -43815,7 +44315,7 @@ function figureCoordinates(headers, position) {
|
|
|
43815
44315
|
}
|
|
43816
44316
|
return {
|
|
43817
44317
|
index: headers.length - 1,
|
|
43818
|
-
offset: convertDotValueToEMU(position - currentPosition +
|
|
44318
|
+
offset: convertDotValueToEMU(position - currentPosition + FIGURE_BORDER_WIDTH),
|
|
43819
44319
|
};
|
|
43820
44320
|
}
|
|
43821
44321
|
function createChartDrawing(figure, sheet, chartRelId) {
|
|
@@ -44575,6 +45075,13 @@ class Model extends EventBus {
|
|
|
44575
45075
|
* Internal status of the model. Important for command handling coordination
|
|
44576
45076
|
*/
|
|
44577
45077
|
this.status = 0 /* Status.Ready */;
|
|
45078
|
+
/**
|
|
45079
|
+
* Check if a command can be dispatched, and returns a DispatchResult object with the possible
|
|
45080
|
+
* reasons the dispatch failed.
|
|
45081
|
+
*/
|
|
45082
|
+
this.canDispatch = (type, payload) => {
|
|
45083
|
+
return this.checkDispatchAllowed({ ...payload, type });
|
|
45084
|
+
};
|
|
44578
45085
|
/**
|
|
44579
45086
|
* The dispatch method is the only entry point to manipulate data in the model.
|
|
44580
45087
|
* This is through this method that commands are dispatched most of the time
|
|
@@ -44718,7 +45225,10 @@ class Model extends EventBus {
|
|
|
44718
45225
|
markRaw(this);
|
|
44719
45226
|
}
|
|
44720
45227
|
get handlers() {
|
|
44721
|
-
return [
|
|
45228
|
+
return [...this.coreHandlers, ...this.allUIPlugins, this.history];
|
|
45229
|
+
}
|
|
45230
|
+
get coreHandlers() {
|
|
45231
|
+
return [this.range, ...this.corePlugins];
|
|
44722
45232
|
}
|
|
44723
45233
|
get allUIPlugins() {
|
|
44724
45234
|
return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
|
|
@@ -44846,6 +45356,16 @@ class Model extends EventBus {
|
|
|
44846
45356
|
* Check if the given command is allowed by all the plugins and the history.
|
|
44847
45357
|
*/
|
|
44848
45358
|
checkDispatchAllowed(command) {
|
|
45359
|
+
if (isCoreCommand(command)) {
|
|
45360
|
+
return this.checkDispatchAllowedCoreCommand(command);
|
|
45361
|
+
}
|
|
45362
|
+
return this.checkDispatchAllowedLocalCommand(command);
|
|
45363
|
+
}
|
|
45364
|
+
checkDispatchAllowedCoreCommand(command) {
|
|
45365
|
+
const results = this.coreHandlers.map((handler) => handler.allowDispatch(command));
|
|
45366
|
+
return new DispatchResult(results.flat());
|
|
45367
|
+
}
|
|
45368
|
+
checkDispatchAllowedLocalCommand(command) {
|
|
44849
45369
|
const results = this.handlers.map((handler) => handler.allowDispatch(command));
|
|
44850
45370
|
return new DispatchResult(results.flat());
|
|
44851
45371
|
}
|
|
@@ -45046,6 +45566,6 @@ function addFunction(functionName, functionDescription) {
|
|
|
45046
45566
|
export { AbstractChart, CommandResult, CorePlugin, DATETIME_FORMAT, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, components, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, invalidateEvaluationCommands, links, load, parse, readonlyAllowedCommands, registries, setTranslationMethod, tokenize };
|
|
45047
45567
|
|
|
45048
45568
|
|
|
45049
|
-
__info__.version = '16.3.0-alpha.
|
|
45050
|
-
__info__.date = '2023-
|
|
45051
|
-
__info__.hash = '
|
|
45569
|
+
__info__.version = '16.3.0-alpha.3';
|
|
45570
|
+
__info__.date = '2023-04-13T08:30:41.165Z';
|
|
45571
|
+
__info__.hash = '573e679';
|