@odoo/o-spreadsheet 16.3.0-alpha.2 → 16.3.0-alpha.4

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.
@@ -114,88 +114,89 @@
114
114
  const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
115
115
  const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
116
116
  const SEPARATOR_COLOR = "#E0E2E4";
117
- // Color picker
117
+ const ICONS_COLOR = "#4A4F59";
118
+ // Color picker defaults as upper case HEX to match `toHex`helper
118
119
  const COLOR_PICKER_DEFAULTS = [
119
120
  "#000000",
120
121
  "#434343",
121
122
  "#666666",
122
123
  "#999999",
123
- "#b7b7b7",
124
- "#cccccc",
125
- "#d9d9d9",
126
- "#efefef",
127
- "#f3f3f3",
128
- "#ffffff",
124
+ "#B7B7B7",
125
+ "#CCCCCC",
126
+ "#D9D9D9",
127
+ "#EFEFEF",
128
+ "#F3F3F3",
129
+ "#FFFFFF",
129
130
  "#980000",
130
- "#ff0000",
131
- "#ff9900",
132
- "#ffff00",
133
- "#00ff00",
134
- "#00ffff",
135
- "#4a86e8",
136
- "#0000ff",
137
- "#9900ff",
138
- "#ff00ff",
139
- "#e6b8af",
140
- "#f4cccc",
141
- "#fce5cd",
142
- "#fff2cc",
143
- "#d9ead3",
144
- "#d0e0e3",
145
- "#c9daf8",
146
- "#cfe2f3",
147
- "#d9d2e9",
148
- "#ead1dc",
149
- "#dd7e6b",
150
- "#ea9999",
151
- "#f9cb9c",
152
- "#ffe599",
153
- "#b6d7a8",
154
- "#a2c4c9",
155
- "#a4c2f4",
156
- "#9fc5e8",
157
- "#b4a7d6",
158
- "#d5a6bd",
159
- "#cc4125",
160
- "#e06666",
161
- "#f6b26b",
162
- "#ffd966",
163
- "#93c47d",
164
- "#76a5af",
165
- "#6d9eeb",
166
- "#6fa8dc",
167
- "#8e7cc3",
168
- "#c27ba0",
169
- "#a61c00",
170
- "#cc0000",
171
- "#e69138",
172
- "#f1c232",
173
- "#6aa84f",
174
- "#45818e",
175
- "#3c78d8",
176
- "#3d85c6",
177
- "#674ea7",
178
- "#a64d79",
179
- "#85200c",
131
+ "#FF0000",
132
+ "#FF9900",
133
+ "#FFFF00",
134
+ "#00FF00",
135
+ "#00FFFF",
136
+ "#4A86E8",
137
+ "#0000FF",
138
+ "#9900FF",
139
+ "#FF00FF",
140
+ "#E6B8AF",
141
+ "#F4CCCC",
142
+ "#FCE5CD",
143
+ "#FFF2CC",
144
+ "#D9EAD3",
145
+ "#D0E0E3",
146
+ "#C9DAF8",
147
+ "#CFE2F3",
148
+ "#D9D2E9",
149
+ "#EAD1DC",
150
+ "#DD7E6B",
151
+ "#EA9999",
152
+ "#F9CB9C",
153
+ "#FFE599",
154
+ "#B6D7A8",
155
+ "#A2C4C9",
156
+ "#A4C2F4",
157
+ "#9FC5E8",
158
+ "#B4A7D6",
159
+ "#D5A6BD",
160
+ "#CC4125",
161
+ "#E06666",
162
+ "#F6B26B",
163
+ "#FFD966",
164
+ "#93C47D",
165
+ "#76A5AF",
166
+ "#6D9EEB",
167
+ "#6FA8DC",
168
+ "#8E7CC3",
169
+ "#C27BA0",
170
+ "#A61C00",
171
+ "#CC0000",
172
+ "#E69138",
173
+ "#F1C232",
174
+ "#6AA84F",
175
+ "#45818E",
176
+ "#3C78D8",
177
+ "#3D85C6",
178
+ "#674EA7",
179
+ "#A64D79",
180
+ "#85200C",
180
181
  "#990000",
181
- "#b45f06",
182
- "#bf9000",
183
- "#38761d",
184
- "#134f5c",
185
- "#1155cc",
186
- "#0b5394",
187
- "#351c75",
188
- "#741b47",
189
- "#5b0f00",
182
+ "#B45F06",
183
+ "#BF9000",
184
+ "#38761D",
185
+ "#134F5C",
186
+ "#1155CC",
187
+ "#0B5394",
188
+ "#351C75",
189
+ "#741B47",
190
+ "#5B0F00",
190
191
  "#660000",
191
- "#783f04",
192
- "#7f6000",
193
- "#274e13",
194
- "#0c343d",
195
- "#1c4587",
192
+ "#783F04",
193
+ "#7F6000",
194
+ "#274E13",
195
+ "#0C343D",
196
+ "#1C4587",
196
197
  "#073763",
197
- "#20124d",
198
- "#4c1130",
198
+ "#20124D",
199
+ "#4C1130",
199
200
  ];
200
201
  // Dimensions
201
202
  const MIN_ROW_HEIGHT = 10;
@@ -220,21 +221,23 @@
220
221
  const FILTER_ICON_EDGE_LENGTH = 17;
221
222
  // Menus
222
223
  const MENU_WIDTH = 250;
223
- const MENU_VERTICAL_PADDING = 8;
224
- const MENU_ITEM_HEIGHT = 28;
224
+ const MENU_VERTICAL_PADDING = 6;
225
+ const MENU_ITEM_HEIGHT = 26;
226
+ const MENU_ITEM_PADDING_HORIZONTAL = 13;
227
+ const MENU_ITEM_PADDING_VERTICAL = 4;
225
228
  const MENU_SEPARATOR_BORDER_WIDTH = 1;
226
229
  const MENU_SEPARATOR_PADDING = 5;
227
- const MENU_SEPARATOR_HEIGHT = MENU_SEPARATOR_BORDER_WIDTH + 2 * MENU_SEPARATOR_PADDING;
228
230
  // Fonts
229
231
  const DEFAULT_FONT_WEIGHT = "400";
230
232
  const DEFAULT_FONT_SIZE = 10;
231
233
  const HEADER_FONT_SIZE = 11;
232
234
  const DEFAULT_FONT = "'Roboto', arial";
235
+ const DEFAULT_VERTICAL_ALIGN = "middle";
233
236
  // Borders
234
237
  const DEFAULT_BORDER_DESC = ["thin", "#000"];
235
238
  const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
236
239
  // DateTimeRegex
237
- const DATETIME_FORMAT = /[ymd:]/;
240
+ const DATETIME_FORMAT = /[ymdhs:]/;
238
241
  // Ranges
239
242
  const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
240
243
  // Max Number of history steps kept in memory
@@ -272,15 +275,22 @@
272
275
  ComponentsImportance[ComponentsImportance["Highlight"] = 5] = "Highlight";
273
276
  ComponentsImportance[ComponentsImportance["Figure"] = 10] = "Figure";
274
277
  ComponentsImportance[ComponentsImportance["ScrollBar"] = 15] = "ScrollBar";
275
- ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
278
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
276
279
  ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
277
- ComponentsImportance[ComponentsImportance["TopBarComposer"] = 21] = "TopBarComposer";
280
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
278
281
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
279
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
282
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
283
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
280
284
  ComponentsImportance[ComponentsImportance["FigureAnchor"] = 1000] = "FigureAnchor";
281
285
  ComponentsImportance[ComponentsImportance["FigureSnapLine"] = 1001] = "FigureSnapLine";
282
286
  })(ComponentsImportance || (ComponentsImportance = {}));
283
- const DEFAULT_SHEETVIEW_SIZE = 1000;
287
+ let DEFAULT_SHEETVIEW_SIZE = 0;
288
+ function getDefaultSheetViewSize() {
289
+ return DEFAULT_SHEETVIEW_SIZE;
290
+ }
291
+ function setDefaultSheetViewSize(size) {
292
+ DEFAULT_SHEETVIEW_SIZE = size;
293
+ }
284
294
  const MAXIMAL_FREEZABLE_RATIO = 0.85;
285
295
  const NEWLINE = "\n";
286
296
  const FONT_SIZES = [6, 7, 8, 9, 10, 11, 12, 14, 18, 24, 36];
@@ -715,7 +725,7 @@
715
725
  * '\w' captures [0-9][a-z][A-Z] and _.
716
726
  * @param sheetName Name of the sheet
717
727
  */
718
- function getComposerSheetName(sheetName) {
728
+ function getCanonicalSheetName(sheetName) {
719
729
  var _a;
720
730
  if (((_a = sheetName.match(/\w/g)) === null || _a === void 0 ? void 0 : _a.length) !== sheetName.length) {
721
731
  sheetName = `'${sheetName}'`;
@@ -736,8 +746,9 @@
736
746
  return DEFAULT_CELL_HEIGHT;
737
747
  }
738
748
  const fontSize = computeTextFontSizeInPixels(cell.style);
739
- const multiLineText = cell.content.split(NEWLINE);
740
- return computeTextLinesHeight(fontSize, multiLineText.length) + 2 * PADDING_AUTORESIZE_VERTICAL;
749
+ // the number of lines should be computed from the formula result, but it's not evaluated at this point
750
+ const numberOfLines = cell.isFormula ? 1 : cell.content.split(NEWLINE).length;
751
+ return computeTextLinesHeight(fontSize, numberOfLines) + 2 * PADDING_AUTORESIZE_VERTICAL;
741
752
  }
742
753
  function computeTextWidth(context, text, style) {
743
754
  context.save();
@@ -1089,6 +1100,8 @@
1089
1100
  return text;
1090
1101
  }
1091
1102
 
1103
+ const RBA_REGEX = /rgba?\(|\s+|\)/gi;
1104
+ const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/g;
1092
1105
  const colors$1 = [
1093
1106
  "#eb6d00",
1094
1107
  "#0074d9",
@@ -1114,7 +1127,10 @@
1114
1127
  }
1115
1128
  /**
1116
1129
  * Converts any CSS color value to a standardized hex6 value.
1117
- * Accepts: hex3, hex6, hex8 and rgb (rgba is not supported)
1130
+ * Accepts: hex3, hex6, hex8, rgb[1] and rgba[1].
1131
+ *
1132
+ * [1] under the form rgb(r, g, b, a?) or rgba(r, g, b, a?)
1133
+ * with r,g,b ∈ [0, 255] and a ∈ [0, 1]
1118
1134
  *
1119
1135
  * toHex("#ABC")
1120
1136
  * >> "#AABBCC"
@@ -1125,27 +1141,31 @@
1125
1141
  * toHex("rgb(30, 80, 16)")
1126
1142
  * >> "#1E5010"
1127
1143
  *
1144
+ * * toHex("rgb(30, 80, 16, 0.5)")
1145
+ * >> "#1E501080"
1146
+ *
1128
1147
  */
1129
1148
  function toHex(color) {
1130
- if (color.includes("rgba")) {
1131
- throw new Error(`rgba() conversion currently not supported: ${color}`);
1132
- }
1133
- if (color.includes("rgb")) {
1134
- return rgbToHex6(color);
1149
+ let hexColor = color;
1150
+ if (color.startsWith("rgb")) {
1151
+ hexColor = rgbaStringToHex(color);
1135
1152
  }
1136
- color = color.replace("#", "").toUpperCase();
1137
- if (color.length === 3 || color.length === 4) {
1138
- color = color.split("").reduce((acc, h) => acc + h + h, "");
1153
+ else {
1154
+ hexColor = color.replace("#", "").toUpperCase();
1155
+ if (hexColor.length === 3 || hexColor.length === 4) {
1156
+ hexColor = hexColor.split("").reduce((acc, h) => acc + h + h, "");
1157
+ }
1158
+ hexColor = `#${hexColor}`;
1139
1159
  }
1140
- if (color.replace(/[a-f0-9]/gi, "") !== "") {
1141
- throw new Error("invalid color");
1160
+ if (!hexColor.match(HEX_MATCH)) {
1161
+ throw new Error(`invalid color input: ${color}`);
1142
1162
  }
1143
- return "#" + color;
1163
+ return hexColor;
1144
1164
  }
1145
1165
  function isColorValid(color) {
1146
1166
  try {
1147
- const { r, g, b, a } = colorToRGBA(color);
1148
- return (isColorValueValid(r) && isColorValueValid(g) && isColorValueValid(b) && isColorValueValid(a));
1167
+ toHex(color);
1168
+ return true;
1149
1169
  }
1150
1170
  catch (error) {
1151
1171
  return false;
@@ -1178,15 +1198,29 @@
1178
1198
  /**
1179
1199
  * Convert a CSS rgb color string to a standardized hex6 color value.
1180
1200
  *
1181
- * rgbToHex6("rgb(30, 80, 16)")
1201
+ * rgbaStringToHex("rgb(30, 80, 16)")
1182
1202
  * >> "#1E5010"
1203
+ *
1204
+ * rgbaStringToHex("rgba(30, 80, 16, 0.5)")
1205
+ * >> "#1E501080"
1206
+ *
1207
+ * DOES NOT SUPPORT NON INTEGER RGB VALUES
1183
1208
  */
1184
- function rgbToHex6(color) {
1185
- return ("#" +
1186
- concat(color
1187
- .slice(4, -1)
1188
- .split(",")
1189
- .map((valueString) => parseInt(valueString, 10).toString(16).padStart(2, "0"))).toUpperCase());
1209
+ function rgbaStringToHex(color) {
1210
+ const stringVals = color.replace(RBA_REGEX, "").split(",");
1211
+ let alphaHex = 255;
1212
+ if (stringVals.length !== 3 && stringVals.length !== 4) {
1213
+ throw new Error("invalid color");
1214
+ }
1215
+ else if (stringVals.length === 4) {
1216
+ const alpha = parseFloat(stringVals.pop() || "1");
1217
+ alphaHex = Math.round((alpha || 1) * 255);
1218
+ }
1219
+ const vals = stringVals.map((val) => parseInt(val, 10));
1220
+ if (alphaHex !== 255) {
1221
+ vals.push(alphaHex);
1222
+ }
1223
+ return "#" + concat(vals.map((value) => value.toString(16).padStart(2, "0"))).toUpperCase();
1190
1224
  }
1191
1225
  /**
1192
1226
  * RGBA to HEX representation (#RRGGBBAA).
@@ -1208,7 +1242,7 @@
1208
1242
  a = "0" + a;
1209
1243
  if (a === "ff")
1210
1244
  a = "";
1211
- return "#" + r + g + b + a;
1245
+ return ("#" + r + g + b + a).toUpperCase();
1212
1246
  }
1213
1247
  /**
1214
1248
  * Color string to RGBA representation
@@ -1329,6 +1363,9 @@
1329
1363
  s = +(s * 100).toFixed(1);
1330
1364
  l = +(l * 100).toFixed(1);
1331
1365
  return { a: rgba.a, h, s, l };
1366
+ }
1367
+ function isSameColor(color1, color2) {
1368
+ return isColorValid(color1) && isColorValid(color2) && toHex(color1) === toHex(color2);
1332
1369
  }
1333
1370
 
1334
1371
  /** Reference of a cell (eg. A1, $B$5) */
@@ -1480,7 +1517,7 @@
1480
1517
  * formula, commas are used to separate arguments
1481
1518
  * - it does not support % symbol, in formulas % is an operator
1482
1519
  */
1483
- const formulaNumberRegexp = /^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+/;
1520
+ const formulaNumberRegexp = /(^-?\d+(\.?\d*(e\d+)?)?|^-?\.\d+)(?!\w|!)/;
1484
1521
  const pIntegerAndDecimals = "(\\d+(,\\d{3,})*(\\.\\d*)?)"; // pattern that match integer number with or without decimal digits
1485
1522
  const pOnlyDecimals = "(\\.\\d+)"; // pattern that match only expression with decimal digits
1486
1523
  const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
@@ -3089,6 +3126,7 @@
3089
3126
  const LINE_HEIGHT = 1.2;
3090
3127
  css /* scss */ `
3091
3128
  div.o-scorecard {
3129
+ font-family: ${DEFAULT_FONT};
3092
3130
  user-select: none;
3093
3131
  background-color: white;
3094
3132
  display: flex;
@@ -5155,6 +5193,11 @@
5155
5193
  this.currentPosition = newPosition;
5156
5194
  });
5157
5195
  }
5196
+ get popoverStyle() {
5197
+ return cssPropertiesToCss({
5198
+ "z-index": `${this.props.zIndex}`,
5199
+ });
5200
+ }
5158
5201
  }
5159
5202
  Popover.template = "o-spreadsheet-Popover";
5160
5203
  Popover.defaultProps = {
@@ -5163,6 +5206,7 @@
5163
5206
  onMouseWheel: () => { },
5164
5207
  onPopoverMoved: () => { },
5165
5208
  onPopoverHidden: () => { },
5209
+ zIndex: ComponentsImportance.Popover,
5166
5210
  };
5167
5211
  Popover.props = {
5168
5212
  anchorRect: Object,
@@ -5174,6 +5218,7 @@
5174
5218
  onMouseWheel: { type: Function, optional: true },
5175
5219
  onPopoverHidden: { type: Function, optional: true },
5176
5220
  onPopoverMoved: { type: Function, optional: true },
5221
+ zIndex: { type: Number, optional: true },
5177
5222
  slots: Object,
5178
5223
  };
5179
5224
  class PopoverPositionContext {
@@ -5317,7 +5362,7 @@
5317
5362
  align-items: center;
5318
5363
  box-sizing: border-box;
5319
5364
  height: ${MENU_ITEM_HEIGHT}px;
5320
- padding: 4px 16px;
5365
+ padding: ${MENU_ITEM_PADDING_VERTICAL}px ${MENU_ITEM_PADDING_HORIZONTAL}px;
5321
5366
  cursor: pointer;
5322
5367
  user-select: none;
5323
5368
 
@@ -5331,11 +5376,18 @@
5331
5376
  display: flex;
5332
5377
  justify-content: space-between;
5333
5378
  }
5379
+
5334
5380
  .o-menu-item-icon {
5335
- margin-top: auto;
5336
- margin-bottom: auto;
5381
+ display: inline-block;
5382
+ margin-right: calc(${MENU_ITEM_PADDING_HORIZONTAL}px * 3 / 5);
5383
+ width: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
5384
+ line-height: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
5385
+
5386
+ .o-icon {
5387
+ color: ${ICONS_COLOR};
5388
+ }
5337
5389
  }
5338
- .o-icon {
5390
+ .o-menu-item-root {
5339
5391
  width: 10px;
5340
5392
  }
5341
5393
 
@@ -5376,24 +5428,30 @@
5376
5428
  }
5377
5429
  });
5378
5430
  }
5379
- get visibleMenuItems() {
5380
- return this.props.menuItems.filter((x) => x.isVisible(this.env));
5431
+ get menuItemsAndSeparators() {
5432
+ const menuItemsAndSeparators = [];
5433
+ for (let i = 0; i < this.props.menuItems.length; i++) {
5434
+ const menuItem = this.props.menuItems[i];
5435
+ if (menuItem.isVisible(this.env)) {
5436
+ menuItemsAndSeparators.push(menuItem);
5437
+ }
5438
+ if (menuItem.separator &&
5439
+ i !== this.props.menuItems.length - 1 && // no separator at the end
5440
+ menuItemsAndSeparators[menuItemsAndSeparators.length - 1] !== "separator" // no double separator
5441
+ ) {
5442
+ menuItemsAndSeparators.push("separator");
5443
+ }
5444
+ }
5445
+ if (menuItemsAndSeparators.length === 1 && menuItemsAndSeparators[0] === "separator") {
5446
+ return [];
5447
+ }
5448
+ return menuItemsAndSeparators;
5381
5449
  }
5382
5450
  get subMenuPosition() {
5383
5451
  const position = Object.assign({}, this.subMenu.position);
5384
5452
  position.y -= this.subMenu.scrollOffset || 0;
5385
5453
  return position;
5386
5454
  }
5387
- get menuHeight() {
5388
- const menuItems = this.visibleMenuItems;
5389
- let menuItemsHeight = this.getMenuItemsHeight(menuItems);
5390
- // We don't display separator at the end of a menu
5391
- if (menuItems[menuItems.length - 1].separator) {
5392
- menuItemsHeight -= MENU_SEPARATOR_HEIGHT;
5393
- }
5394
- const menuHeight = 2 * MENU_VERTICAL_PADDING + menuItemsHeight;
5395
- return this.props.maxHeight ? Math.min(menuHeight, this.props.maxHeight) : menuHeight;
5396
- }
5397
5455
  get popoverProps() {
5398
5456
  const isRoot = this.props.depth === 1;
5399
5457
  return {
@@ -5407,15 +5465,24 @@
5407
5465
  verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
5408
5466
  onPopoverHidden: () => this.closeSubMenu(),
5409
5467
  onPopoverMoved: () => this.closeSubMenu(),
5410
- maxHeight: this.menuHeight,
5411
5468
  };
5412
5469
  }
5470
+ get childrenHaveIcon() {
5471
+ return this.props.menuItems.some((menuItem) => !menuItem.icon && !!menuItem.isActive);
5472
+ }
5473
+ getIconName(menu) {
5474
+ var _a;
5475
+ if ((_a = menu.isActive) === null || _a === void 0 ? void 0 : _a.call(menu, this.env)) {
5476
+ return "o-spreadsheet-Icon.CHECK";
5477
+ }
5478
+ return "";
5479
+ }
5413
5480
  getColor(menu) {
5414
5481
  return menu.textColor ? `color: ${menu.textColor}` : undefined;
5415
5482
  }
5416
5483
  async activateMenu(menu) {
5417
5484
  var _a, _b, _c;
5418
- const result = await ((_a = menu.action) === null || _a === void 0 ? void 0 : _a.call(menu, this.env));
5485
+ const result = await ((_a = menu.execute) === null || _a === void 0 ? void 0 : _a.call(menu, this.env));
5419
5486
  this.close();
5420
5487
  (_c = (_b = this.props).onMenuClicked) === null || _c === void 0 ? void 0 : _c.call(_b, { detail: result });
5421
5488
  }
@@ -5423,14 +5490,6 @@
5423
5490
  this.closeSubMenu();
5424
5491
  this.props.onClose();
5425
5492
  }
5426
- /**
5427
- * Return the number of pixels between the top of the menu
5428
- * and the menu item at a given index.
5429
- */
5430
- subMenuVerticalPosition(menuIndex) {
5431
- const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
5432
- return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
5433
- }
5434
5493
  onExternalClick(ev) {
5435
5494
  // Don't close a root menu when clicked to open the submenus.
5436
5495
  const el = this.menuRef.el;
@@ -5440,15 +5499,11 @@
5440
5499
  ev.closedMenuId = this.props.menuId;
5441
5500
  this.close();
5442
5501
  }
5443
- getMenuItemsHeight(menuItems) {
5444
- const numberOfSeparators = menuItems.filter((m) => m.separator).length;
5445
- return MENU_ITEM_HEIGHT * menuItems.length + MENU_SEPARATOR_HEIGHT * numberOfSeparators;
5446
- }
5447
5502
  getName(menu) {
5448
5503
  return menu.name(this.env);
5449
5504
  }
5450
5505
  isRoot(menu) {
5451
- return !menu.action;
5506
+ return !menu.execute;
5452
5507
  }
5453
5508
  isEnabled(menu) {
5454
5509
  if (menu.isEnabled(this.env)) {
@@ -5463,8 +5518,11 @@
5463
5518
  * If the given menu is not disabled, open it's submenu at the
5464
5519
  * correct position according to available surrounding space.
5465
5520
  */
5466
- openSubMenu(menu, menuIndex) {
5467
- const y = this.subMenuVerticalPosition(menuIndex);
5521
+ openSubMenu(menu, menuIndex, ev) {
5522
+ const parentMenuEl = ev.currentTarget;
5523
+ if (!parentMenuEl)
5524
+ return;
5525
+ const y = parentMenuEl.getBoundingClientRect().top;
5468
5526
  this.subMenu.position = {
5469
5527
  x: this.position.x + this.props.depth * MENU_WIDTH,
5470
5528
  y: y - (this.subMenu.scrollOffset || 0),
@@ -5481,20 +5539,20 @@
5481
5539
  this.subMenu.isOpen = false;
5482
5540
  this.subMenu.parentMenu = undefined;
5483
5541
  }
5484
- onClickMenu(menu, menuIndex) {
5542
+ onClickMenu(menu, menuIndex, ev) {
5485
5543
  if (this.isEnabled(menu)) {
5486
5544
  if (this.isRoot(menu)) {
5487
- this.openSubMenu(menu, menuIndex);
5545
+ this.openSubMenu(menu, menuIndex, ev);
5488
5546
  }
5489
5547
  else {
5490
5548
  this.activateMenu(menu);
5491
5549
  }
5492
5550
  }
5493
5551
  }
5494
- onMouseOver(menu, position) {
5495
- if (menu.isEnabled(this.env)) {
5552
+ onMouseOver(menu, position, ev) {
5553
+ if (this.isEnabled(menu)) {
5496
5554
  if (this.isRoot(menu)) {
5497
- this.openSubMenu(menu, position);
5555
+ this.openSubMenu(menu, position, ev);
5498
5556
  }
5499
5557
  else {
5500
5558
  this.closeSubMenu();
@@ -5629,11 +5687,82 @@
5629
5687
  onClosed: { type: Function, optional: true },
5630
5688
  };
5631
5689
 
5632
- function createMenu(menuItems) {
5633
- return menuItems.map(createMenuItem).sort((a, b) => a.sequence - b.sequence);
5690
+ const linkSheet = {
5691
+ name: _lt("Link sheet"),
5692
+ children: [
5693
+ (env) => {
5694
+ const sheets = env.model.getters
5695
+ .getSheetIds()
5696
+ .map((sheetId) => env.model.getters.getSheet(sheetId));
5697
+ return sheets.map((sheet) => ({
5698
+ id: sheet.id,
5699
+ name: sheet.name,
5700
+ execute: () => markdownLink(sheet.name, buildSheetLink(sheet.id)),
5701
+ }));
5702
+ },
5703
+ ],
5704
+ };
5705
+ const deleteSheet = {
5706
+ name: _lt("Delete"),
5707
+ isVisible: (env) => {
5708
+ return env.model.getters.getSheetIds().length > 1;
5709
+ },
5710
+ execute: (env) => env.askConfirmation(_lt("Are you sure you want to delete this sheet ?"), () => {
5711
+ env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
5712
+ }),
5713
+ };
5714
+ const duplicateSheet = {
5715
+ name: _lt("Duplicate"),
5716
+ execute: (env) => {
5717
+ const sheetIdFrom = env.model.getters.getActiveSheetId();
5718
+ const sheetIdTo = env.model.uuidGenerator.uuidv4();
5719
+ env.model.dispatch("DUPLICATE_SHEET", {
5720
+ sheetId: sheetIdFrom,
5721
+ sheetIdTo,
5722
+ });
5723
+ env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
5724
+ },
5725
+ };
5726
+ const renameSheet = (args) => {
5727
+ return {
5728
+ name: _lt("Rename"),
5729
+ execute: args.renameSheetCallback,
5730
+ };
5731
+ };
5732
+ const sheetMoveRight = {
5733
+ name: _lt("Move right"),
5734
+ isVisible: (env) => {
5735
+ const sheetId = env.model.getters.getActiveSheetId();
5736
+ const sheetIds = env.model.getters.getVisibleSheetIds();
5737
+ return sheetIds.indexOf(sheetId) !== sheetIds.length - 1;
5738
+ },
5739
+ execute: (env) => env.model.dispatch("MOVE_SHEET", {
5740
+ sheetId: env.model.getters.getActiveSheetId(),
5741
+ delta: 1,
5742
+ }),
5743
+ };
5744
+ const sheetMoveLeft = {
5745
+ name: _lt("Move left"),
5746
+ isVisible: (env) => {
5747
+ const sheetId = env.model.getters.getActiveSheetId();
5748
+ return env.model.getters.getVisibleSheetIds()[0] !== sheetId;
5749
+ },
5750
+ execute: (env) => env.model.dispatch("MOVE_SHEET", {
5751
+ sheetId: env.model.getters.getActiveSheetId(),
5752
+ delta: -1,
5753
+ }),
5754
+ };
5755
+ const hideSheet = {
5756
+ name: _lt("Hide sheet"),
5757
+ isVisible: (env) => env.model.getters.getVisibleSheetIds().length !== 1,
5758
+ execute: (env) => env.model.dispatch("HIDE_SHEET", { sheetId: env.model.getters.getActiveSheetId() }),
5759
+ };
5760
+
5761
+ function createActions(menuItems) {
5762
+ return menuItems.map(createAction).sort((a, b) => a.sequence - b.sequence);
5634
5763
  }
5635
5764
  const uuidGenerator$1 = new UuidGenerator();
5636
- function createMenuItem(item) {
5765
+ function createAction(item) {
5637
5766
  const name = item.name;
5638
5767
  const children = item.children;
5639
5768
  return {
@@ -5641,23 +5770,25 @@
5641
5770
  name: typeof name === "function" ? name : () => name,
5642
5771
  isVisible: item.isVisible ? item.isVisible : () => true,
5643
5772
  isEnabled: item.isEnabled ? item.isEnabled : () => true,
5644
- action: item.action,
5773
+ isActive: item.isActive,
5774
+ execute: item.execute,
5645
5775
  children: children
5646
5776
  ? (env) => {
5647
5777
  return children
5648
5778
  .map((child) => (typeof child === "function" ? child(env) : child))
5649
5779
  .flat()
5650
- .map(createMenuItem);
5780
+ .map(createAction);
5651
5781
  }
5652
5782
  : () => [],
5653
5783
  isReadonlyAllowed: item.isReadonlyAllowed || false,
5654
5784
  separator: item.separator || false,
5655
- icon: item.icon,
5785
+ icon: item.icon || "",
5656
5786
  description: item.description || "",
5657
5787
  textColor: item.textColor,
5658
5788
  sequence: item.sequence || 0,
5659
5789
  };
5660
- }
5790
+ }
5791
+
5661
5792
  /**
5662
5793
  * The class Registry is extended in order to add the function addChild
5663
5794
  *
@@ -5704,7 +5835,7 @@
5704
5835
  return this;
5705
5836
  }
5706
5837
  getMenuItems() {
5707
- return createMenu(this.getAll());
5838
+ return createActions(this.getAll());
5708
5839
  }
5709
5840
  }
5710
5841
 
@@ -5712,20 +5843,9 @@
5712
5843
  // Link Menu Registry
5713
5844
  //------------------------------------------------------------------------------
5714
5845
  const linkMenuRegistry = new MenuItemRegistry();
5715
- linkMenuRegistry
5716
- .add("sheet", {
5717
- name: _lt("Link sheet"),
5846
+ linkMenuRegistry.add("sheet", {
5847
+ ...linkSheet,
5718
5848
  sequence: 10,
5719
- })
5720
- .addChild("sheet_list", ["sheet"], (env) => {
5721
- const sheets = env.model.getters
5722
- .getSheetIds()
5723
- .map((sheetId) => env.model.getters.getSheet(sheetId));
5724
- return sheets.map((sheet) => ({
5725
- id: sheet.id,
5726
- name: sheet.name,
5727
- action: () => markdownLink(sheet.name, buildSheetLink(sheet.id)),
5728
- }));
5729
5849
  });
5730
5850
 
5731
5851
  const MENU_OFFSET_X = 320;
@@ -6071,8 +6191,8 @@
6071
6191
  const dataSets = [];
6072
6192
  for (const sheetXC of dataSetsString) {
6073
6193
  const dataRange = getters.getRangeFromSheetXC(sheetId, sheetXC);
6074
- const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName } = dataRange;
6075
- if (invalidSheetName) {
6194
+ const { unboundedZone: zone, sheetId: dataSetSheetId, invalidSheetName, invalidXc } = dataRange;
6195
+ if (invalidSheetName || invalidXc) {
6076
6196
  continue;
6077
6197
  }
6078
6198
  // It's a rectangle. We treat all columns (arbitrary) as different data series.
@@ -6097,14 +6217,8 @@
6097
6217
  : undefined));
6098
6218
  }
6099
6219
  }
6100
- else if (zone.left === zone.right && zone.top === zone.bottom) {
6101
- // A single cell. If it's only the title, the dataset is not added.
6102
- if (!dataSetsHaveTitle) {
6103
- dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
6104
- }
6105
- }
6106
6220
  else {
6107
- /* 1 row or 1 column */
6221
+ /* 1 cell, 1 row or 1 column */
6108
6222
  dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
6109
6223
  ? {
6110
6224
  top: zone.top,
@@ -6158,6 +6272,18 @@
6158
6272
  range: getters.getRangeString(dataRange, "forceSheetReference"),
6159
6273
  };
6160
6274
  }
6275
+ function toExcelLabelRange(getters, labelRange, shouldRemoveFirstLabel) {
6276
+ if (!labelRange)
6277
+ return undefined;
6278
+ let zone = {
6279
+ ...labelRange.zone,
6280
+ };
6281
+ if (shouldRemoveFirstLabel && labelRange.zone.bottom > labelRange.zone.top) {
6282
+ zone.top = zone.top + 1;
6283
+ }
6284
+ const range = labelRange.clone({ zone });
6285
+ return getters.getRangeString(range, "forceSheetReference");
6286
+ }
6161
6287
  /**
6162
6288
  * Transform a chart definition which supports dataSets (dataSets and LabelRange)
6163
6289
  * with an executed command
@@ -6242,6 +6368,20 @@
6242
6368
  }
6243
6369
  return 0 /* CommandResult.Success */;
6244
6370
  }
6371
+ function shouldRemoveFirstLabel(labelRange, dataset, dataSetsHaveTitle) {
6372
+ if (!dataSetsHaveTitle)
6373
+ return false;
6374
+ if (!labelRange)
6375
+ return false;
6376
+ if (!dataset)
6377
+ return true;
6378
+ const datasetLength = getZoneArea(dataset.dataRange.zone);
6379
+ const labelLength = getZoneArea(labelRange.zone);
6380
+ if (labelLength < datasetLength) {
6381
+ return false;
6382
+ }
6383
+ return true;
6384
+ }
6245
6385
  // ---------------------------------------------------------------------------
6246
6386
  // Scorecard
6247
6387
  // ---------------------------------------------------------------------------
@@ -6369,18 +6509,6 @@
6369
6509
  [43 /* CommandResult.GaugeUpperInflectionPointNaN */]: _lt("The upper inflection point value must be a number"),
6370
6510
  },
6371
6511
  };
6372
- const NumberFormatTerms = {
6373
- Automatic: _lt("Automatic"),
6374
- Number: _lt("Number"),
6375
- Percent: _lt("Percent"),
6376
- Currency: _lt("Currency"),
6377
- CurrencyRounded: _lt("Currency rounded"),
6378
- Date: _lt("Date"),
6379
- Time: _lt("Time"),
6380
- DateTime: _lt("Date time"),
6381
- Duration: _lt("Duration"),
6382
- CustomCurrency: _lt("Custom currency"),
6383
- };
6384
6512
  const CustomCurrencyTerms = {
6385
6513
  Custom: _lt("Custom"),
6386
6514
  };
@@ -6611,6 +6739,7 @@
6611
6739
  this.legendPosition = definition.legendPosition;
6612
6740
  this.stacked = definition.stacked;
6613
6741
  this.aggregated = definition.aggregated;
6742
+ this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
6614
6743
  }
6615
6744
  static transformDefinition(definition, executed) {
6616
6745
  return transformChartDefinitionWithDataSetsWithZone(definition, executed);
@@ -6678,11 +6807,13 @@
6678
6807
  const dataSets = this.dataSets
6679
6808
  .map((ds) => toExcelDataset(this.getters, ds))
6680
6809
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
6810
+ const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
6681
6811
  return {
6682
6812
  ...this.getDefinition(),
6683
6813
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
6684
6814
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
6685
6815
  dataSets,
6816
+ labelRange,
6686
6817
  };
6687
6818
  }
6688
6819
  updateRanges(applyChange) {
@@ -6750,6 +6881,11 @@
6750
6881
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
6751
6882
  let labels = labelValues.formattedValues;
6752
6883
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
6884
+ if (chart.dataSetsHaveTitle &&
6885
+ dataSetsValues[0] &&
6886
+ labels.length > dataSetsValues[0].data.length) {
6887
+ labels.shift();
6888
+ }
6753
6889
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
6754
6890
  if (chart.aggregated) {
6755
6891
  ({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
@@ -7172,6 +7308,7 @@
7172
7308
  this.labelsAsText = definition.labelsAsText;
7173
7309
  this.stacked = definition.stacked;
7174
7310
  this.aggregated = definition.aggregated;
7311
+ this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
7175
7312
  }
7176
7313
  static validateChartDefinition(validator, definition) {
7177
7314
  return validator.checkValidations(definition, checkDataset, checkLabelRange);
@@ -7239,11 +7376,13 @@
7239
7376
  const dataSets = this.dataSets
7240
7377
  .map((ds) => toExcelDataset(this.getters, ds))
7241
7378
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
7379
+ const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
7242
7380
  return {
7243
7381
  ...this.getDefinition(),
7244
7382
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
7245
7383
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
7246
7384
  dataSets,
7385
+ labelRange,
7247
7386
  };
7248
7387
  }
7249
7388
  copyForSheetId(sheetId) {
@@ -7381,6 +7520,11 @@
7381
7520
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
7382
7521
  let labels = axisType === "linear" ? labelValues.values : labelValues.formattedValues;
7383
7522
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
7523
+ if (chart.dataSetsHaveTitle &&
7524
+ dataSetsValues[0] &&
7525
+ labels.length > dataSetsValues[0].data.length) {
7526
+ labels.shift();
7527
+ }
7384
7528
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
7385
7529
  if (axisType === "time") {
7386
7530
  ({ labels, dataSetsValues } = fixEmptyLabelsForDateCharts(labels, dataSetsValues));
@@ -7439,6 +7583,7 @@
7439
7583
  this.background = definition.background;
7440
7584
  this.legendPosition = definition.legendPosition;
7441
7585
  this.aggregated = definition.aggregated;
7586
+ this.dataSetsHaveTitle = definition.dataSetsHaveTitle;
7442
7587
  }
7443
7588
  static transformDefinition(definition, executed) {
7444
7589
  return transformChartDefinitionWithDataSetsWithZone(definition, executed);
@@ -7502,12 +7647,14 @@
7502
7647
  const dataSets = this.dataSets
7503
7648
  .map((ds) => toExcelDataset(this.getters, ds))
7504
7649
  .filter((ds) => ds.range !== ""); // && range !== INCORRECT_RANGE_STRING ? show incorrect #ref ?
7650
+ const labelRange = toExcelLabelRange(this.getters, this.labelRange, shouldRemoveFirstLabel(this.labelRange, this.dataSets[0], this.dataSetsHaveTitle));
7505
7651
  return {
7506
7652
  ...this.getDefinition(),
7507
7653
  backgroundColor: toXlsxHexColor(this.background || BACKGROUND_CHART_COLOR),
7508
7654
  fontColor: toXlsxHexColor(chartFontColor(this.background)),
7509
7655
  verticalAxisPosition: "left",
7510
7656
  dataSets,
7657
+ labelRange,
7511
7658
  };
7512
7659
  }
7513
7660
  updateRanges(applyChange) {
@@ -7553,6 +7700,11 @@
7553
7700
  const labelValues = getChartLabelValues(getters, chart.dataSets, chart.labelRange);
7554
7701
  let labels = labelValues.formattedValues;
7555
7702
  let dataSetsValues = getChartDatasetValues(getters, chart.dataSets);
7703
+ if (chart.dataSetsHaveTitle &&
7704
+ dataSetsValues[0] &&
7705
+ labels.length > dataSetsValues[0].data.length) {
7706
+ labels.shift();
7707
+ }
7556
7708
  ({ labels, dataSetsValues } = filterEmptyDataPoints(labels, dataSetsValues));
7557
7709
  if (chart.aggregated) {
7558
7710
  ({ labels, dataSetsValues } = aggregateDataForLabels(labels, dataSetsValues));
@@ -7900,7 +8052,7 @@
7900
8052
  id: "edit",
7901
8053
  name: _lt("Edit"),
7902
8054
  sequence: 1,
7903
- action: () => {
8055
+ execute: () => {
7904
8056
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
7905
8057
  env.openSidePanel("ChartPanel");
7906
8058
  },
@@ -7909,7 +8061,7 @@
7909
8061
  getCutMenuItem(figureId, env),
7910
8062
  getDeleteMenuItem(figureId, onFigureDeleted, env),
7911
8063
  ];
7912
- return createMenu(menuItemSpecs);
8064
+ return createActions(menuItemSpecs);
7913
8065
  }
7914
8066
  function getImageMenuRegistry(figureId, onFigureDeleted, env) {
7915
8067
  const menuItemSpecs = [
@@ -7919,7 +8071,7 @@
7919
8071
  id: "reset_size",
7920
8072
  name: _lt("Reset size"),
7921
8073
  sequence: 4,
7922
- action: () => {
8074
+ execute: () => {
7923
8075
  const size = env.model.getters.getImageSize(figureId);
7924
8076
  const { height, width } = getMaxFigureSize(env.model.getters, size);
7925
8077
  env.model.dispatch("UPDATE_FIGURE", {
@@ -7932,7 +8084,7 @@
7932
8084
  },
7933
8085
  getDeleteMenuItem(figureId, onFigureDeleted, env),
7934
8086
  ];
7935
- return createMenu(menuItemSpecs);
8087
+ return createActions(menuItemSpecs);
7936
8088
  }
7937
8089
  function getCopyMenuItem(figureId, env) {
7938
8090
  return {
@@ -7940,7 +8092,7 @@
7940
8092
  name: _lt("Copy"),
7941
8093
  sequence: 2,
7942
8094
  description: "Ctrl+C",
7943
- action: async () => {
8095
+ execute: async () => {
7944
8096
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
7945
8097
  env.model.dispatch("COPY");
7946
8098
  await env.clipboard.write(env.model.getters.getClipboardContent());
@@ -7953,7 +8105,7 @@
7953
8105
  name: _lt("Cut"),
7954
8106
  sequence: 3,
7955
8107
  description: "Ctrl+X",
7956
- action: async () => {
8108
+ execute: async () => {
7957
8109
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
7958
8110
  env.model.dispatch("CUT");
7959
8111
  await env.clipboard.write(env.model.getters.getClipboardContent());
@@ -7965,7 +8117,7 @@
7965
8117
  id: "delete",
7966
8118
  name: _lt("Delete"),
7967
8119
  sequence: 10,
7968
- action: () => {
8120
+ execute: () => {
7969
8121
  env.model.dispatch("DELETE_FIGURE", {
7970
8122
  sheetId: env.model.getters.getActiveSheetId(),
7971
8123
  id: figureId,
@@ -8072,6 +8224,22 @@
8072
8224
  ];
8073
8225
  }
8074
8226
 
8227
+ const AddMergeInteractiveContent = {
8228
+ MergeIsDestructive: _lt("Merging these cells will only preserve the top-leftmost value. Merge anyway?"),
8229
+ MergeInFilter: _lt("You can't merge cells inside of an existing filter."),
8230
+ };
8231
+ function interactiveAddMerge(env, sheetId, target) {
8232
+ const result = env.model.dispatch("ADD_MERGE", { sheetId, target });
8233
+ if (result.isCancelledBecause(80 /* CommandResult.MergeInFilter */)) {
8234
+ env.raiseError(AddMergeInteractiveContent.MergeInFilter);
8235
+ }
8236
+ else if (result.isCancelledBecause(3 /* CommandResult.MergeIsDestructive */)) {
8237
+ env.askConfirmation(AddMergeInteractiveContent.MergeIsDestructive, () => {
8238
+ env.model.dispatch("ADD_MERGE", { sheetId, target, force: true });
8239
+ });
8240
+ }
8241
+ }
8242
+
8075
8243
  /**
8076
8244
  * Create a function used to create a Chart based on the definition
8077
8245
  */
@@ -8188,7 +8356,6 @@
8188
8356
  labelRangeXc = zoneToXc({
8189
8357
  ...zone,
8190
8358
  right: zone.left,
8191
- top: dataSetsHaveTitle ? zone.top + 1 : zone.top,
8192
8359
  });
8193
8360
  }
8194
8361
  // Only display legend for several datasets.
@@ -8428,9 +8595,9 @@
8428
8595
  interactiveCut(env);
8429
8596
  await env.clipboard.write(env.model.getters.getClipboardContent());
8430
8597
  };
8431
- const PASTE_ACTION = async (env) => paste(env);
8432
- const PASTE_VALUE_ACTION = async (env) => paste(env, "onlyValue");
8433
- async function paste(env, pasteOption) {
8598
+ const PASTE_ACTION = async (env) => paste$1(env);
8599
+ const PASTE_VALUE_ACTION = async (env) => paste$1(env, "onlyValue");
8600
+ async function paste$1(env, pasteOption) {
8434
8601
  const spreadsheetClipboard = env.model.getters.getClipboardTextContent();
8435
8602
  const osClipboard = await env.clipboard.readText();
8436
8603
  switch (osClipboard.status) {
@@ -8984,365 +9151,159 @@
8984
9151
  return env.model.getters.getSelectedZones().length === 1;
8985
9152
  };
8986
9153
 
8987
- //------------------------------------------------------------------------------
8988
- // Context Menu Registry
8989
- //------------------------------------------------------------------------------
8990
- const cellMenuRegistry = new MenuItemRegistry();
8991
- cellMenuRegistry
8992
- .add("cut", {
8993
- name: _lt("Cut"),
8994
- description: "Ctrl+X",
8995
- sequence: 10,
8996
- action: CUT_ACTION,
8997
- })
8998
- .add("copy", {
9154
+ const undo = {
9155
+ name: _lt("Undo"),
9156
+ description: "Ctrl+Z",
9157
+ execute: UNDO_ACTION,
9158
+ isEnabled: (env) => env.model.getters.canUndo(),
9159
+ icon: "o-spreadsheet-Icon.UNDO",
9160
+ };
9161
+ const redo = {
9162
+ name: _lt("Redo"),
9163
+ description: "Ctrl+Y",
9164
+ execute: REDO_ACTION,
9165
+ isEnabled: (env) => env.model.getters.canRedo(),
9166
+ icon: "o-spreadsheet-Icon.REDO",
9167
+ };
9168
+ const copy = {
8999
9169
  name: _lt("Copy"),
9000
9170
  description: "Ctrl+C",
9001
- sequence: 20,
9002
9171
  isReadonlyAllowed: true,
9003
- action: COPY_ACTION,
9004
- })
9005
- .add("paste", {
9006
- name: _lt("Paste"),
9007
- description: "Ctrl+V",
9008
- sequence: 30,
9009
- action: PASTE_ACTION,
9010
- })
9011
- .add("paste_special", {
9012
- name: _lt("Paste special"),
9013
- sequence: 40,
9014
- separator: true,
9015
- isVisible: IS_NOT_CUT_OPERATION,
9016
- })
9017
- .addChild("paste_value_only", ["paste_special"], {
9018
- name: _lt("Paste values only"),
9019
- sequence: 10,
9020
- action: PASTE_VALUE_ACTION,
9021
- })
9022
- .addChild("paste_format_only", ["paste_special"], {
9023
- name: _lt("Paste format only"),
9024
- sequence: 20,
9025
- action: PASTE_FORMAT_ACTION,
9026
- })
9027
- .add("add_row_before", {
9028
- name: CELL_INSERT_ROWS_BEFORE_NAME,
9029
- sequence: 70,
9030
- action: INSERT_ROWS_BEFORE_ACTION,
9031
- isVisible: IS_ONLY_ONE_RANGE,
9032
- })
9033
- .add("add_column_before", {
9034
- name: CELL_INSERT_COLUMNS_BEFORE_NAME,
9035
- sequence: 90,
9036
- action: INSERT_COLUMNS_BEFORE_ACTION,
9037
- isVisible: IS_ONLY_ONE_RANGE,
9038
- })
9039
- .add("insert_cell", {
9040
- name: _lt("Insert cells"),
9041
- sequence: 100,
9042
- isVisible: IS_ONLY_ONE_RANGE,
9043
- separator: true,
9044
- })
9045
- .addChild("insert_cell_down", ["insert_cell"], {
9046
- name: _lt("Shift down"),
9047
- sequence: 10,
9048
- action: INSERT_CELL_SHIFT_DOWN,
9049
- })
9050
- .addChild("insert_cell_right", ["insert_cell"], {
9051
- name: _lt("Shift right"),
9052
- sequence: 20,
9053
- action: INSERT_CELL_SHIFT_RIGHT,
9054
- })
9055
- .add("delete_row", {
9056
- name: REMOVE_ROWS_NAME,
9057
- sequence: 110,
9058
- action: REMOVE_ROWS_ACTION,
9059
- isVisible: IS_ONLY_ONE_RANGE,
9060
- })
9061
- .add("delete_column", {
9062
- name: REMOVE_COLUMNS_NAME,
9063
- sequence: 120,
9064
- action: REMOVE_COLUMNS_ACTION,
9065
- isVisible: IS_ONLY_ONE_RANGE,
9066
- })
9067
- .add("delete_cell", {
9068
- name: _lt("Delete cells"),
9069
- sequence: 130,
9070
- isVisible: IS_ONLY_ONE_RANGE,
9071
- })
9072
- .addChild("delete_cell_up", ["delete_cell"], {
9073
- name: _lt("Shift up"),
9074
- sequence: 10,
9075
- action: DELETE_CELL_SHIFT_UP,
9076
- })
9077
- .addChild("delete_cell_down", ["delete_cell"], {
9078
- name: _lt("Shift left"),
9079
- sequence: 20,
9080
- action: DELETE_CELL_SHIFT_LEFT,
9081
- })
9082
- .add("insert_link", {
9083
- name: _lt("Insert link"),
9084
- separator: true,
9085
- sequence: 150,
9086
- action: INSERT_LINK,
9087
- });
9088
-
9089
- const colMenuRegistry = new MenuItemRegistry();
9090
- colMenuRegistry
9091
- .add("cut", {
9172
+ execute: COPY_ACTION,
9173
+ };
9174
+ const cut = {
9092
9175
  name: _lt("Cut"),
9093
9176
  description: "Ctrl+X",
9094
- sequence: 10,
9095
- action: CUT_ACTION,
9096
- })
9097
- .add("copy", {
9098
- name: _lt("Copy"),
9099
- description: "Ctrl+C",
9100
- sequence: 20,
9101
- isReadonlyAllowed: true,
9102
- action: COPY_ACTION,
9103
- })
9104
- .add("paste", {
9177
+ execute: CUT_ACTION,
9178
+ };
9179
+ const paste = {
9105
9180
  name: _lt("Paste"),
9106
9181
  description: "Ctrl+V",
9107
- sequence: 30,
9108
- action: PASTE_ACTION,
9109
- })
9110
- .add("paste_special", {
9182
+ execute: PASTE_ACTION,
9183
+ };
9184
+ const pasteSpecial = {
9111
9185
  name: _lt("Paste special"),
9112
- sequence: 40,
9113
- separator: true,
9114
9186
  isVisible: IS_NOT_CUT_OPERATION,
9115
- })
9116
- .addChild("paste_value_only", ["paste_special"], {
9187
+ };
9188
+ const pasteSpecialValue = {
9117
9189
  name: _lt("Paste value only"),
9118
- sequence: 10,
9119
- action: PASTE_VALUE_ACTION,
9120
- })
9121
- .addChild("paste_format_only", ["paste_special"], {
9190
+ execute: PASTE_VALUE_ACTION,
9191
+ };
9192
+ const pasteSpecialFormat = {
9122
9193
  name: _lt("Paste format only"),
9123
- sequence: 20,
9124
- action: PASTE_FORMAT_ACTION,
9125
- })
9126
- .add("sort_columns", {
9127
- name: (env) => env.model.getters.getActiveCols().size > 1 ? _lt("Sort columns") : _lt("Sort column"),
9128
- sequence: 50,
9194
+ execute: PASTE_FORMAT_ACTION,
9195
+ };
9196
+ const findAndReplace = {
9197
+ name: _lt("Find and replace"),
9198
+ description: "Ctrl+H",
9199
+ isReadonlyAllowed: true,
9200
+ execute: OPEN_FAR_SIDEPANEL_ACTION,
9201
+ };
9202
+ const deleteValues = {
9203
+ name: _lt("Delete values"),
9204
+ execute: DELETE_CONTENT_ACTION,
9205
+ };
9206
+ const deleteRows = {
9207
+ name: REMOVE_ROWS_NAME,
9208
+ execute: REMOVE_ROWS_ACTION,
9209
+ };
9210
+ const deleteRow = {
9211
+ ...deleteRows,
9129
9212
  isVisible: IS_ONLY_ONE_RANGE,
9130
- separator: true,
9131
- })
9132
- .addChild("sort_ascending", ["sort_columns"], {
9133
- name: _lt("Ascending (A ⟶ Z)"),
9134
- sequence: 10,
9135
- action: SORT_CELLS_ASCENDING,
9136
- })
9137
- .addChild("sort_descending", ["sort_columns"], {
9138
- name: _lt("Descending (Z ⟶ A)"),
9139
- sequence: 20,
9140
- action: SORT_CELLS_DESCENDING,
9141
- })
9142
- .add("add_column_before", {
9143
- name: COLUMN_INSERT_COLUMNS_BEFORE_NAME,
9144
- sequence: 70,
9145
- action: INSERT_COLUMNS_BEFORE_ACTION,
9146
- })
9147
- .add("add_column_after", {
9148
- name: COLUMN_INSERT_COLUMNS_AFTER_NAME,
9149
- sequence: 80,
9150
- action: INSERT_COLUMNS_AFTER_ACTION,
9151
- })
9152
- .add("delete_column", {
9213
+ };
9214
+ const clearRows = {
9215
+ name: DELETE_CONTENT_ROWS_NAME,
9216
+ execute: DELETE_CONTENT_ROWS_ACTION,
9217
+ };
9218
+ const deleteCols = {
9153
9219
  name: REMOVE_COLUMNS_NAME,
9154
- sequence: 90,
9155
- action: REMOVE_COLUMNS_ACTION,
9156
- })
9157
- .add("clear_column", {
9220
+ execute: REMOVE_COLUMNS_ACTION,
9221
+ };
9222
+ const deleteCol = {
9223
+ ...deleteCols,
9224
+ isVisible: IS_ONLY_ONE_RANGE,
9225
+ };
9226
+ const clearCols = {
9158
9227
  name: DELETE_CONTENT_COLUMNS_NAME,
9159
- sequence: 100,
9160
- action: DELETE_CONTENT_COLUMNS_ACTION,
9161
- })
9162
- .add("hide_columns", {
9163
- name: HIDE_COLUMNS_NAME,
9164
- sequence: 85,
9165
- action: HIDE_COLUMNS_ACTION,
9166
- isVisible: (env) => {
9167
- const sheetId = env.model.getters.getActiveSheetId();
9168
- const hiddenCols = env.model.getters.getHiddenColsGroups(sheetId).flat();
9169
- return (env.model.getters.getNumberCols(sheetId) >
9170
- hiddenCols.length + env.model.getters.getElementsFromSelection("COL").length);
9171
- },
9172
- separator: true,
9173
- })
9174
- .add("unhide_columns", {
9175
- name: _lt("Unhide columns"),
9176
- sequence: 86,
9177
- action: UNHIDE_COLUMNS_ACTION,
9178
- isVisible: (env) => {
9179
- const hiddenCols = env.model.getters
9180
- .getHiddenColsGroups(env.model.getters.getActiveSheetId())
9181
- .flat();
9182
- const currentCols = env.model.getters.getElementsFromSelection("COL");
9183
- return currentCols.some((col) => hiddenCols.includes(col));
9184
- },
9185
- separator: true,
9186
- })
9187
- .add("conditional_formatting", {
9188
- name: _lt("Conditional formatting"),
9189
- sequence: 110,
9190
- action: OPEN_CF_SIDEPANEL_ACTION,
9191
- });
9228
+ execute: DELETE_CONTENT_COLUMNS_ACTION,
9229
+ };
9230
+ const deleteCells = {
9231
+ name: _lt("Delete cells"),
9232
+ isVisible: IS_ONLY_ONE_RANGE,
9233
+ };
9234
+ const deleteCellShiftUp = {
9235
+ name: _lt("Delete cell and shift up"),
9236
+ execute: DELETE_CELL_SHIFT_UP,
9237
+ };
9238
+ const deleteCellShiftLeft = {
9239
+ name: _lt("Delete cell and shift left"),
9240
+ execute: DELETE_CELL_SHIFT_LEFT,
9241
+ };
9242
+ const mergeCells = {
9243
+ name: _lt("Merge cells"),
9244
+ isEnabled: (env) => !cannotMerge(env),
9245
+ isActive: (env) => isInMerge(env),
9246
+ execute: (env) => toggleMerge(env),
9247
+ icon: "o-spreadsheet-Icon.MERGE_CELL",
9248
+ };
9249
+ function cannotMerge(env) {
9250
+ const zones = env.model.getters.getSelectedZones();
9251
+ const { top, left, right, bottom } = env.model.getters.getSelectedZone();
9252
+ const { sheetId } = env.model.getters.getActivePosition();
9253
+ const { xSplit, ySplit } = env.model.getters.getPaneDivisions(sheetId);
9254
+ return (zones.length > 1 ||
9255
+ (top === bottom && left === right) ||
9256
+ (left < xSplit && xSplit <= right) ||
9257
+ (top < ySplit && ySplit <= bottom));
9258
+ }
9259
+ function isInMerge(env) {
9260
+ if (!cannotMerge(env)) {
9261
+ const zones = env.model.getters.getSelectedZones();
9262
+ const { col, row, sheetId } = env.model.getters.getActivePosition();
9263
+ const zone = env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
9264
+ return isEqual(zones[0], zone);
9265
+ }
9266
+ return false;
9267
+ }
9268
+ function toggleMerge(env) {
9269
+ if (cannotMerge(env)) {
9270
+ return;
9271
+ }
9272
+ const zones = env.model.getters.getSelectedZones();
9273
+ const target = [zones[zones.length - 1]];
9274
+ const sheetId = env.model.getters.getActiveSheetId();
9275
+ if (isInMerge(env)) {
9276
+ env.model.dispatch("REMOVE_MERGE", { sheetId, target });
9277
+ }
9278
+ else {
9279
+ interactiveAddMerge(env, sheetId, target);
9280
+ }
9281
+ }
9192
9282
 
9193
- const rowMenuRegistry = new MenuItemRegistry();
9194
- rowMenuRegistry
9195
- .add("cut", {
9196
- name: _lt("Cut"),
9197
- sequence: 10,
9198
- description: "Ctrl+X",
9199
- action: CUT_ACTION,
9200
- })
9201
- .add("copy", {
9202
- name: _lt("Copy"),
9203
- description: "Ctrl+C",
9204
- sequence: 20,
9205
- isReadonlyAllowed: true,
9206
- action: COPY_ACTION,
9207
- })
9208
- .add("paste", {
9209
- name: _lt("Paste"),
9210
- description: "Ctrl+V",
9211
- sequence: 30,
9212
- action: PASTE_ACTION,
9213
- })
9214
- .add("paste_special", {
9215
- name: _lt("Paste special"),
9216
- sequence: 40,
9217
- separator: true,
9218
- isVisible: IS_NOT_CUT_OPERATION,
9219
- })
9220
- .addChild("paste_value_only", ["paste_special"], {
9221
- name: _lt("Paste value only"),
9222
- sequence: 10,
9223
- action: PASTE_VALUE_ACTION,
9224
- })
9225
- .addChild("paste_format_only", ["paste_special"], {
9226
- name: _lt("Paste format only"),
9227
- sequence: 20,
9228
- action: PASTE_FORMAT_ACTION,
9229
- })
9230
- .add("add_row_before", {
9231
- name: ROW_INSERT_ROWS_BEFORE_NAME,
9232
- sequence: 50,
9233
- action: INSERT_ROWS_BEFORE_ACTION,
9234
- })
9235
- .add("add_row_after", {
9236
- name: ROW_INSERT_ROWS_AFTER_NAME,
9237
- sequence: 60,
9238
- action: INSERT_ROWS_AFTER_ACTION,
9239
- })
9240
- .add("delete_row", {
9241
- name: REMOVE_ROWS_NAME,
9242
- sequence: 70,
9243
- action: REMOVE_ROWS_ACTION,
9244
- })
9245
- .add("clear_row", {
9246
- name: DELETE_CONTENT_ROWS_NAME,
9247
- sequence: 80,
9248
- action: DELETE_CONTENT_ROWS_ACTION,
9249
- })
9250
- .add("hide_rows", {
9251
- name: HIDE_ROWS_NAME,
9252
- sequence: 85,
9253
- action: HIDE_ROWS_ACTION,
9254
- isVisible: (env) => {
9255
- const sheetId = env.model.getters.getActiveSheetId();
9256
- const hiddenRows = env.model.getters.getHiddenRowsGroups(sheetId).flat();
9257
- return (env.model.getters.getNumberRows(sheetId) >
9258
- hiddenRows.length + env.model.getters.getElementsFromSelection("ROW").length);
9259
- },
9260
- separator: true,
9261
- })
9262
- .add("unhide_rows", {
9263
- name: _lt("Unhide rows"),
9264
- sequence: 86,
9265
- action: UNHIDE_ROWS_ACTION,
9266
- isVisible: (env) => {
9267
- const hiddenRows = env.model.getters
9268
- .getHiddenRowsGroups(env.model.getters.getActiveSheetId())
9269
- .flat();
9270
- const currentRows = env.model.getters.getElementsFromSelection("ROW");
9271
- return currentRows.some((col) => hiddenRows.includes(col));
9272
- },
9273
- separator: true,
9274
- })
9275
- .add("conditional_formatting", {
9276
- name: _lt("Conditional formatting"),
9277
- sequence: 90,
9278
- action: OPEN_CF_SIDEPANEL_ACTION,
9283
+ var ACTION_EDIT = /*#__PURE__*/Object.freeze({
9284
+ __proto__: null,
9285
+ undo: undo,
9286
+ redo: redo,
9287
+ copy: copy,
9288
+ cut: cut,
9289
+ paste: paste,
9290
+ pasteSpecial: pasteSpecial,
9291
+ pasteSpecialValue: pasteSpecialValue,
9292
+ pasteSpecialFormat: pasteSpecialFormat,
9293
+ findAndReplace: findAndReplace,
9294
+ deleteValues: deleteValues,
9295
+ deleteRows: deleteRows,
9296
+ deleteRow: deleteRow,
9297
+ clearRows: clearRows,
9298
+ deleteCols: deleteCols,
9299
+ deleteCol: deleteCol,
9300
+ clearCols: clearCols,
9301
+ deleteCells: deleteCells,
9302
+ deleteCellShiftUp: deleteCellShiftUp,
9303
+ deleteCellShiftLeft: deleteCellShiftLeft,
9304
+ mergeCells: mergeCells
9279
9305
  });
9280
9306
 
9281
- function getSheetMenuRegistry(args) {
9282
- const sheetMenuRegistry = new MenuItemRegistry();
9283
- sheetMenuRegistry
9284
- .add("delete", {
9285
- name: _lt("Delete"),
9286
- sequence: 10,
9287
- isVisible: (env) => {
9288
- return env.model.getters.getSheetIds().length > 1;
9289
- },
9290
- action: (env) => env.askConfirmation(_lt("Are you sure you want to delete this sheet ?"), () => {
9291
- env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
9292
- }),
9293
- })
9294
- .add("duplicate", {
9295
- name: _lt("Duplicate"),
9296
- sequence: 20,
9297
- action: (env) => {
9298
- const sheetIdFrom = env.model.getters.getActiveSheetId();
9299
- const sheetIdTo = env.model.uuidGenerator.uuidv4();
9300
- env.model.dispatch("DUPLICATE_SHEET", {
9301
- sheetId: sheetIdFrom,
9302
- sheetIdTo,
9303
- });
9304
- env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
9305
- },
9306
- })
9307
- .add("rename", {
9308
- name: _lt("Rename"),
9309
- sequence: 30,
9310
- action: () => args.renameSheetCallback(),
9311
- })
9312
- .add("move_right", {
9313
- name: _lt("Move right"),
9314
- sequence: 40,
9315
- isVisible: (env) => {
9316
- const sheetId = env.model.getters.getActiveSheetId();
9317
- const sheetIds = env.model.getters.getVisibleSheetIds();
9318
- return sheetIds.indexOf(sheetId) !== sheetIds.length - 1;
9319
- },
9320
- action: (env) => env.model.dispatch("MOVE_SHEET", {
9321
- sheetId: env.model.getters.getActiveSheetId(),
9322
- delta: 1,
9323
- }),
9324
- })
9325
- .add("move_left", {
9326
- name: _lt("Move left"),
9327
- sequence: 50,
9328
- isVisible: (env) => {
9329
- const sheetId = env.model.getters.getActiveSheetId();
9330
- return env.model.getters.getVisibleSheetIds()[0] !== sheetId;
9331
- },
9332
- action: (env) => env.model.dispatch("MOVE_SHEET", {
9333
- sheetId: env.model.getters.getActiveSheetId(),
9334
- delta: -1,
9335
- }),
9336
- })
9337
- .add("hide_sheet", {
9338
- name: _lt("Hide sheet"),
9339
- sequence: 60,
9340
- isVisible: (env) => env.model.getters.getVisibleSheetIds().length !== 1,
9341
- action: (env) => env.model.dispatch("HIDE_SHEET", { sheetId: env.model.getters.getActiveSheetId() }),
9342
- });
9343
- return sheetMenuRegistry;
9344
- }
9345
-
9346
9307
  //------------------------------------------------------------------------------
9347
9308
  // Arg description DSL
9348
9309
  //------------------------------------------------------------------------------
@@ -15106,7 +15067,7 @@
15106
15067
  cellReference = rowPart + colPart;
15107
15068
  }
15108
15069
  if (sheet !== undefined) {
15109
- return `${getComposerSheetName(toString(sheet))}!${cellReference}`;
15070
+ return `${getCanonicalSheetName(toString(sheet))}!${cellReference}`;
15110
15071
  }
15111
15072
  return cellReference;
15112
15073
  },
@@ -16103,6 +16064,593 @@
16103
16064
  }
16104
16065
  }
16105
16066
 
16067
+ const rowInsertRowBefore = {
16068
+ name: ROW_INSERT_ROWS_BEFORE_NAME,
16069
+ execute: INSERT_ROWS_BEFORE_ACTION,
16070
+ };
16071
+ const topBarInsertRowsBefore = {
16072
+ ...rowInsertRowBefore,
16073
+ name: MENU_INSERT_ROWS_BEFORE_NAME,
16074
+ isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16075
+ };
16076
+ const cellInsertRowsBefore = {
16077
+ ...rowInsertRowBefore,
16078
+ name: CELL_INSERT_ROWS_BEFORE_NAME,
16079
+ isVisible: IS_ONLY_ONE_RANGE,
16080
+ };
16081
+ const rowInsertRowsAfter = {
16082
+ execute: INSERT_ROWS_AFTER_ACTION,
16083
+ name: ROW_INSERT_ROWS_AFTER_NAME,
16084
+ };
16085
+ const topBarInsertRowsAfter = {
16086
+ ...rowInsertRowsAfter,
16087
+ name: MENU_INSERT_ROWS_AFTER_NAME,
16088
+ isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16089
+ };
16090
+ const colInsertColsBefore = {
16091
+ name: COLUMN_INSERT_COLUMNS_BEFORE_NAME,
16092
+ execute: INSERT_COLUMNS_BEFORE_ACTION,
16093
+ };
16094
+ const topBarInsertColsBefore = {
16095
+ ...colInsertColsBefore,
16096
+ name: MENU_INSERT_COLUMNS_BEFORE_NAME,
16097
+ isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16098
+ };
16099
+ const cellInsertColsBefore = {
16100
+ ...colInsertColsBefore,
16101
+ name: CELL_INSERT_COLUMNS_BEFORE_NAME,
16102
+ isVisible: IS_ONLY_ONE_RANGE,
16103
+ };
16104
+ const colInsertColsAfter = {
16105
+ name: COLUMN_INSERT_COLUMNS_AFTER_NAME,
16106
+ execute: INSERT_COLUMNS_AFTER_ACTION,
16107
+ };
16108
+ const topBarInsertColsAfter = {
16109
+ ...colInsertColsAfter,
16110
+ name: MENU_INSERT_COLUMNS_AFTER_NAME,
16111
+ execute: INSERT_COLUMNS_AFTER_ACTION,
16112
+ isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16113
+ };
16114
+ const insertCell = {
16115
+ name: _lt("Insert cells"),
16116
+ isVisible: IS_ONLY_ONE_RANGE,
16117
+ };
16118
+ const insertCellShiftDown = {
16119
+ name: _lt("Insert cells and shift down"),
16120
+ execute: INSERT_CELL_SHIFT_DOWN,
16121
+ };
16122
+ const insertCellShiftRight = {
16123
+ name: _lt("Insert cells and shift right"),
16124
+ execute: INSERT_CELL_SHIFT_RIGHT,
16125
+ };
16126
+ const insertChart = {
16127
+ name: _lt("Chart"),
16128
+ execute: CREATE_CHART,
16129
+ };
16130
+ const insertImage = {
16131
+ name: _lt("Image"),
16132
+ execute: CREATE_IMAGE,
16133
+ isVisible: (env) => env.imageProvider !== undefined,
16134
+ };
16135
+ const insertFunction = {
16136
+ name: _lt("Function"),
16137
+ };
16138
+ const insertFunctionSum = {
16139
+ name: _lt("SUM"),
16140
+ execute: (env) => env.startCellEdition(`=SUM(`),
16141
+ };
16142
+ const insertFunctionAverage = {
16143
+ name: _lt("AVERAGE"),
16144
+ execute: (env) => env.startCellEdition(`=AVERAGE(`),
16145
+ };
16146
+ const insertFunctionCount = {
16147
+ name: _lt("COUNT"),
16148
+ execute: (env) => env.startCellEdition(`=COUNT(`),
16149
+ };
16150
+ const insertFunctionMax = {
16151
+ name: _lt("MAX"),
16152
+ execute: (env) => env.startCellEdition(`=MAX(`),
16153
+ };
16154
+ const insertFunctionMin = {
16155
+ name: _lt("MIN"),
16156
+ execute: (env) => env.startCellEdition(`=MIN(`),
16157
+ };
16158
+ const categorieFunctionAll = {
16159
+ name: _lt("All"),
16160
+ children: allFunctionListMenuBuilder(),
16161
+ };
16162
+ function allFunctionListMenuBuilder() {
16163
+ const fnNames = functionRegistry.getKeys();
16164
+ return createFormulaFunctions(fnNames);
16165
+ }
16166
+ const categoriesFunctionListMenuBuilder = () => {
16167
+ const functions = functionRegistry.content;
16168
+ const categories = [...new Set(functionRegistry.getAll().map((fn) => fn.category))].filter(isDefined$1);
16169
+ return categories.sort().map((category, i) => {
16170
+ const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
16171
+ return {
16172
+ name: category,
16173
+ children: createFormulaFunctions(functionsInCategory),
16174
+ };
16175
+ });
16176
+ };
16177
+ const insertLink = {
16178
+ name: _lt("Link"),
16179
+ execute: INSERT_LINK,
16180
+ };
16181
+ const insertSheet = {
16182
+ name: _lt("New sheet"),
16183
+ execute: CREATE_SHEET_ACTION,
16184
+ };
16185
+ function createFormulaFunctions(fnNames) {
16186
+ return fnNames.sort().map((fnName, i) => {
16187
+ return {
16188
+ name: fnName,
16189
+ sequence: i * 10,
16190
+ execute: (env) => env.startCellEdition(`=${fnName}(`),
16191
+ };
16192
+ });
16193
+ }
16194
+
16195
+ //------------------------------------------------------------------------------
16196
+ // Context Menu Registry
16197
+ //------------------------------------------------------------------------------
16198
+ const cellMenuRegistry = new MenuItemRegistry();
16199
+ cellMenuRegistry
16200
+ .add("cut", {
16201
+ ...cut,
16202
+ sequence: 10,
16203
+ })
16204
+ .add("copy", {
16205
+ ...copy,
16206
+ sequence: 20,
16207
+ })
16208
+ .add("paste", {
16209
+ ...paste,
16210
+ sequence: 30,
16211
+ })
16212
+ .add("paste_special", {
16213
+ ...pasteSpecial,
16214
+ sequence: 40,
16215
+ separator: true,
16216
+ })
16217
+ .addChild("paste_value_only", ["paste_special"], {
16218
+ ...pasteSpecialValue,
16219
+ sequence: 10,
16220
+ })
16221
+ .addChild("paste_format_only", ["paste_special"], {
16222
+ ...pasteSpecialFormat,
16223
+ sequence: 20,
16224
+ })
16225
+ .add("add_row_before", {
16226
+ ...cellInsertRowsBefore,
16227
+ sequence: 70,
16228
+ })
16229
+ .add("add_column_before", {
16230
+ ...cellInsertColsBefore,
16231
+ sequence: 90,
16232
+ })
16233
+ .add("insert_cell", {
16234
+ ...insertCell,
16235
+ sequence: 100,
16236
+ separator: true,
16237
+ })
16238
+ .addChild("insert_cell_down", ["insert_cell"], {
16239
+ ...insertCellShiftDown,
16240
+ name: _lt("Shift down"),
16241
+ sequence: 10,
16242
+ })
16243
+ .addChild("insert_cell_right", ["insert_cell"], {
16244
+ ...insertCellShiftRight,
16245
+ name: _lt("Shift right"),
16246
+ sequence: 20,
16247
+ })
16248
+ .add("delete_row", {
16249
+ ...deleteRow,
16250
+ sequence: 110,
16251
+ })
16252
+ .add("delete_column", {
16253
+ ...deleteCol,
16254
+ sequence: 120,
16255
+ })
16256
+ .add("delete_cell", {
16257
+ ...deleteCells,
16258
+ sequence: 130,
16259
+ })
16260
+ .addChild("delete_cell_up", ["delete_cell"], {
16261
+ ...deleteCellShiftUp,
16262
+ name: _lt("Shift up"),
16263
+ sequence: 10,
16264
+ })
16265
+ .addChild("delete_cell_left", ["delete_cell"], {
16266
+ ...deleteCellShiftLeft,
16267
+ name: _lt("Shift left"),
16268
+ sequence: 20,
16269
+ })
16270
+ .add("insert_link", {
16271
+ ...insertLink,
16272
+ name: _lt("Insert link"),
16273
+ sequence: 150,
16274
+ separator: true,
16275
+ });
16276
+
16277
+ const sortRange = {
16278
+ name: _lt("Sort range"),
16279
+ isVisible: IS_ONLY_ONE_RANGE,
16280
+ };
16281
+ const sortAscending = {
16282
+ name: _lt("Ascending (A ⟶ Z)"),
16283
+ execute: SORT_CELLS_ASCENDING,
16284
+ };
16285
+ const sortDescending = {
16286
+ name: _lt("Descending (Z ⟶ A)"),
16287
+ execute: SORT_CELLS_DESCENDING,
16288
+ };
16289
+ const addDataFilter = {
16290
+ name: _lt("Create filter"),
16291
+ execute: FILTERS_CREATE_FILTER_TABLE,
16292
+ isVisible: (env) => !SELECTION_CONTAINS_FILTER(env),
16293
+ isEnabled: (env) => SELECTION_IS_CONTINUOUS(env),
16294
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16295
+ };
16296
+ const removeDataFilter = {
16297
+ name: _lt("Remove filter"),
16298
+ execute: FILTERS_REMOVE_FILTER_TABLE,
16299
+ isVisible: SELECTION_CONTAINS_FILTER,
16300
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16301
+ };
16302
+
16303
+ const formatNumberAutomatic = {
16304
+ name: _lt("Automatic"),
16305
+ execute: FORMAT_AUTOMATIC_ACTION,
16306
+ isActive: (env) => isAutomaticFormatSelected(env),
16307
+ };
16308
+ const formatNumberNumber = {
16309
+ name: _lt("Number"),
16310
+ description: "1,000.12",
16311
+ execute: FORMAT_NUMBER_ACTION,
16312
+ isActive: (env) => isFormatSelected(env, "#,##0.00"),
16313
+ };
16314
+ const formatPercent = {
16315
+ name: _lt("Format as percent"),
16316
+ execute: FORMAT_PERCENT_ACTION,
16317
+ icon: "o-spreadsheet-Icon.PERCENT",
16318
+ };
16319
+ const formatNumberPercent = {
16320
+ name: _lt("Percent"),
16321
+ description: "10.12%",
16322
+ execute: FORMAT_PERCENT_ACTION,
16323
+ isActive: (env) => isFormatSelected(env, "0.00%"),
16324
+ };
16325
+ const formatNumberCurrency = {
16326
+ name: _lt("Currency"),
16327
+ description: "$1,000.12",
16328
+ execute: FORMAT_CURRENCY_ACTION,
16329
+ isActive: (env) => isFormatSelected(env, "[$$]#,##0.00"),
16330
+ };
16331
+ const formatNumberCurrencyRounded = {
16332
+ name: _lt("Currency rounded"),
16333
+ description: "$1,000",
16334
+ execute: FORMAT_CURRENCY_ROUNDED_ACTION,
16335
+ isActive: (env) => isFormatSelected(env, "[$$]#,##0"),
16336
+ };
16337
+ const formatCustomCurrency = {
16338
+ name: _lt("Custom currency"),
16339
+ isVisible: (env) => env.loadCurrencies !== undefined,
16340
+ execute: OPEN_CUSTOM_CURRENCY_SIDEPANEL_ACTION,
16341
+ };
16342
+ const formatNumberDate = {
16343
+ name: _lt("Date"),
16344
+ description: "9/26/2008",
16345
+ execute: FORMAT_DATE_ACTION,
16346
+ isActive: (env) => isFormatSelected(env, "m/d/yyyy"),
16347
+ };
16348
+ const formatNumberTime = {
16349
+ name: _lt("Time"),
16350
+ description: "10:43:00 PM",
16351
+ execute: FORMAT_TIME_ACTION,
16352
+ isActive: (env) => isFormatSelected(env, "hh:mm:ss a"),
16353
+ };
16354
+ const formatNumberDateTime = {
16355
+ name: _lt("Date time"),
16356
+ description: "9/26/2008 22:43:00",
16357
+ execute: FORMAT_DATE_TIME_ACTION,
16358
+ isActive: (env) => isFormatSelected(env, "m/d/yyyy hh:mm:ss"),
16359
+ };
16360
+ const formatNumberDuration = {
16361
+ name: _lt("Duration"),
16362
+ description: "27:51:38",
16363
+ execute: FORMAT_DURATION_ACTION,
16364
+ isActive: (env) => isFormatSelected(env, "hhhh:mm:ss"),
16365
+ };
16366
+ const incraseDecimalPlaces = {
16367
+ name: _lt("Increase decimal places"),
16368
+ icon: "o-spreadsheet-Icon.INCREASE_DECIMAL",
16369
+ execute: (env) => env.model.dispatch("SET_DECIMAL", {
16370
+ sheetId: env.model.getters.getActiveSheetId(),
16371
+ target: env.model.getters.getSelectedZones(),
16372
+ step: 1,
16373
+ }),
16374
+ };
16375
+ const decraseDecimalPlaces = {
16376
+ name: _lt("Decrease decimal places"),
16377
+ icon: "o-spreadsheet-Icon.DECRASE_DECIMAL",
16378
+ execute: (env) => env.model.dispatch("SET_DECIMAL", {
16379
+ sheetId: env.model.getters.getActiveSheetId(),
16380
+ target: env.model.getters.getSelectedZones(),
16381
+ step: -1,
16382
+ }),
16383
+ };
16384
+ const formatBold = {
16385
+ name: _lt("Bold"),
16386
+ description: "Ctrl+B",
16387
+ execute: FORMAT_BOLD_ACTION,
16388
+ icon: "o-spreadsheet-Icon.BOLD",
16389
+ isActive: (env) => !!env.model.getters.getCurrentStyle().bold,
16390
+ };
16391
+ const formatItalic = {
16392
+ name: _lt("Italic"),
16393
+ description: "Ctrl+I",
16394
+ execute: FORMAT_ITALIC_ACTION,
16395
+ icon: "o-spreadsheet-Icon.ITALIC",
16396
+ isActive: (env) => !!env.model.getters.getCurrentStyle().italic,
16397
+ };
16398
+ const formatUnderline = {
16399
+ name: _lt("Underline"),
16400
+ description: "Ctrl+U",
16401
+ execute: FORMAT_UNDERLINE_ACTION,
16402
+ icon: "o-spreadsheet-Icon.UNDERLINE",
16403
+ isActive: (env) => !!env.model.getters.getCurrentStyle().underline,
16404
+ };
16405
+ const formatStrikethrough = {
16406
+ name: _lt("Strikethrough"),
16407
+ execute: FORMAT_STRIKETHROUGH_ACTION,
16408
+ icon: "o-spreadsheet-Icon.STRIKE",
16409
+ isActive: (env) => !!env.model.getters.getCurrentStyle().strikethrough,
16410
+ };
16411
+ const formatFontSize = {
16412
+ name: _lt("Font size"),
16413
+ children: fontSizeMenuBuilder(),
16414
+ };
16415
+ const formatAlignment = {
16416
+ name: _lt("Alignment"),
16417
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16418
+ };
16419
+ const formatAlignmentHorizontal = {
16420
+ name: _lt("Horizontal align"),
16421
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16422
+ };
16423
+ const formatAlignmentLeft = {
16424
+ name: _lt("Left"),
16425
+ execute: (env) => setStyle(env, { align: "left" }),
16426
+ isActive: (env) => getHorizontalAlign(env) === "left",
16427
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16428
+ };
16429
+ const formatAlignmentCenter = {
16430
+ name: _lt("Center"),
16431
+ execute: (env) => setStyle(env, { align: "center" }),
16432
+ isActive: (env) => getHorizontalAlign(env) === "center",
16433
+ icon: "o-spreadsheet-Icon.ALIGN_CENTER",
16434
+ };
16435
+ const formatAlignmentRight = {
16436
+ name: _lt("Right"),
16437
+ execute: (env) => setStyle(env, { align: "right" }),
16438
+ isActive: (env) => getHorizontalAlign(env) === "right",
16439
+ icon: "o-spreadsheet-Icon.ALIGN_RIGHT",
16440
+ };
16441
+ const formatAlignmentVertical = {
16442
+ name: _lt("Vertical align"),
16443
+ icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
16444
+ };
16445
+ const formatAlignmentTop = {
16446
+ name: _lt("Top"),
16447
+ execute: (env) => setStyle(env, { verticalAlign: "top" }),
16448
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "top",
16449
+ icon: "o-spreadsheet-Icon.ALIGN_TOP",
16450
+ };
16451
+ const formatAlignmentMiddle = {
16452
+ name: _lt("Middle"),
16453
+ execute: (env) => setStyle(env, { verticalAlign: "middle" }),
16454
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "middle",
16455
+ icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
16456
+ };
16457
+ const formatAlignmentBottom = {
16458
+ name: _lt("Bottom"),
16459
+ execute: (env) => setStyle(env, { verticalAlign: "bottom" }),
16460
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "bottom",
16461
+ icon: "o-spreadsheet-Icon.ALIGN_BOTTOM",
16462
+ };
16463
+ const formatWrapping = {
16464
+ name: _lt("Wrapping"),
16465
+ icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
16466
+ };
16467
+ const formatWrappingOverflow = {
16468
+ name: _lt("Overflow"),
16469
+ execute: (env) => setStyle(env, { wrapping: "overflow" }),
16470
+ isActive: (env) => (env.model.getters.getCurrentStyle().wrapping || "overflow") === "overflow",
16471
+ icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
16472
+ };
16473
+ const formatWrappingWrap = {
16474
+ name: _lt("Wrap"),
16475
+ execute: (env) => setStyle(env, { wrapping: "wrap" }),
16476
+ isActive: (env) => env.model.getters.getCurrentStyle().wrapping === "wrap",
16477
+ icon: "o-spreadsheet-Icon.WRAPPING_WRAP",
16478
+ };
16479
+ const formatWrappingClip = {
16480
+ name: _lt("Clip"),
16481
+ execute: (env) => setStyle(env, { wrapping: "clip" }),
16482
+ isActive: (env) => env.model.getters.getCurrentStyle().wrapping === "clip",
16483
+ icon: "o-spreadsheet-Icon.WRAPPING_CLIP",
16484
+ };
16485
+ const textColor = {
16486
+ name: _lt("Text Color"),
16487
+ icon: "o-spreadsheet-Icon.TEXT_COLOR",
16488
+ };
16489
+ const fillColor = {
16490
+ name: _lt("Fill Color"),
16491
+ icon: "o-spreadsheet-Icon.FILL_COLOR",
16492
+ };
16493
+ const formatCF = {
16494
+ name: _lt("Conditional formatting"),
16495
+ execute: OPEN_CF_SIDEPANEL_ACTION,
16496
+ };
16497
+ const paintFormat = {
16498
+ name: _lt("Paint Format"),
16499
+ execute: (env) => env.model.dispatch("ACTIVATE_PAINT_FORMAT", {
16500
+ target: env.model.getters.getSelectedZones(),
16501
+ }),
16502
+ icon: "o-spreadsheet-Icon.PAINT_FORMAT",
16503
+ isActive: (env) => env.model.getters.isPaintingFormat(),
16504
+ };
16505
+ const clearFormat = {
16506
+ name: _lt("Clear formatting"),
16507
+ execute: FORMAT_CLEARFORMAT_ACTION,
16508
+ icon: "o-spreadsheet-Icon.CLEAR_FORMAT",
16509
+ };
16510
+ const borders = {
16511
+ name: _lt("Borders"),
16512
+ icon: "o-spreadsheet-Icon.BORDERS",
16513
+ };
16514
+ const bordersAll = {
16515
+ name: _lt("All borders"),
16516
+ execute: (env) => setBorder(env, "all"),
16517
+ icon: "o-spreadsheet-Icon.BORDERS",
16518
+ };
16519
+ const bordersInner = {
16520
+ name: _lt("Inner borders"),
16521
+ execute: (env) => setBorder(env, "hv"),
16522
+ icon: "o-spreadsheet-Icon.BORDER_HV",
16523
+ };
16524
+ const bordersHorizontal = {
16525
+ name: _lt("Horizontal borders"),
16526
+ execute: (env) => setBorder(env, "h"),
16527
+ icon: "o-spreadsheet-Icon.BORDER_H",
16528
+ };
16529
+ const bordersVertical = {
16530
+ name: _lt("Vertical borders"),
16531
+ execute: (env) => setBorder(env, "v"),
16532
+ icon: "o-spreadsheet-Icon.BORDER_V",
16533
+ };
16534
+ const bordersExternal = {
16535
+ name: _lt("External borders"),
16536
+ execute: (env) => setBorder(env, "external"),
16537
+ icon: "o-spreadsheet-Icon.BORDER_EXTERNAL",
16538
+ };
16539
+ const bordersLeft = {
16540
+ name: _lt("Left borders"),
16541
+ execute: (env) => setBorder(env, "left"),
16542
+ icon: "o-spreadsheet-Icon.BORDER_LEFT",
16543
+ };
16544
+ const bordersTop = {
16545
+ name: _lt("Top borders"),
16546
+ execute: (env) => setBorder(env, "top"),
16547
+ icon: "o-spreadsheet-Icon.BORDER_TOP",
16548
+ };
16549
+ const bordersRight = {
16550
+ name: _lt("Right borders"),
16551
+ execute: (env) => setBorder(env, "right"),
16552
+ icon: "o-spreadsheet-Icon.BORDER_RIGHT",
16553
+ };
16554
+ const bordersBottom = {
16555
+ name: _lt("Bottom borders"),
16556
+ execute: (env) => setBorder(env, "bottom"),
16557
+ icon: "o-spreadsheet-Icon.BORDER_BOTTOM",
16558
+ };
16559
+ const bordersClear = {
16560
+ name: _lt("Clear borders"),
16561
+ execute: (env) => setBorder(env, "clear"),
16562
+ icon: "o-spreadsheet-Icon.BORDER_CLEAR",
16563
+ };
16564
+ function fontSizeMenuBuilder() {
16565
+ return FONT_SIZES.map((fs) => {
16566
+ return {
16567
+ name: fs.toString(),
16568
+ sequence: fs,
16569
+ id: `font_size_${fs}`,
16570
+ execute: (env) => setStyle(env, { fontSize: fs }),
16571
+ isActive: (env) => isFontSizeSelected(env, fs),
16572
+ };
16573
+ });
16574
+ }
16575
+ function isAutomaticFormatSelected(env) {
16576
+ const activeCell = env.model.getters.getActiveCell();
16577
+ return !activeCell || !activeCell.format;
16578
+ }
16579
+ function isFormatSelected(env, format) {
16580
+ const activeCell = env.model.getters.getActiveCell();
16581
+ return activeCell && activeCell.format === format;
16582
+ }
16583
+ function isFontSizeSelected(env, fontSize) {
16584
+ const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
16585
+ return currentFontSize === fontSize;
16586
+ }
16587
+ function setBorder(env, command) {
16588
+ env.model.dispatch("SET_FORMATTING", {
16589
+ sheetId: env.model.getters.getActiveSheetId(),
16590
+ target: env.model.getters.getSelectedZones(),
16591
+ border: command,
16592
+ });
16593
+ }
16594
+ function getHorizontalAlign(env) {
16595
+ const style = env.model.getters.getCurrentStyle();
16596
+ if (style.align) {
16597
+ return style.align;
16598
+ }
16599
+ const cell = env.model.getters.getActiveCell();
16600
+ return cell.defaultAlign;
16601
+ }
16602
+
16603
+ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
16604
+ __proto__: null,
16605
+ formatNumberAutomatic: formatNumberAutomatic,
16606
+ formatNumberNumber: formatNumberNumber,
16607
+ formatPercent: formatPercent,
16608
+ formatNumberPercent: formatNumberPercent,
16609
+ formatNumberCurrency: formatNumberCurrency,
16610
+ formatNumberCurrencyRounded: formatNumberCurrencyRounded,
16611
+ formatCustomCurrency: formatCustomCurrency,
16612
+ formatNumberDate: formatNumberDate,
16613
+ formatNumberTime: formatNumberTime,
16614
+ formatNumberDateTime: formatNumberDateTime,
16615
+ formatNumberDuration: formatNumberDuration,
16616
+ incraseDecimalPlaces: incraseDecimalPlaces,
16617
+ decraseDecimalPlaces: decraseDecimalPlaces,
16618
+ formatBold: formatBold,
16619
+ formatItalic: formatItalic,
16620
+ formatUnderline: formatUnderline,
16621
+ formatStrikethrough: formatStrikethrough,
16622
+ formatFontSize: formatFontSize,
16623
+ formatAlignment: formatAlignment,
16624
+ formatAlignmentHorizontal: formatAlignmentHorizontal,
16625
+ formatAlignmentLeft: formatAlignmentLeft,
16626
+ formatAlignmentCenter: formatAlignmentCenter,
16627
+ formatAlignmentRight: formatAlignmentRight,
16628
+ formatAlignmentVertical: formatAlignmentVertical,
16629
+ formatAlignmentTop: formatAlignmentTop,
16630
+ formatAlignmentMiddle: formatAlignmentMiddle,
16631
+ formatAlignmentBottom: formatAlignmentBottom,
16632
+ formatWrapping: formatWrapping,
16633
+ formatWrappingOverflow: formatWrappingOverflow,
16634
+ formatWrappingWrap: formatWrappingWrap,
16635
+ formatWrappingClip: formatWrappingClip,
16636
+ textColor: textColor,
16637
+ fillColor: fillColor,
16638
+ formatCF: formatCF,
16639
+ paintFormat: paintFormat,
16640
+ clearFormat: clearFormat,
16641
+ borders: borders,
16642
+ bordersAll: bordersAll,
16643
+ bordersInner: bordersInner,
16644
+ bordersHorizontal: bordersHorizontal,
16645
+ bordersVertical: bordersVertical,
16646
+ bordersExternal: bordersExternal,
16647
+ bordersLeft: bordersLeft,
16648
+ bordersTop: bordersTop,
16649
+ bordersRight: bordersRight,
16650
+ bordersBottom: bordersBottom,
16651
+ bordersClear: bordersClear
16652
+ });
16653
+
16106
16654
  function interactiveFreezeColumnsRows(env, dimension, base) {
16107
16655
  const sheetId = env.model.getters.getActiveSheetId();
16108
16656
  const cmd = dimension === "COL" ? "FREEZE_COLUMNS" : "FREEZE_ROWS";
@@ -16112,524 +16660,740 @@
16112
16660
  }
16113
16661
  }
16114
16662
 
16115
- const topbarMenuRegistry = new MenuItemRegistry();
16116
- topbarMenuRegistry
16117
- .add("file", { name: _lt("File"), sequence: 10 })
16118
- .add("edit", { name: _lt("Edit"), sequence: 20 })
16119
- .add("view", { name: _lt("View"), sequence: 30 })
16120
- .add("insert", { name: _lt("Insert"), sequence: 40 })
16121
- .add("format", { name: _lt("Format"), sequence: 50 })
16122
- .add("data", { name: _lt("Data"), sequence: 60 })
16123
- .addChild("save", ["file"], {
16124
- name: _lt("Save"),
16125
- description: "Ctrl+S",
16126
- sequence: 10,
16127
- action: () => console.log("Not implemented"),
16128
- })
16129
- .addChild("undo", ["edit"], {
16130
- name: _lt("Undo"),
16131
- description: "Ctrl+Z",
16663
+ const hideCols = {
16664
+ name: HIDE_COLUMNS_NAME,
16665
+ execute: HIDE_COLUMNS_ACTION,
16666
+ isVisible: (env) => {
16667
+ const sheetId = env.model.getters.getActiveSheetId();
16668
+ const hiddenCols = env.model.getters.getHiddenColsGroups(sheetId).flat();
16669
+ return (env.model.getters.getNumberCols(sheetId) >
16670
+ hiddenCols.length + env.model.getters.getElementsFromSelection("COL").length);
16671
+ },
16672
+ };
16673
+ const unhideCols = {
16674
+ name: _lt("Unhide columns"),
16675
+ execute: UNHIDE_COLUMNS_ACTION,
16676
+ isVisible: (env) => {
16677
+ const hiddenCols = env.model.getters
16678
+ .getHiddenColsGroups(env.model.getters.getActiveSheetId())
16679
+ .flat();
16680
+ const currentCols = env.model.getters.getElementsFromSelection("COL");
16681
+ return currentCols.some((col) => hiddenCols.includes(col));
16682
+ },
16683
+ };
16684
+ const unhideAllCols = {
16685
+ name: _lt("Unhide all columns"),
16686
+ execute: UNHIDE_ALL_COLUMNS_ACTION,
16687
+ isVisible: (env) => env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId()).length > 0,
16688
+ };
16689
+ const hideRows = {
16690
+ name: HIDE_ROWS_NAME,
16691
+ execute: HIDE_ROWS_ACTION,
16692
+ isVisible: (env) => {
16693
+ const sheetId = env.model.getters.getActiveSheetId();
16694
+ const hiddenRows = env.model.getters.getHiddenRowsGroups(sheetId).flat();
16695
+ return (env.model.getters.getNumberRows(sheetId) >
16696
+ hiddenRows.length + env.model.getters.getElementsFromSelection("ROW").length);
16697
+ },
16698
+ };
16699
+ const unhideRows = {
16700
+ name: _lt("Unhide rows"),
16701
+ execute: UNHIDE_ROWS_ACTION,
16702
+ isVisible: (env) => {
16703
+ const hiddenRows = env.model.getters
16704
+ .getHiddenRowsGroups(env.model.getters.getActiveSheetId())
16705
+ .flat();
16706
+ const currentRows = env.model.getters.getElementsFromSelection("ROW");
16707
+ return currentRows.some((col) => hiddenRows.includes(col));
16708
+ },
16709
+ };
16710
+ const unhideAllRows = {
16711
+ name: _lt("Unhide all rows"),
16712
+ execute: UNHIDE_ALL_ROWS_ACTION,
16713
+ isVisible: (env) => env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId()).length > 0,
16714
+ };
16715
+ const unFreezePane = {
16716
+ name: _lt("Unfreeze"),
16717
+ isVisible: (env) => {
16718
+ const { xSplit, ySplit } = env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId());
16719
+ return xSplit + ySplit > 0;
16720
+ },
16721
+ execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS_ROWS", {
16722
+ sheetId: env.model.getters.getActiveSheetId(),
16723
+ }),
16724
+ };
16725
+ const freezePane = {
16726
+ name: _lt("Freeze"),
16727
+ };
16728
+ const unFreezeRows = {
16729
+ name: _lt("No rows"),
16730
+ execute: (env) => env.model.dispatch("UNFREEZE_ROWS", {
16731
+ sheetId: env.model.getters.getActiveSheetId(),
16732
+ }),
16733
+ isReadonlyAllowed: true,
16734
+ isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).ySplit,
16735
+ };
16736
+ const freezeFirstRow = {
16737
+ name: _lt("1 row"),
16738
+ execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 1),
16739
+ isReadonlyAllowed: true,
16740
+ };
16741
+ const freezeSecondRow = {
16742
+ name: _lt("2 rows"),
16743
+ execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 2),
16744
+ isReadonlyAllowed: true,
16745
+ };
16746
+ const freezeCurrentRow = {
16747
+ name: _lt("Up to current row"),
16748
+ execute: (env) => {
16749
+ const { bottom } = env.model.getters.getSelectedZone();
16750
+ interactiveFreezeColumnsRows(env, "ROW", bottom + 1);
16751
+ },
16752
+ isReadonlyAllowed: true,
16753
+ };
16754
+ const unFreezeCols = {
16755
+ name: _lt("No columns"),
16756
+ execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS", {
16757
+ sheetId: env.model.getters.getActiveSheetId(),
16758
+ }),
16759
+ isReadonlyAllowed: true,
16760
+ isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).xSplit,
16761
+ };
16762
+ const freezeFirstCol = {
16763
+ name: _lt("1 column"),
16764
+ execute: (env) => interactiveFreezeColumnsRows(env, "COL", 1),
16765
+ isReadonlyAllowed: true,
16766
+ };
16767
+ const freezeSecondCol = {
16768
+ name: _lt("2 columns"),
16769
+ execute: (env) => interactiveFreezeColumnsRows(env, "COL", 2),
16770
+ isReadonlyAllowed: true,
16771
+ };
16772
+ const freezeCurrentCol = {
16773
+ name: _lt("Up to current column"),
16774
+ execute: (env) => {
16775
+ const { right } = env.model.getters.getSelectedZone();
16776
+ interactiveFreezeColumnsRows(env, "COL", right + 1);
16777
+ },
16778
+ isReadonlyAllowed: true,
16779
+ };
16780
+ const viewGridlines = {
16781
+ name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
16782
+ ? _lt("Hide gridlines")
16783
+ : _lt("Show gridlines"),
16784
+ execute: SET_GRID_LINES_VISIBILITY_ACTION,
16785
+ };
16786
+ const viewFormulas = {
16787
+ name: (env) => env.model.getters.shouldShowFormulas() ? _lt("Hide formulas") : _lt("Show formulas"),
16788
+ execute: SET_FORMULA_VISIBILITY_ACTION,
16789
+ isReadonlyAllowed: true,
16790
+ };
16791
+ const createRemoveFilter = {
16792
+ name: (env) => selectionContainsFilter(env) ? _lt("Remove selected filters") : _lt("Create filter"),
16793
+ isActive: (env) => selectionContainsFilter(env),
16794
+ isEnabled: (env) => !cannotCreateFilter(env),
16795
+ execute: (env) => createRemoveFilterAction(env),
16796
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16797
+ };
16798
+ function selectionContainsFilter(env) {
16799
+ const sheetId = env.model.getters.getActiveSheetId();
16800
+ const selectedZones = env.model.getters.getSelectedZones();
16801
+ return env.model.getters.doesZonesContainFilter(sheetId, selectedZones);
16802
+ }
16803
+ function cannotCreateFilter(env) {
16804
+ return !areZonesContinuous(...env.model.getters.getSelectedZones());
16805
+ }
16806
+ function createRemoveFilterAction(env) {
16807
+ if (selectionContainsFilter(env)) {
16808
+ env.model.dispatch("REMOVE_FILTER_TABLE", {
16809
+ sheetId: env.model.getters.getActiveSheetId(),
16810
+ target: env.model.getters.getSelectedZones(),
16811
+ });
16812
+ return;
16813
+ }
16814
+ if (cannotCreateFilter(env)) {
16815
+ return;
16816
+ }
16817
+ env.model.selection.selectTableAroundSelection();
16818
+ const sheetId = env.model.getters.getActiveSheetId();
16819
+ const selection = env.model.getters.getSelectedZones();
16820
+ interactiveAddFilter(env, sheetId, selection);
16821
+ }
16822
+
16823
+ var ACTION_VIEW = /*#__PURE__*/Object.freeze({
16824
+ __proto__: null,
16825
+ hideCols: hideCols,
16826
+ unhideCols: unhideCols,
16827
+ unhideAllCols: unhideAllCols,
16828
+ hideRows: hideRows,
16829
+ unhideRows: unhideRows,
16830
+ unhideAllRows: unhideAllRows,
16831
+ unFreezePane: unFreezePane,
16832
+ freezePane: freezePane,
16833
+ unFreezeRows: unFreezeRows,
16834
+ freezeFirstRow: freezeFirstRow,
16835
+ freezeSecondRow: freezeSecondRow,
16836
+ freezeCurrentRow: freezeCurrentRow,
16837
+ unFreezeCols: unFreezeCols,
16838
+ freezeFirstCol: freezeFirstCol,
16839
+ freezeSecondCol: freezeSecondCol,
16840
+ freezeCurrentCol: freezeCurrentCol,
16841
+ viewGridlines: viewGridlines,
16842
+ viewFormulas: viewFormulas,
16843
+ createRemoveFilter: createRemoveFilter
16844
+ });
16845
+
16846
+ const colMenuRegistry = new MenuItemRegistry();
16847
+ colMenuRegistry
16848
+ .add("cut", {
16849
+ ...cut,
16132
16850
  sequence: 10,
16133
- action: UNDO_ACTION,
16134
16851
  })
16135
- .addChild("redo", ["edit"], {
16136
- name: _lt("Redo"),
16137
- description: "Ctrl+Y",
16852
+ .add("copy", {
16853
+ ...copy,
16138
16854
  sequence: 20,
16139
- action: REDO_ACTION,
16140
- separator: true,
16141
16855
  })
16142
- .addChild("copy", ["edit"], {
16143
- name: _lt("Copy"),
16144
- description: "Ctrl+C",
16856
+ .add("paste", {
16857
+ ...paste,
16145
16858
  sequence: 30,
16146
- isReadonlyAllowed: true,
16147
- action: COPY_ACTION,
16148
16859
  })
16149
- .addChild("cut", ["edit"], {
16150
- name: _lt("Cut"),
16151
- description: "Ctrl+X",
16860
+ .add("paste_special", {
16861
+ ...pasteSpecial,
16152
16862
  sequence: 40,
16153
- action: CUT_ACTION,
16863
+ separator: true,
16154
16864
  })
16155
- .addChild("paste", ["edit"], {
16156
- name: _lt("Paste"),
16157
- description: "Ctrl+V",
16158
- sequence: 50,
16159
- action: PASTE_ACTION,
16865
+ .addChild("paste_value_only", ["paste_special"], {
16866
+ ...pasteSpecialValue,
16867
+ sequence: 10,
16160
16868
  })
16161
- .addChild("paste_special", ["edit"], {
16162
- name: _lt("Paste special"),
16163
- sequence: 60,
16869
+ .addChild("paste_format_only", ["paste_special"], {
16870
+ ...pasteSpecialFormat,
16871
+ sequence: 20,
16872
+ })
16873
+ .add("sort_columns", {
16874
+ ...sortRange,
16875
+ name: (env) => env.model.getters.getActiveCols().size > 1 ? _lt("Sort columns") : _lt("Sort column"),
16876
+ sequence: 50,
16164
16877
  separator: true,
16165
- isVisible: IS_NOT_CUT_OPERATION,
16166
16878
  })
16167
- .addChild("paste_special_value", ["edit", "paste_special"], {
16168
- name: _lt("Paste value only"),
16879
+ .addChild("sort_ascending", ["sort_columns"], {
16880
+ ...sortAscending,
16169
16881
  sequence: 10,
16170
- action: PASTE_VALUE_ACTION,
16171
16882
  })
16172
- .addChild("paste_special_format", ["edit", "paste_special"], {
16173
- name: _lt("Paste format only"),
16883
+ .addChild("sort_descending", ["sort_columns"], {
16884
+ ...sortDescending,
16174
16885
  sequence: 20,
16175
- action: PASTE_FORMAT_ACTION,
16176
16886
  })
16177
- .addChild("sort_range", ["data"], {
16178
- name: _lt("Sort range"),
16179
- sequence: 20,
16180
- isVisible: IS_ONLY_ONE_RANGE,
16887
+ .add("add_column_before", {
16888
+ ...colInsertColsBefore,
16889
+ sequence: 70,
16890
+ })
16891
+ .add("add_column_after", {
16892
+ ...colInsertColsAfter,
16893
+ sequence: 80,
16894
+ })
16895
+ .add("delete_column", {
16896
+ ...deleteCols,
16897
+ sequence: 90,
16898
+ })
16899
+ .add("clear_column", {
16900
+ ...clearCols,
16901
+ sequence: 100,
16902
+ })
16903
+ .add("hide_columns", {
16904
+ ...hideCols,
16905
+ sequence: 85,
16181
16906
  separator: true,
16182
16907
  })
16183
- .addChild("sort_ascending", ["data", "sort_range"], {
16184
- name: _lt("Ascending (A ⟶ Z)"),
16908
+ .add("unhide_columns", {
16909
+ ...unhideCols,
16910
+ sequence: 86,
16911
+ separator: true,
16912
+ })
16913
+ .add("conditional_formatting", {
16914
+ ...formatCF,
16915
+ sequence: 110,
16916
+ });
16917
+
16918
+ const numberFormatMenuRegistry = new MenuItemRegistry();
16919
+ numberFormatMenuRegistry
16920
+ .add("format_number_automatic", {
16921
+ ...formatNumberAutomatic,
16185
16922
  sequence: 10,
16186
- action: SORT_CELLS_ASCENDING,
16923
+ separator: true,
16187
16924
  })
16188
- .addChild("sort_descending", ["data", "sort_range"], {
16189
- name: _lt("Descending (Z ⟶ A)"),
16925
+ .add("format_number_number", {
16926
+ ...formatNumberNumber,
16190
16927
  sequence: 20,
16191
- action: SORT_CELLS_DESCENDING,
16192
16928
  })
16193
- .addChild("find_and_replace", ["edit"], {
16194
- name: _lt("Find and replace"),
16195
- description: "Ctrl+H",
16196
- sequence: 65,
16197
- isReadonlyAllowed: true,
16198
- action: OPEN_FAR_SIDEPANEL_ACTION,
16929
+ .add("format_number_percent", {
16930
+ ...formatNumberPercent,
16931
+ sequence: 30,
16199
16932
  separator: true,
16200
16933
  })
16201
- .addChild("edit_delete_cell_values", ["edit"], {
16202
- name: _lt("Delete values"),
16203
- sequence: 70,
16204
- action: DELETE_CONTENT_ACTION,
16934
+ .add("format_number_currency", {
16935
+ ...formatNumberCurrency,
16936
+ sequence: 40,
16205
16937
  })
16206
- .addChild("edit_delete_row", ["edit"], {
16207
- name: REMOVE_ROWS_NAME,
16208
- sequence: 80,
16209
- action: REMOVE_ROWS_ACTION,
16938
+ .add("format_number_currency_rounded", {
16939
+ ...formatNumberCurrencyRounded,
16940
+ sequence: 50,
16210
16941
  })
16211
- .addChild("edit_delete_column", ["edit"], {
16212
- name: REMOVE_COLUMNS_NAME,
16213
- sequence: 90,
16214
- action: REMOVE_COLUMNS_ACTION,
16942
+ .add("format_custom_currency", {
16943
+ ...formatCustomCurrency,
16944
+ sequence: 60,
16945
+ separator: true,
16215
16946
  })
16216
- .addChild("edit_delete_cell_shift_up", ["edit"], {
16217
- name: _lt("Delete cell and shift up"),
16218
- sequence: 93,
16219
- action: DELETE_CELL_SHIFT_UP,
16947
+ .add("format_number_date", {
16948
+ ...formatNumberDate,
16949
+ sequence: 70,
16220
16950
  })
16221
- .addChild("edit_delete_cell_shift_left", ["edit"], {
16222
- name: _lt("Delete cell and shift left"),
16223
- sequence: 97,
16224
- action: DELETE_CELL_SHIFT_LEFT,
16951
+ .add("format_number_time", {
16952
+ ...formatNumberTime,
16953
+ sequence: 80,
16225
16954
  })
16226
- .addChild("edit_unhide_columns", ["edit"], {
16227
- name: _lt("Unhide all columns"),
16228
- sequence: 100,
16229
- action: UNHIDE_ALL_COLUMNS_ACTION,
16230
- isVisible: (env) => env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId()).length > 0,
16955
+ .add("format_number_date_time", {
16956
+ ...formatNumberDateTime,
16957
+ sequence: 90,
16231
16958
  })
16232
- .addChild("edit_unhide_rows", ["edit"], {
16233
- name: _lt("Unhide all rows"),
16959
+ .add("format_number_duration", {
16960
+ ...formatNumberDuration,
16234
16961
  sequence: 100,
16235
- action: UNHIDE_ALL_ROWS_ACTION,
16236
- isVisible: (env) => env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId()).length > 0,
16237
- })
16238
- .addChild("insert_row_before", ["insert"], {
16239
- name: MENU_INSERT_ROWS_BEFORE_NAME,
16962
+ separator: true,
16963
+ });
16964
+ const formatNumberMenuItemSpec = {
16965
+ name: _lt("More formats"),
16966
+ icon: "o-spreadsheet-Icon.NUMBER_FORMATS",
16967
+ children: [() => numberFormatMenuRegistry.getAll()],
16968
+ };
16969
+
16970
+ const rowMenuRegistry = new MenuItemRegistry();
16971
+ rowMenuRegistry
16972
+ .add("cut", {
16973
+ ...cut,
16240
16974
  sequence: 10,
16241
- action: INSERT_ROWS_BEFORE_ACTION,
16242
- isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16243
16975
  })
16244
- .addChild("insert_row_after", ["insert"], {
16245
- name: MENU_INSERT_ROWS_AFTER_NAME,
16976
+ .add("copy", {
16977
+ ...copy,
16246
16978
  sequence: 20,
16247
- action: INSERT_ROWS_AFTER_ACTION,
16248
- isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16249
- separator: true,
16250
16979
  })
16251
- .addChild("insert_column_before", ["insert"], {
16252
- name: MENU_INSERT_COLUMNS_BEFORE_NAME,
16980
+ .add("paste", {
16981
+ ...paste,
16253
16982
  sequence: 30,
16254
- action: INSERT_COLUMNS_BEFORE_ACTION,
16255
- isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16256
16983
  })
16257
- .addChild("insert_column_after", ["insert"], {
16258
- name: MENU_INSERT_COLUMNS_AFTER_NAME,
16984
+ .add("paste_special", {
16985
+ ...pasteSpecial,
16259
16986
  sequence: 40,
16260
- action: INSERT_COLUMNS_AFTER_ACTION,
16261
- isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16262
16987
  separator: true,
16263
16988
  })
16264
- .addChild("insert_insert_cell_shift_down", ["insert"], {
16265
- name: _lt("Insert cells and shift down"),
16266
- sequence: 43,
16267
- action: INSERT_CELL_SHIFT_DOWN,
16989
+ .addChild("paste_value_only", ["paste_special"], {
16990
+ ...pasteSpecialValue,
16991
+ sequence: 10,
16268
16992
  })
16269
- .addChild("insert_insert_cell_shift_right", ["insert"], {
16270
- name: _lt("Insert cells and shift right"),
16271
- sequence: 47,
16272
- action: INSERT_CELL_SHIFT_RIGHT,
16273
- separator: true,
16993
+ .addChild("paste_format_only", ["paste_special"], {
16994
+ ...pasteSpecialFormat,
16995
+ sequence: 20,
16274
16996
  })
16275
- .addChild("insert_chart", ["insert"], {
16276
- name: _lt("Chart"),
16997
+ .add("add_row_before", {
16998
+ ...rowInsertRowBefore,
16277
16999
  sequence: 50,
16278
- action: CREATE_CHART,
16279
- })
16280
- .addChild("insert_image", ["insert"], {
16281
- name: _lt("Image"),
16282
- sequence: 55,
16283
- action: CREATE_IMAGE,
16284
- isVisible: (env) => env.imageProvider !== undefined,
16285
17000
  })
16286
- .addChild("insert_function", ["insert"], {
16287
- name: _lt("Function"),
17001
+ .add("add_row_after", {
17002
+ ...rowInsertRowsAfter,
16288
17003
  sequence: 60,
16289
17004
  })
16290
- .addChild("insert_function_sum", ["insert", "insert_function"], {
16291
- name: _lt("SUM"),
16292
- action: (env) => env.startCellEdition(`=SUM(`),
16293
- sequence: 0,
17005
+ .add("delete_row", {
17006
+ ...deleteRows,
17007
+ sequence: 70,
16294
17008
  })
16295
- .addChild("insert_function_average", ["insert", "insert_function"], {
16296
- name: _lt("AVERAGE"),
16297
- action: (env) => env.startCellEdition(`=AVERAGE(`),
17009
+ .add("clear_row", {
17010
+ ...clearRows,
17011
+ sequence: 80,
17012
+ })
17013
+ .add("hide_rows", {
17014
+ ...hideRows,
17015
+ sequence: 85,
17016
+ separator: true,
17017
+ })
17018
+ .add("unhide_rows", {
17019
+ ...unhideRows,
17020
+ sequence: 86,
17021
+ separator: true,
17022
+ })
17023
+ .add("conditional_formatting", {
17024
+ ...formatCF,
17025
+ sequence: 90,
17026
+ });
17027
+
17028
+ function getSheetMenuRegistry(args) {
17029
+ const sheetMenuRegistry = new MenuItemRegistry();
17030
+ sheetMenuRegistry
17031
+ .add("delete", {
17032
+ ...deleteSheet,
17033
+ sequence: 10,
17034
+ })
17035
+ .add("duplicate", {
17036
+ ...duplicateSheet,
17037
+ sequence: 20,
17038
+ })
17039
+ .add("rename", {
17040
+ ...renameSheet(args),
17041
+ sequence: 30,
17042
+ })
17043
+ .add("move_right", {
17044
+ ...sheetMoveRight,
17045
+ sequence: 40,
17046
+ })
17047
+ .add("move_left", {
17048
+ ...sheetMoveLeft,
17049
+ sequence: 50,
17050
+ })
17051
+ .add("hide_sheet", {
17052
+ ...hideSheet,
17053
+ sequence: 60,
17054
+ });
17055
+ return sheetMenuRegistry;
17056
+ }
17057
+
17058
+ const topbarMenuRegistry = new MenuItemRegistry();
17059
+ topbarMenuRegistry
17060
+ // ---------------------------------------------------------------------
17061
+ // FILE MENU ITEMS
17062
+ // ---------------------------------------------------------------------
17063
+ .add("file", {
17064
+ name: _lt("File"),
16298
17065
  sequence: 10,
16299
17066
  })
16300
- .addChild("insert_function_count", ["insert", "insert_function"], {
16301
- name: _lt("COUNT"),
16302
- action: (env) => env.startCellEdition(`=COUNT(`),
17067
+ // ---------------------------------------------------------------------
17068
+ // EDIT MENU ITEMS
17069
+ // ---------------------------------------------------------------------
17070
+ .add("edit", {
17071
+ name: _lt("Edit"),
16303
17072
  sequence: 20,
16304
17073
  })
16305
- .addChild("insert_function_max", ["insert", "insert_function"], {
16306
- name: _lt("MAX"),
16307
- action: (env) => env.startCellEdition(`=MAX(`),
17074
+ .addChild("undo", ["edit"], {
17075
+ ...undo,
17076
+ sequence: 10,
17077
+ })
17078
+ .addChild("redo", ["edit"], {
17079
+ ...redo,
17080
+ sequence: 20,
17081
+ separator: true,
17082
+ })
17083
+ .addChild("copy", ["edit"], {
17084
+ ...copy,
16308
17085
  sequence: 30,
16309
17086
  })
16310
- .addChild("insert_function_min", ["insert", "insert_function"], {
16311
- name: _lt("MIN"),
16312
- action: (env) => env.startCellEdition(`=MIN(`),
17087
+ .addChild("cut", ["edit"], {
17088
+ ...cut,
16313
17089
  sequence: 40,
16314
- separator: true,
16315
17090
  })
16316
- .addChild("categorie_function_all", ["insert", "insert_function"], {
16317
- name: _lt("All"),
17091
+ .addChild("paste", ["edit"], {
17092
+ ...paste,
16318
17093
  sequence: 50,
16319
17094
  })
16320
- .addChild("all_function_list", ["insert", "insert_function", "categorie_function_all"], () => {
16321
- const fnNames = functionRegistry.getKeys();
16322
- return createFormulaFunctionMenuItems(fnNames);
17095
+ .addChild("paste_special", ["edit"], {
17096
+ ...pasteSpecial,
17097
+ sequence: 60,
17098
+ separator: true,
16323
17099
  })
16324
- .addChild("categories_function_list", ["insert", "insert_function"], () => {
16325
- const functions = functionRegistry.content;
16326
- const categories = [...new Set(functionRegistry.getAll().map((fn) => fn.category))].filter(isDefined$1);
16327
- return categories.sort().map((category, i) => {
16328
- const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
16329
- return {
16330
- name: category,
16331
- sequence: 60 + i * 10,
16332
- children: createFormulaFunctionMenuItems(functionsInCategory),
16333
- };
16334
- });
17100
+ .addChild("paste_special_value", ["edit", "paste_special"], {
17101
+ ...pasteSpecialValue,
17102
+ sequence: 10,
16335
17103
  })
16336
- .addChild("insert_link", ["insert"], {
16337
- name: _lt("Link"),
17104
+ .addChild("paste_special_format", ["edit", "paste_special"], {
17105
+ ...pasteSpecialFormat,
17106
+ sequence: 20,
17107
+ })
17108
+ .addChild("find_and_replace", ["edit"], {
17109
+ ...findAndReplace,
17110
+ sequence: 65,
16338
17111
  separator: true,
17112
+ })
17113
+ .addChild("edit_delete_cell_values", ["edit"], {
17114
+ ...deleteValues,
16339
17115
  sequence: 70,
16340
- action: INSERT_LINK,
16341
17116
  })
16342
- .addChild("insert_sheet", ["insert"], {
16343
- name: _lt("New sheet"),
17117
+ .addChild("edit_delete_row", ["edit"], {
17118
+ ...deleteRows,
16344
17119
  sequence: 80,
16345
- action: CREATE_SHEET_ACTION,
16346
- separator: true,
17120
+ })
17121
+ .addChild("edit_delete_column", ["edit"], {
17122
+ ...deleteCols,
17123
+ sequence: 90,
17124
+ })
17125
+ .addChild("edit_delete_cell_shift_up", ["edit"], {
17126
+ ...deleteCellShiftUp,
17127
+ sequence: 93,
17128
+ })
17129
+ .addChild("edit_delete_cell_shift_left", ["edit"], {
17130
+ ...deleteCellShiftLeft,
17131
+ sequence: 97,
17132
+ })
17133
+ .addChild("edit_unhide_columns", ["edit"], {
17134
+ ...unhideAllCols,
17135
+ sequence: 100,
17136
+ })
17137
+ .addChild("edit_unhide_rows", ["edit"], {
17138
+ ...unhideAllRows,
17139
+ sequence: 100,
17140
+ })
17141
+ // ---------------------------------------------------------------------
17142
+ // VIEW MENU ITEMS
17143
+ // ---------------------------------------------------------------------
17144
+ .add("view", {
17145
+ name: _lt("View"),
17146
+ sequence: 30,
16347
17147
  })
16348
17148
  .addChild("unfreeze_panes", ["view"], {
16349
- name: _lt("Unfreeze"),
17149
+ ...unFreezePane,
16350
17150
  sequence: 4,
16351
- isVisible: (env) => {
16352
- const { xSplit, ySplit } = env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId());
16353
- return xSplit + ySplit > 0;
16354
- },
16355
- action: (env) => env.model.dispatch("UNFREEZE_COLUMNS_ROWS", {
16356
- sheetId: env.model.getters.getActiveSheetId(),
16357
- }),
16358
17151
  })
16359
17152
  .addChild("freeze_panes", ["view"], {
16360
- name: _lt("Freeze"),
17153
+ ...freezePane,
16361
17154
  sequence: 5,
16362
17155
  separator: true,
16363
17156
  })
16364
17157
  .addChild("unfreeze_rows", ["view", "freeze_panes"], {
16365
- name: _lt("No rows"),
16366
- action: (env) => env.model.dispatch("UNFREEZE_ROWS", {
16367
- sheetId: env.model.getters.getActiveSheetId(),
16368
- }),
16369
- isReadonlyAllowed: true,
17158
+ ...unFreezeRows,
16370
17159
  sequence: 5,
16371
- isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).ySplit,
16372
17160
  })
16373
17161
  .addChild("freeze_first_row", ["view", "freeze_panes"], {
16374
- name: _lt("1 row"),
16375
- action: (env) => interactiveFreezeColumnsRows(env, "ROW", 1),
16376
- isReadonlyAllowed: true,
17162
+ ...freezeFirstRow,
16377
17163
  sequence: 10,
16378
17164
  })
16379
17165
  .addChild("freeze_second_row", ["view", "freeze_panes"], {
16380
- name: _lt("2 rows"),
16381
- action: (env) => interactiveFreezeColumnsRows(env, "ROW", 2),
16382
- isReadonlyAllowed: true,
17166
+ ...freezeSecondRow,
16383
17167
  sequence: 15,
16384
17168
  })
16385
17169
  .addChild("freeze_current_row", ["view", "freeze_panes"], {
16386
- name: _lt("Up to current row"),
16387
- action: (env) => {
16388
- const { bottom } = env.model.getters.getSelectedZone();
16389
- interactiveFreezeColumnsRows(env, "ROW", bottom + 1);
16390
- },
16391
- isReadonlyAllowed: true,
17170
+ ...freezeCurrentRow,
16392
17171
  sequence: 20,
16393
17172
  separator: true,
16394
17173
  })
16395
17174
  .addChild("unfreeze_columns", ["view", "freeze_panes"], {
16396
- name: _lt("No columns"),
16397
- action: (env) => env.model.dispatch("UNFREEZE_COLUMNS", {
16398
- sheetId: env.model.getters.getActiveSheetId(),
16399
- }),
16400
- isReadonlyAllowed: true,
17175
+ ...unFreezeCols,
16401
17176
  sequence: 25,
16402
- isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).xSplit,
16403
17177
  })
16404
17178
  .addChild("freeze_first_col", ["view", "freeze_panes"], {
16405
- name: _lt("1 column"),
16406
- action: (env) => interactiveFreezeColumnsRows(env, "COL", 1),
16407
- isReadonlyAllowed: true,
17179
+ ...freezeFirstCol,
16408
17180
  sequence: 30,
16409
17181
  })
16410
17182
  .addChild("freeze_second_col", ["view", "freeze_panes"], {
16411
- name: _lt("2 columns"),
16412
- action: (env) => interactiveFreezeColumnsRows(env, "COL", 2),
16413
- isReadonlyAllowed: true,
17183
+ ...freezeSecondCol,
16414
17184
  sequence: 35,
16415
17185
  })
16416
17186
  .addChild("freeze_current_col", ["view", "freeze_panes"], {
16417
- name: _lt("Up to current column"),
16418
- action: (env) => {
16419
- const { right } = env.model.getters.getSelectedZone();
16420
- interactiveFreezeColumnsRows(env, "COL", right + 1);
16421
- },
16422
- isReadonlyAllowed: true,
17187
+ ...freezeCurrentCol,
16423
17188
  sequence: 40,
16424
17189
  })
16425
17190
  .addChild("view_gridlines", ["view"], {
16426
- name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
16427
- ? _lt("Hide gridlines")
16428
- : _lt("Show gridlines"),
16429
- action: SET_GRID_LINES_VISIBILITY_ACTION,
17191
+ ...viewGridlines,
16430
17192
  sequence: 10,
16431
17193
  })
16432
17194
  .addChild("view_formulas", ["view"], {
16433
- name: (env) => env.model.getters.shouldShowFormulas() ? _lt("Hide formulas") : _lt("Show formulas"),
16434
- action: SET_FORMULA_VISIBILITY_ACTION,
16435
- isReadonlyAllowed: true,
17195
+ ...viewFormulas,
16436
17196
  sequence: 15,
16437
17197
  })
16438
- .addChild("format_number", ["format"], {
16439
- name: _lt("Numbers"),
16440
- sequence: 10,
16441
- separator: true,
17198
+ // ---------------------------------------------------------------------
17199
+ // INSERT MENU ITEMS
17200
+ // ---------------------------------------------------------------------
17201
+ .add("insert", {
17202
+ name: _lt("Insert"),
17203
+ sequence: 40,
16442
17204
  })
16443
- .addChild("format_number_automatic", ["format", "format_number"], {
16444
- name: NumberFormatTerms.Automatic,
17205
+ .addChild("insert_row_before", ["insert"], {
17206
+ ...topBarInsertRowsBefore,
16445
17207
  sequence: 10,
16446
- separator: true,
16447
- action: FORMAT_AUTOMATIC_ACTION,
16448
17208
  })
16449
- .addChild("format_number_number", ["format", "format_number"], {
16450
- name: NumberFormatTerms.Number,
16451
- description: "1,000.12",
17209
+ .addChild("insert_row_after", ["insert"], {
17210
+ ...topBarInsertRowsAfter,
16452
17211
  sequence: 20,
16453
- action: FORMAT_NUMBER_ACTION,
17212
+ separator: true,
16454
17213
  })
16455
- .addChild("format_number_percent", ["format", "format_number"], {
16456
- name: NumberFormatTerms.Percent,
16457
- description: "10.12%",
17214
+ .addChild("insert_column_before", ["insert"], {
17215
+ ...topBarInsertColsBefore,
16458
17216
  sequence: 30,
16459
- separator: true,
16460
- action: FORMAT_PERCENT_ACTION,
16461
17217
  })
16462
- .addChild("format_number_currency", ["format", "format_number"], {
16463
- name: NumberFormatTerms.Currency,
16464
- description: "$1,000.12",
16465
- sequence: 37,
16466
- action: FORMAT_CURRENCY_ACTION,
17218
+ .addChild("insert_column_after", ["insert"], {
17219
+ ...topBarInsertColsAfter,
17220
+ sequence: 40,
17221
+ separator: true,
16467
17222
  })
16468
- .addChild("format_number_currency_rounded", ["format", "format_number"], {
16469
- name: NumberFormatTerms.CurrencyRounded,
16470
- description: "$1,000",
16471
- sequence: 38,
16472
- action: FORMAT_CURRENCY_ROUNDED_ACTION,
17223
+ .addChild("insert_insert_cell_shift_down", ["insert"], {
17224
+ ...insertCellShiftDown,
17225
+ sequence: 43,
16473
17226
  })
16474
- .addChild("format_custom_currency", ["format", "format_number"], {
16475
- name: NumberFormatTerms.CustomCurrency,
16476
- sequence: 39,
17227
+ .addChild("insert_insert_cell_shift_right", ["insert"], {
17228
+ ...insertCellShiftRight,
17229
+ sequence: 47,
16477
17230
  separator: true,
16478
- isVisible: (env) => env.loadCurrencies !== undefined,
16479
- action: OPEN_CUSTOM_CURRENCY_SIDEPANEL_ACTION,
16480
17231
  })
16481
- .addChild("format_number_date", ["format", "format_number"], {
16482
- name: NumberFormatTerms.Date,
16483
- description: "9/26/2008",
16484
- sequence: 40,
16485
- action: FORMAT_DATE_ACTION,
16486
- })
16487
- .addChild("format_number_time", ["format", "format_number"], {
16488
- name: NumberFormatTerms.Time,
16489
- description: "10:43:00 PM",
17232
+ .addChild("insert_chart", ["insert"], {
17233
+ ...insertChart,
16490
17234
  sequence: 50,
16491
- action: FORMAT_TIME_ACTION,
16492
17235
  })
16493
- .addChild("format_number_date_time", ["format", "format_number"], {
16494
- name: NumberFormatTerms.DateTime,
16495
- description: "9/26/2008 22:43:00",
17236
+ .addChild("insert_image", ["insert"], {
17237
+ ...insertImage,
17238
+ sequence: 55,
17239
+ })
17240
+ .addChild("insert_function", ["insert"], {
17241
+ ...insertFunction,
16496
17242
  sequence: 60,
16497
- action: FORMAT_DATE_TIME_ACTION,
16498
17243
  })
16499
- .addChild("format_number_duration", ["format", "format_number"], {
16500
- name: NumberFormatTerms.Duration,
16501
- description: "27:51:38",
17244
+ .addChild("insert_function_sum", ["insert", "insert_function"], {
17245
+ ...insertFunctionSum,
17246
+ sequence: 0,
17247
+ })
17248
+ .addChild("insert_function_average", ["insert", "insert_function"], {
17249
+ ...insertFunctionAverage,
17250
+ sequence: 10,
17251
+ })
17252
+ .addChild("insert_function_count", ["insert", "insert_function"], {
17253
+ ...insertFunctionCount,
17254
+ sequence: 20,
17255
+ })
17256
+ .addChild("insert_function_max", ["insert", "insert_function"], {
17257
+ ...insertFunctionMax,
17258
+ sequence: 30,
17259
+ })
17260
+ .addChild("insert_function_min", ["insert", "insert_function"], {
17261
+ ...insertFunctionMin,
17262
+ sequence: 40,
17263
+ separator: true,
17264
+ })
17265
+ .addChild("categorie_function_all", ["insert", "insert_function"], {
17266
+ ...categorieFunctionAll,
17267
+ sequence: 50,
17268
+ })
17269
+ .addChild("categories_function_list", ["insert", "insert_function"], categoriesFunctionListMenuBuilder)
17270
+ .addChild("insert_link", ["insert"], {
17271
+ ...insertLink,
17272
+ separator: true,
16502
17273
  sequence: 70,
17274
+ })
17275
+ .addChild("insert_sheet", ["insert"], {
17276
+ ...insertSheet,
17277
+ sequence: 80,
17278
+ separator: true,
17279
+ })
17280
+ // ---------------------------------------------------------------------
17281
+ // FORMAT MENU ITEMS
17282
+ // ---------------------------------------------------------------------
17283
+ .add("format", { name: _lt("Format"), sequence: 50 })
17284
+ .addChild("format_number", ["format"], {
17285
+ ...formatNumberMenuItemSpec,
17286
+ name: _lt("Number"),
17287
+ sequence: 10,
16503
17288
  separator: true,
16504
- action: FORMAT_DURATION_ACTION,
16505
17289
  })
16506
17290
  .addChild("format_bold", ["format"], {
16507
- name: _lt("Bold"),
17291
+ ...formatBold,
16508
17292
  sequence: 20,
16509
- description: "Ctrl+B",
16510
- action: FORMAT_BOLD_ACTION,
16511
17293
  })
16512
17294
  .addChild("format_italic", ["format"], {
16513
- name: _lt("Italic"),
17295
+ ...formatItalic,
16514
17296
  sequence: 30,
16515
- description: "Ctrl+I",
16516
- action: FORMAT_ITALIC_ACTION,
16517
17297
  })
16518
17298
  .addChild("format_underline", ["format"], {
16519
- name: _lt("Underline"),
16520
- description: "Ctrl+U",
17299
+ ...formatUnderline,
16521
17300
  sequence: 40,
16522
- action: FORMAT_UNDERLINE_ACTION,
16523
17301
  })
16524
17302
  .addChild("format_strikethrough", ["format"], {
16525
- name: _lt("Strikethrough"),
17303
+ ...formatStrikethrough,
16526
17304
  sequence: 50,
16527
- action: FORMAT_STRIKETHROUGH_ACTION,
16528
17305
  separator: true,
16529
17306
  })
16530
17307
  .addChild("format_font_size", ["format"], {
16531
- name: _lt("Font size"),
17308
+ ...formatFontSize,
16532
17309
  sequence: 60,
16533
17310
  separator: true,
16534
17311
  })
16535
17312
  .addChild("format_alignment", ["format"], {
16536
- name: _lt("Alignment"),
17313
+ ...formatAlignment,
16537
17314
  sequence: 70,
16538
17315
  })
16539
17316
  .addChild("format_alignment_left", ["format", "format_alignment"], {
16540
- name: "Left",
17317
+ ...formatAlignmentLeft,
16541
17318
  sequence: 10,
16542
- action: (env) => setStyle(env, { align: "left" }),
16543
17319
  })
16544
17320
  .addChild("format_alignment_center", ["format", "format_alignment"], {
16545
- name: "Center",
17321
+ ...formatAlignmentCenter,
16546
17322
  sequence: 20,
16547
- action: (env) => setStyle(env, { align: "center" }),
16548
17323
  })
16549
17324
  .addChild("format_alignment_right", ["format", "format_alignment"], {
16550
- name: "Right",
17325
+ ...formatAlignmentRight,
16551
17326
  sequence: 30,
16552
- action: (env) => setStyle(env, { align: "right" }),
16553
17327
  separator: true,
16554
17328
  })
16555
17329
  .addChild("format_alignment_top", ["format", "format_alignment"], {
16556
- name: "Top",
17330
+ ...formatAlignmentTop,
16557
17331
  sequence: 40,
16558
- action: (env) => setStyle(env, { verticalAlign: "top" }),
16559
17332
  })
16560
17333
  .addChild("format_alignment_middle", ["format", "format_alignment"], {
16561
- name: "Middle",
17334
+ ...formatAlignmentMiddle,
16562
17335
  sequence: 50,
16563
- action: (env) => setStyle(env, { verticalAlign: "middle" }),
16564
17336
  })
16565
17337
  .addChild("format_alignment_bottom", ["format", "format_alignment"], {
16566
- name: "Bottom",
17338
+ ...formatAlignmentBottom,
16567
17339
  sequence: 60,
16568
- action: (env) => setStyle(env, { verticalAlign: "bottom" }),
16569
17340
  separator: true,
16570
17341
  })
16571
17342
  .addChild("format_wrapping", ["format"], {
16572
- name: _lt("Wrapping"),
17343
+ ...formatWrapping,
16573
17344
  sequence: 80,
16574
17345
  separator: true,
16575
17346
  })
16576
17347
  .addChild("format_wrapping_overflow", ["format", "format_wrapping"], {
16577
- name: _lt("Overflow"),
17348
+ ...formatWrappingOverflow,
16578
17349
  sequence: 10,
16579
- action: (env) => setStyle(env, { wrapping: "overflow" }),
16580
17350
  })
16581
17351
  .addChild("format_wrapping_wrap", ["format", "format_wrapping"], {
16582
- name: _lt("Wrap"),
17352
+ ...formatWrappingWrap,
16583
17353
  sequence: 20,
16584
- action: (env) => setStyle(env, { wrapping: "wrap" }),
16585
17354
  })
16586
17355
  .addChild("format_wrapping_clip", ["format", "format_wrapping"], {
16587
- name: _lt("Clip"),
17356
+ ...formatWrappingClip,
16588
17357
  sequence: 30,
16589
- action: (env) => setStyle(env, { wrapping: "clip" }),
16590
17358
  })
16591
17359
  .addChild("format_cf", ["format"], {
16592
- name: _lt("Conditional formatting"),
17360
+ ...formatCF,
16593
17361
  sequence: 90,
16594
- action: OPEN_CF_SIDEPANEL_ACTION,
16595
17362
  separator: true,
16596
17363
  })
16597
17364
  .addChild("format_clearFormat", ["format"], {
16598
- name: _lt("Clear formatting"),
17365
+ ...clearFormat,
16599
17366
  sequence: 100,
16600
- action: FORMAT_CLEARFORMAT_ACTION,
16601
17367
  separator: true,
17368
+ })
17369
+ // ---------------------------------------------------------------------
17370
+ // DATA MENU ITEMS
17371
+ // ---------------------------------------------------------------------
17372
+ .add("data", {
17373
+ name: _lt("Data"),
17374
+ sequence: 60,
17375
+ })
17376
+ .addChild("sort_range", ["data"], {
17377
+ ...sortRange,
17378
+ sequence: 20,
17379
+ separator: true,
17380
+ })
17381
+ .addChild("sort_ascending", ["data", "sort_range"], {
17382
+ ...sortAscending,
17383
+ sequence: 10,
17384
+ })
17385
+ .addChild("sort_descending", ["data", "sort_range"], {
17386
+ ...sortDescending,
17387
+ sequence: 20,
16602
17388
  })
16603
17389
  .addChild("add_data_filter", ["data"], {
16604
- name: _lt("Create filter"),
17390
+ ...addDataFilter,
16605
17391
  sequence: 10,
16606
- action: FILTERS_CREATE_FILTER_TABLE,
16607
- isVisible: (env) => !SELECTION_CONTAINS_FILTER(env),
16608
- isEnabled: (env) => SELECTION_IS_CONTINUOUS(env),
16609
17392
  })
16610
17393
  .addChild("remove_data_filter", ["data"], {
16611
- name: _lt("Remove filter"),
17394
+ ...removeDataFilter,
16612
17395
  sequence: 10,
16613
- action: FILTERS_REMOVE_FILTER_TABLE,
16614
- isVisible: SELECTION_CONTAINS_FILTER,
16615
- });
16616
- // Font-sizes
16617
- for (let fs of FONT_SIZES) {
16618
- topbarMenuRegistry.addChild(`format_font_size_${fs}`, ["format", "format_font_size"], {
16619
- name: fs.toString(),
16620
- sequence: fs,
16621
- action: (env) => setStyle(env, { fontSize: fs }),
16622
- });
16623
- }
16624
- function createFormulaFunctionMenuItems(fnNames) {
16625
- return fnNames.sort().map((fnName, i) => {
16626
- return {
16627
- name: fnName,
16628
- sequence: i * 10,
16629
- action: (env) => env.startCellEdition(`=${fnName}(`),
16630
- };
16631
- });
16632
- }
17396
+ });
16633
17397
 
16634
17398
  class OTRegistry extends Registry {
16635
17399
  /**
@@ -16931,6 +17695,22 @@
16931
17695
  aggregated: ev.target.checked,
16932
17696
  });
16933
17697
  }
17698
+ calculateHeaderPosition() {
17699
+ if (this.isDatasetInvalid || this.isLabelInvalid) {
17700
+ return undefined;
17701
+ }
17702
+ const getters = this.env.model.getters;
17703
+ const sheetId = getters.getActiveSheetId();
17704
+ const labelRange = createRange(getters, sheetId, this.labelRange);
17705
+ const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
17706
+ if (dataSets.length) {
17707
+ return dataSets[0].dataRange.zone.top + 1;
17708
+ }
17709
+ else if (labelRange) {
17710
+ return labelRange.zone.top + 1;
17711
+ }
17712
+ return undefined;
17713
+ }
16934
17714
  }
16935
17715
  LineBarPieConfigPanel.template = "o-spreadsheet-LineBarPieConfigPanel";
16936
17716
  LineBarPieConfigPanel.components = { SelectionInput };
@@ -17178,6 +17958,9 @@
17178
17958
  top,
17179
17959
  });
17180
17960
  }
17961
+ isSameColor(color1, color2) {
17962
+ return isSameColor(color1, color2);
17963
+ }
17181
17964
  }
17182
17965
  ColorPicker.template = "o-spreadsheet-ColorPicker";
17183
17966
  ColorPicker.defaultProps = {
@@ -17193,8 +17976,9 @@
17193
17976
 
17194
17977
  css /* scss */ `
17195
17978
  .o-color-picker-widget {
17196
- display: inline-block;
17979
+ display: flex;
17197
17980
  position: relative;
17981
+ align-items: center;
17198
17982
 
17199
17983
  .o-color-picker-button-style {
17200
17984
  display: flex;
@@ -17210,6 +17994,7 @@
17210
17994
  }
17211
17995
 
17212
17996
  .o-color-picker-button {
17997
+ height: 30px;
17213
17998
  > span {
17214
17999
  border-bottom: 4px solid;
17215
18000
  height: 16px;
@@ -19419,6 +20204,8 @@
19419
20204
  start = 0;
19420
20205
  if (end > textLength)
19421
20206
  end = textLength;
20207
+ if (start > textLength)
20208
+ start = textLength;
19422
20209
  }
19423
20210
  let startNode = this.findChildAtCharacterIndex(start);
19424
20211
  let endNode = this.findChildAtCharacterIndex(end);
@@ -19688,6 +20475,7 @@
19688
20475
  padding-right: 2px;
19689
20476
 
19690
20477
  box-sizing: border-box;
20478
+ font-family: ${DEFAULT_FONT};
19691
20479
 
19692
20480
  caret-color: black;
19693
20481
  padding-left: 3px;
@@ -20130,7 +20918,7 @@
20130
20918
  const highlights = this.env.model.getters.getHighlights();
20131
20919
  const refSheet = sheetName
20132
20920
  ? this.env.model.getters.getSheetIdByName(sheetName)
20133
- : this.env.model.getters.getEditionSheet();
20921
+ : this.env.model.getters.getCurrentEditedCell().sheetId;
20134
20922
  const highlight = highlights.find((highlight) => {
20135
20923
  if (highlight.sheetId !== refSheet)
20136
20924
  return false;
@@ -20291,7 +21079,7 @@
20291
21079
  get cellReference() {
20292
21080
  const { col, row, sheetId } = this.env.model.getters.getCurrentEditedCell();
20293
21081
  const prefixSheet = sheetId !== this.env.model.getters.getActiveSheetId();
20294
- return `${prefixSheet ? getComposerSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
21082
+ return `${prefixSheet ? getCanonicalSheetName(this.env.model.getters.getSheetName(sheetId)) + "!" : ""}${toXC(col, row)}`;
20295
21083
  }
20296
21084
  get cellReferenceStyle() {
20297
21085
  const { x: left, y: top } = this.rect;
@@ -20476,15 +21264,18 @@
20476
21264
  return { x, y };
20477
21265
  }
20478
21266
 
20479
- function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { scrollX, scrollY }) {
21267
+ function dragFigureForMove({ x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, initialFigure, { x: viewportX, y: viewportY }, { maxX, maxY }, { scrollX, scrollY }) {
20480
21268
  const minX = viewportX ? 0 : -scrollX;
20481
21269
  const minY = viewportY ? 0 : -scrollY;
20482
- let deltaX = mouseX - mouseInitialX;
20483
- const newX = Math.max(initialFigure.x + deltaX, minX);
20484
- let deltaY = mouseY - mouseInitialY;
20485
- const newY = Math.max(initialFigure.y + deltaY, minY);
21270
+ const deltaX = mouseX - mouseInitialX;
21271
+ const newX = clamp(initialFigure.x + deltaX, minX, maxX - initialFigure.width - scrollX);
21272
+ const deltaY = mouseY - mouseInitialY;
21273
+ const newY = clamp(initialFigure.y + deltaY, minY, maxY - initialFigure.height - scrollY);
20486
21274
  return { ...initialFigure, x: newX, y: newY };
20487
21275
  }
21276
+ function clamp(value, min, max) {
21277
+ return Math.min(Math.max(value, min), max);
21278
+ }
20488
21279
  function dragFigureForResize(initialFigure, dirX, dirY, { x: mouseX, y: mouseY }, { x: mouseInitialX, y: mouseInitialY }, keepRatio, minFigSize) {
20489
21280
  let { x, y, width, height } = initialFigure;
20490
21281
  if (keepRatio && dirX != 0 && dirY != 0) {
@@ -20883,12 +21674,16 @@
20883
21674
  }
20884
21675
  const sheetId = this.env.model.getters.getActiveSheetId();
20885
21676
  const initialMousePosition = { x: ev.clientX, y: ev.clientY };
21677
+ const maxDimensions = {
21678
+ maxX: this.env.model.getters.getColDimensions(sheetId, this.env.model.getters.getNumberCols(sheetId) - 1).end,
21679
+ maxY: this.env.model.getters.getRowDimensions(sheetId, this.env.model.getters.getNumberRows(sheetId) - 1).end,
21680
+ };
20886
21681
  const { x, y } = internalFigureToScreen(this.env.model.getters, figure);
20887
21682
  const initialFig = { ...figure, x, y };
20888
21683
  const onMouseMove = (ev) => {
20889
21684
  const getters = this.env.model.getters;
20890
21685
  const currentMousePosition = { x: ev.clientX, y: ev.clientY };
20891
- const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), getters.getActiveSheetScrollInfo());
21686
+ const draggedFigure = dragFigureForMove(currentMousePosition, initialMousePosition, initialFig, this.env.model.getters.getMainViewportCoordinates(), maxDimensions, getters.getActiveSheetScrollInfo());
20892
21687
  const otherFigures = this.getOtherFigures(figure.id);
20893
21688
  const internalDragged = screenFigureToInternal(getters, draggedFigure);
20894
21689
  const snapResult = snapForMove(getters, internalDragged, otherFigures);
@@ -21218,6 +22013,10 @@
21218
22013
  };
21219
22014
 
21220
22015
  class GridPopover extends owl.Component {
22016
+ constructor() {
22017
+ super(...arguments);
22018
+ this.zIndex = ComponentsImportance.GridPopover;
22019
+ }
21221
22020
  get cellPopover() {
21222
22021
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
21223
22022
  if (!popover.isOpen) {
@@ -22582,6 +23381,10 @@
22582
23381
  }
22583
23382
  }
22584
23383
  onInput(ev) {
23384
+ // the user meant to paste in the sheet, not open the composer with the pasted content
23385
+ if (!ev.isComposing && ev.inputType === "insertFromPaste") {
23386
+ return;
23387
+ }
22585
23388
  if (ev.data) {
22586
23389
  // if the user types a character on the grid, it means he wants to start composing the selected cell with that
22587
23390
  // character
@@ -23430,68 +24233,7 @@
23430
24233
  });
23431
24234
  }
23432
24235
 
23433
- function convertBorders(data, warningManager) {
23434
- const borderArray = data.borders.map((border) => {
23435
- addBorderWarnings(border, warningManager);
23436
- const b = {
23437
- top: convertBorderDescr$1(border.top, warningManager),
23438
- bottom: convertBorderDescr$1(border.bottom, warningManager),
23439
- left: convertBorderDescr$1(border.left, warningManager),
23440
- right: convertBorderDescr$1(border.right, warningManager),
23441
- };
23442
- Object.keys(b).forEach((key) => b[key] === undefined && delete b[key]);
23443
- return b;
23444
- });
23445
- return arrayToObject(borderArray, 1);
23446
- }
23447
- function convertBorderDescr$1(borderDescr, warningManager) {
23448
- if (!borderDescr)
23449
- return undefined;
23450
- addBorderDescrWarnings(borderDescr, warningManager);
23451
- const style = BORDER_STYLE_CONVERSION_MAP[borderDescr.style];
23452
- return style ? [style, convertColor(borderDescr.color)] : undefined;
23453
- }
23454
- function convertStyles(data, warningManager) {
23455
- const stylesArray = data.styles.map((style) => {
23456
- return convertStyle({
23457
- fontStyle: data.fonts[style.fontId],
23458
- fillStyle: data.fills[style.fillId],
23459
- alignment: style.alignment,
23460
- }, warningManager);
23461
- });
23462
- return arrayToObject(stylesArray, 1);
23463
- }
23464
- function convertStyle(styleStruct, warningManager) {
23465
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
23466
- addStyleWarnings(styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.fontStyle, styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.fillStyle, warningManager);
23467
- addHorizontalAlignmentWarnings((_a = styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.alignment) === null || _a === void 0 ? void 0 : _a.horizontal, warningManager);
23468
- addVerticalAlignmentWarnings((_b = styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.alignment) === null || _b === void 0 ? void 0 : _b.vertical, warningManager);
23469
- return {
23470
- bold: (_c = styleStruct.fontStyle) === null || _c === void 0 ? void 0 : _c.bold,
23471
- italic: (_d = styleStruct.fontStyle) === null || _d === void 0 ? void 0 : _d.italic,
23472
- strikethrough: (_e = styleStruct.fontStyle) === null || _e === void 0 ? void 0 : _e.strike,
23473
- underline: (_f = styleStruct.fontStyle) === null || _f === void 0 ? void 0 : _f.underline,
23474
- align: ((_g = styleStruct.alignment) === null || _g === void 0 ? void 0 : _g.horizontal)
23475
- ? H_ALIGNMENT_CONVERSION_MAP[styleStruct.alignment.horizontal]
23476
- : undefined,
23477
- // In xlsx fills, bgColor is the color of the fill, and fgColor is the color of the pattern above the background, except in solid fills
23478
- fillColor: ((_h = styleStruct.fillStyle) === null || _h === void 0 ? void 0 : _h.patternType) === "solid"
23479
- ? convertColor((_j = styleStruct.fillStyle) === null || _j === void 0 ? void 0 : _j.fgColor)
23480
- : convertColor((_k = styleStruct.fillStyle) === null || _k === void 0 ? void 0 : _k.bgColor),
23481
- textColor: convertColor((_l = styleStruct.fontStyle) === null || _l === void 0 ? void 0 : _l.color),
23482
- fontSize: (_m = styleStruct.fontStyle) === null || _m === void 0 ? void 0 : _m.size,
23483
- };
23484
- }
23485
- function convertFormats(data, warningManager) {
23486
- const formats = [];
23487
- for (let style of data.styles) {
23488
- const format = convertXlsxFormat(style.numFmtId, data.numFmts, warningManager);
23489
- if (format) {
23490
- formats[style.numFmtId] = format;
23491
- }
23492
- }
23493
- return arrayToObject(formats, 1);
23494
- }
24236
+ 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;
23495
24237
  /**
23496
24238
  * Convert excel format to o_spreadsheet format
23497
24239
  *
@@ -23516,17 +24258,107 @@
23516
24258
  throw new Error("Multiple escaped blocks in format");
23517
24259
  }
23518
24260
  convertedFormat = convertedFormat.replace(/"(.*)"/g, "[$$$1]"); // replace '"..."' by '[$...]'
23519
- convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore with of next char for align purposes. Not supported ATM
24261
+ convertedFormat = convertedFormat.replace(/_.{1}/g, ""); // _ == ignore width of next char for align purposes. Not supported ATM
23520
24262
  convertedFormat = convertedFormat.replace(/\*.{1}/g, ""); // * == repeat next character enough to fill the line. Not supported ATM
23521
24263
  convertedFormat = convertedFormat.replace(/\\ /g, " "); // unescape spaces
23522
- formatValue(0, convertedFormat);
23523
- return convertedFormat;
24264
+ convertedFormat = convertedFormat.replace(/\\./g, (match) => match[1]); // unescape other characters
24265
+ if (isXlsxDateFormat(convertedFormat)) {
24266
+ convertedFormat = convertDateFormat$1(convertedFormat);
24267
+ }
24268
+ if (isFormatSupported(convertedFormat)) {
24269
+ return convertedFormat;
24270
+ }
23524
24271
  }
23525
24272
  catch (e) { }
23526
24273
  }
23527
24274
  warningManager.generateNotSupportedWarning(WarningTypes.NumFmtIdNotSupported, format || `nmFmtId ${numFmtId}`);
23528
24275
  return undefined;
23529
24276
  }
24277
+ function isFormatSupported(format) {
24278
+ try {
24279
+ formatValue(0, format);
24280
+ return true;
24281
+ }
24282
+ catch (e) {
24283
+ return false;
24284
+ }
24285
+ }
24286
+ function isXlsxDateFormat(format) {
24287
+ return format.match(XLSX_DATE_FORMAT_REGEX) !== null;
24288
+ }
24289
+ function convertDateFormat$1(format) {
24290
+ // Some of these aren't defined neither in the OpenXML spec not the Xlsx extension of OpenXML,
24291
+ // but can still occur and are supported by Excel/Google sheets
24292
+ format = format.toLowerCase();
24293
+ format = format.replace(/mmmmm/g, "mmm");
24294
+ format = format.replace(/am\/pm|a\/m/g, "a");
24295
+ format = format.replace(/hhhh/g, "hh");
24296
+ format = format.replace(/\bh\b/g, "hh");
24297
+ return format;
24298
+ }
24299
+
24300
+ function convertBorders(data, warningManager) {
24301
+ const borderArray = data.borders.map((border) => {
24302
+ addBorderWarnings(border, warningManager);
24303
+ const b = {
24304
+ top: convertBorderDescr$1(border.top, warningManager),
24305
+ bottom: convertBorderDescr$1(border.bottom, warningManager),
24306
+ left: convertBorderDescr$1(border.left, warningManager),
24307
+ right: convertBorderDescr$1(border.right, warningManager),
24308
+ };
24309
+ Object.keys(b).forEach((key) => b[key] === undefined && delete b[key]);
24310
+ return b;
24311
+ });
24312
+ return arrayToObject(borderArray, 1);
24313
+ }
24314
+ function convertBorderDescr$1(borderDescr, warningManager) {
24315
+ if (!borderDescr)
24316
+ return undefined;
24317
+ addBorderDescrWarnings(borderDescr, warningManager);
24318
+ const style = BORDER_STYLE_CONVERSION_MAP[borderDescr.style];
24319
+ return style ? [style, convertColor(borderDescr.color)] : undefined;
24320
+ }
24321
+ function convertStyles(data, warningManager) {
24322
+ const stylesArray = data.styles.map((style) => {
24323
+ return convertStyle({
24324
+ fontStyle: data.fonts[style.fontId],
24325
+ fillStyle: data.fills[style.fillId],
24326
+ alignment: style.alignment,
24327
+ }, warningManager);
24328
+ });
24329
+ return arrayToObject(stylesArray, 1);
24330
+ }
24331
+ function convertStyle(styleStruct, warningManager) {
24332
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
24333
+ addStyleWarnings(styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.fontStyle, styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.fillStyle, warningManager);
24334
+ addHorizontalAlignmentWarnings((_a = styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.alignment) === null || _a === void 0 ? void 0 : _a.horizontal, warningManager);
24335
+ addVerticalAlignmentWarnings((_b = styleStruct === null || styleStruct === void 0 ? void 0 : styleStruct.alignment) === null || _b === void 0 ? void 0 : _b.vertical, warningManager);
24336
+ return {
24337
+ bold: (_c = styleStruct.fontStyle) === null || _c === void 0 ? void 0 : _c.bold,
24338
+ italic: (_d = styleStruct.fontStyle) === null || _d === void 0 ? void 0 : _d.italic,
24339
+ strikethrough: (_e = styleStruct.fontStyle) === null || _e === void 0 ? void 0 : _e.strike,
24340
+ underline: (_f = styleStruct.fontStyle) === null || _f === void 0 ? void 0 : _f.underline,
24341
+ align: ((_g = styleStruct.alignment) === null || _g === void 0 ? void 0 : _g.horizontal)
24342
+ ? H_ALIGNMENT_CONVERSION_MAP[styleStruct.alignment.horizontal]
24343
+ : undefined,
24344
+ // In xlsx fills, bgColor is the color of the fill, and fgColor is the color of the pattern above the background, except in solid fills
24345
+ fillColor: ((_h = styleStruct.fillStyle) === null || _h === void 0 ? void 0 : _h.patternType) === "solid"
24346
+ ? convertColor((_j = styleStruct.fillStyle) === null || _j === void 0 ? void 0 : _j.fgColor)
24347
+ : convertColor((_k = styleStruct.fillStyle) === null || _k === void 0 ? void 0 : _k.bgColor),
24348
+ textColor: convertColor((_l = styleStruct.fontStyle) === null || _l === void 0 ? void 0 : _l.color),
24349
+ fontSize: (_m = styleStruct.fontStyle) === null || _m === void 0 ? void 0 : _m.size,
24350
+ };
24351
+ }
24352
+ function convertFormats(data, warningManager) {
24353
+ const formats = [];
24354
+ for (let style of data.styles) {
24355
+ const format = convertXlsxFormat(style.numFmtId, data.numFmts, warningManager);
24356
+ if (format) {
24357
+ formats[style.numFmtId] = format;
24358
+ }
24359
+ }
24360
+ return arrayToObject(formats, 1);
24361
+ }
23530
24362
  // ---------------------------------------------------------------------------
23531
24363
  // Warnings
23532
24364
  // ---------------------------------------------------------------------------
@@ -24081,16 +24913,18 @@
24081
24913
  };
24082
24914
  }
24083
24915
  function convertChartData(chartData) {
24084
- var _a;
24085
- const labelRange = (_a = chartData.dataSets[0].label) === null || _a === void 0 ? void 0 : _a.replace(/\$/g, "");
24086
- let dataSets = chartData.dataSets.map((data) => data.range.replace(/\$/g, ""));
24916
+ const dataSetsHaveTitle = chartData.dataSets[0].label !== undefined;
24917
+ const labelRange = chartData.labelRange
24918
+ ? convertExcelRangeToSheetXC(chartData.labelRange, dataSetsHaveTitle)
24919
+ : undefined;
24920
+ let dataSets = chartData.dataSets.map((data) => convertExcelRangeToSheetXC(data.range, dataSetsHaveTitle));
24087
24921
  // For doughnut charts, in chartJS first dataset = outer dataset, in excel first dataset = inner dataset
24088
24922
  if (chartData.type === "pie") {
24089
24923
  dataSets.reverse();
24090
24924
  }
24091
24925
  return {
24092
24926
  dataSets,
24093
- dataSetsHaveTitle: false,
24927
+ dataSetsHaveTitle,
24094
24928
  labelRange,
24095
24929
  title: chartData.title || "",
24096
24930
  type: chartData.type,
@@ -24101,6 +24935,28 @@
24101
24935
  aggregated: false,
24102
24936
  labelsAsText: false,
24103
24937
  };
24938
+ }
24939
+ function convertExcelRangeToSheetXC(range, dataSetsHaveTitle) {
24940
+ let { sheetName, xc } = splitReference(range);
24941
+ if (sheetName) {
24942
+ sheetName = getCanonicalSheetName(sheetName) + "!";
24943
+ }
24944
+ else {
24945
+ sheetName = "";
24946
+ }
24947
+ let zone = toUnboundedZone(xc);
24948
+ if (dataSetsHaveTitle && zone.bottom !== undefined && zone.right !== undefined) {
24949
+ const height = zone.bottom - zone.top + 1;
24950
+ const width = zone.right - zone.left + 1;
24951
+ if (height === 1) {
24952
+ zone = { ...zone, left: zone.left - 1 };
24953
+ }
24954
+ else if (width === 1) {
24955
+ zone = { ...zone, top: zone.top - 1 };
24956
+ }
24957
+ }
24958
+ const dataXC = zoneToXc(zone);
24959
+ return sheetName + dataXC;
24104
24960
  }
24105
24961
 
24106
24962
  /**
@@ -25168,6 +26024,7 @@
25168
26024
  title: chartTitle,
25169
26025
  type: CHART_TYPE_CONVERSION_MAP[chartType],
25170
26026
  dataSets: this.extractChartDatasets(this.querySelector(rootChartElement, `c:${chartType}`)),
26027
+ labelRange: this.extractChildTextContent(rootChartElement, "c:ser c:cat c:f"),
25171
26028
  backgroundColor: this.extractChildAttr(rootChartElement, "c:chartSpace > c:spPr a:srgbClr", "val", {
25172
26029
  default: "ffffff",
25173
26030
  }).asString(),
@@ -25187,7 +26044,7 @@
25187
26044
  extractChartDatasets(chartElement) {
25188
26045
  return this.mapOnElements({ parent: chartElement, query: "c:ser" }, (chartDataElement) => {
25189
26046
  return {
25190
- label: this.extractChildTextContent(chartDataElement, "c:cat c:f"),
26047
+ label: this.extractChildTextContent(chartDataElement, "c:tx c:f"),
25191
26048
  range: this.extractChildTextContent(chartDataElement, "c:val c:f", { required: true }),
25192
26049
  };
25193
26050
  });
@@ -29104,6 +29961,39 @@
29104
29961
  case "DELETE_FIGURE":
29105
29962
  this.removeFigure(cmd.id, cmd.sheetId);
29106
29963
  break;
29964
+ case "REMOVE_COLUMNS_ROWS":
29965
+ this.onRowColDelete(cmd.sheetId, cmd.dimension);
29966
+ }
29967
+ }
29968
+ onRowColDelete(sheetId, dimension) {
29969
+ dimension === "ROW" ? this.onRowDeletion(sheetId) : this.onColDeletion(sheetId);
29970
+ }
29971
+ onRowDeletion(sheetId) {
29972
+ const numHeader = this.getters.getNumberRows(sheetId);
29973
+ let gridHeight = 0;
29974
+ for (let i = 0; i < numHeader; i++) {
29975
+ gridHeight += this.getters.getRowSize(sheetId, i);
29976
+ }
29977
+ const figures = this.getters.getFigures(sheetId);
29978
+ for (const figure of figures) {
29979
+ const newY = Math.min(figure.y, gridHeight - figure.height);
29980
+ if (newY !== figure.y) {
29981
+ this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, y: newY });
29982
+ }
29983
+ }
29984
+ }
29985
+ onColDeletion(sheetId) {
29986
+ const numHeader = this.getters.getNumberCols(sheetId);
29987
+ let gridWidth = 0;
29988
+ for (let i = 0; i < numHeader; i++) {
29989
+ gridWidth += this.getters.getColSize(sheetId, i);
29990
+ }
29991
+ const figures = this.getters.getFigures(sheetId);
29992
+ for (const figure of figures) {
29993
+ const newX = Math.min(figure.x, gridWidth - figure.width);
29994
+ if (newX !== figure.x) {
29995
+ this.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x: newX });
29996
+ }
29107
29997
  }
29108
29998
  }
29109
29999
  updateFigure(sheetId, figure) {
@@ -30774,7 +31664,7 @@
30774
31664
  sheetName = rangeImpl.invalidSheetName;
30775
31665
  }
30776
31666
  else {
30777
- sheetName = getComposerSheetName(this.getters.getSheetName(rangeImpl.sheetId));
31667
+ sheetName = getCanonicalSheetName(this.getters.getSheetName(rangeImpl.sheetId));
30778
31668
  }
30779
31669
  }
30780
31670
  if (prefixSheet && !sheetName) {
@@ -31825,9 +32715,7 @@
31825
32715
  // remove duplicates first to check validity on a reduced
31826
32716
  // set of colors, then normalize to HEX and remove duplicates
31827
32717
  // again
31828
- [...new Set([...usedColors, ...this.customColors])]
31829
- .filter(isColorValid)
31830
- .map((c) => toHex(c).toLowerCase())),
32718
+ [...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
31831
32719
  ]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
31832
32720
  }
31833
32721
  getColorsFromCells(cells) {
@@ -31888,7 +32776,7 @@
31888
32776
  return [...chartsColors];
31889
32777
  }
31890
32778
  tryToAddColor(color) {
31891
- const formattedColor = toHex(color).toLowerCase();
32779
+ const formattedColor = toHex(color);
31892
32780
  if (color && !COLOR_PICKER_DEFAULTS.includes(formattedColor)) {
31893
32781
  this.customColors.add(formattedColor);
31894
32782
  }
@@ -32903,8 +33791,8 @@
32903
33791
  this.getters = getters;
32904
33792
  this.sheetId = sheetId;
32905
33793
  this.boundaries = boundaries;
32906
- this.width = sizeInGrid.width;
32907
- this.height = sizeInGrid.height;
33794
+ this.viewportWidth = sizeInGrid.width;
33795
+ this.viewportHeight = sizeInGrid.height;
32908
33796
  this.offsetScrollbarX = offsets.x;
32909
33797
  this.offsetScrollbarY = offsets.y;
32910
33798
  this.canScrollVertically = options.canScrollVertically;
@@ -32915,6 +33803,10 @@
32915
33803
  this.adjustViewportOffsetY();
32916
33804
  }
32917
33805
  // PUBLIC
33806
+ /** Returns the maximum size (in Pixels) of the viewport relative to its allocated client size
33807
+ * When the viewport grid size is smaller than its client width (resp. height), it will return
33808
+ * the client width (resp. height).
33809
+ */
32918
33810
  getMaxSize() {
32919
33811
  const lastCol = this.getters.findLastVisibleColRowIndex(this.sheetId, "COL", {
32920
33812
  first: this.boundaries.left,
@@ -32926,20 +33818,24 @@
32926
33818
  });
32927
33819
  const { end: lastColEnd, size: lastColSize } = this.getters.getColDimensions(this.sheetId, lastCol);
32928
33820
  const { end: lastRowEnd, size: lastRowSize } = this.getters.getRowDimensions(this.sheetId, lastRow);
32929
- const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.width, 0);
33821
+ const leftColIndex = this.searchHeaderIndex("COL", lastColEnd - this.viewportWidth, 0);
32930
33822
  const leftColSize = this.getters.getColSize(this.sheetId, leftColIndex);
32931
- const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.height, 0);
33823
+ const leftRowIndex = this.searchHeaderIndex("ROW", lastRowEnd - this.viewportHeight, 0);
32932
33824
  const topRowSize = this.getters.getRowSize(this.sheetId, leftRowIndex);
32933
- const width = lastColEnd -
32934
- this.offsetCorrectionX +
32935
- (this.canScrollHorizontally
32936
- ? Math.max(DEFAULT_CELL_WIDTH, Math.min(leftColSize, this.width - lastColSize))
32937
- : 0);
32938
- const height = lastRowEnd -
32939
- this.offsetCorrectionY +
32940
- (this.canScrollVertically
32941
- ? Math.max(DEFAULT_CELL_HEIGHT + 5, Math.min(topRowSize, this.height - lastRowSize))
32942
- : 0);
33825
+ let width = lastColEnd - this.offsetCorrectionX;
33826
+ if (this.canScrollHorizontally) {
33827
+ width += Math.max(DEFAULT_CELL_WIDTH, // leave some minimal space to let the user know they scrolled all the way
33828
+ Math.min(leftColSize, this.viewportWidth - lastColSize) // Add pixels that allows the snapping at maximum horizontal scroll
33829
+ );
33830
+ width = Math.max(width, this.viewportWidth); // if the viewport grid size is smaller than its client width, return client width
33831
+ }
33832
+ let height = lastRowEnd - this.offsetCorrectionY;
33833
+ if (this.canScrollVertically) {
33834
+ height += Math.max(DEFAULT_CELL_HEIGHT + 5, // leave some space to let the user know they scrolled all the way
33835
+ Math.min(topRowSize, this.viewportHeight - lastRowSize) // Add pixels that allows the snapping at maximum vertical scroll
33836
+ );
33837
+ height = Math.max(height, this.viewportHeight); // if the viewport grid size is smaller than its client height, return client height
33838
+ }
32943
33839
  return { width, height };
32944
33840
  }
32945
33841
  /**
@@ -32948,7 +33844,7 @@
32948
33844
  * It returns -1 if no column is found.
32949
33845
  */
32950
33846
  getColIndex(x, absolute = false) {
32951
- if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.width) {
33847
+ if (x < this.offsetCorrectionX || x > this.offsetCorrectionX + this.viewportWidth) {
32952
33848
  return -1;
32953
33849
  }
32954
33850
  return this.searchHeaderIndex("COL", x - this.offsetCorrectionX, this.left, absolute);
@@ -32959,7 +33855,7 @@
32959
33855
  * It returns -1 if no row is found.
32960
33856
  */
32961
33857
  getRowIndex(y, absolute = false) {
32962
- if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.height) {
33858
+ if (y < this.offsetCorrectionY || y > this.offsetCorrectionY + this.viewportHeight) {
32963
33859
  return -1;
32964
33860
  }
32965
33861
  return this.searchHeaderIndex("ROW", y - this.offsetCorrectionY, this.top, absolute);
@@ -32983,48 +33879,66 @@
32983
33879
  this.adjustPositionY(row);
32984
33880
  }
32985
33881
  }
32986
- adjustPositionX(col) {
33882
+ adjustPositionX(targetCol) {
32987
33883
  const sheetId = this.sheetId;
32988
- const { start, end } = this.getters.getColDimensions(sheetId, col);
32989
- while (end > this.offsetX + this.offsetCorrectionX + this.width &&
32990
- this.offsetX + this.offsetCorrectionX < start) {
32991
- this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
32992
- this.offsetScrollbarX = this.offsetX;
32993
- this.adjustViewportZoneX();
32994
- }
32995
- while (col < this.left) {
32996
- let leftCol;
32997
- for (leftCol = this.left; leftCol >= 0; leftCol--) {
32998
- if (!this.getters.isColHidden(sheetId, leftCol)) {
33884
+ const { end } = this.getters.getColDimensions(sheetId, targetCol);
33885
+ const maxCol = this.getters.getNumberCols(sheetId);
33886
+ if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
33887
+ for (let col = this.left; this.offsetX + this.offsetCorrectionX + this.viewportWidth < end; col++) {
33888
+ if (col > maxCol) {
33889
+ break;
33890
+ }
33891
+ if (this.getters.isColHidden(sheetId, col)) {
33892
+ continue;
33893
+ }
33894
+ this.offsetX = this.getters.getColDimensions(sheetId, col).end - this.offsetCorrectionX;
33895
+ this.offsetScrollbarX = this.offsetX;
33896
+ this.adjustViewportZoneX();
33897
+ }
33898
+ }
33899
+ else if (this.left > targetCol) {
33900
+ for (let col = this.left; col >= targetCol; col--) {
33901
+ if (col < 0) {
32999
33902
  break;
33000
33903
  }
33904
+ if (this.getters.isColHidden(sheetId, col)) {
33905
+ continue;
33906
+ }
33907
+ this.offsetX = this.getters.getColDimensions(sheetId, col).start - this.offsetCorrectionX;
33908
+ this.offsetScrollbarX = this.offsetX;
33909
+ this.adjustViewportZoneX();
33001
33910
  }
33002
- this.offsetX =
33003
- this.getters.getColDimensions(sheetId, leftCol - 1).start - this.offsetCorrectionX;
33004
- this.offsetScrollbarX = this.offsetX;
33005
- this.adjustViewportZoneX();
33006
33911
  }
33007
33912
  }
33008
- adjustPositionY(row) {
33913
+ adjustPositionY(targetRow) {
33009
33914
  const sheetId = this.sheetId;
33010
- while (this.getters.getRowDimensions(sheetId, row).end >
33011
- this.offsetY + this.height + this.offsetCorrectionY &&
33012
- this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
33013
- this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
33014
- this.offsetScrollbarY = this.offsetY;
33015
- this.adjustViewportZoneY();
33016
- }
33017
- while (row < this.top) {
33018
- let topRow;
33019
- for (topRow = this.top; topRow >= 0; topRow--) {
33020
- if (!this.getters.isRowHidden(sheetId, topRow)) {
33915
+ const { end } = this.getters.getRowDimensions(sheetId, targetRow);
33916
+ const maxRow = this.getters.getNumberRows(sheetId);
33917
+ if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
33918
+ for (let row = this.top; this.offsetY + this.viewportHeight + this.offsetCorrectionY < end; row++) {
33919
+ if (row > maxRow) {
33920
+ break;
33921
+ }
33922
+ if (this.getters.isRowHidden(sheetId, row)) {
33923
+ continue;
33924
+ }
33925
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).end - this.offsetCorrectionY;
33926
+ this.offsetScrollbarY = this.offsetY;
33927
+ this.adjustViewportZoneY();
33928
+ }
33929
+ }
33930
+ else if (this.top > targetRow) {
33931
+ for (let row = this.top; row >= targetRow; row--) {
33932
+ if (row < 0) {
33021
33933
  break;
33022
33934
  }
33935
+ if (this.getters.isRowHidden(sheetId, row)) {
33936
+ continue;
33937
+ }
33938
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).start - this.offsetCorrectionY;
33939
+ this.offsetScrollbarY = this.offsetY;
33940
+ this.adjustViewportZoneY();
33023
33941
  }
33024
- this.offsetY =
33025
- this.getters.getRowDimensions(sheetId, topRow - 1).start - this.offsetCorrectionY;
33026
- this.offsetScrollbarY = this.offsetY;
33027
- this.adjustViewportZoneY();
33028
33942
  }
33029
33943
  }
33030
33944
  setViewportOffset(offsetX, offsetY) {
@@ -33046,8 +33960,8 @@
33046
33960
  const x = this.getters.getColRowOffset("COL", this.zone.left, targetZone.left) +
33047
33961
  this.offsetCorrectionX;
33048
33962
  const y = this.getters.getColRowOffset("ROW", this.zone.top, targetZone.top) + this.offsetCorrectionY;
33049
- const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.width);
33050
- const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.height);
33963
+ const width = Math.min(this.getters.getColRowOffset("COL", targetZone.left, targetZone.right + 1), this.viewportWidth);
33964
+ const height = Math.min(this.getters.getColRowOffset("ROW", targetZone.top, targetZone.bottom + 1), this.viewportHeight);
33051
33965
  return {
33052
33966
  x,
33053
33967
  y,
@@ -33110,12 +34024,12 @@
33110
34024
  adjustViewportOffsetX() {
33111
34025
  if (this.canScrollHorizontally) {
33112
34026
  const { width: viewportWidth } = this.getMaxSize();
33113
- if (this.width + this.offsetScrollbarX > viewportWidth) {
33114
- this.offsetScrollbarX = Math.max(0, viewportWidth - this.width);
34027
+ if (this.viewportWidth + this.offsetScrollbarX > viewportWidth) {
34028
+ this.offsetScrollbarX = Math.max(0, viewportWidth - this.viewportWidth);
33115
34029
  }
33116
34030
  }
33117
34031
  this.left = this.getColIndex(this.offsetScrollbarX, true);
33118
- this.right = this.getColIndex(this.offsetScrollbarX + this.width, true);
34032
+ this.right = this.getColIndex(this.offsetScrollbarX + this.viewportWidth, true);
33119
34033
  if (this.right === -1) {
33120
34034
  this.right = this.boundaries.right;
33121
34035
  }
@@ -33127,12 +34041,12 @@
33127
34041
  adjustViewportOffsetY() {
33128
34042
  if (this.canScrollVertically) {
33129
34043
  const { height: paneHeight } = this.getMaxSize();
33130
- if (this.height + this.offsetScrollbarY > paneHeight) {
33131
- this.offsetScrollbarY = Math.max(0, paneHeight - this.height);
34044
+ if (this.viewportHeight + this.offsetScrollbarY > paneHeight) {
34045
+ this.offsetScrollbarY = Math.max(0, paneHeight - this.viewportHeight);
33132
34046
  }
33133
34047
  }
33134
34048
  this.top = this.getRowIndex(this.offsetScrollbarY, true);
33135
- this.bottom = this.getRowIndex(this.offsetScrollbarY + this.width, true);
34049
+ this.bottom = this.getRowIndex(this.offsetScrollbarY + this.viewportWidth, true);
33136
34050
  if (this.bottom === -1) {
33137
34051
  this.bottom = this.boundaries.bottom;
33138
34052
  }
@@ -33143,7 +34057,7 @@
33143
34057
  adjustViewportZoneX() {
33144
34058
  const sheetId = this.sheetId;
33145
34059
  this.left = this.searchHeaderIndex("COL", this.offsetScrollbarX, this.boundaries.left);
33146
- this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.width, this.left));
34060
+ this.right = Math.min(this.boundaries.right, this.searchHeaderIndex("COL", this.viewportWidth, this.left));
33147
34061
  if (this.right === -1) {
33148
34062
  this.right = this.getters.getNumberCols(sheetId) - 1;
33149
34063
  }
@@ -33156,7 +34070,7 @@
33156
34070
  adjustViewportZoneY() {
33157
34071
  const sheetId = this.sheetId;
33158
34072
  this.top = this.searchHeaderIndex("ROW", this.offsetScrollbarY, this.boundaries.top);
33159
- this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.height, this.top));
34073
+ this.bottom = Math.min(this.boundaries.bottom, this.searchHeaderIndex("ROW", this.viewportHeight, this.top));
33160
34074
  if (this.bottom === -1) {
33161
34075
  this.bottom = this.getters.getNumberRows(sheetId) - 1;
33162
34076
  }
@@ -33217,8 +34131,8 @@
33217
34131
  * In the absence of a component (standalone model), is it mandatory to set reasonable default values
33218
34132
  * to ensure the correct operation of this plugin.
33219
34133
  */
33220
- this.sheetViewWidth = DEFAULT_SHEETVIEW_SIZE;
33221
- this.sheetViewHeight = DEFAULT_SHEETVIEW_SIZE;
34134
+ this.sheetViewWidth = getDefaultSheetViewSize();
34135
+ this.sheetViewHeight = getDefaultSheetViewSize();
33222
34136
  this.gridOffsetX = 0;
33223
34137
  this.gridOffsetY = 0;
33224
34138
  this.sheetsWithDirtyViewports = new Set();
@@ -33419,8 +34333,7 @@
33419
34333
  return [...new Set(viewports.map((v) => range(v.top, v.bottom + 1)).flat())].filter((row) => !this.getters.isHeaderHidden(sheetId, "ROW", row));
33420
34334
  }
33421
34335
  /**
33422
- * Return the main viewport maximum size. That is the zone dimension
33423
- * with some bottom and right padding.
34336
+ * Return the main viewport maximum size relative to the client size.
33424
34337
  */
33425
34338
  getMainViewportRect() {
33426
34339
  const sheetId = this.getters.getActiveSheetId();
@@ -33436,8 +34349,8 @@
33436
34349
  const { width, height } = this.getMainViewportRect();
33437
34350
  const viewport = this.getMainInternalViewport(sheetId);
33438
34351
  return {
33439
- maxOffsetX: Math.max(0, width - viewport.width + 1),
33440
- maxOffsetY: Math.max(0, height - viewport.height + 1),
34352
+ maxOffsetX: Math.max(0, width - viewport.viewportWidth + 1),
34353
+ maxOffsetY: Math.max(0, height - viewport.viewportHeight + 1),
33441
34354
  };
33442
34355
  }
33443
34356
  getColRowOffsetInViewport(dimension, referenceIndex, index) {
@@ -35657,7 +36570,7 @@
35657
36570
  const inputSheetId = this.activeSheet;
35658
36571
  const sheetId = this.getters.getActiveSheetId();
35659
36572
  const sheetName = this.getters.getSheetName(sheetId);
35660
- this.add([sheetId === inputSheetId ? xc : `${getComposerSheetName(sheetName)}!${xc}`]);
36573
+ this.add([sheetId === inputSheetId ? xc : `${getCanonicalSheetName(sheetName)}!${xc}`]);
35661
36574
  }
35662
36575
  handle(cmd) {
35663
36576
  switch (cmd.type) {
@@ -37904,13 +38817,19 @@
37904
38817
  */
37905
38818
  paste(target) {
37906
38819
  const sheetId = this.getters.getActiveSheetId();
38820
+ const { width, height } = this.copiedFigure;
38821
+ const numCols = this.getters.getNumberCols(sheetId);
38822
+ const numRows = this.getters.getNumberRows(sheetId);
38823
+ const targetX = this.getters.getColDimensions(sheetId, target[0].left).start;
38824
+ const targetY = this.getters.getRowDimensions(sheetId, target[0].top).start;
38825
+ const maxX = this.getters.getColDimensions(sheetId, numCols - 1).end;
38826
+ const maxY = this.getters.getRowDimensions(sheetId, numRows - 1).end;
37907
38827
  const position = {
37908
- x: this.getters.getColDimensions(sheetId, target[0].left).start,
37909
- y: this.getters.getRowDimensions(sheetId, target[0].top).start,
38828
+ x: maxX < width ? 0 : Math.min(targetX, maxX - width),
38829
+ y: maxY < height ? 0 : Math.min(targetY, maxY - height),
37910
38830
  };
37911
- const size = { height: this.copiedFigure.height, width: this.copiedFigure.width };
37912
38831
  const newId = new UuidGenerator().uuidv4();
37913
- this.copiedFigureContent.paste(sheetId, newId, position, size);
38832
+ this.copiedFigureContent.paste(sheetId, newId, position, { height, width });
37914
38833
  if (this.operation === "CUT") {
37915
38834
  this.dispatch("DELETE_FIGURE", {
37916
38835
  sheetId: this.copiedFigureContent.sheetId,
@@ -38276,7 +39195,7 @@
38276
39195
  return token;
38277
39196
  const { xc, sheetName } = splitReference(token.value);
38278
39197
  const [left, right] = xc.split(":");
38279
- const sheetRef = sheetName ? `${getComposerSheetName(sheetName)}!` : "";
39198
+ const sheetRef = sheetName ? `${getCanonicalSheetName(sheetName)}!` : "";
38280
39199
  const updatedLeft = getTokenNextReferenceType(left);
38281
39200
  const updatedRight = right ? `:${getTokenNextReferenceType(right)}` : "";
38282
39201
  return { ...token, value: sheetRef + updatedLeft + updatedRight };
@@ -38535,9 +39454,6 @@
38535
39454
  }
38536
39455
  return this.currentContent;
38537
39456
  }
38538
- getEditionSheet() {
38539
- return this.sheetId;
38540
- }
38541
39457
  getComposerSelection() {
38542
39458
  return {
38543
39459
  start: this.selectionStart,
@@ -38821,8 +39737,8 @@
38821
39737
  getZoneReference(zone, fixedParts = [{ colFixed: false, rowFixed: false }]) {
38822
39738
  const sheetId = this.getters.getActiveSheetId();
38823
39739
  let selectedXc = this.getters.zoneToXC(sheetId, zone, fixedParts);
38824
- if (this.getters.getEditionSheet() !== this.getters.getActiveSheetId()) {
38825
- const sheetName = getComposerSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
39740
+ if (this.getters.getCurrentEditedCell().sheetId !== this.getters.getActiveSheetId()) {
39741
+ const sheetName = getCanonicalSheetName(this.getters.getSheetName(this.getters.getActiveSheetId()));
38826
39742
  selectedXc = `${sheetName}!${selectedXc}`;
38827
39743
  }
38828
39744
  return selectedXc;
@@ -38836,7 +39752,7 @@
38836
39752
  _fixedParts.pop();
38837
39753
  }
38838
39754
  const newRange = range.clone({ parts: _fixedParts });
38839
- return this.getters.getSelectionRangeString(newRange, this.getters.getEditionSheet());
39755
+ return this.getters.getSelectionRangeString(newRange, this.getters.getCurrentEditedCell().sheetId);
38840
39756
  }
38841
39757
  /**
38842
39758
  * Replace the current selection by a new text.
@@ -38869,7 +39785,7 @@
38869
39785
  if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
38870
39786
  return;
38871
39787
  }
38872
- const editionSheetId = this.getters.getEditionSheet();
39788
+ const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
38873
39789
  const XCs = this.getReferencedRanges().map((range) => this.getters.getRangeString(range, editionSheetId));
38874
39790
  const colorsToKeep = {};
38875
39791
  for (const xc of XCs) {
@@ -38898,7 +39814,7 @@
38898
39814
  if (!this.currentContent.startsWith("=") || this.mode === "inactive") {
38899
39815
  return [];
38900
39816
  }
38901
- const editionSheetId = this.getters.getEditionSheet();
39817
+ const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
38902
39818
  const rangeColor = (rangeString) => {
38903
39819
  const colorIndex = this.colorIndexByRange[rangeString];
38904
39820
  return colors$1[colorIndex % colors$1.length];
@@ -38916,7 +39832,7 @@
38916
39832
  * Return ranges currently referenced in the composer
38917
39833
  */
38918
39834
  getReferencedRanges() {
38919
- const editionSheetId = this.getters.getEditionSheet();
39835
+ const editionSheetId = this.getters.getCurrentEditedCell().sheetId;
38920
39836
  return this.currentTokens
38921
39837
  .filter((token) => token.type === "REFERENCE")
38922
39838
  .map((token) => this.getters.getRangeFromSheetXC(editionSheetId, token.value));
@@ -38975,7 +39891,6 @@
38975
39891
  "isSelectingForComposer",
38976
39892
  "showSelectionIndicator",
38977
39893
  "getCurrentContent",
38978
- "getEditionSheet",
38979
39894
  "getComposerSelection",
38980
39895
  "getCurrentTokens",
38981
39896
  "getTokenAtCursor",
@@ -39648,7 +40563,7 @@
39648
40563
  const clickableCellRegistry = new Registry();
39649
40564
  clickableCellRegistry.add("link", {
39650
40565
  condition: (position, env) => !!env.model.getters.getEvaluatedCell(position).link,
39651
- action: (position, env) => openLink(env.model.getters.getEvaluatedCell(position).link, env),
40566
+ execute: (position, env) => openLink(env.model.getters.getEvaluatedCell(position).link, env),
39652
40567
  sequence: 5,
39653
40568
  });
39654
40569
 
@@ -40105,7 +41020,7 @@
40105
41020
  name: this.getComposedFnName(fnName, fnValue),
40106
41021
  sequence: i,
40107
41022
  isReadonlyAllowed: true,
40108
- action: () => {
41023
+ execute: () => {
40109
41024
  this.selectedStatisticFn = fnName;
40110
41025
  },
40111
41026
  });
@@ -40273,10 +41188,6 @@
40273
41188
  font-size: 15px;
40274
41189
  border-top: 1px solid lightgrey;
40275
41190
 
40276
- .o-add-sheet.disabled {
40277
- cursor: not-allowed;
40278
- }
40279
-
40280
41191
  .o-sheet-item {
40281
41192
  cursor: pointer;
40282
41193
  &:hover {
@@ -40298,10 +41209,6 @@
40298
41209
  .o-bottom-bar-arrows {
40299
41210
  .o-bottom-bar-arrow {
40300
41211
  cursor: pointer;
40301
- &.o-disabled {
40302
- opacity: 0.4;
40303
- cursor: default;
40304
- }
40305
41212
  &:hover:not([class*="o-disabled"]) {
40306
41213
  .o-icon {
40307
41214
  opacity: 0.9;
@@ -40386,7 +41293,7 @@
40386
41293
  sequence: i,
40387
41294
  isReadonlyAllowed: true,
40388
41295
  textColor: sheet.isVisible ? undefined : "grey",
40389
- action: (env) => {
41296
+ execute: (env) => {
40390
41297
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: from, sheetIdTo: sheetId });
40391
41298
  },
40392
41299
  });
@@ -40643,7 +41550,7 @@
40643
41550
  getClickableAction(position) {
40644
41551
  for (const items of clickableCellRegistry.getAll().sort((a, b) => a.sequence - b.sequence)) {
40645
41552
  if (items.condition(position, this.env)) {
40646
- return items.action;
41553
+ return items.execute;
40647
41554
  }
40648
41555
  }
40649
41556
  return false;
@@ -40871,21 +41778,66 @@
40871
41778
  onCloseSidePanel: Function,
40872
41779
  };
40873
41780
 
40874
- const AddMergeInteractiveContent = {
40875
- MergeIsDestructive: _lt("Merging these cells will only preserve the top-leftmost value. Merge anyway?"),
40876
- MergeInFilter: _lt("You can't merge cells inside of an existing filter."),
40877
- };
40878
- function interactiveAddMerge(env, sheetId, target) {
40879
- const result = env.model.dispatch("ADD_MERGE", { sheetId, target });
40880
- if (result.isCancelledBecause(80 /* CommandResult.MergeInFilter */)) {
40881
- env.raiseError(AddMergeInteractiveContent.MergeInFilter);
41781
+ css /* scss */ `
41782
+ .o-menu-item-button {
41783
+ display: flex;
41784
+ justify-content: center;
41785
+ align-items: center;
41786
+ margin: 2px;
41787
+ padding: 0px 3px;
41788
+ border-radius: 2px;
41789
+ min-width: 20px;
41790
+ }
41791
+ .o-disabled {
41792
+ opacity: 0.6;
41793
+ cursor: default;
41794
+ }
41795
+ `;
41796
+ class ActionButton extends owl.Component {
41797
+ constructor() {
41798
+ super(...arguments);
41799
+ this.actionButton = createAction(this.props.action);
40882
41800
  }
40883
- else if (result.isCancelledBecause(3 /* CommandResult.MergeIsDestructive */)) {
40884
- env.askConfirmation(AddMergeInteractiveContent.MergeIsDestructive, () => {
40885
- env.model.dispatch("ADD_MERGE", { sheetId, target, force: true });
40886
- });
41801
+ setup() {
41802
+ owl.onWillUpdateProps(() => (this.actionButton = createAction(this.props.action)));
40887
41803
  }
40888
- }
41804
+ get isVisible() {
41805
+ return this.actionButton.isVisible(this.env);
41806
+ }
41807
+ get isEnabled() {
41808
+ return this.actionButton.isEnabled(this.env);
41809
+ }
41810
+ get isActive() {
41811
+ var _a, _b;
41812
+ return (_b = (_a = this.actionButton).isActive) === null || _b === void 0 ? void 0 : _b.call(_a, this.env);
41813
+ }
41814
+ get title() {
41815
+ const name = this.actionButton.name(this.env);
41816
+ const description = this.actionButton.description;
41817
+ return name + (description ? ` (${description})` : "");
41818
+ }
41819
+ get iconTitle() {
41820
+ return this.actionButton.icon;
41821
+ }
41822
+ onClick(ev) {
41823
+ var _a, _b, _c, _d;
41824
+ if (this.isEnabled) {
41825
+ (_b = (_a = this.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, ev);
41826
+ (_d = (_c = this.actionButton).execute) === null || _d === void 0 ? void 0 : _d.call(_c, this.env);
41827
+ }
41828
+ }
41829
+ get buttonStyle() {
41830
+ if (this.props.selectedColor) {
41831
+ return cssPropertiesToCss({
41832
+ "border-bottom": `4px solid ${this.props.selectedColor}`,
41833
+ height: "16px",
41834
+ "margin-top": "2px",
41835
+ });
41836
+ }
41837
+ return "";
41838
+ }
41839
+ }
41840
+ ActionButton.template = "o-spreadsheet-ActionButton";
40889
41841
 
40890
41842
  const COMPOSER_MAX_HEIGHT = 100;
40891
41843
  css /* scss */ `
@@ -40947,6 +41899,14 @@
40947
41899
  input::-webkit-inner-spin-button {
40948
41900
  -webkit-appearance: none;
40949
41901
  }
41902
+
41903
+ .o-text-options > div {
41904
+ line-height: 26px;
41905
+ padding: 3px 12px;
41906
+ &:hover {
41907
+ background-color: rgba(0, 0, 0, 0.08);
41908
+ }
41909
+ }
40950
41910
  }
40951
41911
  `;
40952
41912
  class FontSizeEditor extends owl.Component {
@@ -41015,41 +41975,6 @@
41015
41975
  dropdownStyle: String,
41016
41976
  };
41017
41977
 
41018
- const FORMATS = [
41019
- { name: "automatic", text: NumberFormatTerms.Automatic },
41020
- { name: "number", text: NumberFormatTerms.Number, description: "1,000.12", value: "#,##0.00" },
41021
- { name: "percent", text: NumberFormatTerms.Percent, description: "10.12%", value: "0.00%" },
41022
- {
41023
- name: "currency",
41024
- text: NumberFormatTerms.Currency,
41025
- description: "$1,000.12",
41026
- value: "[$$]#,##0.00",
41027
- },
41028
- {
41029
- name: "currency_rounded",
41030
- text: NumberFormatTerms.CurrencyRounded,
41031
- description: "$1,000",
41032
- value: "[$$]#,##0",
41033
- },
41034
- { name: "date", text: NumberFormatTerms.Date, description: "9/26/2008", value: "m/d/yyyy" },
41035
- { name: "time", text: NumberFormatTerms.Time, description: "10:43:00 PM", value: "hh:mm:ss a" },
41036
- {
41037
- name: "datetime",
41038
- text: NumberFormatTerms.DateTime,
41039
- description: "9/26/2008 22:43:00",
41040
- value: "m/d/yyyy hh:mm:ss",
41041
- },
41042
- {
41043
- name: "duration",
41044
- text: NumberFormatTerms.Duration,
41045
- description: "27:51:38",
41046
- value: "hhhh:mm:ss",
41047
- },
41048
- ];
41049
- const CUSTOM_FORMATS = [
41050
- { name: "custom_currency", text: NumberFormatTerms.CustomCurrency, sidePanel: "CustomCurrency" },
41051
- ];
41052
- const ICONS_COLOR = "#4A4F59";
41053
41978
  // If we ever change these colors, make sure the filter tool stays green to match the icon in the grid
41054
41979
  const ACTIVE_BG_COLOR = BACKGROUND_HEADER_FILTER_COLOR;
41055
41980
  const ACTIVE_FONT_COLOR = FILTERS_COLOR;
@@ -41114,23 +42039,10 @@
41114
42039
 
41115
42040
  /* Toolbar */
41116
42041
  .o-toolbar-tools {
41117
- .o-tool {
41118
- display: flex;
41119
- justify-content: center;
41120
- align-items: center;
41121
- margin: 2px;
41122
- padding: 0px 3px;
41123
- border-radius: 2px;
41124
- min-width: 20px;
41125
- }
41126
-
41127
- .o-filter-tool {
41128
- margin-right: 8px;
41129
- }
41130
-
41131
- .o-border-dropdown {
41132
- padding: 4px;
41133
- }
42042
+ display: flex;
42043
+ flex-shrink: 0;
42044
+ margin: 0px 6px 0px 16px;
42045
+ cursor: default;
41134
42046
 
41135
42047
  .o-divider {
41136
42048
  display: inline-block;
@@ -41139,69 +42051,33 @@
41139
42051
  margin: 0 6px;
41140
42052
  }
41141
42053
 
41142
- .o-disabled {
41143
- opacity: 0.6;
41144
- cursor: default;
41145
- }
41146
-
41147
42054
  .o-dropdown {
41148
42055
  position: relative;
41149
42056
  display: flex;
41150
42057
  align-items: center;
41151
42058
 
41152
- .o-dropdown-button {
42059
+ > span {
41153
42060
  height: 30px;
41154
42061
  }
41155
42062
 
41156
- .o-text-options > div {
41157
- line-height: 26px;
41158
- padding: 3px 12px;
41159
- &:hover {
41160
- background-color: rgba(0, 0, 0, 0.08);
41161
- }
41162
- }
41163
-
41164
42063
  .o-dropdown-content {
41165
42064
  position: absolute;
41166
42065
  top: 100%;
41167
42066
  left: 0;
41168
42067
  overflow-y: auto;
41169
42068
  overflow-x: hidden;
42069
+ padding: 2px;
41170
42070
  z-index: ${ComponentsImportance.Dropdown};
41171
42071
  box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
41172
42072
  background-color: white;
41173
42073
 
41174
42074
  .o-dropdown-line {
41175
42075
  display: flex;
41176
- margin: 1px;
41177
42076
 
41178
- .o-line-item {
42077
+ > span {
41179
42078
  padding: 4px;
41180
- width: 18px;
41181
- height: 18px;
41182
42079
  }
41183
42080
  }
41184
-
41185
- &.o-format-tool {
41186
- padding: 5px 0;
41187
- width: 250px;
41188
- font-size: 12px;
41189
- > div {
41190
- padding: 0 20px;
41191
- white-space: nowrap;
41192
-
41193
- &.o-dropdown-active:before {
41194
- content: "✓";
41195
- font-weight: bold;
41196
- position: absolute;
41197
- left: 5px;
41198
- }
41199
- }
41200
- }
41201
-
41202
- .o-dropdown-align-item {
41203
- padding: 7px 10px;
41204
- }
41205
42081
  }
41206
42082
  }
41207
42083
  }
@@ -41211,24 +42087,20 @@
41211
42087
  class TopBar extends owl.Component {
41212
42088
  constructor() {
41213
42089
  super(...arguments);
41214
- this.commonFormats = FORMATS;
41215
- this.customFormats = CUSTOM_FORMATS;
41216
- this.currentFormatName = "automatic";
41217
- this.style = {};
41218
42090
  this.state = owl.useState({
41219
42091
  menuState: { isOpen: false, position: null, menuItems: [] },
41220
42092
  activeTool: "",
42093
+ fillColor: "#ffffff",
42094
+ textColor: "#000000",
41221
42095
  });
41222
42096
  this.isSelectingMenu = false;
41223
42097
  this.openedEl = null;
41224
- this.inMerge = false;
41225
- this.cannotMerge = false;
41226
- this.undoTool = false;
41227
- this.redoTool = false;
41228
- this.paintFormatTool = false;
41229
- this.fillColor = "#ffffff";
41230
- this.textColor = "#000000";
41231
42098
  this.menus = [];
42099
+ this.EDIT = ACTION_EDIT;
42100
+ this.FORMAT = ACTION_FORMAT;
42101
+ this.VIEW = ACTION_VIEW;
42102
+ this.formatNumberMenuItemSpec = formatNumberMenuItemSpec;
42103
+ this.isntToolbarMenu = false;
41232
42104
  }
41233
42105
  get dropdownStyle() {
41234
42106
  return `max-height:${this.props.dropdownMaxHeight}px`;
@@ -41258,28 +42130,8 @@
41258
42130
  this.props.onClick();
41259
42131
  this.closeMenus();
41260
42132
  }
41261
- toggleStyle(style) {
41262
- setStyle(this.env, { [style]: !this.style[style] });
41263
- }
41264
- toggleFormat(formatName) {
41265
- const formatter = FORMATS.find((f) => f.name === formatName);
41266
- const value = (formatter && formatter.value) || "";
41267
- setFormatter(this.env, value);
41268
- }
41269
- toggleHorizontalAlign(align) {
41270
- setStyle(this.env, { align });
41271
- this.onClick();
41272
- }
41273
- toggleVerticalAlign(verticalAlign) {
41274
- setStyle(this.env, { verticalAlign });
41275
- this.onClick();
41276
- }
41277
- toggleTextWrapping(wrapping) {
41278
- setStyle(this.env, { wrapping });
41279
- this.onClick();
41280
- }
41281
42133
  onMenuMouseOver(menu, ev) {
41282
- if (this.isSelectingMenu) {
42134
+ if (this.isSelectingMenu && this.isntToolbarMenu) {
41283
42135
  this.openMenu(menu, ev);
41284
42136
  }
41285
42137
  }
@@ -41290,15 +42142,27 @@
41290
42142
  this.openedEl = isOpen ? null : ev.target;
41291
42143
  }
41292
42144
  toggleContextMenu(menu, ev) {
41293
- if (this.state.menuState.isOpen) {
42145
+ if (this.state.menuState.isOpen && this.isntToolbarMenu) {
42146
+ this.closeMenus();
42147
+ }
42148
+ else {
42149
+ this.openMenu(menu, ev);
42150
+ this.isntToolbarMenu = true;
42151
+ }
42152
+ }
42153
+ toggleToolbarContextMenu(menuSpec, ev) {
42154
+ if (this.state.menuState.isOpen && !this.isntToolbarMenu) {
41294
42155
  this.closeMenus();
41295
42156
  }
41296
42157
  else {
42158
+ const menu = createAction(menuSpec);
41297
42159
  this.openMenu(menu, ev);
42160
+ this.isntToolbarMenu = false;
41298
42161
  }
41299
42162
  }
41300
42163
  openMenu(menu, ev) {
41301
- const { left, top, height } = ev.target.getBoundingClientRect();
42164
+ const { left, top, height } = ev.currentTarget.getBoundingClientRect();
42165
+ this.state.activeTool = "";
41302
42166
  this.state.menuState.isOpen = true;
41303
42167
  this.state.menuState.position = { x: left, y: top + height };
41304
42168
  this.state.menuState.menuItems = menu.children(this.env);
@@ -41315,134 +42179,28 @@
41315
42179
  this.openedEl = null;
41316
42180
  }
41317
42181
  updateCellState() {
41318
- const zones = this.env.model.getters.getSelectedZones();
41319
- const { col, row, sheetId } = this.env.model.getters.getActivePosition();
41320
- this.inMerge = false;
41321
- const { top, left, right, bottom } = this.env.model.getters.getSelectedZone();
41322
- const { xSplit, ySplit } = this.env.model.getters.getPaneDivisions(sheetId);
41323
- this.cannotMerge =
41324
- zones.length > 1 ||
41325
- (top === bottom && left === right) ||
41326
- (left < xSplit && xSplit <= right) ||
41327
- (top < ySplit && ySplit <= bottom);
41328
- if (!this.cannotMerge) {
41329
- const zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
41330
- this.inMerge = isEqual(zones[0], zone);
41331
- }
41332
- this.undoTool = this.env.model.getters.canUndo();
41333
- this.redoTool = this.env.model.getters.canRedo();
41334
- this.paintFormatTool = this.env.model.getters.isPaintingFormat();
41335
- const cell = this.env.model.getters.getActiveCell();
41336
- if (cell.format) {
41337
- const currentFormat = this.commonFormats.find((f) => f.value === cell.format);
41338
- this.currentFormatName = currentFormat ? currentFormat.name : "";
41339
- }
41340
- else {
41341
- this.currentFormatName = "automatic";
41342
- }
41343
- this.style = { ...this.env.model.getters.getCurrentStyle() };
41344
- this.style.align = this.style.align || cell.defaultAlign;
41345
- this.fillColor = this.style.fillColor || "#ffffff";
41346
- this.textColor = this.style.textColor || "#000000";
42182
+ const style = this.env.model.getters.getCurrentStyle();
42183
+ this.state.fillColor = style.fillColor || "#ffffff";
42184
+ this.state.textColor = style.textColor || "#000000";
41347
42185
  this.menus = topbarMenuRegistry.getMenuItems();
41348
42186
  }
41349
42187
  getMenuName(menu) {
41350
42188
  return menu.name(this.env);
41351
42189
  }
41352
- toggleMerge() {
41353
- if (this.cannotMerge) {
41354
- return;
41355
- }
41356
- const zones = this.env.model.getters.getSelectedZones();
41357
- const target = [zones[zones.length - 1]];
41358
- const sheetId = this.env.model.getters.getActiveSheetId();
41359
- if (this.inMerge) {
41360
- this.env.model.dispatch("REMOVE_MERGE", { sheetId, target });
41361
- }
41362
- else {
41363
- interactiveAddMerge(this.env, sheetId, target);
41364
- }
41365
- }
41366
42190
  setColor(target, color) {
41367
42191
  setStyle(this.env, { [target]: color });
41368
42192
  this.onClick();
41369
42193
  }
41370
- setBorder(command) {
41371
- this.env.model.dispatch("SET_FORMATTING", {
41372
- sheetId: this.env.model.getters.getActiveSheetId(),
41373
- target: this.env.model.getters.getSelectedZones(),
41374
- border: command,
41375
- });
41376
- this.onClick();
41377
- }
41378
- setFormat(format, custom) {
41379
- if (!custom) {
41380
- this.toggleFormat(format);
41381
- }
41382
- else {
41383
- this.openCustomFormatSidePanel(format);
41384
- }
41385
- this.onClick();
41386
- }
41387
- openCustomFormatSidePanel(custom) {
41388
- const customFormatter = CUSTOM_FORMATS.find((c) => c.name === custom);
41389
- const sidePanel = (customFormatter && customFormatter.sidePanel) || "";
41390
- this.env.openSidePanel(sidePanel);
41391
- }
41392
- setDecimal(step) {
41393
- this.env.model.dispatch("SET_DECIMAL", {
41394
- sheetId: this.env.model.getters.getActiveSheetId(),
41395
- target: this.env.model.getters.getSelectedZones(),
41396
- step: step,
41397
- });
41398
- }
41399
- paintFormat() {
41400
- this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", {
41401
- target: this.env.model.getters.getSelectedZones(),
41402
- });
41403
- }
41404
- clearFormatting() {
41405
- this.env.model.dispatch("CLEAR_FORMATTING", {
41406
- sheetId: this.env.model.getters.getActiveSheetId(),
41407
- target: this.env.model.getters.getSelectedZones(),
41408
- });
41409
- }
41410
- doAction(action) {
41411
- action(this.env);
41412
- this.closeMenus();
41413
- }
41414
- undo() {
41415
- this.env.model.dispatch("REQUEST_UNDO");
41416
- }
41417
- redo() {
41418
- this.env.model.dispatch("REQUEST_REDO");
41419
- }
41420
- get selectionContainsFilter() {
41421
- const sheetId = this.env.model.getters.getActiveSheetId();
41422
- const selectedZones = this.env.model.getters.getSelectedZones();
41423
- return this.env.model.getters.doesZonesContainFilter(sheetId, selectedZones);
41424
- }
41425
- get cannotCreateFilter() {
41426
- return !areZonesContinuous(...this.env.model.getters.getSelectedZones());
41427
- }
41428
- createFilter() {
41429
- if (this.cannotCreateFilter) {
41430
- return;
41431
- }
41432
- this.env.model.selection.selectTableAroundSelection();
41433
- const sheetId = this.env.model.getters.getActiveSheetId();
41434
- const selection = this.env.model.getters.getSelectedZones();
41435
- interactiveAddFilter(this.env, sheetId, selection);
41436
- }
41437
- removeFilter() {
41438
- this.env.model.dispatch("REMOVE_FILTER_TABLE", {
41439
- sheetId: this.env.model.getters.getActiveSheetId(),
41440
- target: this.env.model.getters.getSelectedZones(),
41441
- });
41442
- }
41443
42194
  }
41444
42195
  TopBar.template = "o-spreadsheet-TopBar";
41445
- TopBar.components = { ColorPickerWidget, Menu, TopBarComposer, FontSizeEditor };
42196
+ TopBar.components = {
42197
+ ColorPickerWidget,
42198
+ ColorPicker,
42199
+ Menu,
42200
+ TopBarComposer,
42201
+ FontSizeEditor,
42202
+ ActionButton,
42203
+ };
41446
42204
  TopBar.props = {
41447
42205
  onClick: Function,
41448
42206
  focusComposer: String,
@@ -41518,10 +42276,12 @@
41518
42276
  button {
41519
42277
  color: #333;
41520
42278
  }
41521
-
41522
- * {
41523
- font-family: "Roboto", "RobotoDraft", Helvetica, Arial, sans-serif;
42279
+ .o-disabled {
42280
+ opacity: 0.4;
42281
+ pointer: default;
42282
+ pointer-events: none;
41524
42283
  }
42284
+
41525
42285
  &,
41526
42286
  *,
41527
42287
  *:before,
@@ -41550,6 +42310,10 @@
41550
42310
  height: ${CF_ICON_EDGE_LENGTH}px;
41551
42311
  vertical-align: sub;
41552
42312
  }
42313
+
42314
+ .o-text-icon {
42315
+ vertical-align: middle;
42316
+ }
41553
42317
  `;
41554
42318
  // -----------------------------------------------------------------------------
41555
42319
  // GRID STYLE
@@ -44890,6 +45654,13 @@
44890
45654
  * Internal status of the model. Important for command handling coordination
44891
45655
  */
44892
45656
  this.status = 0 /* Status.Ready */;
45657
+ /**
45658
+ * Check if a command can be dispatched, and returns a DispatchResult object with the possible
45659
+ * reasons the dispatch failed.
45660
+ */
45661
+ this.canDispatch = (type, payload) => {
45662
+ return this.checkDispatchAllowed({ ...payload, type });
45663
+ };
44893
45664
  /**
44894
45665
  * The dispatch method is the only entry point to manipulate data in the model.
44895
45666
  * This is through this method that commands are dispatched most of the time
@@ -45033,7 +45804,10 @@
45033
45804
  owl.markRaw(this);
45034
45805
  }
45035
45806
  get handlers() {
45036
- return [this.range, ...this.corePlugins, ...this.allUIPlugins, this.history];
45807
+ return [...this.coreHandlers, ...this.allUIPlugins, this.history];
45808
+ }
45809
+ get coreHandlers() {
45810
+ return [this.range, ...this.corePlugins];
45037
45811
  }
45038
45812
  get allUIPlugins() {
45039
45813
  return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
@@ -45161,6 +45935,16 @@
45161
45935
  * Check if the given command is allowed by all the plugins and the history.
45162
45936
  */
45163
45937
  checkDispatchAllowed(command) {
45938
+ if (isCoreCommand(command)) {
45939
+ return this.checkDispatchAllowedCoreCommand(command);
45940
+ }
45941
+ return this.checkDispatchAllowedLocalCommand(command);
45942
+ }
45943
+ checkDispatchAllowedCoreCommand(command) {
45944
+ const results = this.coreHandlers.map((handler) => handler.allowDispatch(command));
45945
+ return new DispatchResult(results.flat());
45946
+ }
45947
+ checkDispatchAllowedLocalCommand(command) {
45164
45948
  const results = this.handlers.map((handler) => handler.allowDispatch(command));
45165
45949
  return new DispatchResult(results.flat());
45166
45950
  }
@@ -45301,6 +46085,7 @@
45301
46085
  inverseCommandRegistry,
45302
46086
  urlRegistry,
45303
46087
  cellPopoverRegistry,
46088
+ numberFormatMenuRegistry,
45304
46089
  };
45305
46090
  const helpers = {
45306
46091
  arg,
@@ -45385,15 +46170,16 @@
45385
46170
  exports.parse = parse;
45386
46171
  exports.readonlyAllowedCommands = readonlyAllowedCommands;
45387
46172
  exports.registries = registries;
46173
+ exports.setDefaultSheetViewSize = setDefaultSheetViewSize;
45388
46174
  exports.setTranslationMethod = setTranslationMethod;
45389
46175
  exports.tokenize = tokenize;
45390
46176
 
45391
46177
  Object.defineProperty(exports, '__esModule', { value: true });
45392
46178
 
45393
46179
 
45394
- __info__.version = '16.3.0-alpha.2';
45395
- __info__.date = '2023-03-23T11:36:58.645Z';
45396
- __info__.hash = '59f25bb';
46180
+ __info__.version = '16.3.0-alpha.4';
46181
+ __info__.date = '2023-04-14T12:49:16.671Z';
46182
+ __info__.hash = '6824b8a';
45397
46183
 
45398
46184
 
45399
46185
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);