@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
|
@@ -117,88 +117,88 @@ const FILTERS_COLOR = "#188038";
|
|
|
117
117
|
const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
|
|
118
118
|
const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
|
|
119
119
|
const SEPARATOR_COLOR = "#E0E2E4";
|
|
120
|
-
// Color picker
|
|
120
|
+
// Color picker defaults as upper case HEX to match `toHex`helper
|
|
121
121
|
const COLOR_PICKER_DEFAULTS = [
|
|
122
122
|
"#000000",
|
|
123
123
|
"#434343",
|
|
124
124
|
"#666666",
|
|
125
125
|
"#999999",
|
|
126
|
-
"#
|
|
127
|
-
"#
|
|
128
|
-
"#
|
|
129
|
-
"#
|
|
130
|
-
"#
|
|
131
|
-
"#
|
|
126
|
+
"#B7B7B7",
|
|
127
|
+
"#CCCCCC",
|
|
128
|
+
"#D9D9D9",
|
|
129
|
+
"#EFEFEF",
|
|
130
|
+
"#F3F3F3",
|
|
131
|
+
"#FFFFFF",
|
|
132
132
|
"#980000",
|
|
133
|
-
"#
|
|
134
|
-
"#
|
|
135
|
-
"#
|
|
136
|
-
"#
|
|
137
|
-
"#
|
|
138
|
-
"#
|
|
139
|
-
"#
|
|
140
|
-
"#
|
|
141
|
-
"#
|
|
142
|
-
"#
|
|
143
|
-
"#
|
|
144
|
-
"#
|
|
145
|
-
"#
|
|
146
|
-
"#
|
|
147
|
-
"#
|
|
148
|
-
"#
|
|
149
|
-
"#
|
|
150
|
-
"#
|
|
151
|
-
"#
|
|
152
|
-
"#
|
|
153
|
-
"#
|
|
154
|
-
"#
|
|
155
|
-
"#
|
|
156
|
-
"#
|
|
157
|
-
"#
|
|
158
|
-
"#
|
|
159
|
-
"#
|
|
160
|
-
"#
|
|
161
|
-
"#
|
|
162
|
-
"#
|
|
163
|
-
"#
|
|
164
|
-
"#
|
|
165
|
-
"#
|
|
166
|
-
"#
|
|
167
|
-
"#
|
|
168
|
-
"#
|
|
169
|
-
"#
|
|
170
|
-
"#
|
|
171
|
-
"#
|
|
172
|
-
"#
|
|
173
|
-
"#
|
|
174
|
-
"#
|
|
175
|
-
"#
|
|
176
|
-
"#
|
|
177
|
-
"#
|
|
178
|
-
"#
|
|
179
|
-
"#
|
|
180
|
-
"#
|
|
181
|
-
"#
|
|
182
|
-
"#
|
|
133
|
+
"#FF0000",
|
|
134
|
+
"#FF9900",
|
|
135
|
+
"#FFFF00",
|
|
136
|
+
"#00FF00",
|
|
137
|
+
"#00FFFF",
|
|
138
|
+
"#4A86E8",
|
|
139
|
+
"#0000FF",
|
|
140
|
+
"#9900FF",
|
|
141
|
+
"#FF00FF",
|
|
142
|
+
"#E6B8AF",
|
|
143
|
+
"#F4CCCC",
|
|
144
|
+
"#FCE5CD",
|
|
145
|
+
"#FFF2CC",
|
|
146
|
+
"#D9EAD3",
|
|
147
|
+
"#D0E0E3",
|
|
148
|
+
"#C9DAF8",
|
|
149
|
+
"#CFE2F3",
|
|
150
|
+
"#D9D2E9",
|
|
151
|
+
"#EAD1DC",
|
|
152
|
+
"#DD7E6B",
|
|
153
|
+
"#EA9999",
|
|
154
|
+
"#F9CB9C",
|
|
155
|
+
"#FFE599",
|
|
156
|
+
"#B6D7A8",
|
|
157
|
+
"#A2C4C9",
|
|
158
|
+
"#A4C2F4",
|
|
159
|
+
"#9FC5E8",
|
|
160
|
+
"#B4A7D6",
|
|
161
|
+
"#D5A6BD",
|
|
162
|
+
"#CC4125",
|
|
163
|
+
"#E06666",
|
|
164
|
+
"#F6B26B",
|
|
165
|
+
"#FFD966",
|
|
166
|
+
"#93C47D",
|
|
167
|
+
"#76A5AF",
|
|
168
|
+
"#6D9EEB",
|
|
169
|
+
"#6FA8DC",
|
|
170
|
+
"#8E7CC3",
|
|
171
|
+
"#C27BA0",
|
|
172
|
+
"#A61C00",
|
|
173
|
+
"#CC0000",
|
|
174
|
+
"#E69138",
|
|
175
|
+
"#F1C232",
|
|
176
|
+
"#6AA84F",
|
|
177
|
+
"#45818E",
|
|
178
|
+
"#3C78D8",
|
|
179
|
+
"#3D85C6",
|
|
180
|
+
"#674EA7",
|
|
181
|
+
"#A64D79",
|
|
182
|
+
"#85200C",
|
|
183
183
|
"#990000",
|
|
184
|
-
"#
|
|
185
|
-
"#
|
|
186
|
-
"#
|
|
187
|
-
"#
|
|
188
|
-
"#
|
|
189
|
-
"#
|
|
190
|
-
"#
|
|
191
|
-
"#
|
|
192
|
-
"#
|
|
184
|
+
"#B45F06",
|
|
185
|
+
"#BF9000",
|
|
186
|
+
"#38761D",
|
|
187
|
+
"#134F5C",
|
|
188
|
+
"#1155CC",
|
|
189
|
+
"#0B5394",
|
|
190
|
+
"#351C75",
|
|
191
|
+
"#741B47",
|
|
192
|
+
"#5B0F00",
|
|
193
193
|
"#660000",
|
|
194
|
-
"#
|
|
195
|
-
"#
|
|
196
|
-
"#
|
|
197
|
-
"#
|
|
198
|
-
"#
|
|
194
|
+
"#783F04",
|
|
195
|
+
"#7F6000",
|
|
196
|
+
"#274E13",
|
|
197
|
+
"#0C343D",
|
|
198
|
+
"#1C4587",
|
|
199
199
|
"#073763",
|
|
200
|
-
"#
|
|
201
|
-
"#
|
|
200
|
+
"#20124D",
|
|
201
|
+
"#4C1130",
|
|
202
202
|
];
|
|
203
203
|
// Dimensions
|
|
204
204
|
const MIN_ROW_HEIGHT = 10;
|
|
@@ -227,7 +227,6 @@ const MENU_VERTICAL_PADDING = 8;
|
|
|
227
227
|
const MENU_ITEM_HEIGHT = 28;
|
|
228
228
|
const MENU_SEPARATOR_BORDER_WIDTH = 1;
|
|
229
229
|
const MENU_SEPARATOR_PADDING = 5;
|
|
230
|
-
const MENU_SEPARATOR_HEIGHT = MENU_SEPARATOR_BORDER_WIDTH + 2 * MENU_SEPARATOR_PADDING;
|
|
231
230
|
// Fonts
|
|
232
231
|
const DEFAULT_FONT_WEIGHT = "400";
|
|
233
232
|
const DEFAULT_FONT_SIZE = 10;
|
|
@@ -237,7 +236,7 @@ const DEFAULT_FONT = "'Roboto', arial";
|
|
|
237
236
|
const DEFAULT_BORDER_DESC = ["thin", "#000"];
|
|
238
237
|
const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
|
|
239
238
|
// DateTimeRegex
|
|
240
|
-
const DATETIME_FORMAT = /[
|
|
239
|
+
const DATETIME_FORMAT = /[ymdhs:]/;
|
|
241
240
|
// Ranges
|
|
242
241
|
const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
|
|
243
242
|
// Max Number of history steps kept in memory
|
|
@@ -718,7 +717,7 @@ function getUnquotedSheetName(sheetName) {
|
|
|
718
717
|
* '\w' captures [0-9][a-z][A-Z] and _.
|
|
719
718
|
* @param sheetName Name of the sheet
|
|
720
719
|
*/
|
|
721
|
-
function
|
|
720
|
+
function getCanonicalSheetName(sheetName) {
|
|
722
721
|
var _a;
|
|
723
722
|
if (((_a = sheetName.match(/\w/g)) === null || _a === void 0 ? void 0 : _a.length) !== sheetName.length) {
|
|
724
723
|
sheetName = `'${sheetName}'`;
|
|
@@ -739,8 +738,9 @@ function getDefaultCellHeight(cell) {
|
|
|
739
738
|
return DEFAULT_CELL_HEIGHT;
|
|
740
739
|
}
|
|
741
740
|
const fontSize = computeTextFontSizeInPixels(cell.style);
|
|
742
|
-
|
|
743
|
-
|
|
741
|
+
// the number of lines should be computed from the formula result, but it's not evaluated at this point
|
|
742
|
+
const numberOfLines = cell.isFormula ? 1 : cell.content.split(NEWLINE).length;
|
|
743
|
+
return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
|
|
744
744
|
}
|
|
745
745
|
function computeTextWidth(context, text, style) {
|
|
746
746
|
context.save();
|
|
@@ -1092,6 +1092,8 @@ function replaceSpecialSpaces(text) {
|
|
|
1092
1092
|
return text;
|
|
1093
1093
|
}
|
|
1094
1094
|
|
|
1095
|
+
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
1096
|
+
const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
|
|
1095
1097
|
const colors$1 = [
|
|
1096
1098
|
"#eb6d00",
|
|
1097
1099
|
"#0074d9",
|
|
@@ -1117,7 +1119,10 @@ function colorNumberString(color) {
|
|
|
1117
1119
|
}
|
|
1118
1120
|
/**
|
|
1119
1121
|
* Converts any CSS color value to a standardized hex6 value.
|
|
1120
|
-
* Accepts: hex3, hex6, hex8 and
|
|
1122
|
+
* Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
|
|
1123
|
+
*
|
|
1124
|
+
* [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
|
|
1125
|
+
* with r,g,b ∈ [0, 255] and a ∈ [0, 1]
|
|
1121
1126
|
*
|
|
1122
1127
|
* toHex("#ABC")
|
|
1123
1128
|
* >> "#AABBCC"
|
|
@@ -1128,27 +1133,31 @@ function colorNumberString(color) {
|
|
|
1128
1133
|
* toHex("rgb(30, 80, 16)")
|
|
1129
1134
|
* >> "#1E5010"
|
|
1130
1135
|
*
|
|
1136
|
+
* * toHex("rgb(30, 80, 16, 0.5)")
|
|
1137
|
+
* >> "#1E501080"
|
|
1138
|
+
*
|
|
1131
1139
|
*/
|
|
1132
1140
|
function toHex(color) {
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
if (color.includes("rgb")) {
|
|
1137
|
-
return rgbToHex6(color);
|
|
1141
|
+
let hexColor = color;
|
|
1142
|
+
if (color.startsWith("rgb")) {
|
|
1143
|
+
hexColor = rgbaStringToHex(color);
|
|
1138
1144
|
}
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1145
|
+
else {
|
|
1146
|
+
hexColor = color.replace("#", "").toUpperCase();
|
|
1147
|
+
if (hexColor.length === 3 || hexColor.length === 4) {
|
|
1148
|
+
hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
|
|
1149
|
+
}
|
|
1150
|
+
hexColor = `#${hexColor}`;
|
|
1142
1151
|
}
|
|
1143
|
-
if (
|
|
1144
|
-
throw new Error(
|
|
1152
|
+
if (!hexColor.match(HEX_MATCH)) {
|
|
1153
|
+
throw new Error(`invalid color input: ${color}`);
|
|
1145
1154
|
}
|
|
1146
|
-
return
|
|
1155
|
+
return hexColor;
|
|
1147
1156
|
}
|
|
1148
1157
|
function isColorValid(color) {
|
|
1149
1158
|
try {
|
|
1150
|
-
|
|
1151
|
-
return
|
|
1159
|
+
toHex(color);
|
|
1160
|
+
return true;
|
|
1152
1161
|
}
|
|
1153
1162
|
catch (error) {
|
|
1154
1163
|
return false;
|
|
@@ -1181,15 +1190,29 @@ function relativeLuminance(color) {
|
|
|
1181
1190
|
/**
|
|
1182
1191
|
* Convert a CSS rgb color string to a standardized hex6 color value.
|
|
1183
1192
|
*
|
|
1184
|
-
*
|
|
1193
|
+
* rgbaStringToHex("rgb(30, 80, 16)")
|
|
1185
1194
|
* >> "#1E5010"
|
|
1195
|
+
*
|
|
1196
|
+
* rgbaStringToHex("rgba(30, 80, 16, 0.5)")
|
|
1197
|
+
* >> "#1E501080"
|
|
1198
|
+
*
|
|
1199
|
+
* DOES NOT SUPPORT NON INTEGER RGB VALUES
|
|
1186
1200
|
*/
|
|
1187
|
-
function
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1201
|
+
function rgbaStringToHex(color) {
|
|
1202
|
+
const stringVals = color.replace(RBA_REGEX, "").split(",");
|
|
1203
|
+
let alphaHex = 255;
|
|
1204
|
+
if (stringVals.length !== 3 && stringVals.length !== 4) {
|
|
1205
|
+
throw new Error("invalid color");
|
|
1206
|
+
}
|
|
1207
|
+
else if (stringVals.length === 4) {
|
|
1208
|
+
const alpha = parseFloat(stringVals.pop() || "1");
|
|
1209
|
+
alphaHex = Math.round((alpha || 1) * 255);
|
|
1210
|
+
}
|
|
1211
|
+
const vals = stringVals.map((val) => parseInt(val, 10));
|
|
1212
|
+
if (alphaHex !== 255) {
|
|
1213
|
+
vals.push(alphaHex);
|
|
1214
|
+
}
|
|
1215
|
+
return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
|
|
1193
1216
|
}
|
|
1194
1217
|
/**
|
|
1195
1218
|
* RGBA to HEX representation (#RRGGBBAA).
|
|
@@ -1211,7 +1234,7 @@ function rgbaToHex(rgba) {
|
|
|
1211
1234
|
a = "0" + a;
|
|
1212
1235
|
if (a === "ff")
|
|
1213
1236
|
a = "";
|
|
1214
|
-
return "#" + r + g + b + a;
|
|
1237
|
+
return ("#" + r + g + b + a).toUpperCase();
|
|
1215
1238
|
}
|
|
1216
1239
|
/**
|
|
1217
1240
|
* Color string to RGBA representation
|
|
@@ -1332,6 +1355,9 @@ function rgbaToHSLA(rgba) {
|
|
|
1332
1355
|
s = +(s * 100).toFixed(1);
|
|
1333
1356
|
l = +(l * 100).toFixed(1);
|
|
1334
1357
|
return { a: rgba.a, h, s, l };
|
|
1358
|
+
}
|
|
1359
|
+
function isSameColor(color1, color2) {
|
|
1360
|
+
return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
|
|
1335
1361
|
}
|
|
1336
1362
|
|
|
1337
1363
|
/** Reference of a cell (eg. A1, $B$5) */
|
|
@@ -1483,7 +1509,7 @@ function scrollDelay(value) {
|
|
|
1483
1509
|
* formula, commas are used to separate arguments
|
|
1484
1510
|
* - it does not support % symbol, in formulas % is an operator
|
|
1485
1511
|
*/
|
|
1486
|
-
const formulaNumberRegexp =
|
|
1512
|
+
const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
|
|
1487
1513
|
const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
|
|
1488
1514
|
const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
|
|
1489
1515
|
const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
|
|
@@ -3092,6 +3118,7 @@ const CHART_PADDING_RATIO = 0.02;
|
|
|
3092
3118
|
const LINE_HEIGHT = 1.2;
|
|
3093
3119
|
css /* scss */ `
|
|
3094
3120
|
div.o-scorecard {
|
|
3121
|
+
font-family: ${DEFAULT_FONT};
|
|
3095
3122
|
user-select: none;
|
|
3096
3123
|
background-color: white;
|
|
3097
3124
|
display: flex;
|
|
@@ -5379,24 +5406,30 @@ class Menu extends owl.Component {
|
|
|
5379
5406
|
}
|
|
5380
5407
|
});
|
|
5381
5408
|
}
|
|
5382
|
-
get
|
|
5383
|
-
|
|
5409
|
+
get menuItemsAndSeparators() {
|
|
5410
|
+
const menuItemsAndSeparators = [];
|
|
5411
|
+
for (let i = 0; i < this.props.menuItems.length; i++) {
|
|
5412
|
+
const menuItem = this.props.menuItems[i];
|
|
5413
|
+
if (menuItem.isVisible(this.env)) {
|
|
5414
|
+
menuItemsAndSeparators.push(menuItem);
|
|
5415
|
+
}
|
|
5416
|
+
if (menuItem.separator &&
|
|
5417
|
+
i !== this.props.menuItems.length - 1 && // no separator at the end
|
|
5418
|
+
menuItemsAndSeparators[menuItemsAndSeparators.length - 1] !== "separator" // no double separator
|
|
5419
|
+
) {
|
|
5420
|
+
menuItemsAndSeparators.push("separator");
|
|
5421
|
+
}
|
|
5422
|
+
}
|
|
5423
|
+
if (menuItemsAndSeparators.length === 1 && menuItemsAndSeparators[0] === "separator") {
|
|
5424
|
+
return [];
|
|
5425
|
+
}
|
|
5426
|
+
return menuItemsAndSeparators;
|
|
5384
5427
|
}
|
|
5385
5428
|
get subMenuPosition() {
|
|
5386
5429
|
const position = Object.assign({}, this.subMenu.position);
|
|
5387
5430
|
position.y -= this.subMenu.scrollOffset || 0;
|
|
5388
5431
|
return position;
|
|
5389
5432
|
}
|
|
5390
|
-
get menuHeight() {
|
|
5391
|
-
const menuItems = this.visibleMenuItems;
|
|
5392
|
-
let menuItemsHeight = this.getMenuItemsHeight(menuItems);
|
|
5393
|
-
// We don't display separator at the end of a menu
|
|
5394
|
-
if (menuItems[menuItems.length - 1].separator) {
|
|
5395
|
-
menuItemsHeight -= MENU_SEPARATOR_HEIGHT;
|
|
5396
|
-
}
|
|
5397
|
-
const menuHeight = 2 * MENU_VERTICAL_PADDING + menuItemsHeight;
|
|
5398
|
-
return this.props.maxHeight ? Math.min(menuHeight, this.props.maxHeight) : menuHeight;
|
|
5399
|
-
}
|
|
5400
5433
|
get popoverProps() {
|
|
5401
5434
|
const isRoot = this.props.depth === 1;
|
|
5402
5435
|
return {
|
|
@@ -5410,7 +5443,6 @@ class Menu extends owl.Component {
|
|
|
5410
5443
|
verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
|
|
5411
5444
|
onPopoverHidden: () => this.closeSubMenu(),
|
|
5412
5445
|
onPopoverMoved: () => this.closeSubMenu(),
|
|
5413
|
-
maxHeight: this.menuHeight,
|
|
5414
5446
|
};
|
|
5415
5447
|
}
|
|
5416
5448
|
getColor(menu) {
|
|
@@ -5426,14 +5458,6 @@ class Menu extends owl.Component {
|
|
|
5426
5458
|
this.closeSubMenu();
|
|
5427
5459
|
this.props.onClose();
|
|
5428
5460
|
}
|
|
5429
|
-
/**
|
|
5430
|
-
* Return the number of pixels between the top of the menu
|
|
5431
|
-
* and the menu item at a given index.
|
|
5432
|
-
*/
|
|
5433
|
-
subMenuVerticalPosition(menuIndex) {
|
|
5434
|
-
const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
|
|
5435
|
-
return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
|
|
5436
|
-
}
|
|
5437
5461
|
onExternalClick(ev) {
|
|
5438
5462
|
// Don't close a root menu when clicked to open the submenus.
|
|
5439
5463
|
const el = this.menuRef.el;
|
|
@@ -5443,10 +5467,6 @@ class Menu extends owl.Component {
|
|
|
5443
5467
|
ev.closedMenuId = this.props.menuId;
|
|
5444
5468
|
this.close();
|
|
5445
5469
|
}
|
|
5446
|
-
getMenuItemsHeight(menuItems) {
|
|
5447
|
-
const numberOfSeparators = menuItems.filter((m) => m.separator).length;
|
|
5448
|
-
return MENU_ITEM_HEIGHT * menuItems.length + MENU_SEPARATOR_HEIGHT * numberOfSeparators;
|
|
5449
|
-
}
|
|
5450
5470
|
getName(menu) {
|
|
5451
5471
|
return menu.name(this.env);
|
|
5452
5472
|
}
|
|
@@ -5466,8 +5486,11 @@ class Menu extends owl.Component {
|
|
|
5466
5486
|
* If the given menu is not disabled, open it's submenu at the
|
|
5467
5487
|
* correct position according to available surrounding space.
|
|
5468
5488
|
*/
|
|
5469
|
-
openSubMenu(menu, menuIndex) {
|
|
5470
|
-
const
|
|
5489
|
+
openSubMenu(menu, menuIndex, ev) {
|
|
5490
|
+
const parentMenuEl = ev.currentTarget;
|
|
5491
|
+
if (!parentMenuEl)
|
|
5492
|
+
return;
|
|
5493
|
+
const y = parentMenuEl.getBoundingClientRect().top;
|
|
5471
5494
|
this.subMenu.position = {
|
|
5472
5495
|
x: this.position.x + this.props.depth * MENU_WIDTH,
|
|
5473
5496
|
y: y - (this.subMenu.scrollOffset || 0),
|
|
@@ -5484,20 +5507,20 @@ class Menu extends owl.Component {
|
|
|
5484
5507
|
this.subMenu.isOpen = false;
|
|
5485
5508
|
this.subMenu.parentMenu = undefined;
|
|
5486
5509
|
}
|
|
5487
|
-
onClickMenu(menu, menuIndex) {
|
|
5510
|
+
onClickMenu(menu, menuIndex, ev) {
|
|
5488
5511
|
if (this.isEnabled(menu)) {
|
|
5489
5512
|
if (this.isRoot(menu)) {
|
|
5490
|
-
this.openSubMenu(menu, menuIndex);
|
|
5513
|
+
this.openSubMenu(menu, menuIndex, ev);
|
|
5491
5514
|
}
|
|
5492
5515
|
else {
|
|
5493
5516
|
this.activateMenu(menu);
|
|
5494
5517
|
}
|
|
5495
5518
|
}
|
|
5496
5519
|
}
|
|
5497
|
-
onMouseOver(menu, position) {
|
|
5520
|
+
onMouseOver(menu, position, ev) {
|
|
5498
5521
|
if (menu.isEnabled(this.env)) {
|
|
5499
5522
|
if (this.isRoot(menu)) {
|
|
5500
|
-
this.openSubMenu(menu, position);
|
|
5523
|
+
this.openSubMenu(menu, position, ev);
|
|
5501
5524
|
}
|
|
5502
5525
|
else {
|
|
5503
5526
|
this.closeSubMenu();
|
|
@@ -6074,8 +6097,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6074
6097
|
const dataSets = [];
|
|
6075
6098
|
for (const sheetXC of dataSetsString) {
|
|
6076
6099
|
const dataRange = getters.getRangeFromSheetXC(sheetId, sheetXC);
|
|
6077
|
-
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName } = dataRange;
|
|
6078
|
-
if (invalidSheetName) {
|
|
6100
|
+
const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName, invalidXc } = dataRange;
|
|
6101
|
+
if (invalidSheetName || invalidXc) {
|
|
6079
6102
|
continue;
|
|
6080
6103
|
}
|
|
6081
6104
|
// It's a rectangle. We treat all columns (arbitrary) as different data series.
|
|
@@ -6100,14 +6123,8 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6100
6123
|
: undefined));
|
|
6101
6124
|
}
|
|
6102
6125
|
}
|
|
6103
|
-
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
6104
|
-
// A single cell. If it's only the title, the dataset is not added.
|
|
6105
|
-
if (!dataSetsHaveTitle) {
|
|
6106
|
-
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
6107
|
-
}
|
|
6108
|
-
}
|
|
6109
6126
|
else {
|
|
6110
|
-
/* 1 row or 1 column */
|
|
6127
|
+
/* 1 cell, 1 row or 1 column */
|
|
6111
6128
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
6112
6129
|
? {
|
|
6113
6130
|
top: zone.top,
|
|
@@ -6161,6 +6178,18 @@ function toExcelDataset(getters, ds) {
|
|
|
6161
6178
|
range: getters.getRangeString(dataRange, "forceSheetReference"),
|
|
6162
6179
|
};
|
|
6163
6180
|
}
|
|
6181
|
+
function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
|
|
6182
|
+
if (!labelRange)
|
|
6183
|
+
return undefined;
|
|
6184
|
+
let zone = {
|
|
6185
|
+
...labelRange.zone,
|
|
6186
|
+
};
|
|
6187
|
+
if (shouldRemoveFirstLabel && labelRange.zone.bottom > labelRange.zone.top) {
|
|
6188
|
+
zone.top = zone.top + 1;
|
|
6189
|
+
}
|
|
6190
|
+
const range = labelRange.clone({ zone });
|
|
6191
|
+
return getters.getRangeString(range, "forceSheetReference");
|
|
6192
|
+
}
|
|
6164
6193
|
/**
|
|
6165
6194
|
* Transform a chart definition which supports dataSets (dataSets and LabelRange)
|
|
6166
6195
|
* with an executed command
|
|
@@ -6245,6 +6274,20 @@ function checkLabelRange(definition) {
|
|
|
6245
6274
|
}
|
|
6246
6275
|
return 0 /* CommandResult.Success */;
|
|
6247
6276
|
}
|
|
6277
|
+
function shouldRemoveFirstLabel(labelRange, dataset, dataSetsHaveTitle) {
|
|
6278
|
+
if (!dataSetsHaveTitle)
|
|
6279
|
+
return false;
|
|
6280
|
+
if (!labelRange)
|
|
6281
|
+
return false;
|
|
6282
|
+
if (!dataset)
|
|
6283
|
+
return true;
|
|
6284
|
+
const datasetLength = getZoneArea(dataset.dataRange.zone);
|
|
6285
|
+
const labelLength = getZoneArea(labelRange.zone);
|
|
6286
|
+
if (labelLength < datasetLength) {
|
|
6287
|
+
return false;
|
|
6288
|
+
}
|
|
6289
|
+
return true;
|
|
6290
|
+
}
|
|
6248
6291
|
// ---------------------------------------------------------------------------
|
|
6249
6292
|
// Scorecard
|
|
6250
6293
|
// ---------------------------------------------------------------------------
|
|
@@ -6614,6 +6657,7 @@ class BarChart extends AbstractChart {
|
|
|
6614
6657
|
this.legendPosition = definition.legendPosition;
|
|
6615
6658
|
this.stacked = definition.stacked;
|
|
6616
6659
|
this.aggregated = definition.aggregated;
|
|
6660
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
6617
6661
|
}
|
|
6618
6662
|
static transformDefinition(definition, executed) {
|
|
6619
6663
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -6681,11 +6725,13 @@ class BarChart extends AbstractChart {
|
|
|
6681
6725
|
const dataSets = this.dataSets
|
|
6682
6726
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
6683
6727
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
6728
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
6684
6729
|
return {
|
|
6685
6730
|
...this.getDefinition(),
|
|
6686
6731
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
6687
6732
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
6688
6733
|
dataSets,
|
|
6734
|
+
labelRange,
|
|
6689
6735
|
};
|
|
6690
6736
|
}
|
|
6691
6737
|
updateRanges(applyChange) {
|
|
@@ -6753,6 +6799,11 @@ function createBarChartRuntime(chart, getters) {
|
|
|
6753
6799
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
6754
6800
|
let labels = labelValues.formattedValues;
|
|
6755
6801
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
6802
|
+
if (chart.dataSetsHaveTitle &&
|
|
6803
|
+
dataSetsValues[0] &&
|
|
6804
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
6805
|
+
labels.shift();
|
|
6806
|
+
}
|
|
6756
6807
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
6757
6808
|
if (chart.aggregated) {
|
|
6758
6809
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
@@ -7175,6 +7226,7 @@ class LineChart extends AbstractChart {
|
|
|
7175
7226
|
this.labelsAsText = definition.labelsAsText;
|
|
7176
7227
|
this.stacked = definition.stacked;
|
|
7177
7228
|
this.aggregated = definition.aggregated;
|
|
7229
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
7178
7230
|
}
|
|
7179
7231
|
static validateChartDefinition(validator, definition) {
|
|
7180
7232
|
return validator.checkValidations(definition, checkDataset, checkLabelRange);
|
|
@@ -7242,11 +7294,13 @@ class LineChart extends AbstractChart {
|
|
|
7242
7294
|
const dataSets = this.dataSets
|
|
7243
7295
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
7244
7296
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
7297
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
7245
7298
|
return {
|
|
7246
7299
|
...this.getDefinition(),
|
|
7247
7300
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
7248
7301
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
7249
7302
|
dataSets,
|
|
7303
|
+
labelRange,
|
|
7250
7304
|
};
|
|
7251
7305
|
}
|
|
7252
7306
|
copyForSheetId(sheetId) {
|
|
@@ -7384,6 +7438,11 @@ function createLineChartRuntime(chart, getters) {
|
|
|
7384
7438
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
7385
7439
|
let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
|
|
7386
7440
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
7441
|
+
if (chart.dataSetsHaveTitle &&
|
|
7442
|
+
dataSetsValues[0] &&
|
|
7443
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
7444
|
+
labels.shift();
|
|
7445
|
+
}
|
|
7387
7446
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
7388
7447
|
if (axisType === "time") {
|
|
7389
7448
|
({ labels, dataSetsValues } = fixEmptyLabelsForDateCharts(labels, dataSetsValues));
|
|
@@ -7442,6 +7501,7 @@ class PieChart extends AbstractChart {
|
|
|
7442
7501
|
this.background = definition.background;
|
|
7443
7502
|
this.legendPosition = definition.legendPosition;
|
|
7444
7503
|
this.aggregated = definition.aggregated;
|
|
7504
|
+
this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
|
|
7445
7505
|
}
|
|
7446
7506
|
static transformDefinition(definition, executed) {
|
|
7447
7507
|
return transformChartDefinitionWithDataSetsWithZone(definition, executed);
|
|
@@ -7505,12 +7565,14 @@ class PieChart extends AbstractChart {
|
|
|
7505
7565
|
const dataSets = this.dataSets
|
|
7506
7566
|
.map((ds) => toExcelDataset(this.getters, ds))
|
|
7507
7567
|
.filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
|
|
7568
|
+
const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
|
|
7508
7569
|
return {
|
|
7509
7570
|
...this.getDefinition(),
|
|
7510
7571
|
backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
|
|
7511
7572
|
fontColor: toXlsxHexColor(chartFontColor(this.background)),
|
|
7512
7573
|
verticalAxisPosition: "left",
|
|
7513
7574
|
dataSets,
|
|
7575
|
+
labelRange,
|
|
7514
7576
|
};
|
|
7515
7577
|
}
|
|
7516
7578
|
updateRanges(applyChange) {
|
|
@@ -7556,6 +7618,11 @@ function createPieChartRuntime(chart, getters) {
|
|
|
7556
7618
|
const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
|
|
7557
7619
|
let labels = labelValues.formattedValues;
|
|
7558
7620
|
let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
|
|
7621
|
+
if (chart.dataSetsHaveTitle &&
|
|
7622
|
+
dataSetsValues[0] &&
|
|
7623
|
+
labels.length > dataSetsValues[0].data.length) {
|
|
7624
|
+
labels.shift();
|
|
7625
|
+
}
|
|
7559
7626
|
({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
|
|
7560
7627
|
if (chart.aggregated) {
|
|
7561
7628
|
({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
|
|
@@ -8191,7 +8258,6 @@ function getSmartChartDefinition(zone, getters) {
|
|
|
8191
8258
|
labelRangeXc = zoneToXc({
|
|
8192
8259
|
...zone,
|
|
8193
8260
|
right: zone.left,
|
|
8194
|
-
top: dataSetsHaveTitle ? zone.top + 1 : zone.top,
|
|
8195
8261
|
});
|
|
8196
8262
|
}
|
|
8197
8263
|
// Only display legend for several datasets.
|
|
@@ -15109,7 +15175,7 @@ const ADDRESS = {
|
|
|
15109
15175
|
cellReference = rowPart + colPart;
|
|
15110
15176
|
}
|
|
15111
15177
|
if (sheet !== undefined) {
|
|
15112
|
-
return `${
|
|
15178
|
+
return `${getCanonicalSheetName(toString(sheet))}!${cellReference}`;
|
|
15113
15179
|
}
|
|
15114
15180
|
return cellReference;
|
|
15115
15181
|
},
|
|
@@ -16934,6 +17000,22 @@ class LineBarPieConfigPanel extends owl.Component {
|
|
|
16934
17000
|
aggregated: ev.target.checked,
|
|
16935
17001
|
});
|
|
16936
17002
|
}
|
|
17003
|
+
calculateHeaderPosition() {
|
|
17004
|
+
if (this.isDatasetInvalid || this.isLabelInvalid) {
|
|
17005
|
+
return undefined;
|
|
17006
|
+
}
|
|
17007
|
+
const getters = this.env.model.getters;
|
|
17008
|
+
const sheetId = getters.getActiveSheetId();
|
|
17009
|
+
const labelRange = createRange(getters, sheetId, this.labelRange);
|
|
17010
|
+
const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
|
|
17011
|
+
if (dataSets.length) {
|
|
17012
|
+
return dataSets[0].dataRange.zone.top + 1;
|
|
17013
|
+
}
|
|
17014
|
+
else if (labelRange) {
|
|
17015
|
+
return labelRange.zone.top + 1;
|
|
17016
|
+
}
|
|
17017
|
+
return undefined;
|
|
17018
|
+
}
|
|
16937
17019
|
}
|
|
16938
17020
|
LineBarPieConfigPanel.template = "o-spreadsheet-LineBarPieConfigPanel";
|
|
16939
17021
|
LineBarPieConfigPanel.components = { SelectionInput };
|
|
@@ -17181,6 +17263,9 @@ class ColorPicker extends owl.Component {
|
|
|
17181
17263
|
top,
|
|
17182
17264
|
});
|
|
17183
17265
|
}
|
|
17266
|
+
isSameColor(color1, color2) {
|
|
17267
|
+
return isSameColor(color1, color2);
|
|
17268
|
+
}
|
|
17184
17269
|
}
|
|
17185
17270
|
ColorPicker.template = "o-spreadsheet-ColorPicker";
|
|
17186
17271
|
ColorPicker.defaultProps = {
|
|
@@ -19422,6 +19507,8 @@ class ContentEditableHelper {
|
|
|
19422
19507
|
start = 0;
|
|
19423
19508
|
if (end > textLength)
|
|
19424
19509
|
end = textLength;
|
|
19510
|
+
if (start > textLength)
|
|
19511
|
+
start = textLength;
|
|
19425
19512
|
}
|
|
19426
19513
|
let startNode = this.findChildAtCharacterIndex(start);
|
|
19427
19514
|
let endNode = this.findChildAtCharacterIndex(end);
|
|
@@ -19691,6 +19778,7 @@ css /* scss */ `
|
|
|
19691
19778
|
padding-right: 2px;
|
|
19692
19779
|
|
|
19693
19780
|
box-sizing: border-box;
|
|
19781
|
+
font-family: ${DEFAULT_FONT};
|
|
19694
19782
|
|
|
19695
19783
|
caret-color: black;
|
|
19696
19784
|
padding-left: 3px;
|
|
@@ -20133,7 +20221,7 @@ class Composer extends owl.Component {
|
|
|
20133
20221
|
const highlights = this.env.model.getters.getHighlights();
|
|
20134
20222
|
const refSheet = sheetName
|
|
20135
20223
|
? this.env.model.getters.getSheetIdByName(sheetName)
|
|
20136
|
-
: this.env.model.getters.
|
|
20224
|
+
: this.env.model.getters.getCurrentEditedCell().sheetId;
|
|
20137
20225
|
const highlight = highlights.find((highlight) => {
|
|
20138
20226
|
if (highlight.sheetId !== refSheet)
|
|
20139
20227
|
return false;
|
|
@@ -20294,7 +20382,7 @@ class GridComposer extends owl.Component {
|
|
|
20294
20382
|
get cellReference() {
|
|
20295
20383
|
const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
|
|
20296
20384
|
const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
|
|
20297
|
-
return `${prefixSheet ?
|
|
20385
|
+
return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
|
|
20298
20386
|
}
|
|
20299
20387
|
get cellReferenceStyle() {
|
|
20300
20388
|
const { x: left, y: top } = this.rect;
|
|
@@ -20479,15 +20567,18 @@ function screenCoordinatesToInternal(getters, { x, y }) {
|
|
|
20479
20567
|
return { x, y };
|
|
20480
20568
|
}
|
|
20481
20569
|
|
|
20482
|
-
function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { scrollX, scrollY }) {
|
|
20570
|
+
function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { maxX, maxY }, { scrollX, scrollY }) {
|
|
20483
20571
|
const minX = viewportX ? 0 : -scrollX;
|
|
20484
20572
|
const minY = viewportY ? 0 : -scrollY;
|
|
20485
|
-
|
|
20486
|
-
const newX =
|
|
20487
|
-
|
|
20488
|
-
const newY =
|
|
20573
|
+
const deltaX = mouseX - mouseInitialX;
|
|
20574
|
+
const newX = clamp(initialFigure.x + deltaX, minX, maxX - initialFigure.width - scrollX);
|
|
20575
|
+
const deltaY = mouseY - mouseInitialY;
|
|
20576
|
+
const newY = clamp(initialFigure.y + deltaY, minY, maxY - initialFigure.height - scrollY);
|
|
20489
20577
|
return { ...initialFigure, x: newX, y: newY };
|
|
20490
20578
|
}
|
|
20579
|
+
function clamp(value, min, max) {
|
|
20580
|
+
return Math.min(Math.max(value, min), max);
|
|
20581
|
+
}
|
|
20491
20582
|
function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, keepRatio, minFigSize) {
|
|
20492
20583
|
let { x, y, width, height } = initialFigure;
|
|
20493
20584
|
if (keepRatio && dirX != 0 && dirY != 0) {
|
|
@@ -20886,12 +20977,16 @@ class FiguresContainer extends owl.Component {
|
|
|
20886
20977
|
}
|
|
20887
20978
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
20888
20979
|
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
20980
|
+
const maxDimensions = {
|
|
20981
|
+
maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
|
|
20982
|
+
maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
|
|
20983
|
+
};
|
|
20889
20984
|
const { x, y } = internalFigureToScreen(this.env.model.getters, figure);
|
|
20890
20985
|
const initialFig = { ...figure, x, y };
|
|
20891
20986
|
const onMouseMove = (ev) => {
|
|
20892
20987
|
const getters = this.env.model.getters;
|
|
20893
20988
|
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
20894
|
-
const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), getters.getActiveSheetScrollInfo());
|
|
20989
|
+
const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), maxDimensions, getters.getActiveSheetScrollInfo());
|
|
20895
20990
|
const otherFigures = this.getOtherFigures(figure.id);
|
|
20896
20991
|
const internalDragged = screenFigureToInternal(getters, draggedFigure);
|
|
20897
20992
|
const snapResult = snapForMove(getters, internalDragged, otherFigures);
|
|
@@ -22585,6 +22680,10 @@ class Grid extends owl.Component {
|
|
|
22585
22680
|
}
|
|
22586
22681
|
}
|
|
22587
22682
|
onInput(ev) {
|
|
22683
|
+
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
22684
|
+
if (!ev.isComposing && ev.inputType === "insertFromPaste") {
|
|
22685
|
+
return;
|
|
22686
|
+
}
|
|
22588
22687
|
if (ev.data) {
|
|
22589
22688
|
// if the user types a character on the grid, it means he wants to start composing the selected cell with that
|
|
22590
22689
|
// character
|
|
@@ -23433,6 +23532,70 @@ function fixXlsxUnicode(str) {
|
|
|
23433
23532
|
});
|
|
23434
23533
|
}
|
|
23435
23534
|
|
|
23535
|
+
const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
|
|
23536
|
+
/**
|
|
23537
|
+
* Convert excel format to o_spreadsheet format
|
|
23538
|
+
*
|
|
23539
|
+
* Excel format are defined in openXML §18.8.31
|
|
23540
|
+
*/
|
|
23541
|
+
function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
23542
|
+
var _a, _b, _c;
|
|
23543
|
+
if (numFmtId === 0) {
|
|
23544
|
+
return undefined;
|
|
23545
|
+
}
|
|
23546
|
+
// Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
|
|
23547
|
+
let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
|
|
23548
|
+
if (format) {
|
|
23549
|
+
try {
|
|
23550
|
+
let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
|
|
23551
|
+
convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
|
|
23552
|
+
convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
|
|
23553
|
+
// Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
|
|
23554
|
+
const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
23555
|
+
const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
|
|
23556
|
+
if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
|
|
23557
|
+
throw new Error("Multiple escaped blocks in format");
|
|
23558
|
+
}
|
|
23559
|
+
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
23560
|
+
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
|
|
23561
|
+
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
|
|
23562
|
+
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
23563
|
+
convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
|
|
23564
|
+
if (isXlsxDateFormat(convertedFormat)) {
|
|
23565
|
+
convertedFormat = convertDateFormat$1(convertedFormat);
|
|
23566
|
+
}
|
|
23567
|
+
if (isFormatSupported(convertedFormat)) {
|
|
23568
|
+
return convertedFormat;
|
|
23569
|
+
}
|
|
23570
|
+
}
|
|
23571
|
+
catch (e) { }
|
|
23572
|
+
}
|
|
23573
|
+
warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
|
|
23574
|
+
return undefined;
|
|
23575
|
+
}
|
|
23576
|
+
function isFormatSupported(format) {
|
|
23577
|
+
try {
|
|
23578
|
+
formatValue(0, format);
|
|
23579
|
+
return true;
|
|
23580
|
+
}
|
|
23581
|
+
catch (e) {
|
|
23582
|
+
return false;
|
|
23583
|
+
}
|
|
23584
|
+
}
|
|
23585
|
+
function isXlsxDateFormat(format) {
|
|
23586
|
+
return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
|
|
23587
|
+
}
|
|
23588
|
+
function convertDateFormat$1(format) {
|
|
23589
|
+
// Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
|
|
23590
|
+
// but can still occur and are supported by Excel/Google sheets
|
|
23591
|
+
format = format.toLowerCase();
|
|
23592
|
+
format = format.replace(/mmmmm/g, "mmm");
|
|
23593
|
+
format = format.replace(/am\/pm|a\/m/g, "a");
|
|
23594
|
+
format = format.replace(/hhhh/g, "hh");
|
|
23595
|
+
format = format.replace(/\bh\b/g, "hh");
|
|
23596
|
+
return format;
|
|
23597
|
+
}
|
|
23598
|
+
|
|
23436
23599
|
function convertBorders(data, warningManager) {
|
|
23437
23600
|
const borderArray = data.borders.map((border) => {
|
|
23438
23601
|
addBorderWarnings(border, warningManager);
|
|
@@ -23495,41 +23658,6 @@ function convertFormats(data, warningManager) {
|
|
|
23495
23658
|
}
|
|
23496
23659
|
return arrayToObject(formats, 1);
|
|
23497
23660
|
}
|
|
23498
|
-
/**
|
|
23499
|
-
* Convert excel format to o_spreadsheet format
|
|
23500
|
-
*
|
|
23501
|
-
* Excel format are defined in openXML §18.8.31
|
|
23502
|
-
*/
|
|
23503
|
-
function convertXlsxFormat(numFmtId, formats, warningManager) {
|
|
23504
|
-
var _a, _b, _c;
|
|
23505
|
-
if (numFmtId === 0) {
|
|
23506
|
-
return undefined;
|
|
23507
|
-
}
|
|
23508
|
-
// Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
|
|
23509
|
-
let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || ((_a = formats.find((f) => f.id === numFmtId)) === null || _a === void 0 ? void 0 : _a.format);
|
|
23510
|
-
if (format) {
|
|
23511
|
-
try {
|
|
23512
|
-
let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
|
|
23513
|
-
convertedFormat = convertedFormat.replace(/\[(.*)-[A-Z0-9]{3}\]/g, "[$1]"); // remove currency and locale/date system/number system info (ECMA §18.8.31)
|
|
23514
|
-
convertedFormat = convertedFormat.replace(/\[\$\]/g, ""); // remove empty bocks
|
|
23515
|
-
// Quotes in format escape sequences of characters. ATM we only support [$...] blocks to escape characters, and only one of them per format
|
|
23516
|
-
const numberOfQuotes = ((_b = convertedFormat.match(/"/g)) === null || _b === void 0 ? void 0 : _b.length) || 0;
|
|
23517
|
-
const numberOfOpenBrackets = ((_c = convertedFormat.match(/\[/g)) === null || _c === void 0 ? void 0 : _c.length) || 0;
|
|
23518
|
-
if (numberOfQuotes / 2 + numberOfOpenBrackets > 1) {
|
|
23519
|
-
throw new Error("Multiple escaped blocks in format");
|
|
23520
|
-
}
|
|
23521
|
-
convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
|
|
23522
|
-
convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
|
|
23523
|
-
convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
|
|
23524
|
-
convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
|
|
23525
|
-
formatValue(0, convertedFormat);
|
|
23526
|
-
return convertedFormat;
|
|
23527
|
-
}
|
|
23528
|
-
catch (e) { }
|
|
23529
|
-
}
|
|
23530
|
-
warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
|
|
23531
|
-
return undefined;
|
|
23532
|
-
}
|
|
23533
23661
|
// ---------------------------------------------------------------------------
|
|
23534
23662
|
// Warnings
|
|
23535
23663
|
// ---------------------------------------------------------------------------
|
|
@@ -24084,16 +24212,18 @@ function convertFigure(figure, id, sheetData) {
|
|
|
24084
24212
|
};
|
|
24085
24213
|
}
|
|
24086
24214
|
function convertChartData(chartData) {
|
|
24087
|
-
|
|
24088
|
-
const labelRange =
|
|
24089
|
-
|
|
24215
|
+
const dataSetsHaveTitle = chartData.dataSets[0].label !== undefined;
|
|
24216
|
+
const labelRange = chartData.labelRange
|
|
24217
|
+
? convertExcelRangeToSheetXC(chartData.labelRange, dataSetsHaveTitle)
|
|
24218
|
+
: undefined;
|
|
24219
|
+
let dataSets = chartData.dataSets.map((data) => convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle));
|
|
24090
24220
|
// For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
|
|
24091
24221
|
if (chartData.type === "pie") {
|
|
24092
24222
|
dataSets.reverse();
|
|
24093
24223
|
}
|
|
24094
24224
|
return {
|
|
24095
24225
|
dataSets,
|
|
24096
|
-
dataSetsHaveTitle
|
|
24226
|
+
dataSetsHaveTitle,
|
|
24097
24227
|
labelRange,
|
|
24098
24228
|
title: chartData.title || "",
|
|
24099
24229
|
type: chartData.type,
|
|
@@ -24104,6 +24234,28 @@ function convertChartData(chartData) {
|
|
|
24104
24234
|
aggregated: false,
|
|
24105
24235
|
labelsAsText: false,
|
|
24106
24236
|
};
|
|
24237
|
+
}
|
|
24238
|
+
function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
|
|
24239
|
+
let { sheetName, xc } = splitReference(range);
|
|
24240
|
+
if (sheetName) {
|
|
24241
|
+
sheetName = getCanonicalSheetName(sheetName) + "!";
|
|
24242
|
+
}
|
|
24243
|
+
else {
|
|
24244
|
+
sheetName = "";
|
|
24245
|
+
}
|
|
24246
|
+
let zone = toUnboundedZone(xc);
|
|
24247
|
+
if (dataSetsHaveTitle && zone.bottom !== undefined && zone.right !== undefined) {
|
|
24248
|
+
const height = zone.bottom - zone.top + 1;
|
|
24249
|
+
const width = zone.right - zone.left + 1;
|
|
24250
|
+
if (height === 1) {
|
|
24251
|
+
zone = { ...zone, left: zone.left - 1 };
|
|
24252
|
+
}
|
|
24253
|
+
else if (width === 1) {
|
|
24254
|
+
zone = { ...zone, top: zone.top - 1 };
|
|
24255
|
+
}
|
|
24256
|
+
}
|
|
24257
|
+
const dataXC = zoneToXc(zone);
|
|
24258
|
+
return sheetName + dataXC;
|
|
24107
24259
|
}
|
|
24108
24260
|
|
|
24109
24261
|
/**
|
|
@@ -25171,6 +25323,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
25171
25323
|
title: chartTitle,
|
|
25172
25324
|
type: CHART_TYPE_CONVERSION_MAP[chartType],
|
|
25173
25325
|
dataSets: this.extractChartDatasets(this.querySelector(rootChartElement, `c:${chartType}`)),
|
|
25326
|
+
labelRange: this.extractChildTextContent(rootChartElement, "c:ser c:cat c:f"),
|
|
25174
25327
|
backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
|
|
25175
25328
|
default: "ffffff",
|
|
25176
25329
|
}).asString(),
|
|
@@ -25190,7 +25343,7 @@ class XlsxChartExtractor extends XlsxBaseExtractor {
|
|
|
25190
25343
|
extractChartDatasets(chartElement) {
|
|
25191
25344
|
return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
|
|
25192
25345
|
return {
|
|
25193
|
-
label: this.extractChildTextContent(chartDataElement, "c:
|
|
25346
|
+
label: this.extractChildTextContent(chartDataElement, "c:tx c:f"),
|
|
25194
25347
|
range: this.extractChildTextContent(chartDataElement, "c:val c:f", { required: true }),
|
|
25195
25348
|
};
|
|
25196
25349
|
});
|
|
@@ -29107,6 +29260,39 @@ class FigurePlugin extends CorePlugin {
|
|
|
29107
29260
|
case "DELETE_FIGURE":
|
|
29108
29261
|
this.removeFigure(cmd.id, cmd.sheetId);
|
|
29109
29262
|
break;
|
|
29263
|
+
case "REMOVE_COLUMNS_ROWS":
|
|
29264
|
+
this.onRowColDelete(cmd.sheetId, cmd.dimension);
|
|
29265
|
+
}
|
|
29266
|
+
}
|
|
29267
|
+
onRowColDelete(sheetId, dimension) {
|
|
29268
|
+
dimension === "ROW" ? this.onRowDeletion(sheetId) : this.onColDeletion(sheetId);
|
|
29269
|
+
}
|
|
29270
|
+
onRowDeletion(sheetId) {
|
|
29271
|
+
const numHeader = this.getters.getNumberRows(sheetId);
|
|
29272
|
+
let gridHeight = 0;
|
|
29273
|
+
for (let i = 0; i < numHeader; i++) {
|
|
29274
|
+
gridHeight += this.getters.getRowSize(sheetId, i);
|
|
29275
|
+
}
|
|
29276
|
+
const figures = this.getters.getFigures(sheetId);
|
|
29277
|
+
for (const figure of figures) {
|
|
29278
|
+
const newY = Math.min(figure.y, gridHeight - figure.height);
|
|
29279
|
+
if (newY !== figure.y) {
|
|
29280
|
+
this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, y: newY });
|
|
29281
|
+
}
|
|
29282
|
+
}
|
|
29283
|
+
}
|
|
29284
|
+
onColDeletion(sheetId) {
|
|
29285
|
+
const numHeader = this.getters.getNumberCols(sheetId);
|
|
29286
|
+
let gridWidth = 0;
|
|
29287
|
+
for (let i = 0; i < numHeader; i++) {
|
|
29288
|
+
gridWidth += this.getters.getColSize(sheetId, i);
|
|
29289
|
+
}
|
|
29290
|
+
const figures = this.getters.getFigures(sheetId);
|
|
29291
|
+
for (const figure of figures) {
|
|
29292
|
+
const newX = Math.min(figure.x, gridWidth - figure.width);
|
|
29293
|
+
if (newX !== figure.x) {
|
|
29294
|
+
this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x: newX });
|
|
29295
|
+
}
|
|
29110
29296
|
}
|
|
29111
29297
|
}
|
|
29112
29298
|
updateFigure(sheetId, figure) {
|
|
@@ -30777,7 +30963,7 @@ class RangeAdapter {
|
|
|
30777
30963
|
sheetName = rangeImpl.invalidSheetName;
|
|
30778
30964
|
}
|
|
30779
30965
|
else {
|
|
30780
|
-
sheetName =
|
|
30966
|
+
sheetName = getCanonicalSheetName(this.getters.getSheetName(rangeImpl.sheetId));
|
|
30781
30967
|
}
|
|
30782
30968
|
}
|
|
30783
30969
|
if (prefixSheet && !sheetName) {
|
|
@@ -31828,9 +32014,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
31828
32014
|
// remove duplicates first to check validity on a reduced
|
|
31829
32015
|
// set of colors, then normalize to HEX and remove duplicates
|
|
31830
32016
|
// again
|
|
31831
|
-
[...new Set([...usedColors, ...this.customColors])]
|
|
31832
|
-
.filter(isColorValid)
|
|
31833
|
-
.map((c) => toHex(c).toLowerCase())),
|
|
32017
|
+
[...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
|
|
31834
32018
|
]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
|
|
31835
32019
|
}
|
|
31836
32020
|
getColorsFromCells(cells) {
|
|
@@ -31891,7 +32075,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
31891
32075
|
return [...chartsColors];
|
|
31892
32076
|
}
|
|
31893
32077
|
tryToAddColor(color) {
|
|
31894
|
-
const formattedColor = toHex(color)
|
|
32078
|
+
const formattedColor = toHex(color);
|
|
31895
32079
|
if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
|
|
31896
32080
|
this.customColors.add(formattedColor);
|
|
31897
32081
|
}
|
|
@@ -32906,8 +33090,8 @@ class InternalViewport {
|
|
|
32906
33090
|
this.getters = getters;
|
|
32907
33091
|
this.sheetId = sheetId;
|
|
32908
33092
|
this.boundaries = boundaries;
|
|
32909
|
-
this.
|
|
32910
|
-
this.
|
|
33093
|
+
this.viewportWidth = sizeInGrid.width;
|
|
33094
|
+
this.viewportHeight = sizeInGrid.height;
|
|
32911
33095
|
this.offsetScrollbarX = offsets.x;
|
|
32912
33096
|
this.offsetScrollbarY = offsets.y;
|
|
32913
33097
|
this.canScrollVertically = options.canScrollVertically;
|
|
@@ -32918,6 +33102,10 @@ class InternalViewport {
|
|
|
32918
33102
|
this.adjustViewportOffsetY();
|
|
32919
33103
|
}
|
|
32920
33104
|
// PUBLIC
|
|
33105
|
+
/** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
|
|
33106
|
+
* When the viewport grid size is smaller than its client width (resp. height), it will return
|
|
33107
|
+
* the client width (resp. height).
|
|
33108
|
+
*/
|
|
32921
33109
|
getMaxSize() {
|
|
32922
33110
|
const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
|
|
32923
33111
|
first: this.boundaries.left,
|
|
@@ -32929,20 +33117,24 @@ class InternalViewport {
|
|
|
32929
33117
|
});
|
|
32930
33118
|
const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
|
|
32931
33119
|
const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
|
|
32932
|
-
const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.
|
|
33120
|
+
const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
|
|
32933
33121
|
const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
|
|
32934
|
-
const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.
|
|
33122
|
+
const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
|
|
32935
33123
|
const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
|
|
32936
|
-
|
|
32937
|
-
|
|
32938
|
-
(
|
|
32939
|
-
|
|
32940
|
-
|
|
32941
|
-
|
|
32942
|
-
|
|
32943
|
-
|
|
32944
|
-
|
|
32945
|
-
|
|
33124
|
+
let width = lastColEnd - this.offsetCorrectionX;
|
|
33125
|
+
if (this.canScrollHorizontally) {
|
|
33126
|
+
width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
|
|
33127
|
+
Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
|
|
33128
|
+
);
|
|
33129
|
+
width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
|
|
33130
|
+
}
|
|
33131
|
+
let height = lastRowEnd - this.offsetCorrectionY;
|
|
33132
|
+
if (this.canScrollVertically) {
|
|
33133
|
+
height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
|
|
33134
|
+
Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
|
|
33135
|
+
);
|
|
33136
|
+
height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
|
|
33137
|
+
}
|
|
32946
33138
|
return { width, height };
|
|
32947
33139
|
}
|
|
32948
33140
|
/**
|
|
@@ -32951,7 +33143,7 @@ class InternalViewport {
|
|
|
32951
33143
|
* It returns -1 if no column is found.
|
|
32952
33144
|
*/
|
|
32953
33145
|
getColIndex(x, absolute = false) {
|
|
32954
|
-
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.
|
|
33146
|
+
if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
|
|
32955
33147
|
return -1;
|
|
32956
33148
|
}
|
|
32957
33149
|
return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
|
|
@@ -32962,7 +33154,7 @@ class InternalViewport {
|
|
|
32962
33154
|
* It returns -1 if no row is found.
|
|
32963
33155
|
*/
|
|
32964
33156
|
getRowIndex(y, absolute = false) {
|
|
32965
|
-
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.
|
|
33157
|
+
if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
|
|
32966
33158
|
return -1;
|
|
32967
33159
|
}
|
|
32968
33160
|
return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
|
|
@@ -32989,7 +33181,7 @@ class InternalViewport {
|
|
|
32989
33181
|
adjustPositionX(col) {
|
|
32990
33182
|
const sheetId = this.sheetId;
|
|
32991
33183
|
const { start, end } = this.getters.getColDimensions(sheetId, col);
|
|
32992
|
-
while (end > this.offsetX + this.offsetCorrectionX + this.
|
|
33184
|
+
while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
|
|
32993
33185
|
this.offsetX + this.offsetCorrectionX < start) {
|
|
32994
33186
|
this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
|
|
32995
33187
|
this.offsetScrollbarX = this.offsetX;
|
|
@@ -33011,7 +33203,7 @@ class InternalViewport {
|
|
|
33011
33203
|
adjustPositionY(row) {
|
|
33012
33204
|
const sheetId = this.sheetId;
|
|
33013
33205
|
while (this.getters.getRowDimensions(sheetId, row).end >
|
|
33014
|
-
this.offsetY + this.
|
|
33206
|
+
this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
|
|
33015
33207
|
this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
|
|
33016
33208
|
this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
|
|
33017
33209
|
this.offsetScrollbarY = this.offsetY;
|
|
@@ -33049,8 +33241,8 @@ class InternalViewport {
|
|
|
33049
33241
|
const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
|
|
33050
33242
|
this.offsetCorrectionX;
|
|
33051
33243
|
const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
|
|
33052
|
-
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.
|
|
33053
|
-
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.
|
|
33244
|
+
const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
|
|
33245
|
+
const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
|
|
33054
33246
|
return {
|
|
33055
33247
|
x,
|
|
33056
33248
|
y,
|
|
@@ -33113,12 +33305,12 @@ class InternalViewport {
|
|
|
33113
33305
|
adjustViewportOffsetX() {
|
|
33114
33306
|
if (this.canScrollHorizontally) {
|
|
33115
33307
|
const { width: viewportWidth } = this.getMaxSize();
|
|
33116
|
-
if (this.
|
|
33117
|
-
this.offsetScrollbarX = Math.max(0, viewportWidth - this.
|
|
33308
|
+
if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
|
|
33309
|
+
this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
|
|
33118
33310
|
}
|
|
33119
33311
|
}
|
|
33120
33312
|
this.left = this.getColIndex(this.offsetScrollbarX, true);
|
|
33121
|
-
this.right = this.getColIndex(this.offsetScrollbarX + this.
|
|
33313
|
+
this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
|
|
33122
33314
|
if (this.right === -1) {
|
|
33123
33315
|
this.right = this.boundaries.right;
|
|
33124
33316
|
}
|
|
@@ -33130,12 +33322,12 @@ class InternalViewport {
|
|
|
33130
33322
|
adjustViewportOffsetY() {
|
|
33131
33323
|
if (this.canScrollVertically) {
|
|
33132
33324
|
const { height: paneHeight } = this.getMaxSize();
|
|
33133
|
-
if (this.
|
|
33134
|
-
this.offsetScrollbarY = Math.max(0, paneHeight - this.
|
|
33325
|
+
if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
|
|
33326
|
+
this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
|
|
33135
33327
|
}
|
|
33136
33328
|
}
|
|
33137
33329
|
this.top = this.getRowIndex(this.offsetScrollbarY, true);
|
|
33138
|
-
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.
|
|
33330
|
+
this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
|
|
33139
33331
|
if (this.bottom === -1) {
|
|
33140
33332
|
this.bottom = this.boundaries.bottom;
|
|
33141
33333
|
}
|
|
@@ -33146,7 +33338,7 @@ class InternalViewport {
|
|
|
33146
33338
|
adjustViewportZoneX() {
|
|
33147
33339
|
const sheetId = this.sheetId;
|
|
33148
33340
|
this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
|
|
33149
|
-
this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.
|
|
33341
|
+
this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
|
|
33150
33342
|
if (this.right === -1) {
|
|
33151
33343
|
this.right = this.getters.getNumberCols(sheetId) - 1;
|
|
33152
33344
|
}
|
|
@@ -33159,7 +33351,7 @@ class InternalViewport {
|
|
|
33159
33351
|
adjustViewportZoneY() {
|
|
33160
33352
|
const sheetId = this.sheetId;
|
|
33161
33353
|
this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
|
|
33162
|
-
this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.
|
|
33354
|
+
this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
|
|
33163
33355
|
if (this.bottom === -1) {
|
|
33164
33356
|
this.bottom = this.getters.getNumberRows(sheetId) - 1;
|
|
33165
33357
|
}
|
|
@@ -33422,8 +33614,7 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33422
33614
|
return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
|
|
33423
33615
|
}
|
|
33424
33616
|
/**
|
|
33425
|
-
* Return the main viewport maximum size
|
|
33426
|
-
* with some bottom and right padding.
|
|
33617
|
+
* Return the main viewport maximum size relative to the client size.
|
|
33427
33618
|
*/
|
|
33428
33619
|
getMainViewportRect() {
|
|
33429
33620
|
const sheetId = this.getters.getActiveSheetId();
|
|
@@ -33439,8 +33630,8 @@ class SheetViewPlugin extends UIPlugin {
|
|
|
33439
33630
|
const { width, height } = this.getMainViewportRect();
|
|
33440
33631
|
const viewport = this.getMainInternalViewport(sheetId);
|
|
33441
33632
|
return {
|
|
33442
|
-
maxOffsetX: Math.max(0, width - viewport.
|
|
33443
|
-
maxOffsetY: Math.max(0, height - viewport.
|
|
33633
|
+
maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
|
|
33634
|
+
maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
|
|
33444
33635
|
};
|
|
33445
33636
|
}
|
|
33446
33637
|
getColRowOffsetInViewport(dimension, referenceIndex, index) {
|
|
@@ -35660,7 +35851,7 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
35660
35851
|
const inputSheetId = this.activeSheet;
|
|
35661
35852
|
const sheetId = this.getters.getActiveSheetId();
|
|
35662
35853
|
const sheetName = this.getters.getSheetName(sheetId);
|
|
35663
|
-
this.add([sheetId === inputSheetId ? xc : `${
|
|
35854
|
+
this.add([sheetId === inputSheetId ? xc : `${getCanonicalSheetName(sheetName)}!${xc}`]);
|
|
35664
35855
|
}
|
|
35665
35856
|
handle(cmd) {
|
|
35666
35857
|
switch (cmd.type) {
|
|
@@ -37907,13 +38098,19 @@ class ClipboardFigureState {
|
|
|
37907
38098
|
*/
|
|
37908
38099
|
paste(target) {
|
|
37909
38100
|
const sheetId = this.getters.getActiveSheetId();
|
|
38101
|
+
const { width, height } = this.copiedFigure;
|
|
38102
|
+
const numCols = this.getters.getNumberCols(sheetId);
|
|
38103
|
+
const numRows = this.getters.getNumberRows(sheetId);
|
|
38104
|
+
const targetX = this.getters.getColDimensions(sheetId, target[0].left).start;
|
|
38105
|
+
const targetY = this.getters.getRowDimensions(sheetId, target[0].top).start;
|
|
38106
|
+
const maxX = this.getters.getColDimensions(sheetId, numCols - 1).end;
|
|
38107
|
+
const maxY = this.getters.getRowDimensions(sheetId, numRows - 1).end;
|
|
37910
38108
|
const position = {
|
|
37911
|
-
x:
|
|
37912
|
-
y:
|
|
38109
|
+
x: maxX < width ? 0 : Math.min(targetX, maxX - width),
|
|
38110
|
+
y: maxY < height ? 0 : Math.min(targetY, maxY - height),
|
|
37913
38111
|
};
|
|
37914
|
-
const size = { height: this.copiedFigure.height, width: this.copiedFigure.width };
|
|
37915
38112
|
const newId = new UuidGenerator().uuidv4();
|
|
37916
|
-
this.copiedFigureContent.paste(sheetId, newId, position,
|
|
38113
|
+
this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
|
|
37917
38114
|
if (this.operation === "CUT") {
|
|
37918
38115
|
this.dispatch("DELETE_FIGURE", {
|
|
37919
38116
|
sheetId: this.copiedFigureContent.sheetId,
|
|
@@ -38279,7 +38476,7 @@ function loopThroughReferenceType(token) {
|
|
|
38279
38476
|
return token;
|
|
38280
38477
|
const { xc, sheetName } = splitReference(token.value);
|
|
38281
38478
|
const [left, right] = xc.split(":");
|
|
38282
|
-
const sheetRef = sheetName ? `${
|
|
38479
|
+
const sheetRef = sheetName ? `${getCanonicalSheetName(sheetName)}!` : "";
|
|
38283
38480
|
const updatedLeft = getTokenNextReferenceType(left);
|
|
38284
38481
|
const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
|
|
38285
38482
|
return { ...token, value: sheetRef + updatedLeft + updatedRight };
|
|
@@ -38538,9 +38735,6 @@ class EditionPlugin extends UIPlugin {
|
|
|
38538
38735
|
}
|
|
38539
38736
|
return this.currentContent;
|
|
38540
38737
|
}
|
|
38541
|
-
getEditionSheet() {
|
|
38542
|
-
return this.sheetId;
|
|
38543
|
-
}
|
|
38544
38738
|
getComposerSelection() {
|
|
38545
38739
|
return {
|
|
38546
38740
|
start: this.selectionStart,
|
|
@@ -38824,8 +39018,8 @@ class EditionPlugin extends UIPlugin {
|
|
|
38824
39018
|
getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
|
|
38825
39019
|
const sheetId = this.getters.getActiveSheetId();
|
|
38826
39020
|
let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
|
|
38827
|
-
if (this.getters.
|
|
38828
|
-
const sheetName =
|
|
39021
|
+
if (this.getters.getCurrentEditedCell().sheetId !== this.getters.getActiveSheetId()) {
|
|
39022
|
+
const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
|
|
38829
39023
|
selectedXc = `${sheetName}!${selectedXc}`;
|
|
38830
39024
|
}
|
|
38831
39025
|
return selectedXc;
|
|
@@ -38839,7 +39033,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38839
39033
|
_fixedParts.pop();
|
|
38840
39034
|
}
|
|
38841
39035
|
const newRange = range.clone({ parts: _fixedParts });
|
|
38842
|
-
return this.getters.getSelectionRangeString(newRange, this.getters.
|
|
39036
|
+
return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().sheetId);
|
|
38843
39037
|
}
|
|
38844
39038
|
/**
|
|
38845
39039
|
* Replace the current selection by a new text.
|
|
@@ -38872,7 +39066,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38872
39066
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
38873
39067
|
return;
|
|
38874
39068
|
}
|
|
38875
|
-
const editionSheetId = this.getters.
|
|
39069
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38876
39070
|
const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
|
|
38877
39071
|
const colorsToKeep = {};
|
|
38878
39072
|
for (const xc of XCs) {
|
|
@@ -38901,7 +39095,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38901
39095
|
if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
|
|
38902
39096
|
return [];
|
|
38903
39097
|
}
|
|
38904
|
-
const editionSheetId = this.getters.
|
|
39098
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38905
39099
|
const rangeColor = (rangeString) => {
|
|
38906
39100
|
const colorIndex = this.colorIndexByRange[rangeString];
|
|
38907
39101
|
return colors$1[colorIndex % colors$1.length];
|
|
@@ -38919,7 +39113,7 @@ class EditionPlugin extends UIPlugin {
|
|
|
38919
39113
|
* Return ranges currently referenced in the composer
|
|
38920
39114
|
*/
|
|
38921
39115
|
getReferencedRanges() {
|
|
38922
|
-
const editionSheetId = this.getters.
|
|
39116
|
+
const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
|
|
38923
39117
|
return this.currentTokens
|
|
38924
39118
|
.filter((token) => token.type === "REFERENCE")
|
|
38925
39119
|
.map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
|
|
@@ -38978,7 +39172,6 @@ EditionPlugin.getters = [
|
|
|
38978
39172
|
"isSelectingForComposer",
|
|
38979
39173
|
"showSelectionIndicator",
|
|
38980
39174
|
"getCurrentContent",
|
|
38981
|
-
"getEditionSheet",
|
|
38982
39175
|
"getComposerSelection",
|
|
38983
39176
|
"getCurrentTokens",
|
|
38984
39177
|
"getTokenAtCursor",
|
|
@@ -40301,10 +40494,6 @@ css /* scss */ `
|
|
|
40301
40494
|
.o-bottom-bar-arrows {
|
|
40302
40495
|
.o-bottom-bar-arrow {
|
|
40303
40496
|
cursor: pointer;
|
|
40304
|
-
&.o-disabled {
|
|
40305
|
-
opacity: 0.4;
|
|
40306
|
-
cursor: default;
|
|
40307
|
-
}
|
|
40308
40497
|
&:hover:not([class*="o-disabled"]) {
|
|
40309
40498
|
.o-icon {
|
|
40310
40499
|
opacity: 0.9;
|
|
@@ -41142,11 +41331,6 @@ css /* scss */ `
|
|
|
41142
41331
|
margin: 0 6px;
|
|
41143
41332
|
}
|
|
41144
41333
|
|
|
41145
|
-
.o-disabled {
|
|
41146
|
-
opacity: 0.6;
|
|
41147
|
-
cursor: default;
|
|
41148
|
-
}
|
|
41149
|
-
|
|
41150
41334
|
.o-dropdown {
|
|
41151
41335
|
position: relative;
|
|
41152
41336
|
display: flex;
|
|
@@ -41521,10 +41705,12 @@ css /* scss */ `
|
|
|
41521
41705
|
button {
|
|
41522
41706
|
color: #333;
|
|
41523
41707
|
}
|
|
41524
|
-
|
|
41525
|
-
|
|
41526
|
-
|
|
41708
|
+
.o-disabled {
|
|
41709
|
+
opacity: 0.4;
|
|
41710
|
+
pointer: default;
|
|
41711
|
+
pointer-events: none;
|
|
41527
41712
|
}
|
|
41713
|
+
|
|
41528
41714
|
&,
|
|
41529
41715
|
*,
|
|
41530
41716
|
*:before,
|
|
@@ -44893,6 +45079,13 @@ class Model extends EventBus {
|
|
|
44893
45079
|
* Internal status of the model. Important for command handling coordination
|
|
44894
45080
|
*/
|
|
44895
45081
|
this.status = 0 /* Status.Ready */;
|
|
45082
|
+
/**
|
|
45083
|
+
* Check if a command can be dispatched, and returns a DispatchResult object with the possible
|
|
45084
|
+
* reasons the dispatch failed.
|
|
45085
|
+
*/
|
|
45086
|
+
this.canDispatch = (type, payload) => {
|
|
45087
|
+
return this.checkDispatchAllowed({ ...payload, type });
|
|
45088
|
+
};
|
|
44896
45089
|
/**
|
|
44897
45090
|
* The dispatch method is the only entry point to manipulate data in the model.
|
|
44898
45091
|
* This is through this method that commands are dispatched most of the time
|
|
@@ -45036,7 +45229,10 @@ class Model extends EventBus {
|
|
|
45036
45229
|
owl.markRaw(this);
|
|
45037
45230
|
}
|
|
45038
45231
|
get handlers() {
|
|
45039
|
-
return [
|
|
45232
|
+
return [...this.coreHandlers, ...this.allUIPlugins, this.history];
|
|
45233
|
+
}
|
|
45234
|
+
get coreHandlers() {
|
|
45235
|
+
return [this.range, ...this.corePlugins];
|
|
45040
45236
|
}
|
|
45041
45237
|
get allUIPlugins() {
|
|
45042
45238
|
return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
|
|
@@ -45164,6 +45360,16 @@ class Model extends EventBus {
|
|
|
45164
45360
|
* Check if the given command is allowed by all the plugins and the history.
|
|
45165
45361
|
*/
|
|
45166
45362
|
checkDispatchAllowed(command) {
|
|
45363
|
+
if (isCoreCommand(command)) {
|
|
45364
|
+
return this.checkDispatchAllowedCoreCommand(command);
|
|
45365
|
+
}
|
|
45366
|
+
return this.checkDispatchAllowedLocalCommand(command);
|
|
45367
|
+
}
|
|
45368
|
+
checkDispatchAllowedCoreCommand(command) {
|
|
45369
|
+
const results = this.coreHandlers.map((handler) => handler.allowDispatch(command));
|
|
45370
|
+
return new DispatchResult(results.flat());
|
|
45371
|
+
}
|
|
45372
|
+
checkDispatchAllowedLocalCommand(command) {
|
|
45167
45373
|
const results = this.handlers.map((handler) => handler.allowDispatch(command));
|
|
45168
45374
|
return new DispatchResult(results.flat());
|
|
45169
45375
|
}
|
|
@@ -45392,6 +45598,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
45392
45598
|
exports.tokenize = tokenize;
|
|
45393
45599
|
|
|
45394
45600
|
|
|
45395
|
-
__info__.version = '16.3.0-alpha.
|
|
45396
|
-
__info__.date = '2023-
|
|
45397
|
-
__info__.hash = '
|
|
45601
|
+
__info__.version = '16.3.0-alpha.3';
|
|
45602
|
+
__info__.date = '2023-04-13T08:30:41.165Z';
|
|
45603
|
+
__info__.hash = '573e679';
|