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