@odoo/o-spreadsheet 16.3.0-alpha.2 → 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 +466 -260
- package/dist/o-spreadsheet.d.ts +130 -115
- package/dist/o-spreadsheet.esm.js +466 -260
- package/dist/o-spreadsheet.iife.js +466 -260
- package/dist/o-spreadsheet.iife.min.js +251 -256
- package/package.json +2 -2
|
@@ -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,7 +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
226
|
// Fonts
|
|
228
227
|
const DEFAULT_FONT_WEIGHT = "400";
|
|
229
228
|
const DEFAULT_FONT_SIZE = 10;
|
|
@@ -233,7 +232,7 @@ const DEFAULT_FONT = "'Roboto', arial";
|
|
|
233
232
|
const DEFAULT_BORDER_DESC = ["thin", "#000"];
|
|
234
233
|
const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
|
|
235
234
|
// DateTimeRegex
|
|
236
|
-
const DATETIME_FORMAT = /[
|
|
235
|
+
const DATETIME_FORMAT = /[ymdhs:]/;
|
|
237
236
|
// Ranges
|
|
238
237
|
const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
|
|
239
238
|
// Max Number of history steps kept in memory
|
|
@@ -714,7 +713,7 @@ function getUnquotedSheetName(sheetName) {
|
|
|
714
713
|
* '\w' captures [0-9][a-z][A-Z] and _.
|
|
715
714
|
* @param sheetName Name of the sheet
|
|
716
715
|
*/
|
|
717
|
-
function
|
|
716
|
+
function getCanonicalSheetName(sheetName) {
|
|
718
717
|
var _a;
|
|
719
718
|
if (((_a = sheetName.match(/\w/g)) === null || _a === void 0 ? void 0 : _a.length) !== sheetName.length) {
|
|
720
719
|
sheetName = `'${sheetName}'`;
|
|
@@ -735,8 +734,9 @@ function getDefaultCellHeight(cell) {
|
|
|
735
734
|
return DEFAULT_CELL_HEIGHT;
|
|
736
735
|
}
|
|
737
736
|
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
738
|
-
|
|
739
|
-
|
|
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;
|
|
740
740
|
}
|
|
741
741
|
function computeTextWidth(context, text, style) {
|
|
742
742
|
context.save();
|
|
@@ -1088,6 +1088,8 @@ function replaceSpecialSpaces(text) {
|
|
|
1088
1088
|
return text;
|
|
1089
1089
|
}
|
|
1090
1090
|
|
|
1091
|
+
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
1092
|
+
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
|
|
1091
1093
|
const colors$1 = [
|
|
1092
1094
|
"#eb6d00",
|
|
1093
1095
|
"#0074d9",
|
|
@@ -1113,7 +1115,10 @@ function colorNumberString(color) {
|
|
|
1113
1115
|
}
|
|
1114
1116
|
/**
|
|
1115
1117
|
* Converts any CSS color value to a standardized hex6 value.
|
|
1116
|
-
* 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]
|
|
1117
1122
|
*
|
|
1118
1123
|
* toHex("#ABC")
|
|
1119
1124
|
* >> "#AABBCC"
|
|
@@ -1124,27 +1129,31 @@ function colorNumberString(color) {
|
|
|
1124
1129
|
* toHex("rgb(30, 80, 16)")
|
|
1125
1130
|
* >> "#1E5010"
|
|
1126
1131
|
*
|
|
1132
|
+
* * toHex("rgb(30, 80, 16, 0.5)")
|
|
1133
|
+
* >> "#1E501080"
|
|
1134
|
+
*
|
|
1127
1135
|
*/
|
|
1128
1136
|
function toHex(color) {
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
if (color.includes("rgb")) {
|
|
1133
|
-
return rgbToHex6(color);
|
|
1137
|
+
let hexColor = color;
|
|
1138
|
+
if (color.startsWith("rgb")) {
|
|
1139
|
+
hexColor = rgbaStringToHex(color);
|
|
1134
1140
|
}
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
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}`;
|
|
1138
1147
|
}
|
|
1139
|
-
if (
|
|
1140
|
-
throw new Error(
|
|
1148
|
+
if (!hexColor.match(HEX_MATCH)) {
|
|
1149
|
+
throw new Error(`invalid color input: ${color}`);
|
|
1141
1150
|
}
|
|
1142
|
-
return
|
|
1151
|
+
return hexColor;
|
|
1143
1152
|
}
|
|
1144
1153
|
function isColorValid(color) {
|
|
1145
1154
|
try {
|
|
1146
|
-
|
|
1147
|
-
return
|
|
1155
|
+
toHex(color);
|
|
1156
|
+
return true;
|
|
1148
1157
|
}
|
|
1149
1158
|
catch (error) {
|
|
1150
1159
|
return false;
|
|
@@ -1177,15 +1186,29 @@ function relativeLuminance(color) {
|
|
|
1177
1186
|
/**
|
|
1178
1187
|
* Convert a CSS rgb color string to a standardized hex6 color value.
|
|
1179
1188
|
*
|
|
1180
|
-
*
|
|
1189
|
+
* rgbaStringToHex("rgb(30, 80, 16)")
|
|
1181
1190
|
* >> "#1E5010"
|
|
1191
|
+
*
|
|
1192
|
+
* rgbaStringToHex("rgba(30, 80, 16, 0.5)")
|
|
1193
|
+
* >> "#1E501080"
|
|
1194
|
+
*
|
|
1195
|
+
* DOES NOT SUPPORT NON INTEGER RGB VALUES
|
|
1182
1196
|
*/
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
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();
|
|
1189
1212
|
}
|
|
1190
1213
|
/**
|
|
1191
1214
|
* RGBA to HEX representation (#RRGGBBAA).
|
|
@@ -1207,7 +1230,7 @@ function rgbaToHex(rgba) {
|
|
|
1207
1230
|
a = "0" + a;
|
|
1208
1231
|
if (a === "ff")
|
|
1209
1232
|
a = "";
|
|
1210
|
-
return "#" + r + g + b + a;
|
|
1233
|
+
return ("#" + r + g + b + a).toUpperCase();
|
|
1211
1234
|
}
|
|
1212
1235
|
/**
|
|
1213
1236
|
* Color string to RGBA representation
|
|
@@ -1328,6 +1351,9 @@ function rgbaToHSLA(rgba) {
|
|
|
1328
1351
|
s = +(s * 100).toFixed(1);
|
|
1329
1352
|
l = +(l * 100).toFixed(1);
|
|
1330
1353
|
return { a: rgba.a, h, s, l };
|
|
1354
|
+
}
|
|
1355
|
+
function isSameColor(color1, color2) {
|
|
1356
|
+
return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
|
|
1331
1357
|
}
|
|
1332
1358
|
|
|
1333
1359
|
/** Reference of a cell (eg. A1, $B$5) */
|
|
@@ -1479,7 +1505,7 @@ function scrollDelay(value) {
|
|
|
1479
1505
|
* formula, commas are used to separate arguments
|
|
1480
1506
|
* - it does not support % symbol, in formulas % is an operator
|
|
1481
1507
|
*/
|
|
1482
|
-
const formulaNumberRegexp =
|
|
1508
|
+
const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
|
|
1483
1509
|
const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
|
|
1484
1510
|
const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
|
|
1485
1511
|
const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
|
|
@@ -3088,6 +3114,7 @@ const CHART_PADDING_RATIO = 0.02;
|
|
|
3088
3114
|
const LINE_HEIGHT = 1.2;
|
|
3089
3115
|
css /* scss */ `
|
|
3090
3116
|
div.o-scorecard {
|
|
3117
|
+
font-family: ${DEFAULT_FONT};
|
|
3091
3118
|
user-select: none;
|
|
3092
3119
|
background-color: white;
|
|
3093
3120
|
display: flex;
|
|
@@ -5375,24 +5402,30 @@ class Menu extends Component {
|
|
|
5375
5402
|
}
|
|
5376
5403
|
});
|
|
5377
5404
|
}
|
|
5378
|
-
get
|
|
5379
|
-
|
|
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;
|
|
5380
5423
|
}
|
|
5381
5424
|
get subMenuPosition() {
|
|
5382
5425
|
const position = Object.assign({}, this.subMenu.position);
|
|
5383
5426
|
position.y -= this.subMenu.scrollOffset || 0;
|
|
5384
5427
|
return position;
|
|
5385
5428
|
}
|
|
5386
|
-
get menuHeight() {
|
|
5387
|
-
const menuItems = this.visibleMenuItems;
|
|
5388
|
-
let menuItemsHeight = this.getMenuItemsHeight(menuItems);
|
|
5389
|
-
// We don't display separator at the end of a menu
|
|
5390
|
-
if (menuItems[menuItems.length - 1].separator) {
|
|
5391
|
-
menuItemsHeight -= MENU_SEPARATOR_HEIGHT;
|
|
5392
|
-
}
|
|
5393
|
-
const menuHeight = 2 * MENU_VERTICAL_PADDING + menuItemsHeight;
|
|
5394
|
-
return this.props.maxHeight ? Math.min(menuHeight, this.props.maxHeight) : menuHeight;
|
|
5395
|
-
}
|
|
5396
5429
|
get popoverProps() {
|
|
5397
5430
|
const isRoot = this.props.depth === 1;
|
|
5398
5431
|
return {
|
|
@@ -5406,7 +5439,6 @@ class Menu extends Component {
|
|
|
5406
5439
|
verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
|
|
5407
5440
|
onPopoverHidden: () => this.closeSubMenu(),
|
|
5408
5441
|
onPopoverMoved: () => this.closeSubMenu(),
|
|
5409
|
-
maxHeight: this.menuHeight,
|
|
5410
5442
|
};
|
|
5411
5443
|
}
|
|
5412
5444
|
getColor(menu) {
|
|
@@ -5422,14 +5454,6 @@ class Menu extends Component {
|
|
|
5422
5454
|
this.closeSubMenu();
|
|
5423
5455
|
this.props.onClose();
|
|
5424
5456
|
}
|
|
5425
|
-
/**
|
|
5426
|
-
* Return the number of pixels between the top of the menu
|
|
5427
|
-
* and the menu item at a given index.
|
|
5428
|
-
*/
|
|
5429
|
-
subMenuVerticalPosition(menuIndex) {
|
|
5430
|
-
const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
|
|
5431
|
-
return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
|
|
5432
|
-
}
|
|
5433
5457
|
onExternalClick(ev) {
|
|
5434
5458
|
// Don't close a root menu when clicked to open the submenus.
|
|
5435
5459
|
const el = this.menuRef.el;
|
|
@@ -5439,10 +5463,6 @@ class Menu extends Component {
|
|
|
5439
5463
|
ev.closedMenuId = this.props.menuId;
|
|
5440
5464
|
this.close();
|
|
5441
5465
|
}
|
|
5442
|
-
getMenuItemsHeight(menuItems) {
|
|
5443
|
-
const numberOfSeparators = menuItems.filter((m) => m.separator).length;
|
|
5444
|
-
return MENU_ITEM_HEIGHT * menuItems.length + MENU_SEPARATOR_HEIGHT * numberOfSeparators;
|
|
5445
|
-
}
|
|
5446
5466
|
getName(menu) {
|
|
5447
5467
|
return menu.name(this.env);
|
|
5448
5468
|
}
|
|
@@ -5462,8 +5482,11 @@ class Menu extends Component {
|
|
|
5462
5482
|
* If the given menu is not disabled, open it's submenu at the
|
|
5463
5483
|
* correct position according to available surrounding space.
|
|
5464
5484
|
*/
|
|
5465
|
-
openSubMenu(menu, menuIndex) {
|
|
5466
|
-
const
|
|
5485
|
+
openSubMenu(menu, menuIndex, ev) {
|
|
5486
|
+
const parentMenuEl = ev.currentTarget;
|
|
5487
|
+
if (!parentMenuEl)
|
|
5488
|
+
return;
|
|
5489
|
+
const y = parentMenuEl.getBoundingClientRect().top;
|
|
5467
5490
|
this.subMenu.position = {
|
|
5468
5491
|
x: this.position.x + this.props.depth * MENU_WIDTH,
|
|
5469
5492
|
y: y - (this.subMenu.scrollOffset || 0),
|
|
@@ -5480,20 +5503,20 @@ class Menu extends Component {
|
|
|
5480
5503
|
this.subMenu.isOpen = false;
|
|
5481
5504
|
this.subMenu.parentMenu = undefined;
|
|
5482
5505
|
}
|
|
5483
|
-
onClickMenu(menu, menuIndex) {
|
|
5506
|
+
onClickMenu(menu, menuIndex, ev) {
|
|
5484
5507
|
if (this.isEnabled(menu)) {
|
|
5485
5508
|
if (this.isRoot(menu)) {
|
|
5486
|
-
this.openSubMenu(menu, menuIndex);
|
|
5509
|
+
this.openSubMenu(menu, menuIndex, ev);
|
|
5487
5510
|
}
|
|
5488
5511
|
else {
|
|
5489
5512
|
this.activateMenu(menu);
|
|
5490
5513
|
}
|
|
5491
5514
|
}
|
|
5492
5515
|
}
|
|
5493
|
-
onMouseOver(menu, position) {
|
|
5516
|
+
onMouseOver(menu, position, ev) {
|
|
5494
5517
|
if (menu.isEnabled(this.env)) {
|
|
5495
5518
|
if (this.isRoot(menu)) {
|
|
5496
|
-
this.openSubMenu(menu, position);
|
|
5519
|
+
this.openSubMenu(menu, position, ev);
|
|
5497
5520
|
}
|
|
5498
5521
|
else {
|
|
5499
5522
|
this.closeSubMenu();
|
|
@@ -6070,8 +6093,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6070
6093
|
const dataSets = [];
|
|
6071
6094
|
for (const sheetXC of dataSetsString) {
|
|
6072
6095
|
const dataRange = getters.getRangeFromSheetXC(sheetId, sheetXC);
|
|
6073
|
-
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName } = dataRange;
|
|
6074
|
-
if (invalidSheetName) {
|
|
6096
|
+
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName, invalidXc } = dataRange;
|
|
6097
|
+
if (invalidSheetName || invalidXc) {
|
|
6075
6098
|
continue;
|
|
6076
6099
|
}
|
|
6077
6100
|
// It's a rectangle. We treat all columns (arbitrary) as different data series.
|
|
@@ -6096,14 +6119,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6096
6119
|
: undefined));
|
|
6097
6120
|
}
|
|
6098
6121
|
}
|
|
6099
|
-
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
6100
|
-
// A single cell. If it's only the title, the dataset is not added.
|
|
6101
|
-
if (!dataSetsHaveTitle) {
|
|
6102
|
-
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
6103
|
-
}
|
|
6104
|
-
}
|
|
6105
6122
|
else {
|
|
6106
|
-
/* 1 row or 1 column */
|
|
6123
|
+
/* 1 cell, 1 row or 1 column */
|
|
6107
6124
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
6108
6125
|
? {
|
|
6109
6126
|
top: zone.top,
|
|
@@ -6157,6 +6174,18 @@ function toExcelDataset(getters, ds) {
|
|
|
6157
6174
|
range: getters.getRangeString(dataRange, "forceSheetReference"),
|
|
6158
6175
|
};
|
|
6159
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
|
+
}
|
|
6160
6189
|
/**
|
|
6161
6190
|
* Transform a chart definition which supports dataSets (dataSets and LabelRange)
|
|
6162
6191
|
* with an executed command
|
|
@@ -6241,6 +6270,20 @@ function checkLabelRange(definition) {
|
|
|
6241
6270
|
}
|
|
6242
6271
|
return 0 /* CommandResult.Success */;
|
|
6243
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
|
+
}
|
|
6244
6287
|
// ---------------------------------------------------------------------------
|
|
6245
6288
|
// Scorecard
|
|
6246
6289
|
// ---------------------------------------------------------------------------
|
|
@@ -6610,6 +6653,7 @@ class BarChart extends AbstractChart {
|
|
|
6610
6653
|
this.legendPosition = definition.legendPosition;
|
|
6611
6654
|
this.stacked = definition.stacked;
|
|
6612
6655
|
this.aggregated = definition.aggregated;
|
|
6656
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
6613
6657
|
}
|
|
6614
6658
|
static transformDefinition(definition, executed) {
|
|
6615
6659
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -6677,11 +6721,13 @@ class BarChart extends AbstractChart {
|
|
|
6677
6721
|
const dataSets = this.dataSets
|
|
6678
6722
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
6679
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));
|
|
6680
6725
|
return {
|
|
6681
6726
|
...this.getDefinition(),
|
|
6682
6727
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
6683
6728
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
6684
6729
|
dataSets,
|
|
6730
|
+
labelRange,
|
|
6685
6731
|
};
|
|
6686
6732
|
}
|
|
6687
6733
|
updateRanges(applyChange) {
|
|
@@ -6749,6 +6795,11 @@ function createBarChartRuntime(chart, getters) {
|
|
|
6749
6795
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
6750
6796
|
let labels = labelValues.formattedValues;
|
|
6751
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
|
+
}
|
|
6752
6803
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
6753
6804
|
if (chart.aggregated) {
|
|
6754
6805
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
@@ -7171,6 +7222,7 @@ class LineChart extends AbstractChart {
|
|
|
7171
7222
|
this.labelsAsText = definition.labelsAsText;
|
|
7172
7223
|
this.stacked = definition.stacked;
|
|
7173
7224
|
this.aggregated = definition.aggregated;
|
|
7225
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
7174
7226
|
}
|
|
7175
7227
|
static validateChartDefinition(validator, definition) {
|
|
7176
7228
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -7238,11 +7290,13 @@ class LineChart extends AbstractChart {
|
|
|
7238
7290
|
const dataSets = this.dataSets
|
|
7239
7291
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
7240
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));
|
|
7241
7294
|
return {
|
|
7242
7295
|
...this.getDefinition(),
|
|
7243
7296
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
7244
7297
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
7245
7298
|
dataSets,
|
|
7299
|
+
labelRange,
|
|
7246
7300
|
};
|
|
7247
7301
|
}
|
|
7248
7302
|
copyForSheetId(sheetId) {
|
|
@@ -7380,6 +7434,11 @@ function createLineChartRuntime(chart, getters) {
|
|
|
7380
7434
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
7381
7435
|
let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
|
|
7382
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
|
+
}
|
|
7383
7442
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
7384
7443
|
if (axisType === "time") {
|
|
7385
7444
|
({ labels, dataSetsValues } = fixEmptyLabelsForDateCharts(labels, dataSetsValues));
|
|
@@ -7438,6 +7497,7 @@ class PieChart extends AbstractChart {
|
|
|
7438
7497
|
this.background = definition.background;
|
|
7439
7498
|
this.legendPosition = definition.legendPosition;
|
|
7440
7499
|
this.aggregated = definition.aggregated;
|
|
7500
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
7441
7501
|
}
|
|
7442
7502
|
static transformDefinition(definition, executed) {
|
|
7443
7503
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -7501,12 +7561,14 @@ class PieChart extends AbstractChart {
|
|
|
7501
7561
|
const dataSets = this.dataSets
|
|
7502
7562
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
7503
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));
|
|
7504
7565
|
return {
|
|
7505
7566
|
...this.getDefinition(),
|
|
7506
7567
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
7507
7568
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
7508
7569
|
verticalAxisPosition: "left",
|
|
7509
7570
|
dataSets,
|
|
7571
|
+
labelRange,
|
|
7510
7572
|
};
|
|
7511
7573
|
}
|
|
7512
7574
|
updateRanges(applyChange) {
|
|
@@ -7552,6 +7614,11 @@ function createPieChartRuntime(chart, getters) {
|
|
|
7552
7614
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
7553
7615
|
let labels = labelValues.formattedValues;
|
|
7554
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
|
+
}
|
|
7555
7622
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
7556
7623
|
if (chart.aggregated) {
|
|
7557
7624
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
@@ -8187,7 +8254,6 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
8187
8254
|
labelRangeXc = zoneToXc({
|
|
8188
8255
|
...zone,
|
|
8189
8256
|
right: zone.left,
|
|
8190
|
-
top: dataSetsHaveTitle ? zone.top + 1 : zone.top,
|
|
8191
8257
|
});
|
|
8192
8258
|
}
|
|
8193
8259
|
// Only display legend for several datasets.
|
|
@@ -15105,7 +15171,7 @@ const ADDRESS = {
|
|
|
15105
15171
|
cellReference = rowPart + colPart;
|
|
15106
15172
|
}
|
|
15107
15173
|
if (sheet !== undefined) {
|
|
15108
|
-
return `${
|
|
15174
|
+
return `${getCanonicalSheetName(toString(sheet))}!${cellReference}`;
|
|
15109
15175
|
}
|
|
15110
15176
|
return cellReference;
|
|
15111
15177
|
},
|
|
@@ -16930,6 +16996,22 @@ class LineBarPieConfigPanel extends Component {
|
|
|
16930
16996
|
aggregated: ev.target.checked,
|
|
16931
16997
|
});
|
|
16932
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
|
+
}
|
|
16933
17015
|
}
|
|
16934
17016
|
LineBarPieConfigPanel.template = "o-spreadsheet-LineBarPieConfigPanel";
|
|
16935
17017
|
LineBarPieConfigPanel.components = { SelectionInput };
|
|
@@ -17177,6 +17259,9 @@ class ColorPicker extends Component {
|
|
|
17177
17259
|
top,
|
|
17178
17260
|
});
|
|
17179
17261
|
}
|
|
17262
|
+
isSameColor(color1, color2) {
|
|
17263
|
+
return isSameColor(color1, color2);
|
|
17264
|
+
}
|
|
17180
17265
|
}
|
|
17181
17266
|
ColorPicker.template = "o-spreadsheet-ColorPicker";
|
|
17182
17267
|
ColorPicker.defaultProps = {
|
|
@@ -19418,6 +19503,8 @@ class ContentEditableHelper {
|
|
|
19418
19503
|
start = 0;
|
|
19419
19504
|
if (end > textLength)
|
|
19420
19505
|
end = textLength;
|
|
19506
|
+
if (start > textLength)
|
|
19507
|
+
start = textLength;
|
|
19421
19508
|
}
|
|
19422
19509
|
let startNode = this.findChildAtCharacterIndex(start);
|
|
19423
19510
|
let endNode = this.findChildAtCharacterIndex(end);
|
|
@@ -19687,6 +19774,7 @@ css /* scss */ `
|
|
|
19687
19774
|
padding-right: 2px;
|
|
19688
19775
|
|
|
19689
19776
|
box-sizing: border-box;
|
|
19777
|
+
font-family: ${DEFAULT_FONT};
|
|
19690
19778
|
|
|
19691
19779
|
caret-color: black;
|
|
19692
19780
|
padding-left: 3px;
|
|
@@ -20129,7 +20217,7 @@ class Composer extends Component {
|
|
|
20129
20217
|
const highlights = this.env.model.getters.getHighlights();
|
|
20130
20218
|
const refSheet = sheetName
|
|
20131
20219
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
20132
|
-
: this.env.model.getters.
|
|
20220
|
+
: this.env.model.getters.getCurrentEditedCell().sheetId;
|
|
20133
20221
|
const highlight = highlights.find((highlight) => {
|
|
20134
20222
|
if (highlight.sheetId !== refSheet)
|
|
20135
20223
|
return false;
|
|
@@ -20290,7 +20378,7 @@ class GridComposer extends Component {
|
|
|
20290
20378
|
get cellReference() {
|
|
20291
20379
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
20292
20380
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
20293
|
-
return `${prefixSheet ?
|
|
20381
|
+
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
20294
20382
|
}
|
|
20295
20383
|
get cellReferenceStyle() {
|
|
20296
20384
|
const { x: left, y: top } = this.rect;
|
|
@@ -20475,15 +20563,18 @@ function screenCoordinatesToInternal(getters, { x, y }) {
|
|
|
20475
20563
|
return { x, y };
|
|
20476
20564
|
}
|
|
20477
20565
|
|
|
20478
|
-
function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { scrollX, scrollY }) {
|
|
20566
|
+
function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { maxX, maxY }, { scrollX, scrollY }) {
|
|
20479
20567
|
const minX = viewportX ? 0 : -scrollX;
|
|
20480
20568
|
const minY = viewportY ? 0 : -scrollY;
|
|
20481
|
-
|
|
20482
|
-
const newX =
|
|
20483
|
-
|
|
20484
|
-
const newY =
|
|
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);
|
|
20485
20573
|
return { ...initialFigure, x: newX, y: newY };
|
|
20486
20574
|
}
|
|
20575
|
+
function clamp(value, min, max) {
|
|
20576
|
+
return Math.min(Math.max(value, min), max);
|
|
20577
|
+
}
|
|
20487
20578
|
function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, keepRatio, minFigSize) {
|
|
20488
20579
|
let { x, y, width, height } = initialFigure;
|
|
20489
20580
|
if (keepRatio && dirX != 0 && dirY != 0) {
|
|
@@ -20882,12 +20973,16 @@ class FiguresContainer extends Component {
|
|
|
20882
20973
|
}
|
|
20883
20974
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
20884
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
|
+
};
|
|
20885
20980
|
const { x, y } = internalFigureToScreen(this.env.model.getters, figure);
|
|
20886
20981
|
const initialFig = { ...figure, x, y };
|
|
20887
20982
|
const onMouseMove = (ev) => {
|
|
20888
20983
|
const getters = this.env.model.getters;
|
|
20889
20984
|
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
20890
|
-
const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), getters.getActiveSheetScrollInfo());
|
|
20985
|
+
const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), maxDimensions, getters.getActiveSheetScrollInfo());
|
|
20891
20986
|
const otherFigures = this.getOtherFigures(figure.id);
|
|
20892
20987
|
const internalDragged = screenFigureToInternal(getters, draggedFigure);
|
|
20893
20988
|
const snapResult = snapForMove(getters, internalDragged, otherFigures);
|
|
@@ -22581,6 +22676,10 @@ class Grid extends Component {
|
|
|
22581
22676
|
}
|
|
22582
22677
|
}
|
|
22583
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
|
+
}
|
|
22584
22683
|
if (ev.data) {
|
|
22585
22684
|
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
22586
22685
|
// character
|
|
@@ -23429,6 +23528,70 @@ function fixXlsxUnicode(str) {
|
|
|
23429
23528
|
});
|
|
23430
23529
|
}
|
|
23431
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
|
+
|
|
23432
23595
|
function convertBorders(data, warningManager) {
|
|
23433
23596
|
const borderArray = data.borders.map((border) => {
|
|
23434
23597
|
addBorderWarnings(border, warningManager);
|
|
@@ -23491,41 +23654,6 @@ function convertFormats(data, warningManager) {
|
|
|
23491
23654
|
}
|
|
23492
23655
|
return arrayToObject(formats, 1);
|
|
23493
23656
|
}
|
|
23494
|
-
/**
|
|
23495
|
-
* Convert excel format to o_spreadsheet format
|
|
23496
|
-
*
|
|
23497
|
-
* Excel format are defined in openXML §18.8.31
|
|
23498
|
-
*/
|
|
23499
|
-
function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
23500
|
-
var _a, _b, _c;
|
|
23501
|
-
if (numFmtId === 0) {
|
|
23502
|
-
return undefined;
|
|
23503
|
-
}
|
|
23504
|
-
// Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
|
|
23505
|
-
let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
|
|
23506
|
-
if (format) {
|
|
23507
|
-
try {
|
|
23508
|
-
let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
|
|
23509
|
-
convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
|
|
23510
|
-
convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
|
|
23511
|
-
// Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
|
|
23512
|
-
const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
23513
|
-
const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
|
|
23514
|
-
if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
|
|
23515
|
-
throw new Error("Multiple escaped blocks in format");
|
|
23516
|
-
}
|
|
23517
|
-
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
23518
|
-
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
|
|
23519
|
-
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
|
|
23520
|
-
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
23521
|
-
formatValue(0, convertedFormat);
|
|
23522
|
-
return convertedFormat;
|
|
23523
|
-
}
|
|
23524
|
-
catch (e) { }
|
|
23525
|
-
}
|
|
23526
|
-
warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
|
|
23527
|
-
return undefined;
|
|
23528
|
-
}
|
|
23529
23657
|
// ---------------------------------------------------------------------------
|
|
23530
23658
|
// Warnings
|
|
23531
23659
|
// ---------------------------------------------------------------------------
|
|
@@ -24080,16 +24208,18 @@ function convertFigure(figure, id, sheetData) {
|
|
|
24080
24208
|
};
|
|
24081
24209
|
}
|
|
24082
24210
|
function convertChartData(chartData) {
|
|
24083
|
-
|
|
24084
|
-
const labelRange =
|
|
24085
|
-
|
|
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));
|
|
24086
24216
|
// For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
|
|
24087
24217
|
if (chartData.type === "pie") {
|
|
24088
24218
|
dataSets.reverse();
|
|
24089
24219
|
}
|
|
24090
24220
|
return {
|
|
24091
24221
|
dataSets,
|
|
24092
|
-
dataSetsHaveTitle
|
|
24222
|
+
dataSetsHaveTitle,
|
|
24093
24223
|
labelRange,
|
|
24094
24224
|
title: chartData.title || "",
|
|
24095
24225
|
type: chartData.type,
|
|
@@ -24100,6 +24230,28 @@ function convertChartData(chartData) {
|
|
|
24100
24230
|
aggregated: false,
|
|
24101
24231
|
labelsAsText: false,
|
|
24102
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;
|
|
24103
24255
|
}
|
|
24104
24256
|
|
|
24105
24257
|
/**
|
|
@@ -25167,6 +25319,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
25167
25319
|
title: chartTitle,
|
|
25168
25320
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
25169
25321
|
dataSets: this.extractChartDatasets(this.querySelector(rootChartElement, `c:${chartType}`)),
|
|
25322
|
+
labelRange: this.extractChildTextContent(rootChartElement, "c:ser c:cat c:f"),
|
|
25170
25323
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
25171
25324
|
default: "ffffff",
|
|
25172
25325
|
}).asString(),
|
|
@@ -25186,7 +25339,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
25186
25339
|
extractChartDatasets(chartElement) {
|
|
25187
25340
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
25188
25341
|
return {
|
|
25189
|
-
label: this.extractChildTextContent(chartDataElement, "c:
|
|
25342
|
+
label: this.extractChildTextContent(chartDataElement, "c:tx c:f"),
|
|
25190
25343
|
range: this.extractChildTextContent(chartDataElement, "c:val c:f", { required: true }),
|
|
25191
25344
|
};
|
|
25192
25345
|
});
|
|
@@ -29103,6 +29256,39 @@ class FigurePlugin extends CorePlugin {
|
|
|
29103
29256
|
case "DELETE_FIGURE":
|
|
29104
29257
|
this.removeFigure(cmd.id, cmd.sheetId);
|
|
29105
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
|
+
}
|
|
29106
29292
|
}
|
|
29107
29293
|
}
|
|
29108
29294
|
updateFigure(sheetId, figure) {
|
|
@@ -30773,7 +30959,7 @@ class RangeAdapter {
|
|
|
30773
30959
|
sheetName = rangeImpl.invalidSheetName;
|
|
30774
30960
|
}
|
|
30775
30961
|
else {
|
|
30776
|
-
sheetName =
|
|
30962
|
+
sheetName = getCanonicalSheetName(this.getters.getSheetName(rangeImpl.sheetId));
|
|
30777
30963
|
}
|
|
30778
30964
|
}
|
|
30779
30965
|
if (prefixSheet && !sheetName) {
|
|
@@ -31824,9 +32010,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
31824
32010
|
// remove duplicates first to check validity on a reduced
|
|
31825
32011
|
// set of colors, then normalize to HEX and remove duplicates
|
|
31826
32012
|
// again
|
|
31827
|
-
[...new Set([...usedColors, ...this.customColors])]
|
|
31828
|
-
.filter(isColorValid)
|
|
31829
|
-
.map((c) => toHex(c).toLowerCase())),
|
|
32013
|
+
[...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
|
|
31830
32014
|
]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
|
|
31831
32015
|
}
|
|
31832
32016
|
getColorsFromCells(cells) {
|
|
@@ -31887,7 +32071,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
31887
32071
|
return [...chartsColors];
|
|
31888
32072
|
}
|
|
31889
32073
|
tryToAddColor(color) {
|
|
31890
|
-
const formattedColor = toHex(color)
|
|
32074
|
+
const formattedColor = toHex(color);
|
|
31891
32075
|
if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
|
|
31892
32076
|
this.customColors.add(formattedColor);
|
|
31893
32077
|
}
|
|
@@ -32902,8 +33086,8 @@ class InternalViewport {
|
|
|
32902
33086
|
this.getters = getters;
|
|
32903
33087
|
this.sheetId = sheetId;
|
|
32904
33088
|
this.boundaries = boundaries;
|
|
32905
|
-
this.
|
|
32906
|
-
this.
|
|
33089
|
+
this.viewportWidth = sizeInGrid.width;
|
|
33090
|
+
this.viewportHeight = sizeInGrid.height;
|
|
32907
33091
|
this.offsetScrollbarX = offsets.x;
|
|
32908
33092
|
this.offsetScrollbarY = offsets.y;
|
|
32909
33093
|
this.canScrollVertically = options.canScrollVertically;
|
|
@@ -32914,6 +33098,10 @@ class InternalViewport {
|
|
|
32914
33098
|
this.adjustViewportOffsetY();
|
|
32915
33099
|
}
|
|
32916
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
|
+
*/
|
|
32917
33105
|
getMaxSize() {
|
|
32918
33106
|
const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
|
|
32919
33107
|
first: this.boundaries.left,
|
|
@@ -32925,20 +33113,24 @@ class InternalViewport {
|
|
|
32925
33113
|
});
|
|
32926
33114
|
const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
|
|
32927
33115
|
const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
|
|
32928
|
-
const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.
|
|
33116
|
+
const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
|
|
32929
33117
|
const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
|
|
32930
|
-
const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.
|
|
33118
|
+
const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
|
|
32931
33119
|
const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
|
|
32932
|
-
|
|
32933
|
-
|
|
32934
|
-
(
|
|
32935
|
-
|
|
32936
|
-
|
|
32937
|
-
|
|
32938
|
-
|
|
32939
|
-
|
|
32940
|
-
|
|
32941
|
-
|
|
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
|
+
}
|
|
32942
33134
|
return { width, height };
|
|
32943
33135
|
}
|
|
32944
33136
|
/**
|
|
@@ -32947,7 +33139,7 @@ class InternalViewport {
|
|
|
32947
33139
|
* It returns -1 if no column is found.
|
|
32948
33140
|
*/
|
|
32949
33141
|
getColIndex(x, absolute = false) {
|
|
32950
|
-
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.
|
|
33142
|
+
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
|
|
32951
33143
|
return -1;
|
|
32952
33144
|
}
|
|
32953
33145
|
return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
|
|
@@ -32958,7 +33150,7 @@ class InternalViewport {
|
|
|
32958
33150
|
* It returns -1 if no row is found.
|
|
32959
33151
|
*/
|
|
32960
33152
|
getRowIndex(y, absolute = false) {
|
|
32961
|
-
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.
|
|
33153
|
+
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
|
|
32962
33154
|
return -1;
|
|
32963
33155
|
}
|
|
32964
33156
|
return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
|
|
@@ -32985,7 +33177,7 @@ class InternalViewport {
|
|
|
32985
33177
|
adjustPositionX(col) {
|
|
32986
33178
|
const sheetId = this.sheetId;
|
|
32987
33179
|
const { start, end } = this.getters.getColDimensions(sheetId, col);
|
|
32988
|
-
while (end > this.offsetX + this.offsetCorrectionX + this.
|
|
33180
|
+
while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
|
|
32989
33181
|
this.offsetX + this.offsetCorrectionX < start) {
|
|
32990
33182
|
this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
|
|
32991
33183
|
this.offsetScrollbarX = this.offsetX;
|
|
@@ -33007,7 +33199,7 @@ class InternalViewport {
|
|
|
33007
33199
|
adjustPositionY(row) {
|
|
33008
33200
|
const sheetId = this.sheetId;
|
|
33009
33201
|
while (this.getters.getRowDimensions(sheetId, row).end >
|
|
33010
|
-
this.offsetY + this.
|
|
33202
|
+
this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
|
|
33011
33203
|
this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
|
|
33012
33204
|
this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
|
|
33013
33205
|
this.offsetScrollbarY = this.offsetY;
|
|
@@ -33045,8 +33237,8 @@ class InternalViewport {
|
|
|
33045
33237
|
const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
|
|
33046
33238
|
this.offsetCorrectionX;
|
|
33047
33239
|
const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
|
|
33048
|
-
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.
|
|
33049
|
-
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);
|
|
33050
33242
|
return {
|
|
33051
33243
|
x,
|
|
33052
33244
|
y,
|
|
@@ -33109,12 +33301,12 @@ class InternalViewport {
|
|
|
33109
33301
|
adjustViewportOffsetX() {
|
|
33110
33302
|
if (this.canScrollHorizontally) {
|
|
33111
33303
|
const { width: viewportWidth } = this.getMaxSize();
|
|
33112
|
-
if (this.
|
|
33113
|
-
this.offsetScrollbarX = Math.max(0, viewportWidth - this.
|
|
33304
|
+
if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
|
|
33305
|
+
this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
|
|
33114
33306
|
}
|
|
33115
33307
|
}
|
|
33116
33308
|
this.left = this.getColIndex(this.offsetScrollbarX, true);
|
|
33117
|
-
this.right = this.getColIndex(this.offsetScrollbarX + this.
|
|
33309
|
+
this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
|
|
33118
33310
|
if (this.right === -1) {
|
|
33119
33311
|
this.right = this.boundaries.right;
|
|
33120
33312
|
}
|
|
@@ -33126,12 +33318,12 @@ class InternalViewport {
|
|
|
33126
33318
|
adjustViewportOffsetY() {
|
|
33127
33319
|
if (this.canScrollVertically) {
|
|
33128
33320
|
const { height: paneHeight } = this.getMaxSize();
|
|
33129
|
-
if (this.
|
|
33130
|
-
this.offsetScrollbarY = Math.max(0, paneHeight - this.
|
|
33321
|
+
if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
|
|
33322
|
+
this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
|
|
33131
33323
|
}
|
|
33132
33324
|
}
|
|
33133
33325
|
this.top = this.getRowIndex(this.offsetScrollbarY, true);
|
|
33134
|
-
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.
|
|
33326
|
+
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
|
|
33135
33327
|
if (this.bottom === -1) {
|
|
33136
33328
|
this.bottom = this.boundaries.bottom;
|
|
33137
33329
|
}
|
|
@@ -33142,7 +33334,7 @@ class InternalViewport {
|
|
|
33142
33334
|
adjustViewportZoneX() {
|
|
33143
33335
|
const sheetId = this.sheetId;
|
|
33144
33336
|
this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
|
|
33145
|
-
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));
|
|
33146
33338
|
if (this.right === -1) {
|
|
33147
33339
|
this.right = this.getters.getNumberCols(sheetId) - 1;
|
|
33148
33340
|
}
|
|
@@ -33155,7 +33347,7 @@ class InternalViewport {
|
|
|
33155
33347
|
adjustViewportZoneY() {
|
|
33156
33348
|
const sheetId = this.sheetId;
|
|
33157
33349
|
this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
|
|
33158
|
-
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));
|
|
33159
33351
|
if (this.bottom === -1) {
|
|
33160
33352
|
this.bottom = this.getters.getNumberRows(sheetId) - 1;
|
|
33161
33353
|
}
|
|
@@ -33418,8 +33610,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33418
33610
|
return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
|
|
33419
33611
|
}
|
|
33420
33612
|
/**
|
|
33421
|
-
* Return the main viewport maximum size
|
|
33422
|
-
* with some bottom and right padding.
|
|
33613
|
+
* Return the main viewport maximum size relative to the client size.
|
|
33423
33614
|
*/
|
|
33424
33615
|
getMainViewportRect() {
|
|
33425
33616
|
const sheetId = this.getters.getActiveSheetId();
|
|
@@ -33435,8 +33626,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33435
33626
|
const { width, height } = this.getMainViewportRect();
|
|
33436
33627
|
const viewport = this.getMainInternalViewport(sheetId);
|
|
33437
33628
|
return {
|
|
33438
|
-
maxOffsetX: Math.max(0, width - viewport.
|
|
33439
|
-
maxOffsetY: Math.max(0, height - viewport.
|
|
33629
|
+
maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
|
|
33630
|
+
maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
|
|
33440
33631
|
};
|
|
33441
33632
|
}
|
|
33442
33633
|
getColRowOffsetInViewport(dimension, referenceIndex, index) {
|
|
@@ -35656,7 +35847,7 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
35656
35847
|
const inputSheetId = this.activeSheet;
|
|
35657
35848
|
const sheetId = this.getters.getActiveSheetId();
|
|
35658
35849
|
const sheetName = this.getters.getSheetName(sheetId);
|
|
35659
|
-
this.add([sheetId === inputSheetId ? xc : `${
|
|
35850
|
+
this.add([sheetId === inputSheetId ? xc : `${getCanonicalSheetName(sheetName)}!${xc}`]);
|
|
35660
35851
|
}
|
|
35661
35852
|
handle(cmd) {
|
|
35662
35853
|
switch (cmd.type) {
|
|
@@ -37903,13 +38094,19 @@ class ClipboardFigureState {
|
|
|
37903
38094
|
*/
|
|
37904
38095
|
paste(target) {
|
|
37905
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;
|
|
37906
38104
|
const position = {
|
|
37907
|
-
x:
|
|
37908
|
-
y:
|
|
38105
|
+
x: maxX < width ? 0 : Math.min(targetX, maxX - width),
|
|
38106
|
+
y: maxY < height ? 0 : Math.min(targetY, maxY - height),
|
|
37909
38107
|
};
|
|
37910
|
-
const size = { height: this.copiedFigure.height, width: this.copiedFigure.width };
|
|
37911
38108
|
const newId = new UuidGenerator().uuidv4();
|
|
37912
|
-
this.copiedFigureContent.paste(sheetId, newId, position,
|
|
38109
|
+
this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
|
|
37913
38110
|
if (this.operation === "CUT") {
|
|
37914
38111
|
this.dispatch("DELETE_FIGURE", {
|
|
37915
38112
|
sheetId: this.copiedFigureContent.sheetId,
|
|
@@ -38275,7 +38472,7 @@ function loopThroughReferenceType(token) {
|
|
|
38275
38472
|
return token;
|
|
38276
38473
|
const { xc, sheetName } = splitReference(token.value);
|
|
38277
38474
|
const [left, right] = xc.split(":");
|
|
38278
|
-
const sheetRef = sheetName ? `${
|
|
38475
|
+
const sheetRef = sheetName ? `${getCanonicalSheetName(sheetName)}!` : "";
|
|
38279
38476
|
const updatedLeft = getTokenNextReferenceType(left);
|
|
38280
38477
|
const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
|
|
38281
38478
|
return { ...token, value: sheetRef + updatedLeft + updatedRight };
|
|
@@ -38534,9 +38731,6 @@ class EditionPlugin extends UIPlugin {
|
|
|
38534
38731
|
}
|
|
38535
38732
|
return this.currentContent;
|
|
38536
38733
|
}
|
|
38537
|
-
getEditionSheet() {
|
|
38538
|
-
return this.sheetId;
|
|
38539
|
-
}
|
|
38540
38734
|
getComposerSelection() {
|
|
38541
38735
|
return {
|
|
38542
38736
|
start: this.selectionStart,
|
|
@@ -38820,8 +39014,8 @@ class EditionPlugin extends UIPlugin {
|
|
|
38820
39014
|
getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
|
|
38821
39015
|
const sheetId = this.getters.getActiveSheetId();
|
|
38822
39016
|
let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
|
|
38823
|
-
if (this.getters.
|
|
38824
|
-
const sheetName =
|
|
39017
|
+
if (this.getters.getCurrentEditedCell().sheetId !== this.getters.getActiveSheetId()) {
|
|
39018
|
+
const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
|
|
38825
39019
|
selectedXc = `${sheetName}!${selectedXc}`;
|
|
38826
39020
|
}
|
|
38827
39021
|
return selectedXc;
|
|
@@ -38835,7 +39029,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38835
39029
|
_fixedParts.pop();
|
|
38836
39030
|
}
|
|
38837
39031
|
const newRange = range.clone({ parts: _fixedParts });
|
|
38838
|
-
return this.getters.getSelectionRangeString(newRange, this.getters.
|
|
39032
|
+
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().sheetId);
|
|
38839
39033
|
}
|
|
38840
39034
|
/**
|
|
38841
39035
|
* Replace the current selection by a new text.
|
|
@@ -38868,7 +39062,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38868
39062
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
38869
39063
|
return;
|
|
38870
39064
|
}
|
|
38871
|
-
const editionSheetId = this.getters.
|
|
39065
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38872
39066
|
const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
|
|
38873
39067
|
const colorsToKeep = {};
|
|
38874
39068
|
for (const xc of XCs) {
|
|
@@ -38897,7 +39091,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38897
39091
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
38898
39092
|
return [];
|
|
38899
39093
|
}
|
|
38900
|
-
const editionSheetId = this.getters.
|
|
39094
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38901
39095
|
const rangeColor = (rangeString) => {
|
|
38902
39096
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
38903
39097
|
return colors$1[colorIndex % colors$1.length];
|
|
@@ -38915,7 +39109,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38915
39109
|
* Return ranges currently referenced in the composer
|
|
38916
39110
|
*/
|
|
38917
39111
|
getReferencedRanges() {
|
|
38918
|
-
const editionSheetId = this.getters.
|
|
39112
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38919
39113
|
return this.currentTokens
|
|
38920
39114
|
.filter((token) => token.type === "REFERENCE")
|
|
38921
39115
|
.map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
|
|
@@ -38974,7 +39168,6 @@ EditionPlugin.getters = [
|
|
|
38974
39168
|
"isSelectingForComposer",
|
|
38975
39169
|
"showSelectionIndicator",
|
|
38976
39170
|
"getCurrentContent",
|
|
38977
|
-
"getEditionSheet",
|
|
38978
39171
|
"getComposerSelection",
|
|
38979
39172
|
"getCurrentTokens",
|
|
38980
39173
|
"getTokenAtCursor",
|
|
@@ -40297,10 +40490,6 @@ css /* scss */ `
|
|
|
40297
40490
|
.o-bottom-bar-arrows {
|
|
40298
40491
|
.o-bottom-bar-arrow {
|
|
40299
40492
|
cursor: pointer;
|
|
40300
|
-
&.o-disabled {
|
|
40301
|
-
opacity: 0.4;
|
|
40302
|
-
cursor: default;
|
|
40303
|
-
}
|
|
40304
40493
|
&:hover:not([class*="o-disabled"]) {
|
|
40305
40494
|
.o-icon {
|
|
40306
40495
|
opacity: 0.9;
|
|
@@ -41138,11 +41327,6 @@ css /* scss */ `
|
|
|
41138
41327
|
margin: 0 6px;
|
|
41139
41328
|
}
|
|
41140
41329
|
|
|
41141
|
-
.o-disabled {
|
|
41142
|
-
opacity: 0.6;
|
|
41143
|
-
cursor: default;
|
|
41144
|
-
}
|
|
41145
|
-
|
|
41146
41330
|
.o-dropdown {
|
|
41147
41331
|
position: relative;
|
|
41148
41332
|
display: flex;
|
|
@@ -41517,10 +41701,12 @@ css /* scss */ `
|
|
|
41517
41701
|
button {
|
|
41518
41702
|
color: #333;
|
|
41519
41703
|
}
|
|
41520
|
-
|
|
41521
|
-
|
|
41522
|
-
|
|
41704
|
+
.o-disabled {
|
|
41705
|
+
opacity: 0.4;
|
|
41706
|
+
pointer: default;
|
|
41707
|
+
pointer-events: none;
|
|
41523
41708
|
}
|
|
41709
|
+
|
|
41524
41710
|
&,
|
|
41525
41711
|
*,
|
|
41526
41712
|
*:before,
|
|
@@ -44889,6 +45075,13 @@ class Model extends EventBus {
|
|
|
44889
45075
|
* Internal status of the model. Important for command handling coordination
|
|
44890
45076
|
*/
|
|
44891
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
|
+
};
|
|
44892
45085
|
/**
|
|
44893
45086
|
* The dispatch method is the only entry point to manipulate data in the model.
|
|
44894
45087
|
* This is through this method that commands are dispatched most of the time
|
|
@@ -45032,7 +45225,10 @@ class Model extends EventBus {
|
|
|
45032
45225
|
markRaw(this);
|
|
45033
45226
|
}
|
|
45034
45227
|
get handlers() {
|
|
45035
|
-
return [
|
|
45228
|
+
return [...this.coreHandlers, ...this.allUIPlugins, this.history];
|
|
45229
|
+
}
|
|
45230
|
+
get coreHandlers() {
|
|
45231
|
+
return [this.range, ...this.corePlugins];
|
|
45036
45232
|
}
|
|
45037
45233
|
get allUIPlugins() {
|
|
45038
45234
|
return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
|
|
@@ -45160,6 +45356,16 @@ class Model extends EventBus {
|
|
|
45160
45356
|
* Check if the given command is allowed by all the plugins and the history.
|
|
45161
45357
|
*/
|
|
45162
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) {
|
|
45163
45369
|
const results = this.handlers.map((handler) => handler.allowDispatch(command));
|
|
45164
45370
|
return new DispatchResult(results.flat());
|
|
45165
45371
|
}
|
|
@@ -45360,6 +45566,6 @@ function addFunction(functionName, functionDescription) {
|
|
|
45360
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 };
|
|
45361
45567
|
|
|
45362
45568
|
|
|
45363
|
-
__info__.version = '16.3.0-alpha.
|
|
45364
|
-
__info__.date = '2023-
|
|
45365
|
-
__info__.hash = '
|
|
45569
|
+
__info__.version = '16.3.0-alpha.3';
|
|
45570
|
+
__info__.date = '2023-04-13T08:30:41.165Z';
|
|
45571
|
+
__info__.hash = '573e679';
|