@odoo/o-spreadsheet 16.3.0-alpha.3 → 16.3.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -114,6 +114,7 @@
114
114
  const BACKGROUND_HEADER_FILTER_COLOR = "#E6F4EA";
115
115
  const BACKGROUND_HEADER_SELECTED_FILTER_COLOR = "#CEEAD6";
116
116
  const SEPARATOR_COLOR = "#E0E2E4";
117
+ const ICONS_COLOR = "#4A4F59";
117
118
  // Color picker defaults as upper case HEX to match `toHex`helper
118
119
  const COLOR_PICKER_DEFAULTS = [
119
120
  "#000000",
@@ -220,8 +221,10 @@
220
221
  const FILTER_ICON_EDGE_LENGTH = 17;
221
222
  // Menus
222
223
  const MENU_WIDTH = 250;
223
- const MENU_VERTICAL_PADDING = 8;
224
- const MENU_ITEM_HEIGHT = 28;
224
+ const MENU_VERTICAL_PADDING = 6;
225
+ const MENU_ITEM_HEIGHT = 26;
226
+ const MENU_ITEM_PADDING_HORIZONTAL = 13;
227
+ const MENU_ITEM_PADDING_VERTICAL = 4;
225
228
  const MENU_SEPARATOR_BORDER_WIDTH = 1;
226
229
  const MENU_SEPARATOR_PADDING = 5;
227
230
  // Fonts
@@ -229,6 +232,7 @@
229
232
  const DEFAULT_FONT_SIZE = 10;
230
233
  const HEADER_FONT_SIZE = 11;
231
234
  const DEFAULT_FONT = "'Roboto', arial";
235
+ const DEFAULT_VERTICAL_ALIGN = "middle";
232
236
  // Borders
233
237
  const DEFAULT_BORDER_DESC = ["thin", "#000"];
234
238
  const DEFAULT_FILTER_BORDER_DESC = ["thin", FILTERS_COLOR];
@@ -271,15 +275,22 @@
271
275
  ComponentsImportance[ComponentsImportance["Highlight"] = 5] = "Highlight";
272
276
  ComponentsImportance[ComponentsImportance["Figure"] = 10] = "Figure";
273
277
  ComponentsImportance[ComponentsImportance["ScrollBar"] = 15] = "ScrollBar";
274
- ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
278
+ ComponentsImportance[ComponentsImportance["GridPopover"] = 19] = "GridPopover";
275
279
  ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
276
- ComponentsImportance[ComponentsImportance["TopBarComposer"] = 21] = "TopBarComposer";
280
+ ComponentsImportance[ComponentsImportance["Dropdown"] = 21] = "Dropdown";
277
281
  ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
278
- ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
282
+ ComponentsImportance[ComponentsImportance["TopBarComposer"] = 30] = "TopBarComposer";
283
+ ComponentsImportance[ComponentsImportance["Popover"] = 35] = "Popover";
279
284
  ComponentsImportance[ComponentsImportance["FigureAnchor"] = 1000] = "FigureAnchor";
280
285
  ComponentsImportance[ComponentsImportance["FigureSnapLine"] = 1001] = "FigureSnapLine";
281
286
  })(ComponentsImportance || (ComponentsImportance = {}));
282
- const DEFAULT_SHEETVIEW_SIZE = 1000;
287
+ let DEFAULT_SHEETVIEW_SIZE = 0;
288
+ function getDefaultSheetViewSize() {
289
+ return DEFAULT_SHEETVIEW_SIZE;
290
+ }
291
+ function setDefaultSheetViewSize(size) {
292
+ DEFAULT_SHEETVIEW_SIZE = size;
293
+ }
283
294
  const MAXIMAL_FREEZABLE_RATIO = 0.85;
284
295
  const NEWLINE = "\n";
285
296
  const FONT_SIZES = [6, 7, 8, 9, 10, 11, 12, 14, 18, 24, 36];
@@ -1710,12 +1721,77 @@
1710
1721
  * - all digit stored in the decimal part of the number
1711
1722
  *
1712
1723
  * The 'maxDecimal' parameter allows to indicate the number of digits to not
1713
- * exceed in the decimal part, in which case digits are rounded
1724
+ * exceed in the decimal part, in which case digits are rounded.
1714
1725
  *
1715
- * Intl.Numberformat is used to properly handle all the roundings.
1716
- * e.g. 1234.7 with format ### (<> maxDecimals=0) should become 1235, not 1234
1717
1726
  **/
1718
1727
  function splitNumber(value, maxDecimals = MAX_DECIMAL_PLACES) {
1728
+ const asString = value.toString();
1729
+ if (asString.includes("e"))
1730
+ return splitNumberIntl(value, maxDecimals);
1731
+ if (Number.isInteger(value)) {
1732
+ return { integerDigits: asString, decimalDigits: undefined };
1733
+ }
1734
+ const indexOfDot = asString.indexOf(".");
1735
+ let integerDigits = asString.substring(0, indexOfDot);
1736
+ let decimalDigits = asString.substring(indexOfDot + 1);
1737
+ if (maxDecimals === 0) {
1738
+ if (Number(decimalDigits[0]) >= 5) {
1739
+ integerDigits = (Number(integerDigits) + 1).toString();
1740
+ }
1741
+ return { integerDigits, decimalDigits: undefined };
1742
+ }
1743
+ if (decimalDigits.length > maxDecimals) {
1744
+ const { integerDigits: roundedIntegerDigits, decimalDigits: roundedDecimalDigits } = limitDecimalDigits(decimalDigits, maxDecimals);
1745
+ decimalDigits = roundedDecimalDigits;
1746
+ if (roundedIntegerDigits !== "0") {
1747
+ integerDigits = (Number(integerDigits) + Number(roundedIntegerDigits)).toString();
1748
+ }
1749
+ }
1750
+ return { integerDigits, decimalDigits: removeTrailingZeroes(decimalDigits || "") };
1751
+ }
1752
+ /**
1753
+ * Return the given string minus the trailing "0" characters.
1754
+ *
1755
+ * @param numberString : a string of integers
1756
+ * @returns the numberString, minus the eventual zeroes at the end
1757
+ */
1758
+ function removeTrailingZeroes(numberString) {
1759
+ let i = numberString.length - 1;
1760
+ while (i >= 0 && numberString[i] === "0") {
1761
+ i--;
1762
+ }
1763
+ return numberString.slice(0, i + 1) || undefined;
1764
+ }
1765
+ /**
1766
+ * Limit the size of the decimal part of a number to the given number of digits.
1767
+ */
1768
+ function limitDecimalDigits(decimalDigits, maxDecimals) {
1769
+ let integerDigits = "0";
1770
+ let resultDecimalDigits = decimalDigits;
1771
+ // Note : we'd want to simply use number.toFixed() to handle the max digits & rounding,
1772
+ // but it has very strange behaviour. Ex: 12.345.toFixed(2) => "12.35", but 1.345.toFixed(2) => "1.34"
1773
+ let slicedDecimalDigits = decimalDigits.slice(0, maxDecimals);
1774
+ const i = maxDecimals;
1775
+ if (Number(Number(decimalDigits[i]) < 5)) {
1776
+ return { integerDigits, decimalDigits: slicedDecimalDigits };
1777
+ }
1778
+ // round up
1779
+ const slicedRoundedUp = (Number(slicedDecimalDigits) + 1).toString();
1780
+ if (slicedRoundedUp.length > slicedDecimalDigits.length) {
1781
+ integerDigits = (Number(integerDigits) + 1).toString();
1782
+ resultDecimalDigits = undefined;
1783
+ }
1784
+ else {
1785
+ resultDecimalDigits = slicedRoundedUp;
1786
+ }
1787
+ return { integerDigits, decimalDigits: resultDecimalDigits };
1788
+ }
1789
+ /**
1790
+ * Split numbers into decimal/integer digits using Intl.NumberFormat.
1791
+ * Supports numbers with a lot of digits that are transformed to scientific notation by
1792
+ * number.toString(), but is slow.
1793
+ */
1794
+ function splitNumberIntl(value, maxDecimals = MAX_DECIMAL_PLACES) {
1719
1795
  let formatter = numberRepresentation[maxDecimals];
1720
1796
  if (!formatter) {
1721
1797
  formatter = new Intl.NumberFormat("en-US", {
@@ -5182,6 +5258,11 @@
5182
5258
  this.currentPosition = newPosition;
5183
5259
  });
5184
5260
  }
5261
+ get popoverStyle() {
5262
+ return cssPropertiesToCss({
5263
+ "z-index": `${this.props.zIndex}`,
5264
+ });
5265
+ }
5185
5266
  }
5186
5267
  Popover.template = "o-spreadsheet-Popover";
5187
5268
  Popover.defaultProps = {
@@ -5190,6 +5271,7 @@
5190
5271
  onMouseWheel: () => { },
5191
5272
  onPopoverMoved: () => { },
5192
5273
  onPopoverHidden: () => { },
5274
+ zIndex: ComponentsImportance.Popover,
5193
5275
  };
5194
5276
  Popover.props = {
5195
5277
  anchorRect: Object,
@@ -5201,6 +5283,7 @@
5201
5283
  onMouseWheel: { type: Function, optional: true },
5202
5284
  onPopoverHidden: { type: Function, optional: true },
5203
5285
  onPopoverMoved: { type: Function, optional: true },
5286
+ zIndex: { type: Number, optional: true },
5204
5287
  slots: Object,
5205
5288
  };
5206
5289
  class PopoverPositionContext {
@@ -5344,7 +5427,7 @@
5344
5427
  align-items: center;
5345
5428
  box-sizing: border-box;
5346
5429
  height: ${MENU_ITEM_HEIGHT}px;
5347
- padding: 4px 16px;
5430
+ padding: ${MENU_ITEM_PADDING_VERTICAL}px ${MENU_ITEM_PADDING_HORIZONTAL}px;
5348
5431
  cursor: pointer;
5349
5432
  user-select: none;
5350
5433
 
@@ -5358,11 +5441,18 @@
5358
5441
  display: flex;
5359
5442
  justify-content: space-between;
5360
5443
  }
5444
+
5361
5445
  .o-menu-item-icon {
5362
- margin-top: auto;
5363
- margin-bottom: auto;
5446
+ display: inline-block;
5447
+ margin-right: calc(${MENU_ITEM_PADDING_HORIZONTAL}px * 3 / 5);
5448
+ width: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
5449
+ line-height: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
5450
+
5451
+ .o-icon {
5452
+ color: ${ICONS_COLOR};
5453
+ }
5364
5454
  }
5365
- .o-icon {
5455
+ .o-menu-item-root {
5366
5456
  width: 10px;
5367
5457
  }
5368
5458
 
@@ -5442,12 +5532,22 @@
5442
5532
  onPopoverMoved: () => this.closeSubMenu(),
5443
5533
  };
5444
5534
  }
5535
+ get childrenHaveIcon() {
5536
+ return this.props.menuItems.some((menuItem) => !menuItem.icon && !!menuItem.isActive);
5537
+ }
5538
+ getIconName(menu) {
5539
+ var _a;
5540
+ if ((_a = menu.isActive) === null || _a === void 0 ? void 0 : _a.call(menu, this.env)) {
5541
+ return "o-spreadsheet-Icon.CHECK";
5542
+ }
5543
+ return "";
5544
+ }
5445
5545
  getColor(menu) {
5446
5546
  return menu.textColor ? `color: ${menu.textColor}` : undefined;
5447
5547
  }
5448
5548
  async activateMenu(menu) {
5449
5549
  var _a, _b, _c;
5450
- const result = await ((_a = menu.action) === null || _a === void 0 ? void 0 : _a.call(menu, this.env));
5550
+ const result = await ((_a = menu.execute) === null || _a === void 0 ? void 0 : _a.call(menu, this.env));
5451
5551
  this.close();
5452
5552
  (_c = (_b = this.props).onMenuClicked) === null || _c === void 0 ? void 0 : _c.call(_b, { detail: result });
5453
5553
  }
@@ -5468,7 +5568,7 @@
5468
5568
  return menu.name(this.env);
5469
5569
  }
5470
5570
  isRoot(menu) {
5471
- return !menu.action;
5571
+ return !menu.execute;
5472
5572
  }
5473
5573
  isEnabled(menu) {
5474
5574
  if (menu.isEnabled(this.env)) {
@@ -5515,7 +5615,7 @@
5515
5615
  }
5516
5616
  }
5517
5617
  onMouseOver(menu, position, ev) {
5518
- if (menu.isEnabled(this.env)) {
5618
+ if (this.isEnabled(menu)) {
5519
5619
  if (this.isRoot(menu)) {
5520
5620
  this.openSubMenu(menu, position, ev);
5521
5621
  }
@@ -5652,35 +5752,108 @@
5652
5752
  onClosed: { type: Function, optional: true },
5653
5753
  };
5654
5754
 
5655
- function createMenu(menuItems) {
5656
- return menuItems.map(createMenuItem).sort((a, b) => a.sequence - b.sequence);
5755
+ const linkSheet = {
5756
+ name: _lt("Link sheet"),
5757
+ children: [
5758
+ (env) => {
5759
+ const sheets = env.model.getters
5760
+ .getSheetIds()
5761
+ .map((sheetId) => env.model.getters.getSheet(sheetId));
5762
+ return sheets.map((sheet) => ({
5763
+ id: sheet.id,
5764
+ name: sheet.name,
5765
+ execute: () => markdownLink(sheet.name, buildSheetLink(sheet.id)),
5766
+ }));
5767
+ },
5768
+ ],
5769
+ };
5770
+ const deleteSheet = {
5771
+ name: _lt("Delete"),
5772
+ isVisible: (env) => {
5773
+ return env.model.getters.getSheetIds().length > 1;
5774
+ },
5775
+ execute: (env) => env.askConfirmation(_lt("Are you sure you want to delete this sheet ?"), () => {
5776
+ env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
5777
+ }),
5778
+ };
5779
+ const duplicateSheet = {
5780
+ name: _lt("Duplicate"),
5781
+ execute: (env) => {
5782
+ const sheetIdFrom = env.model.getters.getActiveSheetId();
5783
+ const sheetIdTo = env.model.uuidGenerator.uuidv4();
5784
+ env.model.dispatch("DUPLICATE_SHEET", {
5785
+ sheetId: sheetIdFrom,
5786
+ sheetIdTo,
5787
+ });
5788
+ env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
5789
+ },
5790
+ };
5791
+ const renameSheet = (args) => {
5792
+ return {
5793
+ name: _lt("Rename"),
5794
+ execute: args.renameSheetCallback,
5795
+ };
5796
+ };
5797
+ const sheetMoveRight = {
5798
+ name: _lt("Move right"),
5799
+ isVisible: (env) => {
5800
+ const sheetId = env.model.getters.getActiveSheetId();
5801
+ const sheetIds = env.model.getters.getVisibleSheetIds();
5802
+ return sheetIds.indexOf(sheetId) !== sheetIds.length - 1;
5803
+ },
5804
+ execute: (env) => env.model.dispatch("MOVE_SHEET", {
5805
+ sheetId: env.model.getters.getActiveSheetId(),
5806
+ delta: 1,
5807
+ }),
5808
+ };
5809
+ const sheetMoveLeft = {
5810
+ name: _lt("Move left"),
5811
+ isVisible: (env) => {
5812
+ const sheetId = env.model.getters.getActiveSheetId();
5813
+ return env.model.getters.getVisibleSheetIds()[0] !== sheetId;
5814
+ },
5815
+ execute: (env) => env.model.dispatch("MOVE_SHEET", {
5816
+ sheetId: env.model.getters.getActiveSheetId(),
5817
+ delta: -1,
5818
+ }),
5819
+ };
5820
+ const hideSheet = {
5821
+ name: _lt("Hide sheet"),
5822
+ isVisible: (env) => env.model.getters.getVisibleSheetIds().length !== 1,
5823
+ execute: (env) => env.model.dispatch("HIDE_SHEET", { sheetId: env.model.getters.getActiveSheetId() }),
5824
+ };
5825
+
5826
+ function createActions(menuItems) {
5827
+ return menuItems.map(createAction).sort((a, b) => a.sequence - b.sequence);
5657
5828
  }
5658
- const uuidGenerator$1 = new UuidGenerator();
5659
- function createMenuItem(item) {
5829
+ const uuidGenerator$2 = new UuidGenerator();
5830
+ function createAction(item) {
5660
5831
  const name = item.name;
5661
5832
  const children = item.children;
5662
5833
  return {
5663
- id: item.id || uuidGenerator$1.uuidv4(),
5834
+ id: item.id || uuidGenerator$2.uuidv4(),
5664
5835
  name: typeof name === "function" ? name : () => name,
5665
5836
  isVisible: item.isVisible ? item.isVisible : () => true,
5666
5837
  isEnabled: item.isEnabled ? item.isEnabled : () => true,
5667
- action: item.action,
5838
+ isActive: item.isActive,
5839
+ execute: item.execute,
5668
5840
  children: children
5669
5841
  ? (env) => {
5670
5842
  return children
5671
5843
  .map((child) => (typeof child === "function" ? child(env) : child))
5672
5844
  .flat()
5673
- .map(createMenuItem);
5845
+ .map(createAction);
5674
5846
  }
5675
5847
  : () => [],
5676
5848
  isReadonlyAllowed: item.isReadonlyAllowed || false,
5677
5849
  separator: item.separator || false,
5678
- icon: item.icon,
5850
+ icon: item.icon || "",
5679
5851
  description: item.description || "",
5680
5852
  textColor: item.textColor,
5681
5853
  sequence: item.sequence || 0,
5682
5854
  };
5683
- }
5855
+ }
5856
+
5684
5857
  /**
5685
5858
  * The class Registry is extended in order to add the function addChild
5686
5859
  *
@@ -5727,7 +5900,7 @@
5727
5900
  return this;
5728
5901
  }
5729
5902
  getMenuItems() {
5730
- return createMenu(this.getAll());
5903
+ return createActions(this.getAll());
5731
5904
  }
5732
5905
  }
5733
5906
 
@@ -5735,20 +5908,9 @@
5735
5908
  // Link Menu Registry
5736
5909
  //------------------------------------------------------------------------------
5737
5910
  const linkMenuRegistry = new MenuItemRegistry();
5738
- linkMenuRegistry
5739
- .add("sheet", {
5740
- name: _lt("Link sheet"),
5911
+ linkMenuRegistry.add("sheet", {
5912
+ ...linkSheet,
5741
5913
  sequence: 10,
5742
- })
5743
- .addChild("sheet_list", ["sheet"], (env) => {
5744
- const sheets = env.model.getters
5745
- .getSheetIds()
5746
- .map((sheetId) => env.model.getters.getSheet(sheetId));
5747
- return sheets.map((sheet) => ({
5748
- id: sheet.id,
5749
- name: sheet.name,
5750
- action: () => markdownLink(sheet.name, buildSheetLink(sheet.id)),
5751
- }));
5752
5914
  });
5753
5915
 
5754
5916
  const MENU_OFFSET_X = 320;
@@ -6412,18 +6574,6 @@
6412
6574
  [43 /* CommandResult.GaugeUpperInflectionPointNaN */]: _lt("The upper inflection point value must be a number"),
6413
6575
  },
6414
6576
  };
6415
- const NumberFormatTerms = {
6416
- Automatic: _lt("Automatic"),
6417
- Number: _lt("Number"),
6418
- Percent: _lt("Percent"),
6419
- Currency: _lt("Currency"),
6420
- CurrencyRounded: _lt("Currency rounded"),
6421
- Date: _lt("Date"),
6422
- Time: _lt("Time"),
6423
- DateTime: _lt("Date time"),
6424
- Duration: _lt("Duration"),
6425
- CustomCurrency: _lt("Custom currency"),
6426
- };
6427
6577
  const CustomCurrencyTerms = {
6428
6578
  Custom: _lt("Custom"),
6429
6579
  };
@@ -7967,7 +8117,7 @@
7967
8117
  id: "edit",
7968
8118
  name: _lt("Edit"),
7969
8119
  sequence: 1,
7970
- action: () => {
8120
+ execute: () => {
7971
8121
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
7972
8122
  env.openSidePanel("ChartPanel");
7973
8123
  },
@@ -7976,7 +8126,7 @@
7976
8126
  getCutMenuItem(figureId, env),
7977
8127
  getDeleteMenuItem(figureId, onFigureDeleted, env),
7978
8128
  ];
7979
- return createMenu(menuItemSpecs);
8129
+ return createActions(menuItemSpecs);
7980
8130
  }
7981
8131
  function getImageMenuRegistry(figureId, onFigureDeleted, env) {
7982
8132
  const menuItemSpecs = [
@@ -7986,7 +8136,7 @@
7986
8136
  id: "reset_size",
7987
8137
  name: _lt("Reset size"),
7988
8138
  sequence: 4,
7989
- action: () => {
8139
+ execute: () => {
7990
8140
  const size = env.model.getters.getImageSize(figureId);
7991
8141
  const { height, width } = getMaxFigureSize(env.model.getters, size);
7992
8142
  env.model.dispatch("UPDATE_FIGURE", {
@@ -7999,7 +8149,7 @@
7999
8149
  },
8000
8150
  getDeleteMenuItem(figureId, onFigureDeleted, env),
8001
8151
  ];
8002
- return createMenu(menuItemSpecs);
8152
+ return createActions(menuItemSpecs);
8003
8153
  }
8004
8154
  function getCopyMenuItem(figureId, env) {
8005
8155
  return {
@@ -8007,7 +8157,7 @@
8007
8157
  name: _lt("Copy"),
8008
8158
  sequence: 2,
8009
8159
  description: "Ctrl+C",
8010
- action: async () => {
8160
+ execute: async () => {
8011
8161
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
8012
8162
  env.model.dispatch("COPY");
8013
8163
  await env.clipboard.write(env.model.getters.getClipboardContent());
@@ -8020,7 +8170,7 @@
8020
8170
  name: _lt("Cut"),
8021
8171
  sequence: 3,
8022
8172
  description: "Ctrl+X",
8023
- action: async () => {
8173
+ execute: async () => {
8024
8174
  env.model.dispatch("SELECT_FIGURE", { id: figureId });
8025
8175
  env.model.dispatch("CUT");
8026
8176
  await env.clipboard.write(env.model.getters.getClipboardContent());
@@ -8032,7 +8182,7 @@
8032
8182
  id: "delete",
8033
8183
  name: _lt("Delete"),
8034
8184
  sequence: 10,
8035
- action: () => {
8185
+ execute: () => {
8036
8186
  env.model.dispatch("DELETE_FIGURE", {
8037
8187
  sheetId: env.model.getters.getActiveSheetId(),
8038
8188
  id: figureId,
@@ -8139,6 +8289,22 @@
8139
8289
  ];
8140
8290
  }
8141
8291
 
8292
+ const AddMergeInteractiveContent = {
8293
+ MergeIsDestructive: _lt("Merging these cells will only preserve the top-leftmost value. Merge anyway?"),
8294
+ MergeInFilter: _lt("You can't merge cells inside of an existing filter."),
8295
+ };
8296
+ function interactiveAddMerge(env, sheetId, target) {
8297
+ const result = env.model.dispatch("ADD_MERGE", { sheetId, target });
8298
+ if (result.isCancelledBecause(80 /* CommandResult.MergeInFilter */)) {
8299
+ env.raiseError(AddMergeInteractiveContent.MergeInFilter);
8300
+ }
8301
+ else if (result.isCancelledBecause(3 /* CommandResult.MergeIsDestructive */)) {
8302
+ env.askConfirmation(AddMergeInteractiveContent.MergeIsDestructive, () => {
8303
+ env.model.dispatch("ADD_MERGE", { sheetId, target, force: true });
8304
+ });
8305
+ }
8306
+ }
8307
+
8142
8308
  /**
8143
8309
  * Create a function used to create a Chart based on the definition
8144
8310
  */
@@ -8494,9 +8660,9 @@
8494
8660
  interactiveCut(env);
8495
8661
  await env.clipboard.write(env.model.getters.getClipboardContent());
8496
8662
  };
8497
- const PASTE_ACTION = async (env) => paste(env);
8498
- const PASTE_VALUE_ACTION = async (env) => paste(env, "onlyValue");
8499
- async function paste(env, pasteOption) {
8663
+ const PASTE_ACTION = async (env) => paste$1(env);
8664
+ const PASTE_VALUE_ACTION = async (env) => paste$1(env, "onlyValue");
8665
+ async function paste$1(env, pasteOption) {
8500
8666
  const spreadsheetClipboard = env.model.getters.getClipboardTextContent();
8501
8667
  const osClipboard = await env.clipboard.readText();
8502
8668
  switch (osClipboard.status) {
@@ -9050,365 +9216,159 @@
9050
9216
  return env.model.getters.getSelectedZones().length === 1;
9051
9217
  };
9052
9218
 
9053
- //------------------------------------------------------------------------------
9054
- // Context Menu Registry
9055
- //------------------------------------------------------------------------------
9056
- const cellMenuRegistry = new MenuItemRegistry();
9057
- cellMenuRegistry
9058
- .add("cut", {
9059
- name: _lt("Cut"),
9060
- description: "Ctrl+X",
9061
- sequence: 10,
9062
- action: CUT_ACTION,
9063
- })
9064
- .add("copy", {
9219
+ const undo = {
9220
+ name: _lt("Undo"),
9221
+ description: "Ctrl+Z",
9222
+ execute: UNDO_ACTION,
9223
+ isEnabled: (env) => env.model.getters.canUndo(),
9224
+ icon: "o-spreadsheet-Icon.UNDO",
9225
+ };
9226
+ const redo = {
9227
+ name: _lt("Redo"),
9228
+ description: "Ctrl+Y",
9229
+ execute: REDO_ACTION,
9230
+ isEnabled: (env) => env.model.getters.canRedo(),
9231
+ icon: "o-spreadsheet-Icon.REDO",
9232
+ };
9233
+ const copy = {
9065
9234
  name: _lt("Copy"),
9066
9235
  description: "Ctrl+C",
9067
- sequence: 20,
9068
9236
  isReadonlyAllowed: true,
9069
- action: COPY_ACTION,
9070
- })
9071
- .add("paste", {
9072
- name: _lt("Paste"),
9073
- description: "Ctrl+V",
9074
- sequence: 30,
9075
- action: PASTE_ACTION,
9076
- })
9077
- .add("paste_special", {
9078
- name: _lt("Paste special"),
9079
- sequence: 40,
9080
- separator: true,
9081
- isVisible: IS_NOT_CUT_OPERATION,
9082
- })
9083
- .addChild("paste_value_only", ["paste_special"], {
9084
- name: _lt("Paste values only"),
9085
- sequence: 10,
9086
- action: PASTE_VALUE_ACTION,
9087
- })
9088
- .addChild("paste_format_only", ["paste_special"], {
9089
- name: _lt("Paste format only"),
9090
- sequence: 20,
9091
- action: PASTE_FORMAT_ACTION,
9092
- })
9093
- .add("add_row_before", {
9094
- name: CELL_INSERT_ROWS_BEFORE_NAME,
9095
- sequence: 70,
9096
- action: INSERT_ROWS_BEFORE_ACTION,
9097
- isVisible: IS_ONLY_ONE_RANGE,
9098
- })
9099
- .add("add_column_before", {
9100
- name: CELL_INSERT_COLUMNS_BEFORE_NAME,
9101
- sequence: 90,
9102
- action: INSERT_COLUMNS_BEFORE_ACTION,
9103
- isVisible: IS_ONLY_ONE_RANGE,
9104
- })
9105
- .add("insert_cell", {
9106
- name: _lt("Insert cells"),
9107
- sequence: 100,
9108
- isVisible: IS_ONLY_ONE_RANGE,
9109
- separator: true,
9110
- })
9111
- .addChild("insert_cell_down", ["insert_cell"], {
9112
- name: _lt("Shift down"),
9113
- sequence: 10,
9114
- action: INSERT_CELL_SHIFT_DOWN,
9115
- })
9116
- .addChild("insert_cell_right", ["insert_cell"], {
9117
- name: _lt("Shift right"),
9118
- sequence: 20,
9119
- action: INSERT_CELL_SHIFT_RIGHT,
9120
- })
9121
- .add("delete_row", {
9122
- name: REMOVE_ROWS_NAME,
9123
- sequence: 110,
9124
- action: REMOVE_ROWS_ACTION,
9125
- isVisible: IS_ONLY_ONE_RANGE,
9126
- })
9127
- .add("delete_column", {
9128
- name: REMOVE_COLUMNS_NAME,
9129
- sequence: 120,
9130
- action: REMOVE_COLUMNS_ACTION,
9131
- isVisible: IS_ONLY_ONE_RANGE,
9132
- })
9133
- .add("delete_cell", {
9134
- name: _lt("Delete cells"),
9135
- sequence: 130,
9136
- isVisible: IS_ONLY_ONE_RANGE,
9137
- })
9138
- .addChild("delete_cell_up", ["delete_cell"], {
9139
- name: _lt("Shift up"),
9140
- sequence: 10,
9141
- action: DELETE_CELL_SHIFT_UP,
9142
- })
9143
- .addChild("delete_cell_down", ["delete_cell"], {
9144
- name: _lt("Shift left"),
9145
- sequence: 20,
9146
- action: DELETE_CELL_SHIFT_LEFT,
9147
- })
9148
- .add("insert_link", {
9149
- name: _lt("Insert link"),
9150
- separator: true,
9151
- sequence: 150,
9152
- action: INSERT_LINK,
9153
- });
9154
-
9155
- const colMenuRegistry = new MenuItemRegistry();
9156
- colMenuRegistry
9157
- .add("cut", {
9237
+ execute: COPY_ACTION,
9238
+ };
9239
+ const cut = {
9158
9240
  name: _lt("Cut"),
9159
9241
  description: "Ctrl+X",
9160
- sequence: 10,
9161
- action: CUT_ACTION,
9162
- })
9163
- .add("copy", {
9164
- name: _lt("Copy"),
9165
- description: "Ctrl+C",
9166
- sequence: 20,
9167
- isReadonlyAllowed: true,
9168
- action: COPY_ACTION,
9169
- })
9170
- .add("paste", {
9242
+ execute: CUT_ACTION,
9243
+ };
9244
+ const paste = {
9171
9245
  name: _lt("Paste"),
9172
9246
  description: "Ctrl+V",
9173
- sequence: 30,
9174
- action: PASTE_ACTION,
9175
- })
9176
- .add("paste_special", {
9247
+ execute: PASTE_ACTION,
9248
+ };
9249
+ const pasteSpecial = {
9177
9250
  name: _lt("Paste special"),
9178
- sequence: 40,
9179
- separator: true,
9180
9251
  isVisible: IS_NOT_CUT_OPERATION,
9181
- })
9182
- .addChild("paste_value_only", ["paste_special"], {
9252
+ };
9253
+ const pasteSpecialValue = {
9183
9254
  name: _lt("Paste value only"),
9184
- sequence: 10,
9185
- action: PASTE_VALUE_ACTION,
9186
- })
9187
- .addChild("paste_format_only", ["paste_special"], {
9255
+ execute: PASTE_VALUE_ACTION,
9256
+ };
9257
+ const pasteSpecialFormat = {
9188
9258
  name: _lt("Paste format only"),
9189
- sequence: 20,
9190
- action: PASTE_FORMAT_ACTION,
9191
- })
9192
- .add("sort_columns", {
9193
- name: (env) => env.model.getters.getActiveCols().size > 1 ? _lt("Sort columns") : _lt("Sort column"),
9194
- sequence: 50,
9259
+ execute: PASTE_FORMAT_ACTION,
9260
+ };
9261
+ const findAndReplace = {
9262
+ name: _lt("Find and replace"),
9263
+ description: "Ctrl+H",
9264
+ isReadonlyAllowed: true,
9265
+ execute: OPEN_FAR_SIDEPANEL_ACTION,
9266
+ };
9267
+ const deleteValues = {
9268
+ name: _lt("Delete values"),
9269
+ execute: DELETE_CONTENT_ACTION,
9270
+ };
9271
+ const deleteRows = {
9272
+ name: REMOVE_ROWS_NAME,
9273
+ execute: REMOVE_ROWS_ACTION,
9274
+ };
9275
+ const deleteRow = {
9276
+ ...deleteRows,
9195
9277
  isVisible: IS_ONLY_ONE_RANGE,
9196
- separator: true,
9197
- })
9198
- .addChild("sort_ascending", ["sort_columns"], {
9199
- name: _lt("Ascending (A ⟶ Z)"),
9200
- sequence: 10,
9201
- action: SORT_CELLS_ASCENDING,
9202
- })
9203
- .addChild("sort_descending", ["sort_columns"], {
9204
- name: _lt("Descending (Z ⟶ A)"),
9205
- sequence: 20,
9206
- action: SORT_CELLS_DESCENDING,
9207
- })
9208
- .add("add_column_before", {
9209
- name: COLUMN_INSERT_COLUMNS_BEFORE_NAME,
9210
- sequence: 70,
9211
- action: INSERT_COLUMNS_BEFORE_ACTION,
9212
- })
9213
- .add("add_column_after", {
9214
- name: COLUMN_INSERT_COLUMNS_AFTER_NAME,
9215
- sequence: 80,
9216
- action: INSERT_COLUMNS_AFTER_ACTION,
9217
- })
9218
- .add("delete_column", {
9278
+ };
9279
+ const clearRows = {
9280
+ name: DELETE_CONTENT_ROWS_NAME,
9281
+ execute: DELETE_CONTENT_ROWS_ACTION,
9282
+ };
9283
+ const deleteCols = {
9219
9284
  name: REMOVE_COLUMNS_NAME,
9220
- sequence: 90,
9221
- action: REMOVE_COLUMNS_ACTION,
9222
- })
9223
- .add("clear_column", {
9285
+ execute: REMOVE_COLUMNS_ACTION,
9286
+ };
9287
+ const deleteCol = {
9288
+ ...deleteCols,
9289
+ isVisible: IS_ONLY_ONE_RANGE,
9290
+ };
9291
+ const clearCols = {
9224
9292
  name: DELETE_CONTENT_COLUMNS_NAME,
9225
- sequence: 100,
9226
- action: DELETE_CONTENT_COLUMNS_ACTION,
9227
- })
9228
- .add("hide_columns", {
9229
- name: HIDE_COLUMNS_NAME,
9230
- sequence: 85,
9231
- action: HIDE_COLUMNS_ACTION,
9232
- isVisible: (env) => {
9233
- const sheetId = env.model.getters.getActiveSheetId();
9234
- const hiddenCols = env.model.getters.getHiddenColsGroups(sheetId).flat();
9235
- return (env.model.getters.getNumberCols(sheetId) >
9236
- hiddenCols.length + env.model.getters.getElementsFromSelection("COL").length);
9237
- },
9238
- separator: true,
9239
- })
9240
- .add("unhide_columns", {
9241
- name: _lt("Unhide columns"),
9242
- sequence: 86,
9243
- action: UNHIDE_COLUMNS_ACTION,
9244
- isVisible: (env) => {
9245
- const hiddenCols = env.model.getters
9246
- .getHiddenColsGroups(env.model.getters.getActiveSheetId())
9247
- .flat();
9248
- const currentCols = env.model.getters.getElementsFromSelection("COL");
9249
- return currentCols.some((col) => hiddenCols.includes(col));
9250
- },
9251
- separator: true,
9252
- })
9253
- .add("conditional_formatting", {
9254
- name: _lt("Conditional formatting"),
9255
- sequence: 110,
9256
- action: OPEN_CF_SIDEPANEL_ACTION,
9257
- });
9293
+ execute: DELETE_CONTENT_COLUMNS_ACTION,
9294
+ };
9295
+ const deleteCells = {
9296
+ name: _lt("Delete cells"),
9297
+ isVisible: IS_ONLY_ONE_RANGE,
9298
+ };
9299
+ const deleteCellShiftUp = {
9300
+ name: _lt("Delete cell and shift up"),
9301
+ execute: DELETE_CELL_SHIFT_UP,
9302
+ };
9303
+ const deleteCellShiftLeft = {
9304
+ name: _lt("Delete cell and shift left"),
9305
+ execute: DELETE_CELL_SHIFT_LEFT,
9306
+ };
9307
+ const mergeCells = {
9308
+ name: _lt("Merge cells"),
9309
+ isEnabled: (env) => !cannotMerge(env),
9310
+ isActive: (env) => isInMerge(env),
9311
+ execute: (env) => toggleMerge(env),
9312
+ icon: "o-spreadsheet-Icon.MERGE_CELL",
9313
+ };
9314
+ function cannotMerge(env) {
9315
+ const zones = env.model.getters.getSelectedZones();
9316
+ const { top, left, right, bottom } = env.model.getters.getSelectedZone();
9317
+ const { sheetId } = env.model.getters.getActivePosition();
9318
+ const { xSplit, ySplit } = env.model.getters.getPaneDivisions(sheetId);
9319
+ return (zones.length > 1 ||
9320
+ (top === bottom && left === right) ||
9321
+ (left < xSplit && xSplit <= right) ||
9322
+ (top < ySplit && ySplit <= bottom));
9323
+ }
9324
+ function isInMerge(env) {
9325
+ if (!cannotMerge(env)) {
9326
+ const zones = env.model.getters.getSelectedZones();
9327
+ const { col, row, sheetId } = env.model.getters.getActivePosition();
9328
+ const zone = env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
9329
+ return isEqual(zones[0], zone);
9330
+ }
9331
+ return false;
9332
+ }
9333
+ function toggleMerge(env) {
9334
+ if (cannotMerge(env)) {
9335
+ return;
9336
+ }
9337
+ const zones = env.model.getters.getSelectedZones();
9338
+ const target = [zones[zones.length - 1]];
9339
+ const sheetId = env.model.getters.getActiveSheetId();
9340
+ if (isInMerge(env)) {
9341
+ env.model.dispatch("REMOVE_MERGE", { sheetId, target });
9342
+ }
9343
+ else {
9344
+ interactiveAddMerge(env, sheetId, target);
9345
+ }
9346
+ }
9258
9347
 
9259
- const rowMenuRegistry = new MenuItemRegistry();
9260
- rowMenuRegistry
9261
- .add("cut", {
9262
- name: _lt("Cut"),
9263
- sequence: 10,
9264
- description: "Ctrl+X",
9265
- action: CUT_ACTION,
9266
- })
9267
- .add("copy", {
9268
- name: _lt("Copy"),
9269
- description: "Ctrl+C",
9270
- sequence: 20,
9271
- isReadonlyAllowed: true,
9272
- action: COPY_ACTION,
9273
- })
9274
- .add("paste", {
9275
- name: _lt("Paste"),
9276
- description: "Ctrl+V",
9277
- sequence: 30,
9278
- action: PASTE_ACTION,
9279
- })
9280
- .add("paste_special", {
9281
- name: _lt("Paste special"),
9282
- sequence: 40,
9283
- separator: true,
9284
- isVisible: IS_NOT_CUT_OPERATION,
9285
- })
9286
- .addChild("paste_value_only", ["paste_special"], {
9287
- name: _lt("Paste value only"),
9288
- sequence: 10,
9289
- action: PASTE_VALUE_ACTION,
9290
- })
9291
- .addChild("paste_format_only", ["paste_special"], {
9292
- name: _lt("Paste format only"),
9293
- sequence: 20,
9294
- action: PASTE_FORMAT_ACTION,
9295
- })
9296
- .add("add_row_before", {
9297
- name: ROW_INSERT_ROWS_BEFORE_NAME,
9298
- sequence: 50,
9299
- action: INSERT_ROWS_BEFORE_ACTION,
9300
- })
9301
- .add("add_row_after", {
9302
- name: ROW_INSERT_ROWS_AFTER_NAME,
9303
- sequence: 60,
9304
- action: INSERT_ROWS_AFTER_ACTION,
9305
- })
9306
- .add("delete_row", {
9307
- name: REMOVE_ROWS_NAME,
9308
- sequence: 70,
9309
- action: REMOVE_ROWS_ACTION,
9310
- })
9311
- .add("clear_row", {
9312
- name: DELETE_CONTENT_ROWS_NAME,
9313
- sequence: 80,
9314
- action: DELETE_CONTENT_ROWS_ACTION,
9315
- })
9316
- .add("hide_rows", {
9317
- name: HIDE_ROWS_NAME,
9318
- sequence: 85,
9319
- action: HIDE_ROWS_ACTION,
9320
- isVisible: (env) => {
9321
- const sheetId = env.model.getters.getActiveSheetId();
9322
- const hiddenRows = env.model.getters.getHiddenRowsGroups(sheetId).flat();
9323
- return (env.model.getters.getNumberRows(sheetId) >
9324
- hiddenRows.length + env.model.getters.getElementsFromSelection("ROW").length);
9325
- },
9326
- separator: true,
9327
- })
9328
- .add("unhide_rows", {
9329
- name: _lt("Unhide rows"),
9330
- sequence: 86,
9331
- action: UNHIDE_ROWS_ACTION,
9332
- isVisible: (env) => {
9333
- const hiddenRows = env.model.getters
9334
- .getHiddenRowsGroups(env.model.getters.getActiveSheetId())
9335
- .flat();
9336
- const currentRows = env.model.getters.getElementsFromSelection("ROW");
9337
- return currentRows.some((col) => hiddenRows.includes(col));
9338
- },
9339
- separator: true,
9340
- })
9341
- .add("conditional_formatting", {
9342
- name: _lt("Conditional formatting"),
9343
- sequence: 90,
9344
- action: OPEN_CF_SIDEPANEL_ACTION,
9348
+ var ACTION_EDIT = /*#__PURE__*/Object.freeze({
9349
+ __proto__: null,
9350
+ undo: undo,
9351
+ redo: redo,
9352
+ copy: copy,
9353
+ cut: cut,
9354
+ paste: paste,
9355
+ pasteSpecial: pasteSpecial,
9356
+ pasteSpecialValue: pasteSpecialValue,
9357
+ pasteSpecialFormat: pasteSpecialFormat,
9358
+ findAndReplace: findAndReplace,
9359
+ deleteValues: deleteValues,
9360
+ deleteRows: deleteRows,
9361
+ deleteRow: deleteRow,
9362
+ clearRows: clearRows,
9363
+ deleteCols: deleteCols,
9364
+ deleteCol: deleteCol,
9365
+ clearCols: clearCols,
9366
+ deleteCells: deleteCells,
9367
+ deleteCellShiftUp: deleteCellShiftUp,
9368
+ deleteCellShiftLeft: deleteCellShiftLeft,
9369
+ mergeCells: mergeCells
9345
9370
  });
9346
9371
 
9347
- function getSheetMenuRegistry(args) {
9348
- const sheetMenuRegistry = new MenuItemRegistry();
9349
- sheetMenuRegistry
9350
- .add("delete", {
9351
- name: _lt("Delete"),
9352
- sequence: 10,
9353
- isVisible: (env) => {
9354
- return env.model.getters.getSheetIds().length > 1;
9355
- },
9356
- action: (env) => env.askConfirmation(_lt("Are you sure you want to delete this sheet ?"), () => {
9357
- env.model.dispatch("DELETE_SHEET", { sheetId: env.model.getters.getActiveSheetId() });
9358
- }),
9359
- })
9360
- .add("duplicate", {
9361
- name: _lt("Duplicate"),
9362
- sequence: 20,
9363
- action: (env) => {
9364
- const sheetIdFrom = env.model.getters.getActiveSheetId();
9365
- const sheetIdTo = env.model.uuidGenerator.uuidv4();
9366
- env.model.dispatch("DUPLICATE_SHEET", {
9367
- sheetId: sheetIdFrom,
9368
- sheetIdTo,
9369
- });
9370
- env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom, sheetIdTo });
9371
- },
9372
- })
9373
- .add("rename", {
9374
- name: _lt("Rename"),
9375
- sequence: 30,
9376
- action: () => args.renameSheetCallback(),
9377
- })
9378
- .add("move_right", {
9379
- name: _lt("Move right"),
9380
- sequence: 40,
9381
- isVisible: (env) => {
9382
- const sheetId = env.model.getters.getActiveSheetId();
9383
- const sheetIds = env.model.getters.getVisibleSheetIds();
9384
- return sheetIds.indexOf(sheetId) !== sheetIds.length - 1;
9385
- },
9386
- action: (env) => env.model.dispatch("MOVE_SHEET", {
9387
- sheetId: env.model.getters.getActiveSheetId(),
9388
- delta: 1,
9389
- }),
9390
- })
9391
- .add("move_left", {
9392
- name: _lt("Move left"),
9393
- sequence: 50,
9394
- isVisible: (env) => {
9395
- const sheetId = env.model.getters.getActiveSheetId();
9396
- return env.model.getters.getVisibleSheetIds()[0] !== sheetId;
9397
- },
9398
- action: (env) => env.model.dispatch("MOVE_SHEET", {
9399
- sheetId: env.model.getters.getActiveSheetId(),
9400
- delta: -1,
9401
- }),
9402
- })
9403
- .add("hide_sheet", {
9404
- name: _lt("Hide sheet"),
9405
- sequence: 60,
9406
- isVisible: (env) => env.model.getters.getVisibleSheetIds().length !== 1,
9407
- action: (env) => env.model.dispatch("HIDE_SHEET", { sheetId: env.model.getters.getActiveSheetId() }),
9408
- });
9409
- return sheetMenuRegistry;
9410
- }
9411
-
9412
9372
  //------------------------------------------------------------------------------
9413
9373
  // Arg description DSL
9414
9374
  //------------------------------------------------------------------------------
@@ -16169,6 +16129,593 @@
16169
16129
  }
16170
16130
  }
16171
16131
 
16132
+ const rowInsertRowBefore = {
16133
+ name: ROW_INSERT_ROWS_BEFORE_NAME,
16134
+ execute: INSERT_ROWS_BEFORE_ACTION,
16135
+ };
16136
+ const topBarInsertRowsBefore = {
16137
+ ...rowInsertRowBefore,
16138
+ name: MENU_INSERT_ROWS_BEFORE_NAME,
16139
+ isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16140
+ };
16141
+ const cellInsertRowsBefore = {
16142
+ ...rowInsertRowBefore,
16143
+ name: CELL_INSERT_ROWS_BEFORE_NAME,
16144
+ isVisible: IS_ONLY_ONE_RANGE,
16145
+ };
16146
+ const rowInsertRowsAfter = {
16147
+ execute: INSERT_ROWS_AFTER_ACTION,
16148
+ name: ROW_INSERT_ROWS_AFTER_NAME,
16149
+ };
16150
+ const topBarInsertRowsAfter = {
16151
+ ...rowInsertRowsAfter,
16152
+ name: MENU_INSERT_ROWS_AFTER_NAME,
16153
+ isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16154
+ };
16155
+ const colInsertColsBefore = {
16156
+ name: COLUMN_INSERT_COLUMNS_BEFORE_NAME,
16157
+ execute: INSERT_COLUMNS_BEFORE_ACTION,
16158
+ };
16159
+ const topBarInsertColsBefore = {
16160
+ ...colInsertColsBefore,
16161
+ name: MENU_INSERT_COLUMNS_BEFORE_NAME,
16162
+ isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16163
+ };
16164
+ const cellInsertColsBefore = {
16165
+ ...colInsertColsBefore,
16166
+ name: CELL_INSERT_COLUMNS_BEFORE_NAME,
16167
+ isVisible: IS_ONLY_ONE_RANGE,
16168
+ };
16169
+ const colInsertColsAfter = {
16170
+ name: COLUMN_INSERT_COLUMNS_AFTER_NAME,
16171
+ execute: INSERT_COLUMNS_AFTER_ACTION,
16172
+ };
16173
+ const topBarInsertColsAfter = {
16174
+ ...colInsertColsAfter,
16175
+ name: MENU_INSERT_COLUMNS_AFTER_NAME,
16176
+ execute: INSERT_COLUMNS_AFTER_ACTION,
16177
+ isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16178
+ };
16179
+ const insertCell = {
16180
+ name: _lt("Insert cells"),
16181
+ isVisible: IS_ONLY_ONE_RANGE,
16182
+ };
16183
+ const insertCellShiftDown = {
16184
+ name: _lt("Insert cells and shift down"),
16185
+ execute: INSERT_CELL_SHIFT_DOWN,
16186
+ };
16187
+ const insertCellShiftRight = {
16188
+ name: _lt("Insert cells and shift right"),
16189
+ execute: INSERT_CELL_SHIFT_RIGHT,
16190
+ };
16191
+ const insertChart = {
16192
+ name: _lt("Chart"),
16193
+ execute: CREATE_CHART,
16194
+ };
16195
+ const insertImage = {
16196
+ name: _lt("Image"),
16197
+ execute: CREATE_IMAGE,
16198
+ isVisible: (env) => env.imageProvider !== undefined,
16199
+ };
16200
+ const insertFunction = {
16201
+ name: _lt("Function"),
16202
+ };
16203
+ const insertFunctionSum = {
16204
+ name: _lt("SUM"),
16205
+ execute: (env) => env.startCellEdition(`=SUM(`),
16206
+ };
16207
+ const insertFunctionAverage = {
16208
+ name: _lt("AVERAGE"),
16209
+ execute: (env) => env.startCellEdition(`=AVERAGE(`),
16210
+ };
16211
+ const insertFunctionCount = {
16212
+ name: _lt("COUNT"),
16213
+ execute: (env) => env.startCellEdition(`=COUNT(`),
16214
+ };
16215
+ const insertFunctionMax = {
16216
+ name: _lt("MAX"),
16217
+ execute: (env) => env.startCellEdition(`=MAX(`),
16218
+ };
16219
+ const insertFunctionMin = {
16220
+ name: _lt("MIN"),
16221
+ execute: (env) => env.startCellEdition(`=MIN(`),
16222
+ };
16223
+ const categorieFunctionAll = {
16224
+ name: _lt("All"),
16225
+ children: allFunctionListMenuBuilder(),
16226
+ };
16227
+ function allFunctionListMenuBuilder() {
16228
+ const fnNames = functionRegistry.getKeys();
16229
+ return createFormulaFunctions(fnNames);
16230
+ }
16231
+ const categoriesFunctionListMenuBuilder = () => {
16232
+ const functions = functionRegistry.content;
16233
+ const categories = [...new Set(functionRegistry.getAll().map((fn) => fn.category))].filter(isDefined$1);
16234
+ return categories.sort().map((category, i) => {
16235
+ const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
16236
+ return {
16237
+ name: category,
16238
+ children: createFormulaFunctions(functionsInCategory),
16239
+ };
16240
+ });
16241
+ };
16242
+ const insertLink = {
16243
+ name: _lt("Link"),
16244
+ execute: INSERT_LINK,
16245
+ };
16246
+ const insertSheet = {
16247
+ name: _lt("New sheet"),
16248
+ execute: CREATE_SHEET_ACTION,
16249
+ };
16250
+ function createFormulaFunctions(fnNames) {
16251
+ return fnNames.sort().map((fnName, i) => {
16252
+ return {
16253
+ name: fnName,
16254
+ sequence: i * 10,
16255
+ execute: (env) => env.startCellEdition(`=${fnName}(`),
16256
+ };
16257
+ });
16258
+ }
16259
+
16260
+ //------------------------------------------------------------------------------
16261
+ // Context Menu Registry
16262
+ //------------------------------------------------------------------------------
16263
+ const cellMenuRegistry = new MenuItemRegistry();
16264
+ cellMenuRegistry
16265
+ .add("cut", {
16266
+ ...cut,
16267
+ sequence: 10,
16268
+ })
16269
+ .add("copy", {
16270
+ ...copy,
16271
+ sequence: 20,
16272
+ })
16273
+ .add("paste", {
16274
+ ...paste,
16275
+ sequence: 30,
16276
+ })
16277
+ .add("paste_special", {
16278
+ ...pasteSpecial,
16279
+ sequence: 40,
16280
+ separator: true,
16281
+ })
16282
+ .addChild("paste_value_only", ["paste_special"], {
16283
+ ...pasteSpecialValue,
16284
+ sequence: 10,
16285
+ })
16286
+ .addChild("paste_format_only", ["paste_special"], {
16287
+ ...pasteSpecialFormat,
16288
+ sequence: 20,
16289
+ })
16290
+ .add("add_row_before", {
16291
+ ...cellInsertRowsBefore,
16292
+ sequence: 70,
16293
+ })
16294
+ .add("add_column_before", {
16295
+ ...cellInsertColsBefore,
16296
+ sequence: 90,
16297
+ })
16298
+ .add("insert_cell", {
16299
+ ...insertCell,
16300
+ sequence: 100,
16301
+ separator: true,
16302
+ })
16303
+ .addChild("insert_cell_down", ["insert_cell"], {
16304
+ ...insertCellShiftDown,
16305
+ name: _lt("Shift down"),
16306
+ sequence: 10,
16307
+ })
16308
+ .addChild("insert_cell_right", ["insert_cell"], {
16309
+ ...insertCellShiftRight,
16310
+ name: _lt("Shift right"),
16311
+ sequence: 20,
16312
+ })
16313
+ .add("delete_row", {
16314
+ ...deleteRow,
16315
+ sequence: 110,
16316
+ })
16317
+ .add("delete_column", {
16318
+ ...deleteCol,
16319
+ sequence: 120,
16320
+ })
16321
+ .add("delete_cell", {
16322
+ ...deleteCells,
16323
+ sequence: 130,
16324
+ })
16325
+ .addChild("delete_cell_up", ["delete_cell"], {
16326
+ ...deleteCellShiftUp,
16327
+ name: _lt("Shift up"),
16328
+ sequence: 10,
16329
+ })
16330
+ .addChild("delete_cell_left", ["delete_cell"], {
16331
+ ...deleteCellShiftLeft,
16332
+ name: _lt("Shift left"),
16333
+ sequence: 20,
16334
+ })
16335
+ .add("insert_link", {
16336
+ ...insertLink,
16337
+ name: _lt("Insert link"),
16338
+ sequence: 150,
16339
+ separator: true,
16340
+ });
16341
+
16342
+ const sortRange = {
16343
+ name: _lt("Sort range"),
16344
+ isVisible: IS_ONLY_ONE_RANGE,
16345
+ };
16346
+ const sortAscending = {
16347
+ name: _lt("Ascending (A ⟶ Z)"),
16348
+ execute: SORT_CELLS_ASCENDING,
16349
+ };
16350
+ const sortDescending = {
16351
+ name: _lt("Descending (Z ⟶ A)"),
16352
+ execute: SORT_CELLS_DESCENDING,
16353
+ };
16354
+ const addDataFilter = {
16355
+ name: _lt("Create filter"),
16356
+ execute: FILTERS_CREATE_FILTER_TABLE,
16357
+ isVisible: (env) => !SELECTION_CONTAINS_FILTER(env),
16358
+ isEnabled: (env) => SELECTION_IS_CONTINUOUS(env),
16359
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16360
+ };
16361
+ const removeDataFilter = {
16362
+ name: _lt("Remove filter"),
16363
+ execute: FILTERS_REMOVE_FILTER_TABLE,
16364
+ isVisible: SELECTION_CONTAINS_FILTER,
16365
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16366
+ };
16367
+
16368
+ const formatNumberAutomatic = {
16369
+ name: _lt("Automatic"),
16370
+ execute: FORMAT_AUTOMATIC_ACTION,
16371
+ isActive: (env) => isAutomaticFormatSelected(env),
16372
+ };
16373
+ const formatNumberNumber = {
16374
+ name: _lt("Number"),
16375
+ description: "1,000.12",
16376
+ execute: FORMAT_NUMBER_ACTION,
16377
+ isActive: (env) => isFormatSelected(env, "#,##0.00"),
16378
+ };
16379
+ const formatPercent = {
16380
+ name: _lt("Format as percent"),
16381
+ execute: FORMAT_PERCENT_ACTION,
16382
+ icon: "o-spreadsheet-Icon.PERCENT",
16383
+ };
16384
+ const formatNumberPercent = {
16385
+ name: _lt("Percent"),
16386
+ description: "10.12%",
16387
+ execute: FORMAT_PERCENT_ACTION,
16388
+ isActive: (env) => isFormatSelected(env, "0.00%"),
16389
+ };
16390
+ const formatNumberCurrency = {
16391
+ name: _lt("Currency"),
16392
+ description: "$1,000.12",
16393
+ execute: FORMAT_CURRENCY_ACTION,
16394
+ isActive: (env) => isFormatSelected(env, "[$$]#,##0.00"),
16395
+ };
16396
+ const formatNumberCurrencyRounded = {
16397
+ name: _lt("Currency rounded"),
16398
+ description: "$1,000",
16399
+ execute: FORMAT_CURRENCY_ROUNDED_ACTION,
16400
+ isActive: (env) => isFormatSelected(env, "[$$]#,##0"),
16401
+ };
16402
+ const formatCustomCurrency = {
16403
+ name: _lt("Custom currency"),
16404
+ isVisible: (env) => env.loadCurrencies !== undefined,
16405
+ execute: OPEN_CUSTOM_CURRENCY_SIDEPANEL_ACTION,
16406
+ };
16407
+ const formatNumberDate = {
16408
+ name: _lt("Date"),
16409
+ description: "9/26/2008",
16410
+ execute: FORMAT_DATE_ACTION,
16411
+ isActive: (env) => isFormatSelected(env, "m/d/yyyy"),
16412
+ };
16413
+ const formatNumberTime = {
16414
+ name: _lt("Time"),
16415
+ description: "10:43:00 PM",
16416
+ execute: FORMAT_TIME_ACTION,
16417
+ isActive: (env) => isFormatSelected(env, "hh:mm:ss a"),
16418
+ };
16419
+ const formatNumberDateTime = {
16420
+ name: _lt("Date time"),
16421
+ description: "9/26/2008 22:43:00",
16422
+ execute: FORMAT_DATE_TIME_ACTION,
16423
+ isActive: (env) => isFormatSelected(env, "m/d/yyyy hh:mm:ss"),
16424
+ };
16425
+ const formatNumberDuration = {
16426
+ name: _lt("Duration"),
16427
+ description: "27:51:38",
16428
+ execute: FORMAT_DURATION_ACTION,
16429
+ isActive: (env) => isFormatSelected(env, "hhhh:mm:ss"),
16430
+ };
16431
+ const incraseDecimalPlaces = {
16432
+ name: _lt("Increase decimal places"),
16433
+ icon: "o-spreadsheet-Icon.INCREASE_DECIMAL",
16434
+ execute: (env) => env.model.dispatch("SET_DECIMAL", {
16435
+ sheetId: env.model.getters.getActiveSheetId(),
16436
+ target: env.model.getters.getSelectedZones(),
16437
+ step: 1,
16438
+ }),
16439
+ };
16440
+ const decraseDecimalPlaces = {
16441
+ name: _lt("Decrease decimal places"),
16442
+ icon: "o-spreadsheet-Icon.DECRASE_DECIMAL",
16443
+ execute: (env) => env.model.dispatch("SET_DECIMAL", {
16444
+ sheetId: env.model.getters.getActiveSheetId(),
16445
+ target: env.model.getters.getSelectedZones(),
16446
+ step: -1,
16447
+ }),
16448
+ };
16449
+ const formatBold = {
16450
+ name: _lt("Bold"),
16451
+ description: "Ctrl+B",
16452
+ execute: FORMAT_BOLD_ACTION,
16453
+ icon: "o-spreadsheet-Icon.BOLD",
16454
+ isActive: (env) => !!env.model.getters.getCurrentStyle().bold,
16455
+ };
16456
+ const formatItalic = {
16457
+ name: _lt("Italic"),
16458
+ description: "Ctrl+I",
16459
+ execute: FORMAT_ITALIC_ACTION,
16460
+ icon: "o-spreadsheet-Icon.ITALIC",
16461
+ isActive: (env) => !!env.model.getters.getCurrentStyle().italic,
16462
+ };
16463
+ const formatUnderline = {
16464
+ name: _lt("Underline"),
16465
+ description: "Ctrl+U",
16466
+ execute: FORMAT_UNDERLINE_ACTION,
16467
+ icon: "o-spreadsheet-Icon.UNDERLINE",
16468
+ isActive: (env) => !!env.model.getters.getCurrentStyle().underline,
16469
+ };
16470
+ const formatStrikethrough = {
16471
+ name: _lt("Strikethrough"),
16472
+ execute: FORMAT_STRIKETHROUGH_ACTION,
16473
+ icon: "o-spreadsheet-Icon.STRIKE",
16474
+ isActive: (env) => !!env.model.getters.getCurrentStyle().strikethrough,
16475
+ };
16476
+ const formatFontSize = {
16477
+ name: _lt("Font size"),
16478
+ children: fontSizeMenuBuilder(),
16479
+ };
16480
+ const formatAlignment = {
16481
+ name: _lt("Alignment"),
16482
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16483
+ };
16484
+ const formatAlignmentHorizontal = {
16485
+ name: _lt("Horizontal align"),
16486
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16487
+ };
16488
+ const formatAlignmentLeft = {
16489
+ name: _lt("Left"),
16490
+ execute: (env) => setStyle(env, { align: "left" }),
16491
+ isActive: (env) => getHorizontalAlign(env) === "left",
16492
+ icon: "o-spreadsheet-Icon.ALIGN_LEFT",
16493
+ };
16494
+ const formatAlignmentCenter = {
16495
+ name: _lt("Center"),
16496
+ execute: (env) => setStyle(env, { align: "center" }),
16497
+ isActive: (env) => getHorizontalAlign(env) === "center",
16498
+ icon: "o-spreadsheet-Icon.ALIGN_CENTER",
16499
+ };
16500
+ const formatAlignmentRight = {
16501
+ name: _lt("Right"),
16502
+ execute: (env) => setStyle(env, { align: "right" }),
16503
+ isActive: (env) => getHorizontalAlign(env) === "right",
16504
+ icon: "o-spreadsheet-Icon.ALIGN_RIGHT",
16505
+ };
16506
+ const formatAlignmentVertical = {
16507
+ name: _lt("Vertical align"),
16508
+ icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
16509
+ };
16510
+ const formatAlignmentTop = {
16511
+ name: _lt("Top"),
16512
+ execute: (env) => setStyle(env, { verticalAlign: "top" }),
16513
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "top",
16514
+ icon: "o-spreadsheet-Icon.ALIGN_TOP",
16515
+ };
16516
+ const formatAlignmentMiddle = {
16517
+ name: _lt("Middle"),
16518
+ execute: (env) => setStyle(env, { verticalAlign: "middle" }),
16519
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "middle",
16520
+ icon: "o-spreadsheet-Icon.ALIGN_MIDDLE",
16521
+ };
16522
+ const formatAlignmentBottom = {
16523
+ name: _lt("Bottom"),
16524
+ execute: (env) => setStyle(env, { verticalAlign: "bottom" }),
16525
+ isActive: (env) => (env.model.getters.getCurrentStyle().verticalAlign || DEFAULT_VERTICAL_ALIGN) === "bottom",
16526
+ icon: "o-spreadsheet-Icon.ALIGN_BOTTOM",
16527
+ };
16528
+ const formatWrapping = {
16529
+ name: _lt("Wrapping"),
16530
+ icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
16531
+ };
16532
+ const formatWrappingOverflow = {
16533
+ name: _lt("Overflow"),
16534
+ execute: (env) => setStyle(env, { wrapping: "overflow" }),
16535
+ isActive: (env) => (env.model.getters.getCurrentStyle().wrapping || "overflow") === "overflow",
16536
+ icon: "o-spreadsheet-Icon.WRAPPING_OVERFLOW",
16537
+ };
16538
+ const formatWrappingWrap = {
16539
+ name: _lt("Wrap"),
16540
+ execute: (env) => setStyle(env, { wrapping: "wrap" }),
16541
+ isActive: (env) => env.model.getters.getCurrentStyle().wrapping === "wrap",
16542
+ icon: "o-spreadsheet-Icon.WRAPPING_WRAP",
16543
+ };
16544
+ const formatWrappingClip = {
16545
+ name: _lt("Clip"),
16546
+ execute: (env) => setStyle(env, { wrapping: "clip" }),
16547
+ isActive: (env) => env.model.getters.getCurrentStyle().wrapping === "clip",
16548
+ icon: "o-spreadsheet-Icon.WRAPPING_CLIP",
16549
+ };
16550
+ const textColor = {
16551
+ name: _lt("Text Color"),
16552
+ icon: "o-spreadsheet-Icon.TEXT_COLOR",
16553
+ };
16554
+ const fillColor = {
16555
+ name: _lt("Fill Color"),
16556
+ icon: "o-spreadsheet-Icon.FILL_COLOR",
16557
+ };
16558
+ const formatCF = {
16559
+ name: _lt("Conditional formatting"),
16560
+ execute: OPEN_CF_SIDEPANEL_ACTION,
16561
+ };
16562
+ const paintFormat = {
16563
+ name: _lt("Paint Format"),
16564
+ execute: (env) => env.model.dispatch("ACTIVATE_PAINT_FORMAT", {
16565
+ target: env.model.getters.getSelectedZones(),
16566
+ }),
16567
+ icon: "o-spreadsheet-Icon.PAINT_FORMAT",
16568
+ isActive: (env) => env.model.getters.isPaintingFormat(),
16569
+ };
16570
+ const clearFormat = {
16571
+ name: _lt("Clear formatting"),
16572
+ execute: FORMAT_CLEARFORMAT_ACTION,
16573
+ icon: "o-spreadsheet-Icon.CLEAR_FORMAT",
16574
+ };
16575
+ const borders = {
16576
+ name: _lt("Borders"),
16577
+ icon: "o-spreadsheet-Icon.BORDERS",
16578
+ };
16579
+ const bordersAll = {
16580
+ name: _lt("All borders"),
16581
+ execute: (env) => setBorder(env, "all"),
16582
+ icon: "o-spreadsheet-Icon.BORDERS",
16583
+ };
16584
+ const bordersInner = {
16585
+ name: _lt("Inner borders"),
16586
+ execute: (env) => setBorder(env, "hv"),
16587
+ icon: "o-spreadsheet-Icon.BORDER_HV",
16588
+ };
16589
+ const bordersHorizontal = {
16590
+ name: _lt("Horizontal borders"),
16591
+ execute: (env) => setBorder(env, "h"),
16592
+ icon: "o-spreadsheet-Icon.BORDER_H",
16593
+ };
16594
+ const bordersVertical = {
16595
+ name: _lt("Vertical borders"),
16596
+ execute: (env) => setBorder(env, "v"),
16597
+ icon: "o-spreadsheet-Icon.BORDER_V",
16598
+ };
16599
+ const bordersExternal = {
16600
+ name: _lt("External borders"),
16601
+ execute: (env) => setBorder(env, "external"),
16602
+ icon: "o-spreadsheet-Icon.BORDER_EXTERNAL",
16603
+ };
16604
+ const bordersLeft = {
16605
+ name: _lt("Left borders"),
16606
+ execute: (env) => setBorder(env, "left"),
16607
+ icon: "o-spreadsheet-Icon.BORDER_LEFT",
16608
+ };
16609
+ const bordersTop = {
16610
+ name: _lt("Top borders"),
16611
+ execute: (env) => setBorder(env, "top"),
16612
+ icon: "o-spreadsheet-Icon.BORDER_TOP",
16613
+ };
16614
+ const bordersRight = {
16615
+ name: _lt("Right borders"),
16616
+ execute: (env) => setBorder(env, "right"),
16617
+ icon: "o-spreadsheet-Icon.BORDER_RIGHT",
16618
+ };
16619
+ const bordersBottom = {
16620
+ name: _lt("Bottom borders"),
16621
+ execute: (env) => setBorder(env, "bottom"),
16622
+ icon: "o-spreadsheet-Icon.BORDER_BOTTOM",
16623
+ };
16624
+ const bordersClear = {
16625
+ name: _lt("Clear borders"),
16626
+ execute: (env) => setBorder(env, "clear"),
16627
+ icon: "o-spreadsheet-Icon.BORDER_CLEAR",
16628
+ };
16629
+ function fontSizeMenuBuilder() {
16630
+ return FONT_SIZES.map((fs) => {
16631
+ return {
16632
+ name: fs.toString(),
16633
+ sequence: fs,
16634
+ id: `font_size_${fs}`,
16635
+ execute: (env) => setStyle(env, { fontSize: fs }),
16636
+ isActive: (env) => isFontSizeSelected(env, fs),
16637
+ };
16638
+ });
16639
+ }
16640
+ function isAutomaticFormatSelected(env) {
16641
+ const activeCell = env.model.getters.getActiveCell();
16642
+ return !activeCell || !activeCell.format;
16643
+ }
16644
+ function isFormatSelected(env, format) {
16645
+ const activeCell = env.model.getters.getActiveCell();
16646
+ return activeCell && activeCell.format === format;
16647
+ }
16648
+ function isFontSizeSelected(env, fontSize) {
16649
+ const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
16650
+ return currentFontSize === fontSize;
16651
+ }
16652
+ function setBorder(env, command) {
16653
+ env.model.dispatch("SET_FORMATTING", {
16654
+ sheetId: env.model.getters.getActiveSheetId(),
16655
+ target: env.model.getters.getSelectedZones(),
16656
+ border: command,
16657
+ });
16658
+ }
16659
+ function getHorizontalAlign(env) {
16660
+ const style = env.model.getters.getCurrentStyle();
16661
+ if (style.align) {
16662
+ return style.align;
16663
+ }
16664
+ const cell = env.model.getters.getActiveCell();
16665
+ return cell.defaultAlign;
16666
+ }
16667
+
16668
+ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
16669
+ __proto__: null,
16670
+ formatNumberAutomatic: formatNumberAutomatic,
16671
+ formatNumberNumber: formatNumberNumber,
16672
+ formatPercent: formatPercent,
16673
+ formatNumberPercent: formatNumberPercent,
16674
+ formatNumberCurrency: formatNumberCurrency,
16675
+ formatNumberCurrencyRounded: formatNumberCurrencyRounded,
16676
+ formatCustomCurrency: formatCustomCurrency,
16677
+ formatNumberDate: formatNumberDate,
16678
+ formatNumberTime: formatNumberTime,
16679
+ formatNumberDateTime: formatNumberDateTime,
16680
+ formatNumberDuration: formatNumberDuration,
16681
+ incraseDecimalPlaces: incraseDecimalPlaces,
16682
+ decraseDecimalPlaces: decraseDecimalPlaces,
16683
+ formatBold: formatBold,
16684
+ formatItalic: formatItalic,
16685
+ formatUnderline: formatUnderline,
16686
+ formatStrikethrough: formatStrikethrough,
16687
+ formatFontSize: formatFontSize,
16688
+ formatAlignment: formatAlignment,
16689
+ formatAlignmentHorizontal: formatAlignmentHorizontal,
16690
+ formatAlignmentLeft: formatAlignmentLeft,
16691
+ formatAlignmentCenter: formatAlignmentCenter,
16692
+ formatAlignmentRight: formatAlignmentRight,
16693
+ formatAlignmentVertical: formatAlignmentVertical,
16694
+ formatAlignmentTop: formatAlignmentTop,
16695
+ formatAlignmentMiddle: formatAlignmentMiddle,
16696
+ formatAlignmentBottom: formatAlignmentBottom,
16697
+ formatWrapping: formatWrapping,
16698
+ formatWrappingOverflow: formatWrappingOverflow,
16699
+ formatWrappingWrap: formatWrappingWrap,
16700
+ formatWrappingClip: formatWrappingClip,
16701
+ textColor: textColor,
16702
+ fillColor: fillColor,
16703
+ formatCF: formatCF,
16704
+ paintFormat: paintFormat,
16705
+ clearFormat: clearFormat,
16706
+ borders: borders,
16707
+ bordersAll: bordersAll,
16708
+ bordersInner: bordersInner,
16709
+ bordersHorizontal: bordersHorizontal,
16710
+ bordersVertical: bordersVertical,
16711
+ bordersExternal: bordersExternal,
16712
+ bordersLeft: bordersLeft,
16713
+ bordersTop: bordersTop,
16714
+ bordersRight: bordersRight,
16715
+ bordersBottom: bordersBottom,
16716
+ bordersClear: bordersClear
16717
+ });
16718
+
16172
16719
  function interactiveFreezeColumnsRows(env, dimension, base) {
16173
16720
  const sheetId = env.model.getters.getActiveSheetId();
16174
16721
  const cmd = dimension === "COL" ? "FREEZE_COLUMNS" : "FREEZE_ROWS";
@@ -16178,524 +16725,740 @@
16178
16725
  }
16179
16726
  }
16180
16727
 
16181
- const topbarMenuRegistry = new MenuItemRegistry();
16182
- topbarMenuRegistry
16183
- .add("file", { name: _lt("File"), sequence: 10 })
16184
- .add("edit", { name: _lt("Edit"), sequence: 20 })
16185
- .add("view", { name: _lt("View"), sequence: 30 })
16186
- .add("insert", { name: _lt("Insert"), sequence: 40 })
16187
- .add("format", { name: _lt("Format"), sequence: 50 })
16188
- .add("data", { name: _lt("Data"), sequence: 60 })
16189
- .addChild("save", ["file"], {
16190
- name: _lt("Save"),
16191
- description: "Ctrl+S",
16192
- sequence: 10,
16193
- action: () => console.log("Not implemented"),
16194
- })
16195
- .addChild("undo", ["edit"], {
16196
- name: _lt("Undo"),
16197
- description: "Ctrl+Z",
16728
+ const hideCols = {
16729
+ name: HIDE_COLUMNS_NAME,
16730
+ execute: HIDE_COLUMNS_ACTION,
16731
+ isVisible: (env) => {
16732
+ const sheetId = env.model.getters.getActiveSheetId();
16733
+ const hiddenCols = env.model.getters.getHiddenColsGroups(sheetId).flat();
16734
+ return (env.model.getters.getNumberCols(sheetId) >
16735
+ hiddenCols.length + env.model.getters.getElementsFromSelection("COL").length);
16736
+ },
16737
+ };
16738
+ const unhideCols = {
16739
+ name: _lt("Unhide columns"),
16740
+ execute: UNHIDE_COLUMNS_ACTION,
16741
+ isVisible: (env) => {
16742
+ const hiddenCols = env.model.getters
16743
+ .getHiddenColsGroups(env.model.getters.getActiveSheetId())
16744
+ .flat();
16745
+ const currentCols = env.model.getters.getElementsFromSelection("COL");
16746
+ return currentCols.some((col) => hiddenCols.includes(col));
16747
+ },
16748
+ };
16749
+ const unhideAllCols = {
16750
+ name: _lt("Unhide all columns"),
16751
+ execute: UNHIDE_ALL_COLUMNS_ACTION,
16752
+ isVisible: (env) => env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId()).length > 0,
16753
+ };
16754
+ const hideRows = {
16755
+ name: HIDE_ROWS_NAME,
16756
+ execute: HIDE_ROWS_ACTION,
16757
+ isVisible: (env) => {
16758
+ const sheetId = env.model.getters.getActiveSheetId();
16759
+ const hiddenRows = env.model.getters.getHiddenRowsGroups(sheetId).flat();
16760
+ return (env.model.getters.getNumberRows(sheetId) >
16761
+ hiddenRows.length + env.model.getters.getElementsFromSelection("ROW").length);
16762
+ },
16763
+ };
16764
+ const unhideRows = {
16765
+ name: _lt("Unhide rows"),
16766
+ execute: UNHIDE_ROWS_ACTION,
16767
+ isVisible: (env) => {
16768
+ const hiddenRows = env.model.getters
16769
+ .getHiddenRowsGroups(env.model.getters.getActiveSheetId())
16770
+ .flat();
16771
+ const currentRows = env.model.getters.getElementsFromSelection("ROW");
16772
+ return currentRows.some((col) => hiddenRows.includes(col));
16773
+ },
16774
+ };
16775
+ const unhideAllRows = {
16776
+ name: _lt("Unhide all rows"),
16777
+ execute: UNHIDE_ALL_ROWS_ACTION,
16778
+ isVisible: (env) => env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId()).length > 0,
16779
+ };
16780
+ const unFreezePane = {
16781
+ name: _lt("Unfreeze"),
16782
+ isVisible: (env) => {
16783
+ const { xSplit, ySplit } = env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId());
16784
+ return xSplit + ySplit > 0;
16785
+ },
16786
+ execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS_ROWS", {
16787
+ sheetId: env.model.getters.getActiveSheetId(),
16788
+ }),
16789
+ };
16790
+ const freezePane = {
16791
+ name: _lt("Freeze"),
16792
+ };
16793
+ const unFreezeRows = {
16794
+ name: _lt("No rows"),
16795
+ execute: (env) => env.model.dispatch("UNFREEZE_ROWS", {
16796
+ sheetId: env.model.getters.getActiveSheetId(),
16797
+ }),
16798
+ isReadonlyAllowed: true,
16799
+ isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).ySplit,
16800
+ };
16801
+ const freezeFirstRow = {
16802
+ name: _lt("1 row"),
16803
+ execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 1),
16804
+ isReadonlyAllowed: true,
16805
+ };
16806
+ const freezeSecondRow = {
16807
+ name: _lt("2 rows"),
16808
+ execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 2),
16809
+ isReadonlyAllowed: true,
16810
+ };
16811
+ const freezeCurrentRow = {
16812
+ name: _lt("Up to current row"),
16813
+ execute: (env) => {
16814
+ const { bottom } = env.model.getters.getSelectedZone();
16815
+ interactiveFreezeColumnsRows(env, "ROW", bottom + 1);
16816
+ },
16817
+ isReadonlyAllowed: true,
16818
+ };
16819
+ const unFreezeCols = {
16820
+ name: _lt("No columns"),
16821
+ execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS", {
16822
+ sheetId: env.model.getters.getActiveSheetId(),
16823
+ }),
16824
+ isReadonlyAllowed: true,
16825
+ isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).xSplit,
16826
+ };
16827
+ const freezeFirstCol = {
16828
+ name: _lt("1 column"),
16829
+ execute: (env) => interactiveFreezeColumnsRows(env, "COL", 1),
16830
+ isReadonlyAllowed: true,
16831
+ };
16832
+ const freezeSecondCol = {
16833
+ name: _lt("2 columns"),
16834
+ execute: (env) => interactiveFreezeColumnsRows(env, "COL", 2),
16835
+ isReadonlyAllowed: true,
16836
+ };
16837
+ const freezeCurrentCol = {
16838
+ name: _lt("Up to current column"),
16839
+ execute: (env) => {
16840
+ const { right } = env.model.getters.getSelectedZone();
16841
+ interactiveFreezeColumnsRows(env, "COL", right + 1);
16842
+ },
16843
+ isReadonlyAllowed: true,
16844
+ };
16845
+ const viewGridlines = {
16846
+ name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
16847
+ ? _lt("Hide gridlines")
16848
+ : _lt("Show gridlines"),
16849
+ execute: SET_GRID_LINES_VISIBILITY_ACTION,
16850
+ };
16851
+ const viewFormulas = {
16852
+ name: (env) => env.model.getters.shouldShowFormulas() ? _lt("Hide formulas") : _lt("Show formulas"),
16853
+ execute: SET_FORMULA_VISIBILITY_ACTION,
16854
+ isReadonlyAllowed: true,
16855
+ };
16856
+ const createRemoveFilter = {
16857
+ name: (env) => selectionContainsFilter(env) ? _lt("Remove selected filters") : _lt("Create filter"),
16858
+ isActive: (env) => selectionContainsFilter(env),
16859
+ isEnabled: (env) => !cannotCreateFilter(env),
16860
+ execute: (env) => createRemoveFilterAction(env),
16861
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
16862
+ };
16863
+ function selectionContainsFilter(env) {
16864
+ const sheetId = env.model.getters.getActiveSheetId();
16865
+ const selectedZones = env.model.getters.getSelectedZones();
16866
+ return env.model.getters.doesZonesContainFilter(sheetId, selectedZones);
16867
+ }
16868
+ function cannotCreateFilter(env) {
16869
+ return !areZonesContinuous(...env.model.getters.getSelectedZones());
16870
+ }
16871
+ function createRemoveFilterAction(env) {
16872
+ if (selectionContainsFilter(env)) {
16873
+ env.model.dispatch("REMOVE_FILTER_TABLE", {
16874
+ sheetId: env.model.getters.getActiveSheetId(),
16875
+ target: env.model.getters.getSelectedZones(),
16876
+ });
16877
+ return;
16878
+ }
16879
+ if (cannotCreateFilter(env)) {
16880
+ return;
16881
+ }
16882
+ env.model.selection.selectTableAroundSelection();
16883
+ const sheetId = env.model.getters.getActiveSheetId();
16884
+ const selection = env.model.getters.getSelectedZones();
16885
+ interactiveAddFilter(env, sheetId, selection);
16886
+ }
16887
+
16888
+ var ACTION_VIEW = /*#__PURE__*/Object.freeze({
16889
+ __proto__: null,
16890
+ hideCols: hideCols,
16891
+ unhideCols: unhideCols,
16892
+ unhideAllCols: unhideAllCols,
16893
+ hideRows: hideRows,
16894
+ unhideRows: unhideRows,
16895
+ unhideAllRows: unhideAllRows,
16896
+ unFreezePane: unFreezePane,
16897
+ freezePane: freezePane,
16898
+ unFreezeRows: unFreezeRows,
16899
+ freezeFirstRow: freezeFirstRow,
16900
+ freezeSecondRow: freezeSecondRow,
16901
+ freezeCurrentRow: freezeCurrentRow,
16902
+ unFreezeCols: unFreezeCols,
16903
+ freezeFirstCol: freezeFirstCol,
16904
+ freezeSecondCol: freezeSecondCol,
16905
+ freezeCurrentCol: freezeCurrentCol,
16906
+ viewGridlines: viewGridlines,
16907
+ viewFormulas: viewFormulas,
16908
+ createRemoveFilter: createRemoveFilter
16909
+ });
16910
+
16911
+ const colMenuRegistry = new MenuItemRegistry();
16912
+ colMenuRegistry
16913
+ .add("cut", {
16914
+ ...cut,
16198
16915
  sequence: 10,
16199
- action: UNDO_ACTION,
16200
16916
  })
16201
- .addChild("redo", ["edit"], {
16202
- name: _lt("Redo"),
16203
- description: "Ctrl+Y",
16917
+ .add("copy", {
16918
+ ...copy,
16204
16919
  sequence: 20,
16205
- action: REDO_ACTION,
16206
- separator: true,
16207
16920
  })
16208
- .addChild("copy", ["edit"], {
16209
- name: _lt("Copy"),
16210
- description: "Ctrl+C",
16921
+ .add("paste", {
16922
+ ...paste,
16211
16923
  sequence: 30,
16212
- isReadonlyAllowed: true,
16213
- action: COPY_ACTION,
16214
16924
  })
16215
- .addChild("cut", ["edit"], {
16216
- name: _lt("Cut"),
16217
- description: "Ctrl+X",
16925
+ .add("paste_special", {
16926
+ ...pasteSpecial,
16218
16927
  sequence: 40,
16219
- action: CUT_ACTION,
16928
+ separator: true,
16220
16929
  })
16221
- .addChild("paste", ["edit"], {
16222
- name: _lt("Paste"),
16223
- description: "Ctrl+V",
16224
- sequence: 50,
16225
- action: PASTE_ACTION,
16930
+ .addChild("paste_value_only", ["paste_special"], {
16931
+ ...pasteSpecialValue,
16932
+ sequence: 10,
16226
16933
  })
16227
- .addChild("paste_special", ["edit"], {
16228
- name: _lt("Paste special"),
16229
- sequence: 60,
16934
+ .addChild("paste_format_only", ["paste_special"], {
16935
+ ...pasteSpecialFormat,
16936
+ sequence: 20,
16937
+ })
16938
+ .add("sort_columns", {
16939
+ ...sortRange,
16940
+ name: (env) => env.model.getters.getActiveCols().size > 1 ? _lt("Sort columns") : _lt("Sort column"),
16941
+ sequence: 50,
16230
16942
  separator: true,
16231
- isVisible: IS_NOT_CUT_OPERATION,
16232
16943
  })
16233
- .addChild("paste_special_value", ["edit", "paste_special"], {
16234
- name: _lt("Paste value only"),
16944
+ .addChild("sort_ascending", ["sort_columns"], {
16945
+ ...sortAscending,
16235
16946
  sequence: 10,
16236
- action: PASTE_VALUE_ACTION,
16237
16947
  })
16238
- .addChild("paste_special_format", ["edit", "paste_special"], {
16239
- name: _lt("Paste format only"),
16948
+ .addChild("sort_descending", ["sort_columns"], {
16949
+ ...sortDescending,
16240
16950
  sequence: 20,
16241
- action: PASTE_FORMAT_ACTION,
16242
16951
  })
16243
- .addChild("sort_range", ["data"], {
16244
- name: _lt("Sort range"),
16245
- sequence: 20,
16246
- isVisible: IS_ONLY_ONE_RANGE,
16952
+ .add("add_column_before", {
16953
+ ...colInsertColsBefore,
16954
+ sequence: 70,
16955
+ })
16956
+ .add("add_column_after", {
16957
+ ...colInsertColsAfter,
16958
+ sequence: 80,
16959
+ })
16960
+ .add("delete_column", {
16961
+ ...deleteCols,
16962
+ sequence: 90,
16963
+ })
16964
+ .add("clear_column", {
16965
+ ...clearCols,
16966
+ sequence: 100,
16967
+ })
16968
+ .add("hide_columns", {
16969
+ ...hideCols,
16970
+ sequence: 85,
16247
16971
  separator: true,
16248
16972
  })
16249
- .addChild("sort_ascending", ["data", "sort_range"], {
16250
- name: _lt("Ascending (A ⟶ Z)"),
16973
+ .add("unhide_columns", {
16974
+ ...unhideCols,
16975
+ sequence: 86,
16976
+ separator: true,
16977
+ })
16978
+ .add("conditional_formatting", {
16979
+ ...formatCF,
16980
+ sequence: 110,
16981
+ });
16982
+
16983
+ const numberFormatMenuRegistry = new MenuItemRegistry();
16984
+ numberFormatMenuRegistry
16985
+ .add("format_number_automatic", {
16986
+ ...formatNumberAutomatic,
16251
16987
  sequence: 10,
16252
- action: SORT_CELLS_ASCENDING,
16988
+ separator: true,
16253
16989
  })
16254
- .addChild("sort_descending", ["data", "sort_range"], {
16255
- name: _lt("Descending (Z ⟶ A)"),
16990
+ .add("format_number_number", {
16991
+ ...formatNumberNumber,
16256
16992
  sequence: 20,
16257
- action: SORT_CELLS_DESCENDING,
16258
16993
  })
16259
- .addChild("find_and_replace", ["edit"], {
16260
- name: _lt("Find and replace"),
16261
- description: "Ctrl+H",
16262
- sequence: 65,
16263
- isReadonlyAllowed: true,
16264
- action: OPEN_FAR_SIDEPANEL_ACTION,
16994
+ .add("format_number_percent", {
16995
+ ...formatNumberPercent,
16996
+ sequence: 30,
16265
16997
  separator: true,
16266
16998
  })
16267
- .addChild("edit_delete_cell_values", ["edit"], {
16268
- name: _lt("Delete values"),
16269
- sequence: 70,
16270
- action: DELETE_CONTENT_ACTION,
16999
+ .add("format_number_currency", {
17000
+ ...formatNumberCurrency,
17001
+ sequence: 40,
16271
17002
  })
16272
- .addChild("edit_delete_row", ["edit"], {
16273
- name: REMOVE_ROWS_NAME,
16274
- sequence: 80,
16275
- action: REMOVE_ROWS_ACTION,
17003
+ .add("format_number_currency_rounded", {
17004
+ ...formatNumberCurrencyRounded,
17005
+ sequence: 50,
16276
17006
  })
16277
- .addChild("edit_delete_column", ["edit"], {
16278
- name: REMOVE_COLUMNS_NAME,
16279
- sequence: 90,
16280
- action: REMOVE_COLUMNS_ACTION,
17007
+ .add("format_custom_currency", {
17008
+ ...formatCustomCurrency,
17009
+ sequence: 60,
17010
+ separator: true,
16281
17011
  })
16282
- .addChild("edit_delete_cell_shift_up", ["edit"], {
16283
- name: _lt("Delete cell and shift up"),
16284
- sequence: 93,
16285
- action: DELETE_CELL_SHIFT_UP,
17012
+ .add("format_number_date", {
17013
+ ...formatNumberDate,
17014
+ sequence: 70,
16286
17015
  })
16287
- .addChild("edit_delete_cell_shift_left", ["edit"], {
16288
- name: _lt("Delete cell and shift left"),
16289
- sequence: 97,
16290
- action: DELETE_CELL_SHIFT_LEFT,
17016
+ .add("format_number_time", {
17017
+ ...formatNumberTime,
17018
+ sequence: 80,
16291
17019
  })
16292
- .addChild("edit_unhide_columns", ["edit"], {
16293
- name: _lt("Unhide all columns"),
16294
- sequence: 100,
16295
- action: UNHIDE_ALL_COLUMNS_ACTION,
16296
- isVisible: (env) => env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId()).length > 0,
17020
+ .add("format_number_date_time", {
17021
+ ...formatNumberDateTime,
17022
+ sequence: 90,
16297
17023
  })
16298
- .addChild("edit_unhide_rows", ["edit"], {
16299
- name: _lt("Unhide all rows"),
17024
+ .add("format_number_duration", {
17025
+ ...formatNumberDuration,
16300
17026
  sequence: 100,
16301
- action: UNHIDE_ALL_ROWS_ACTION,
16302
- isVisible: (env) => env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId()).length > 0,
16303
- })
16304
- .addChild("insert_row_before", ["insert"], {
16305
- name: MENU_INSERT_ROWS_BEFORE_NAME,
17027
+ separator: true,
17028
+ });
17029
+ const formatNumberMenuItemSpec = {
17030
+ name: _lt("More formats"),
17031
+ icon: "o-spreadsheet-Icon.NUMBER_FORMATS",
17032
+ children: [() => numberFormatMenuRegistry.getAll()],
17033
+ };
17034
+
17035
+ const rowMenuRegistry = new MenuItemRegistry();
17036
+ rowMenuRegistry
17037
+ .add("cut", {
17038
+ ...cut,
16306
17039
  sequence: 10,
16307
- action: INSERT_ROWS_BEFORE_ACTION,
16308
- isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16309
17040
  })
16310
- .addChild("insert_row_after", ["insert"], {
16311
- name: MENU_INSERT_ROWS_AFTER_NAME,
17041
+ .add("copy", {
17042
+ ...copy,
16312
17043
  sequence: 20,
16313
- action: INSERT_ROWS_AFTER_ACTION,
16314
- isVisible: (env) => env.model.getters.getActiveCols().size === 0,
16315
- separator: true,
16316
17044
  })
16317
- .addChild("insert_column_before", ["insert"], {
16318
- name: MENU_INSERT_COLUMNS_BEFORE_NAME,
17045
+ .add("paste", {
17046
+ ...paste,
16319
17047
  sequence: 30,
16320
- action: INSERT_COLUMNS_BEFORE_ACTION,
16321
- isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16322
17048
  })
16323
- .addChild("insert_column_after", ["insert"], {
16324
- name: MENU_INSERT_COLUMNS_AFTER_NAME,
17049
+ .add("paste_special", {
17050
+ ...pasteSpecial,
16325
17051
  sequence: 40,
16326
- action: INSERT_COLUMNS_AFTER_ACTION,
16327
- isVisible: (env) => env.model.getters.getActiveRows().size === 0,
16328
17052
  separator: true,
16329
17053
  })
16330
- .addChild("insert_insert_cell_shift_down", ["insert"], {
16331
- name: _lt("Insert cells and shift down"),
16332
- sequence: 43,
16333
- action: INSERT_CELL_SHIFT_DOWN,
17054
+ .addChild("paste_value_only", ["paste_special"], {
17055
+ ...pasteSpecialValue,
17056
+ sequence: 10,
16334
17057
  })
16335
- .addChild("insert_insert_cell_shift_right", ["insert"], {
16336
- name: _lt("Insert cells and shift right"),
16337
- sequence: 47,
16338
- action: INSERT_CELL_SHIFT_RIGHT,
16339
- separator: true,
17058
+ .addChild("paste_format_only", ["paste_special"], {
17059
+ ...pasteSpecialFormat,
17060
+ sequence: 20,
16340
17061
  })
16341
- .addChild("insert_chart", ["insert"], {
16342
- name: _lt("Chart"),
17062
+ .add("add_row_before", {
17063
+ ...rowInsertRowBefore,
16343
17064
  sequence: 50,
16344
- action: CREATE_CHART,
16345
- })
16346
- .addChild("insert_image", ["insert"], {
16347
- name: _lt("Image"),
16348
- sequence: 55,
16349
- action: CREATE_IMAGE,
16350
- isVisible: (env) => env.imageProvider !== undefined,
16351
17065
  })
16352
- .addChild("insert_function", ["insert"], {
16353
- name: _lt("Function"),
17066
+ .add("add_row_after", {
17067
+ ...rowInsertRowsAfter,
16354
17068
  sequence: 60,
16355
17069
  })
16356
- .addChild("insert_function_sum", ["insert", "insert_function"], {
16357
- name: _lt("SUM"),
16358
- action: (env) => env.startCellEdition(`=SUM(`),
16359
- sequence: 0,
17070
+ .add("delete_row", {
17071
+ ...deleteRows,
17072
+ sequence: 70,
16360
17073
  })
16361
- .addChild("insert_function_average", ["insert", "insert_function"], {
16362
- name: _lt("AVERAGE"),
16363
- action: (env) => env.startCellEdition(`=AVERAGE(`),
17074
+ .add("clear_row", {
17075
+ ...clearRows,
17076
+ sequence: 80,
17077
+ })
17078
+ .add("hide_rows", {
17079
+ ...hideRows,
17080
+ sequence: 85,
17081
+ separator: true,
17082
+ })
17083
+ .add("unhide_rows", {
17084
+ ...unhideRows,
17085
+ sequence: 86,
17086
+ separator: true,
17087
+ })
17088
+ .add("conditional_formatting", {
17089
+ ...formatCF,
17090
+ sequence: 90,
17091
+ });
17092
+
17093
+ function getSheetMenuRegistry(args) {
17094
+ const sheetMenuRegistry = new MenuItemRegistry();
17095
+ sheetMenuRegistry
17096
+ .add("delete", {
17097
+ ...deleteSheet,
17098
+ sequence: 10,
17099
+ })
17100
+ .add("duplicate", {
17101
+ ...duplicateSheet,
17102
+ sequence: 20,
17103
+ })
17104
+ .add("rename", {
17105
+ ...renameSheet(args),
17106
+ sequence: 30,
17107
+ })
17108
+ .add("move_right", {
17109
+ ...sheetMoveRight,
17110
+ sequence: 40,
17111
+ })
17112
+ .add("move_left", {
17113
+ ...sheetMoveLeft,
17114
+ sequence: 50,
17115
+ })
17116
+ .add("hide_sheet", {
17117
+ ...hideSheet,
17118
+ sequence: 60,
17119
+ });
17120
+ return sheetMenuRegistry;
17121
+ }
17122
+
17123
+ const topbarMenuRegistry = new MenuItemRegistry();
17124
+ topbarMenuRegistry
17125
+ // ---------------------------------------------------------------------
17126
+ // FILE MENU ITEMS
17127
+ // ---------------------------------------------------------------------
17128
+ .add("file", {
17129
+ name: _lt("File"),
16364
17130
  sequence: 10,
16365
17131
  })
16366
- .addChild("insert_function_count", ["insert", "insert_function"], {
16367
- name: _lt("COUNT"),
16368
- action: (env) => env.startCellEdition(`=COUNT(`),
17132
+ // ---------------------------------------------------------------------
17133
+ // EDIT MENU ITEMS
17134
+ // ---------------------------------------------------------------------
17135
+ .add("edit", {
17136
+ name: _lt("Edit"),
16369
17137
  sequence: 20,
16370
17138
  })
16371
- .addChild("insert_function_max", ["insert", "insert_function"], {
16372
- name: _lt("MAX"),
16373
- action: (env) => env.startCellEdition(`=MAX(`),
17139
+ .addChild("undo", ["edit"], {
17140
+ ...undo,
17141
+ sequence: 10,
17142
+ })
17143
+ .addChild("redo", ["edit"], {
17144
+ ...redo,
17145
+ sequence: 20,
17146
+ separator: true,
17147
+ })
17148
+ .addChild("copy", ["edit"], {
17149
+ ...copy,
16374
17150
  sequence: 30,
16375
17151
  })
16376
- .addChild("insert_function_min", ["insert", "insert_function"], {
16377
- name: _lt("MIN"),
16378
- action: (env) => env.startCellEdition(`=MIN(`),
17152
+ .addChild("cut", ["edit"], {
17153
+ ...cut,
16379
17154
  sequence: 40,
16380
- separator: true,
16381
17155
  })
16382
- .addChild("categorie_function_all", ["insert", "insert_function"], {
16383
- name: _lt("All"),
17156
+ .addChild("paste", ["edit"], {
17157
+ ...paste,
16384
17158
  sequence: 50,
16385
17159
  })
16386
- .addChild("all_function_list", ["insert", "insert_function", "categorie_function_all"], () => {
16387
- const fnNames = functionRegistry.getKeys();
16388
- return createFormulaFunctionMenuItems(fnNames);
17160
+ .addChild("paste_special", ["edit"], {
17161
+ ...pasteSpecial,
17162
+ sequence: 60,
17163
+ separator: true,
16389
17164
  })
16390
- .addChild("categories_function_list", ["insert", "insert_function"], () => {
16391
- const functions = functionRegistry.content;
16392
- const categories = [...new Set(functionRegistry.getAll().map((fn) => fn.category))].filter(isDefined$1);
16393
- return categories.sort().map((category, i) => {
16394
- const functionsInCategory = Object.keys(functions).filter((key) => functions[key].category === category);
16395
- return {
16396
- name: category,
16397
- sequence: 60 + i * 10,
16398
- children: createFormulaFunctionMenuItems(functionsInCategory),
16399
- };
16400
- });
17165
+ .addChild("paste_special_value", ["edit", "paste_special"], {
17166
+ ...pasteSpecialValue,
17167
+ sequence: 10,
16401
17168
  })
16402
- .addChild("insert_link", ["insert"], {
16403
- name: _lt("Link"),
17169
+ .addChild("paste_special_format", ["edit", "paste_special"], {
17170
+ ...pasteSpecialFormat,
17171
+ sequence: 20,
17172
+ })
17173
+ .addChild("find_and_replace", ["edit"], {
17174
+ ...findAndReplace,
17175
+ sequence: 65,
16404
17176
  separator: true,
17177
+ })
17178
+ .addChild("edit_delete_cell_values", ["edit"], {
17179
+ ...deleteValues,
16405
17180
  sequence: 70,
16406
- action: INSERT_LINK,
16407
17181
  })
16408
- .addChild("insert_sheet", ["insert"], {
16409
- name: _lt("New sheet"),
17182
+ .addChild("edit_delete_row", ["edit"], {
17183
+ ...deleteRows,
16410
17184
  sequence: 80,
16411
- action: CREATE_SHEET_ACTION,
16412
- separator: true,
17185
+ })
17186
+ .addChild("edit_delete_column", ["edit"], {
17187
+ ...deleteCols,
17188
+ sequence: 90,
17189
+ })
17190
+ .addChild("edit_delete_cell_shift_up", ["edit"], {
17191
+ ...deleteCellShiftUp,
17192
+ sequence: 93,
17193
+ })
17194
+ .addChild("edit_delete_cell_shift_left", ["edit"], {
17195
+ ...deleteCellShiftLeft,
17196
+ sequence: 97,
17197
+ })
17198
+ .addChild("edit_unhide_columns", ["edit"], {
17199
+ ...unhideAllCols,
17200
+ sequence: 100,
17201
+ })
17202
+ .addChild("edit_unhide_rows", ["edit"], {
17203
+ ...unhideAllRows,
17204
+ sequence: 100,
17205
+ })
17206
+ // ---------------------------------------------------------------------
17207
+ // VIEW MENU ITEMS
17208
+ // ---------------------------------------------------------------------
17209
+ .add("view", {
17210
+ name: _lt("View"),
17211
+ sequence: 30,
16413
17212
  })
16414
17213
  .addChild("unfreeze_panes", ["view"], {
16415
- name: _lt("Unfreeze"),
17214
+ ...unFreezePane,
16416
17215
  sequence: 4,
16417
- isVisible: (env) => {
16418
- const { xSplit, ySplit } = env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId());
16419
- return xSplit + ySplit > 0;
16420
- },
16421
- action: (env) => env.model.dispatch("UNFREEZE_COLUMNS_ROWS", {
16422
- sheetId: env.model.getters.getActiveSheetId(),
16423
- }),
16424
17216
  })
16425
17217
  .addChild("freeze_panes", ["view"], {
16426
- name: _lt("Freeze"),
17218
+ ...freezePane,
16427
17219
  sequence: 5,
16428
17220
  separator: true,
16429
17221
  })
16430
17222
  .addChild("unfreeze_rows", ["view", "freeze_panes"], {
16431
- name: _lt("No rows"),
16432
- action: (env) => env.model.dispatch("UNFREEZE_ROWS", {
16433
- sheetId: env.model.getters.getActiveSheetId(),
16434
- }),
16435
- isReadonlyAllowed: true,
17223
+ ...unFreezeRows,
16436
17224
  sequence: 5,
16437
- isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).ySplit,
16438
17225
  })
16439
17226
  .addChild("freeze_first_row", ["view", "freeze_panes"], {
16440
- name: _lt("1 row"),
16441
- action: (env) => interactiveFreezeColumnsRows(env, "ROW", 1),
16442
- isReadonlyAllowed: true,
17227
+ ...freezeFirstRow,
16443
17228
  sequence: 10,
16444
17229
  })
16445
17230
  .addChild("freeze_second_row", ["view", "freeze_panes"], {
16446
- name: _lt("2 rows"),
16447
- action: (env) => interactiveFreezeColumnsRows(env, "ROW", 2),
16448
- isReadonlyAllowed: true,
17231
+ ...freezeSecondRow,
16449
17232
  sequence: 15,
16450
17233
  })
16451
17234
  .addChild("freeze_current_row", ["view", "freeze_panes"], {
16452
- name: _lt("Up to current row"),
16453
- action: (env) => {
16454
- const { bottom } = env.model.getters.getSelectedZone();
16455
- interactiveFreezeColumnsRows(env, "ROW", bottom + 1);
16456
- },
16457
- isReadonlyAllowed: true,
17235
+ ...freezeCurrentRow,
16458
17236
  sequence: 20,
16459
17237
  separator: true,
16460
17238
  })
16461
17239
  .addChild("unfreeze_columns", ["view", "freeze_panes"], {
16462
- name: _lt("No columns"),
16463
- action: (env) => env.model.dispatch("UNFREEZE_COLUMNS", {
16464
- sheetId: env.model.getters.getActiveSheetId(),
16465
- }),
16466
- isReadonlyAllowed: true,
17240
+ ...unFreezeCols,
16467
17241
  sequence: 25,
16468
- isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).xSplit,
16469
17242
  })
16470
17243
  .addChild("freeze_first_col", ["view", "freeze_panes"], {
16471
- name: _lt("1 column"),
16472
- action: (env) => interactiveFreezeColumnsRows(env, "COL", 1),
16473
- isReadonlyAllowed: true,
17244
+ ...freezeFirstCol,
16474
17245
  sequence: 30,
16475
17246
  })
16476
17247
  .addChild("freeze_second_col", ["view", "freeze_panes"], {
16477
- name: _lt("2 columns"),
16478
- action: (env) => interactiveFreezeColumnsRows(env, "COL", 2),
16479
- isReadonlyAllowed: true,
17248
+ ...freezeSecondCol,
16480
17249
  sequence: 35,
16481
17250
  })
16482
17251
  .addChild("freeze_current_col", ["view", "freeze_panes"], {
16483
- name: _lt("Up to current column"),
16484
- action: (env) => {
16485
- const { right } = env.model.getters.getSelectedZone();
16486
- interactiveFreezeColumnsRows(env, "COL", right + 1);
16487
- },
16488
- isReadonlyAllowed: true,
17252
+ ...freezeCurrentCol,
16489
17253
  sequence: 40,
16490
17254
  })
16491
17255
  .addChild("view_gridlines", ["view"], {
16492
- name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
16493
- ? _lt("Hide gridlines")
16494
- : _lt("Show gridlines"),
16495
- action: SET_GRID_LINES_VISIBILITY_ACTION,
17256
+ ...viewGridlines,
16496
17257
  sequence: 10,
16497
17258
  })
16498
17259
  .addChild("view_formulas", ["view"], {
16499
- name: (env) => env.model.getters.shouldShowFormulas() ? _lt("Hide formulas") : _lt("Show formulas"),
16500
- action: SET_FORMULA_VISIBILITY_ACTION,
16501
- isReadonlyAllowed: true,
17260
+ ...viewFormulas,
16502
17261
  sequence: 15,
16503
17262
  })
16504
- .addChild("format_number", ["format"], {
16505
- name: _lt("Numbers"),
16506
- sequence: 10,
16507
- separator: true,
17263
+ // ---------------------------------------------------------------------
17264
+ // INSERT MENU ITEMS
17265
+ // ---------------------------------------------------------------------
17266
+ .add("insert", {
17267
+ name: _lt("Insert"),
17268
+ sequence: 40,
16508
17269
  })
16509
- .addChild("format_number_automatic", ["format", "format_number"], {
16510
- name: NumberFormatTerms.Automatic,
17270
+ .addChild("insert_row_before", ["insert"], {
17271
+ ...topBarInsertRowsBefore,
16511
17272
  sequence: 10,
16512
- separator: true,
16513
- action: FORMAT_AUTOMATIC_ACTION,
16514
17273
  })
16515
- .addChild("format_number_number", ["format", "format_number"], {
16516
- name: NumberFormatTerms.Number,
16517
- description: "1,000.12",
17274
+ .addChild("insert_row_after", ["insert"], {
17275
+ ...topBarInsertRowsAfter,
16518
17276
  sequence: 20,
16519
- action: FORMAT_NUMBER_ACTION,
17277
+ separator: true,
16520
17278
  })
16521
- .addChild("format_number_percent", ["format", "format_number"], {
16522
- name: NumberFormatTerms.Percent,
16523
- description: "10.12%",
17279
+ .addChild("insert_column_before", ["insert"], {
17280
+ ...topBarInsertColsBefore,
16524
17281
  sequence: 30,
16525
- separator: true,
16526
- action: FORMAT_PERCENT_ACTION,
16527
17282
  })
16528
- .addChild("format_number_currency", ["format", "format_number"], {
16529
- name: NumberFormatTerms.Currency,
16530
- description: "$1,000.12",
16531
- sequence: 37,
16532
- action: FORMAT_CURRENCY_ACTION,
17283
+ .addChild("insert_column_after", ["insert"], {
17284
+ ...topBarInsertColsAfter,
17285
+ sequence: 40,
17286
+ separator: true,
16533
17287
  })
16534
- .addChild("format_number_currency_rounded", ["format", "format_number"], {
16535
- name: NumberFormatTerms.CurrencyRounded,
16536
- description: "$1,000",
16537
- sequence: 38,
16538
- action: FORMAT_CURRENCY_ROUNDED_ACTION,
17288
+ .addChild("insert_insert_cell_shift_down", ["insert"], {
17289
+ ...insertCellShiftDown,
17290
+ sequence: 43,
16539
17291
  })
16540
- .addChild("format_custom_currency", ["format", "format_number"], {
16541
- name: NumberFormatTerms.CustomCurrency,
16542
- sequence: 39,
17292
+ .addChild("insert_insert_cell_shift_right", ["insert"], {
17293
+ ...insertCellShiftRight,
17294
+ sequence: 47,
16543
17295
  separator: true,
16544
- isVisible: (env) => env.loadCurrencies !== undefined,
16545
- action: OPEN_CUSTOM_CURRENCY_SIDEPANEL_ACTION,
16546
17296
  })
16547
- .addChild("format_number_date", ["format", "format_number"], {
16548
- name: NumberFormatTerms.Date,
16549
- description: "9/26/2008",
16550
- sequence: 40,
16551
- action: FORMAT_DATE_ACTION,
16552
- })
16553
- .addChild("format_number_time", ["format", "format_number"], {
16554
- name: NumberFormatTerms.Time,
16555
- description: "10:43:00 PM",
17297
+ .addChild("insert_chart", ["insert"], {
17298
+ ...insertChart,
16556
17299
  sequence: 50,
16557
- action: FORMAT_TIME_ACTION,
16558
17300
  })
16559
- .addChild("format_number_date_time", ["format", "format_number"], {
16560
- name: NumberFormatTerms.DateTime,
16561
- description: "9/26/2008 22:43:00",
17301
+ .addChild("insert_image", ["insert"], {
17302
+ ...insertImage,
17303
+ sequence: 55,
17304
+ })
17305
+ .addChild("insert_function", ["insert"], {
17306
+ ...insertFunction,
16562
17307
  sequence: 60,
16563
- action: FORMAT_DATE_TIME_ACTION,
16564
17308
  })
16565
- .addChild("format_number_duration", ["format", "format_number"], {
16566
- name: NumberFormatTerms.Duration,
16567
- description: "27:51:38",
17309
+ .addChild("insert_function_sum", ["insert", "insert_function"], {
17310
+ ...insertFunctionSum,
17311
+ sequence: 0,
17312
+ })
17313
+ .addChild("insert_function_average", ["insert", "insert_function"], {
17314
+ ...insertFunctionAverage,
17315
+ sequence: 10,
17316
+ })
17317
+ .addChild("insert_function_count", ["insert", "insert_function"], {
17318
+ ...insertFunctionCount,
17319
+ sequence: 20,
17320
+ })
17321
+ .addChild("insert_function_max", ["insert", "insert_function"], {
17322
+ ...insertFunctionMax,
17323
+ sequence: 30,
17324
+ })
17325
+ .addChild("insert_function_min", ["insert", "insert_function"], {
17326
+ ...insertFunctionMin,
17327
+ sequence: 40,
17328
+ separator: true,
17329
+ })
17330
+ .addChild("categorie_function_all", ["insert", "insert_function"], {
17331
+ ...categorieFunctionAll,
17332
+ sequence: 50,
17333
+ })
17334
+ .addChild("categories_function_list", ["insert", "insert_function"], categoriesFunctionListMenuBuilder)
17335
+ .addChild("insert_link", ["insert"], {
17336
+ ...insertLink,
17337
+ separator: true,
16568
17338
  sequence: 70,
17339
+ })
17340
+ .addChild("insert_sheet", ["insert"], {
17341
+ ...insertSheet,
17342
+ sequence: 80,
17343
+ separator: true,
17344
+ })
17345
+ // ---------------------------------------------------------------------
17346
+ // FORMAT MENU ITEMS
17347
+ // ---------------------------------------------------------------------
17348
+ .add("format", { name: _lt("Format"), sequence: 50 })
17349
+ .addChild("format_number", ["format"], {
17350
+ ...formatNumberMenuItemSpec,
17351
+ name: _lt("Number"),
17352
+ sequence: 10,
16569
17353
  separator: true,
16570
- action: FORMAT_DURATION_ACTION,
16571
17354
  })
16572
17355
  .addChild("format_bold", ["format"], {
16573
- name: _lt("Bold"),
17356
+ ...formatBold,
16574
17357
  sequence: 20,
16575
- description: "Ctrl+B",
16576
- action: FORMAT_BOLD_ACTION,
16577
17358
  })
16578
17359
  .addChild("format_italic", ["format"], {
16579
- name: _lt("Italic"),
17360
+ ...formatItalic,
16580
17361
  sequence: 30,
16581
- description: "Ctrl+I",
16582
- action: FORMAT_ITALIC_ACTION,
16583
17362
  })
16584
17363
  .addChild("format_underline", ["format"], {
16585
- name: _lt("Underline"),
16586
- description: "Ctrl+U",
17364
+ ...formatUnderline,
16587
17365
  sequence: 40,
16588
- action: FORMAT_UNDERLINE_ACTION,
16589
17366
  })
16590
17367
  .addChild("format_strikethrough", ["format"], {
16591
- name: _lt("Strikethrough"),
17368
+ ...formatStrikethrough,
16592
17369
  sequence: 50,
16593
- action: FORMAT_STRIKETHROUGH_ACTION,
16594
17370
  separator: true,
16595
17371
  })
16596
17372
  .addChild("format_font_size", ["format"], {
16597
- name: _lt("Font size"),
17373
+ ...formatFontSize,
16598
17374
  sequence: 60,
16599
17375
  separator: true,
16600
17376
  })
16601
17377
  .addChild("format_alignment", ["format"], {
16602
- name: _lt("Alignment"),
17378
+ ...formatAlignment,
16603
17379
  sequence: 70,
16604
17380
  })
16605
17381
  .addChild("format_alignment_left", ["format", "format_alignment"], {
16606
- name: "Left",
17382
+ ...formatAlignmentLeft,
16607
17383
  sequence: 10,
16608
- action: (env) => setStyle(env, { align: "left" }),
16609
17384
  })
16610
17385
  .addChild("format_alignment_center", ["format", "format_alignment"], {
16611
- name: "Center",
17386
+ ...formatAlignmentCenter,
16612
17387
  sequence: 20,
16613
- action: (env) => setStyle(env, { align: "center" }),
16614
17388
  })
16615
17389
  .addChild("format_alignment_right", ["format", "format_alignment"], {
16616
- name: "Right",
17390
+ ...formatAlignmentRight,
16617
17391
  sequence: 30,
16618
- action: (env) => setStyle(env, { align: "right" }),
16619
17392
  separator: true,
16620
17393
  })
16621
17394
  .addChild("format_alignment_top", ["format", "format_alignment"], {
16622
- name: "Top",
17395
+ ...formatAlignmentTop,
16623
17396
  sequence: 40,
16624
- action: (env) => setStyle(env, { verticalAlign: "top" }),
16625
17397
  })
16626
17398
  .addChild("format_alignment_middle", ["format", "format_alignment"], {
16627
- name: "Middle",
17399
+ ...formatAlignmentMiddle,
16628
17400
  sequence: 50,
16629
- action: (env) => setStyle(env, { verticalAlign: "middle" }),
16630
17401
  })
16631
17402
  .addChild("format_alignment_bottom", ["format", "format_alignment"], {
16632
- name: "Bottom",
17403
+ ...formatAlignmentBottom,
16633
17404
  sequence: 60,
16634
- action: (env) => setStyle(env, { verticalAlign: "bottom" }),
16635
17405
  separator: true,
16636
17406
  })
16637
17407
  .addChild("format_wrapping", ["format"], {
16638
- name: _lt("Wrapping"),
17408
+ ...formatWrapping,
16639
17409
  sequence: 80,
16640
17410
  separator: true,
16641
17411
  })
16642
17412
  .addChild("format_wrapping_overflow", ["format", "format_wrapping"], {
16643
- name: _lt("Overflow"),
17413
+ ...formatWrappingOverflow,
16644
17414
  sequence: 10,
16645
- action: (env) => setStyle(env, { wrapping: "overflow" }),
16646
17415
  })
16647
17416
  .addChild("format_wrapping_wrap", ["format", "format_wrapping"], {
16648
- name: _lt("Wrap"),
17417
+ ...formatWrappingWrap,
16649
17418
  sequence: 20,
16650
- action: (env) => setStyle(env, { wrapping: "wrap" }),
16651
17419
  })
16652
17420
  .addChild("format_wrapping_clip", ["format", "format_wrapping"], {
16653
- name: _lt("Clip"),
17421
+ ...formatWrappingClip,
16654
17422
  sequence: 30,
16655
- action: (env) => setStyle(env, { wrapping: "clip" }),
16656
17423
  })
16657
17424
  .addChild("format_cf", ["format"], {
16658
- name: _lt("Conditional formatting"),
17425
+ ...formatCF,
16659
17426
  sequence: 90,
16660
- action: OPEN_CF_SIDEPANEL_ACTION,
16661
17427
  separator: true,
16662
17428
  })
16663
17429
  .addChild("format_clearFormat", ["format"], {
16664
- name: _lt("Clear formatting"),
17430
+ ...clearFormat,
16665
17431
  sequence: 100,
16666
- action: FORMAT_CLEARFORMAT_ACTION,
16667
17432
  separator: true,
17433
+ })
17434
+ // ---------------------------------------------------------------------
17435
+ // DATA MENU ITEMS
17436
+ // ---------------------------------------------------------------------
17437
+ .add("data", {
17438
+ name: _lt("Data"),
17439
+ sequence: 60,
17440
+ })
17441
+ .addChild("sort_range", ["data"], {
17442
+ ...sortRange,
17443
+ sequence: 20,
17444
+ separator: true,
17445
+ })
17446
+ .addChild("sort_ascending", ["data", "sort_range"], {
17447
+ ...sortAscending,
17448
+ sequence: 10,
17449
+ })
17450
+ .addChild("sort_descending", ["data", "sort_range"], {
17451
+ ...sortDescending,
17452
+ sequence: 20,
16668
17453
  })
16669
17454
  .addChild("add_data_filter", ["data"], {
16670
- name: _lt("Create filter"),
17455
+ ...addDataFilter,
16671
17456
  sequence: 10,
16672
- action: FILTERS_CREATE_FILTER_TABLE,
16673
- isVisible: (env) => !SELECTION_CONTAINS_FILTER(env),
16674
- isEnabled: (env) => SELECTION_IS_CONTINUOUS(env),
16675
17457
  })
16676
17458
  .addChild("remove_data_filter", ["data"], {
16677
- name: _lt("Remove filter"),
17459
+ ...removeDataFilter,
16678
17460
  sequence: 10,
16679
- action: FILTERS_REMOVE_FILTER_TABLE,
16680
- isVisible: SELECTION_CONTAINS_FILTER,
16681
- });
16682
- // Font-sizes
16683
- for (let fs of FONT_SIZES) {
16684
- topbarMenuRegistry.addChild(`format_font_size_${fs}`, ["format", "format_font_size"], {
16685
- name: fs.toString(),
16686
- sequence: fs,
16687
- action: (env) => setStyle(env, { fontSize: fs }),
16688
- });
16689
- }
16690
- function createFormulaFunctionMenuItems(fnNames) {
16691
- return fnNames.sort().map((fnName, i) => {
16692
- return {
16693
- name: fnName,
16694
- sequence: i * 10,
16695
- action: (env) => env.startCellEdition(`=${fnName}(`),
16696
- };
16697
- });
16698
- }
17461
+ });
16699
17462
 
16700
17463
  class OTRegistry extends Registry {
16701
17464
  /**
@@ -16738,7 +17501,7 @@
16738
17501
  }
16739
17502
  }
16740
17503
 
16741
- const uuidGenerator = new UuidGenerator();
17504
+ const uuidGenerator$1 = new UuidGenerator();
16742
17505
  css /* scss */ `
16743
17506
  .o-selection {
16744
17507
  .o-selection-input {
@@ -16795,7 +17558,7 @@
16795
17558
  class SelectionInput extends owl.Component {
16796
17559
  constructor() {
16797
17560
  super(...arguments);
16798
- this.id = uuidGenerator.uuidv4();
17561
+ this.id = uuidGenerator$1.uuidv4();
16799
17562
  this.previousRanges = this.props.ranges || [];
16800
17563
  this.originSheet = this.env.model.getters.getActiveSheetId();
16801
17564
  this.state = owl.useState({
@@ -17278,8 +18041,9 @@
17278
18041
 
17279
18042
  css /* scss */ `
17280
18043
  .o-color-picker-widget {
17281
- display: inline-block;
18044
+ display: flex;
17282
18045
  position: relative;
18046
+ align-items: center;
17283
18047
 
17284
18048
  .o-color-picker-button-style {
17285
18049
  display: flex;
@@ -17295,6 +18059,7 @@
17295
18059
  }
17296
18060
 
17297
18061
  .o-color-picker-button {
18062
+ height: 30px;
17298
18063
  > span {
17299
18064
  border-bottom: 4px solid;
17300
18065
  height: 16px;
@@ -20486,13 +21251,26 @@
20486
21251
  const sheetId = this.env.model.getters.getActiveSheetId();
20487
21252
  const rowDims = this.env.model.getters.getRowDimensionsInViewport(sheetId, position.row);
20488
21253
  const colDims = this.env.model.getters.getColDimensionsInViewport(sheetId, position.col);
20489
- // TODO : change this offset when we support vertical cell align
20490
- const centeringOffset = Math.floor((rowDims.size - FILTER_ICON_EDGE_LENGTH) / 2);
21254
+ const cell = this.env.model.getters.getCell({ sheetId, ...position });
21255
+ const verticalFilterIconPosition = this.getIconVerticalPosition(rowDims, cell);
20491
21256
  return {
20492
21257
  x: colDims.end - FILTER_ICON_EDGE_LENGTH + this.props.gridPosition.x - FILTER_ICON_MARGIN - 1,
20493
- y: rowDims.end - FILTER_ICON_EDGE_LENGTH + this.props.gridPosition.y - centeringOffset,
21258
+ y: verticalFilterIconPosition + this.props.gridPosition.y,
20494
21259
  };
20495
21260
  }
21261
+ // Calculates the vertical position of the filter icon based on the row dimensions and cell styles.
21262
+ getIconVerticalPosition(rowDims, cell) {
21263
+ var _a;
21264
+ const centeringOffset = Math.floor((rowDims.size - FILTER_ICON_EDGE_LENGTH) / 2);
21265
+ switch ((_a = cell === null || cell === void 0 ? void 0 : cell.style) === null || _a === void 0 ? void 0 : _a.verticalAlign) {
21266
+ case "bottom":
21267
+ return rowDims.end - FILTER_ICON_MARGIN - FILTER_ICON_EDGE_LENGTH;
21268
+ case "top":
21269
+ return rowDims.start + FILTER_ICON_MARGIN;
21270
+ default:
21271
+ return rowDims.end - FILTER_ICON_EDGE_LENGTH - centeringOffset;
21272
+ }
21273
+ }
20496
21274
  isFilterActive(position) {
20497
21275
  const sheetId = this.env.model.getters.getActiveSheetId();
20498
21276
  return this.env.model.getters.isFilterActive({ sheetId, ...position });
@@ -21313,6 +22091,10 @@
21313
22091
  };
21314
22092
 
21315
22093
  class GridPopover extends owl.Component {
22094
+ constructor() {
22095
+ super(...arguments);
22096
+ this.zIndex = ComponentsImportance.GridPopover;
22097
+ }
21316
22098
  get cellPopover() {
21317
22099
  const popover = this.env.model.getters.getCellPopover(this.props.hoveredCell);
21318
22100
  if (!popover.isOpen) {
@@ -22404,6 +23186,7 @@
22404
23186
  "CTRL+A": () => this.env.model.selection.loopSelection(),
22405
23187
  "CTRL+Z": () => this.env.model.dispatch("REQUEST_UNDO"),
22406
23188
  "CTRL+Y": () => this.env.model.dispatch("REQUEST_REDO"),
23189
+ F4: () => this.env.model.dispatch("REQUEST_REDO"),
22407
23190
  "CTRL+B": () => this.env.model.dispatch("SET_FORMATTING", {
22408
23191
  sheetId: this.env.model.getters.getActiveSheetId(),
22409
23192
  target: this.env.model.getters.getSelectedZones(),
@@ -22447,8 +23230,8 @@
22447
23230
  },
22448
23231
  "CTRL+END": () => {
22449
23232
  const sheetId = this.env.model.getters.getActiveSheetId();
22450
- const col = this.env.model.getters.findVisibleHeader(sheetId, "COL", range(0, this.env.model.getters.getNumberCols(sheetId)).reverse());
22451
- const row = this.env.model.getters.findVisibleHeader(sheetId, "ROW", range(0, this.env.model.getters.getNumberRows(sheetId)).reverse());
23233
+ const col = this.env.model.getters.findVisibleHeader(sheetId, "COL", this.env.model.getters.getNumberCols(sheetId) - 1, 0);
23234
+ const row = this.env.model.getters.findVisibleHeader(sheetId, "ROW", this.env.model.getters.getNumberRows(sheetId) - 1, 0);
22452
23235
  this.env.model.selection.selectCell(col, row);
22453
23236
  },
22454
23237
  "SHIFT+ ": () => {
@@ -22528,9 +23311,10 @@
22528
23311
  this.focus();
22529
23312
  }
22530
23313
  focus() {
23314
+ var _a;
22531
23315
  if (!this.env.model.getters.getSelectedFigureId() &&
22532
23316
  this.env.model.getters.getEditionMode() === "inactive") {
22533
- this.hiddenInput.el.focus();
23317
+ (_a = this.hiddenInput.el) === null || _a === void 0 ? void 0 : _a.focus();
22534
23318
  }
22535
23319
  }
22536
23320
  get gridEl() {
@@ -26450,7 +27234,7 @@
26450
27234
  }
26451
27235
  }
26452
27236
  }
26453
- data = JSON.parse(JSON.stringify(data));
27237
+ data = deepCopy(data);
26454
27238
  // apply migrations, if needed
26455
27239
  if ("version" in data) {
26456
27240
  if (data.version < CURRENT_VERSION) {
@@ -31568,7 +32352,7 @@
31568
32352
  duplicateSheet(fromId, toId) {
31569
32353
  const sheet = this.getSheet(fromId);
31570
32354
  const toName = this.getDuplicateSheetName(sheet.name);
31571
- const newSheet = JSON.parse(JSON.stringify(sheet));
32355
+ const newSheet = deepCopy(sheet);
31572
32356
  newSheet.id = toId;
31573
32357
  newSheet.name = toName;
31574
32358
  for (let col = 0; col <= newSheet.numberOfCols; col++) {
@@ -31695,10 +32479,10 @@
31695
32479
  }
31696
32480
  }
31697
32481
  moveCellOnColumnsDeletion(sheet, deletedColumn) {
31698
- for (let [index, row] of Object.entries(sheet.rows)) {
31699
- const rowIndex = parseInt(index, 10);
32482
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
32483
+ const row = sheet.rows[rowIndex];
31700
32484
  for (let i in row.cells) {
31701
- const colIndex = parseInt(i, 10);
32485
+ const colIndex = Number(i);
31702
32486
  const cellId = row.cells[i];
31703
32487
  if (cellId) {
31704
32488
  if (colIndex === deletedColumn) {
@@ -31725,11 +32509,11 @@
31725
32509
  */
31726
32510
  moveCellsOnAddition(sheet, addedElement, quantity, dimension) {
31727
32511
  const commands = [];
31728
- for (const [index, row] of Object.entries(sheet.rows)) {
31729
- const rowIndex = parseInt(index, 10);
32512
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
32513
+ const row = sheet.rows[rowIndex];
31730
32514
  if (dimension !== "rows" || rowIndex >= addedElement) {
31731
32515
  for (let i in row.cells) {
31732
- const colIndex = parseInt(i, 10);
32516
+ const colIndex = Number(i);
31733
32517
  const cellId = row.cells[i];
31734
32518
  if (cellId) {
31735
32519
  if (dimension === "rows" || colIndex >= addedElement) {
@@ -31759,11 +32543,11 @@
31759
32543
  */
31760
32544
  moveCellOnRowsDeletion(sheet, deleteFromRow, deleteToRow) {
31761
32545
  const numberRows = deleteToRow - deleteFromRow + 1;
31762
- for (let [index, row] of Object.entries(sheet.rows)) {
31763
- const rowIndex = parseInt(index, 10);
32546
+ for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
32547
+ const row = sheet.rows[rowIndex];
31764
32548
  if (rowIndex >= deleteFromRow && rowIndex <= deleteToRow) {
31765
32549
  for (let i in row.cells) {
31766
- const colIndex = parseInt(i, 10);
32550
+ const colIndex = Number(i);
31767
32551
  const cellId = row.cells[i];
31768
32552
  if (cellId) {
31769
32553
  this.dispatch("CLEAR_CELL", {
@@ -31776,7 +32560,7 @@
31776
32560
  }
31777
32561
  if (rowIndex > deleteToRow) {
31778
32562
  for (let i in row.cells) {
31779
- const colIndex = parseInt(i, 10);
32563
+ const colIndex = Number(i);
31780
32564
  const cellId = row.cells[i];
31781
32565
  if (cellId) {
31782
32566
  this.dispatch("UPDATE_CELL_POSITION", {
@@ -31794,7 +32578,7 @@
31794
32578
  const rows = [];
31795
32579
  const cellsQueue = sheet.rows.map((row) => row.cells);
31796
32580
  for (let i in sheet.rows) {
31797
- if (parseInt(i, 10) === index) {
32581
+ if (Number(i) === index) {
31798
32582
  continue;
31799
32583
  }
31800
32584
  rows.push({
@@ -32965,13 +33749,11 @@
32965
33749
  return Boolean(id && ((_b = (_a = this.filterValues[sheetId]) === null || _a === void 0 ? void 0 : _a[id]) === null || _b === void 0 ? void 0 : _b.length));
32966
33750
  }
32967
33751
  intersectZoneWithViewport(sheetId, zone) {
32968
- const colsRange = range(zone.left, zone.right + 1);
32969
- const rowsRange = range(zone.top, zone.bottom + 1);
32970
33752
  return {
32971
- left: this.getters.findVisibleHeader(sheetId, "COL", colsRange),
32972
- right: this.getters.findVisibleHeader(sheetId, "COL", colsRange.reverse()),
32973
- top: this.getters.findVisibleHeader(sheetId, "ROW", rowsRange),
32974
- bottom: this.getters.findVisibleHeader(sheetId, "ROW", rowsRange.reverse()),
33753
+ left: this.getters.findVisibleHeader(sheetId, "COL", zone.left, zone.right),
33754
+ right: this.getters.findVisibleHeader(sheetId, "COL", zone.right, zone.left),
33755
+ top: this.getters.findVisibleHeader(sheetId, "ROW", zone.top, zone.bottom),
33756
+ bottom: this.getters.findVisibleHeader(sheetId, "ROW", zone.bottom, zone.top),
32975
33757
  };
32976
33758
  }
32977
33759
  updateFilter({ col, row, values, sheetId }) {
@@ -33175,48 +33957,66 @@
33175
33957
  this.adjustPositionY(row);
33176
33958
  }
33177
33959
  }
33178
- adjustPositionX(col) {
33960
+ adjustPositionX(targetCol) {
33179
33961
  const sheetId = this.sheetId;
33180
- const { start, end } = this.getters.getColDimensions(sheetId, col);
33181
- while (end > this.offsetX + this.offsetCorrectionX + this.viewportWidth &&
33182
- this.offsetX + this.offsetCorrectionX < start) {
33183
- this.offsetX = this.getters.getColDimensions(sheetId, this.left).end - this.offsetCorrectionX;
33184
- this.offsetScrollbarX = this.offsetX;
33185
- this.adjustViewportZoneX();
33186
- }
33187
- while (col < this.left) {
33188
- let leftCol;
33189
- for (leftCol = this.left; leftCol >= 0; leftCol--) {
33190
- if (!this.getters.isColHidden(sheetId, leftCol)) {
33962
+ const { end } = this.getters.getColDimensions(sheetId, targetCol);
33963
+ const maxCol = this.getters.getNumberCols(sheetId);
33964
+ if (this.offsetX + this.offsetCorrectionX + this.viewportWidth < end) {
33965
+ for (let col = this.left; this.offsetX + this.offsetCorrectionX + this.viewportWidth < end; col++) {
33966
+ if (col > maxCol) {
33967
+ break;
33968
+ }
33969
+ if (this.getters.isColHidden(sheetId, col)) {
33970
+ continue;
33971
+ }
33972
+ this.offsetX = this.getters.getColDimensions(sheetId, col).end - this.offsetCorrectionX;
33973
+ this.offsetScrollbarX = this.offsetX;
33974
+ this.adjustViewportZoneX();
33975
+ }
33976
+ }
33977
+ else if (this.left > targetCol) {
33978
+ for (let col = this.left; col >= targetCol; col--) {
33979
+ if (col < 0) {
33191
33980
  break;
33192
33981
  }
33982
+ if (this.getters.isColHidden(sheetId, col)) {
33983
+ continue;
33984
+ }
33985
+ this.offsetX = this.getters.getColDimensions(sheetId, col).start - this.offsetCorrectionX;
33986
+ this.offsetScrollbarX = this.offsetX;
33987
+ this.adjustViewportZoneX();
33193
33988
  }
33194
- this.offsetX =
33195
- this.getters.getColDimensions(sheetId, leftCol - 1).start - this.offsetCorrectionX;
33196
- this.offsetScrollbarX = this.offsetX;
33197
- this.adjustViewportZoneX();
33198
33989
  }
33199
33990
  }
33200
- adjustPositionY(row) {
33991
+ adjustPositionY(targetRow) {
33201
33992
  const sheetId = this.sheetId;
33202
- while (this.getters.getRowDimensions(sheetId, row).end >
33203
- this.offsetY + this.viewportHeight + this.offsetCorrectionY &&
33204
- this.offsetY + this.offsetCorrectionY < this.getters.getRowDimensions(sheetId, row).start) {
33205
- this.offsetY = this.getters.getRowDimensions(sheetId, this.top).end - this.offsetCorrectionY;
33206
- this.offsetScrollbarY = this.offsetY;
33207
- this.adjustViewportZoneY();
33208
- }
33209
- while (row < this.top) {
33210
- let topRow;
33211
- for (topRow = this.top; topRow >= 0; topRow--) {
33212
- if (!this.getters.isRowHidden(sheetId, topRow)) {
33993
+ const { end } = this.getters.getRowDimensions(sheetId, targetRow);
33994
+ const maxRow = this.getters.getNumberRows(sheetId);
33995
+ if (this.offsetY + this.viewportHeight + this.offsetCorrectionY < end) {
33996
+ for (let row = this.top; this.offsetY + this.viewportHeight + this.offsetCorrectionY < end; row++) {
33997
+ if (row > maxRow) {
33998
+ break;
33999
+ }
34000
+ if (this.getters.isRowHidden(sheetId, row)) {
34001
+ continue;
34002
+ }
34003
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).end - this.offsetCorrectionY;
34004
+ this.offsetScrollbarY = this.offsetY;
34005
+ this.adjustViewportZoneY();
34006
+ }
34007
+ }
34008
+ else if (this.top > targetRow) {
34009
+ for (let row = this.top; row >= targetRow; row--) {
34010
+ if (row < 0) {
33213
34011
  break;
33214
34012
  }
34013
+ if (this.getters.isRowHidden(sheetId, row)) {
34014
+ continue;
34015
+ }
34016
+ this.offsetY = this.getters.getRowDimensions(sheetId, row).start - this.offsetCorrectionY;
34017
+ this.offsetScrollbarY = this.offsetY;
34018
+ this.adjustViewportZoneY();
33215
34019
  }
33216
- this.offsetY =
33217
- this.getters.getRowDimensions(sheetId, topRow - 1).start - this.offsetCorrectionY;
33218
- this.offsetScrollbarY = this.offsetY;
33219
- this.adjustViewportZoneY();
33220
34020
  }
33221
34021
  }
33222
34022
  setViewportOffset(offsetX, offsetY) {
@@ -33409,8 +34209,8 @@
33409
34209
  * In the absence of a component (standalone model), is it mandatory to set reasonable default values
33410
34210
  * to ensure the correct operation of this plugin.
33411
34211
  */
33412
- this.sheetViewWidth = DEFAULT_SHEETVIEW_SIZE;
33413
- this.sheetViewHeight = DEFAULT_SHEETVIEW_SIZE;
34212
+ this.sheetViewWidth = getDefaultSheetViewSize();
34213
+ this.sheetViewHeight = getDefaultSheetViewSize();
33414
34214
  this.gridOffsetX = 0;
33415
34215
  this.gridOffsetY = 0;
33416
34216
  this.sheetsWithDirtyViewports = new Set();
@@ -35075,13 +35875,33 @@
35075
35875
  getNextVisibleCellPosition({ sheetId, col, row }) {
35076
35876
  return {
35077
35877
  sheetId,
35078
- col: this.findVisibleHeader(sheetId, "COL", range(col, this.getters.getNumberCols(sheetId))),
35079
- row: this.findVisibleHeader(sheetId, "ROW", range(row, this.getters.getNumberRows(sheetId))),
35878
+ col: this.findVisibleHeader(sheetId, "COL", col, this.getters.getNumberCols(sheetId) - 1),
35879
+ row: this.findVisibleHeader(sheetId, "ROW", row, this.getters.getNumberRows(sheetId) - 1),
35080
35880
  };
35081
35881
  }
35082
- findVisibleHeader(sheetId, dimension, indexes) {
35083
- return indexes.find((index) => this.getters.doesHeaderExist(sheetId, dimension, index) &&
35084
- !this.isHeaderHidden(sheetId, dimension, index));
35882
+ /**
35883
+ * Find the first visible header in the range [`from` => `to`].
35884
+ *
35885
+ * Both `from` and `to` are inclusive.
35886
+ */
35887
+ findVisibleHeader(sheetId, dimension, from, to) {
35888
+ if (from <= to) {
35889
+ for (let i = from; i <= to; i++) {
35890
+ if (this.getters.doesHeaderExist(sheetId, dimension, i) &&
35891
+ !this.isHeaderHidden(sheetId, dimension, i)) {
35892
+ return i;
35893
+ }
35894
+ }
35895
+ }
35896
+ if (from > to) {
35897
+ for (let i = from; i >= to; i--) {
35898
+ if (this.getters.doesHeaderExist(sheetId, dimension, i) &&
35899
+ !this.isHeaderHidden(sheetId, dimension, i)) {
35900
+ return i;
35901
+ }
35902
+ }
35903
+ }
35904
+ return undefined;
35085
35905
  }
35086
35906
  findLastVisibleColRowIndex(sheetId, dimension, { last, first }) {
35087
35907
  const lastVisibleIndex = range(last, first, -1).find((index) => !this.isHeaderHidden(sheetId, dimension, index));
@@ -36542,7 +37362,8 @@
36542
37362
  * - clientId: Client who initiated the action
36543
37363
  * - changes: List of changes applied on the state.
36544
37364
  */
36545
- constructor(id, clientId, commands, changes) {
37365
+ constructor(id, clientId, commands, rootCommand, changes) {
37366
+ this.rootCommand = rootCommand;
36546
37367
  this._commands = [];
36547
37368
  this._changes = [];
36548
37369
  this.id = id;
@@ -36606,10 +37427,10 @@
36606
37427
  * Add a new revision to the collaborative session.
36607
37428
  * It will be transmitted to all other connected clients.
36608
37429
  */
36609
- save(commands, changes) {
37430
+ save(rootCommand, commands, changes) {
36610
37431
  if (!commands.length || !changes.length || !this.canApplyOptimisticUpdate())
36611
37432
  return;
36612
- const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, changes);
37433
+ const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes);
36613
37434
  this.revisions.append(revision.id, revision);
36614
37435
  this.trigger("new-local-state-update", { id: revision.id });
36615
37436
  this.sendUpdateMessage({
@@ -36710,6 +37531,22 @@
36710
37531
  isFullySynchronized() {
36711
37532
  return this.pendingMessages.length === 0;
36712
37533
  }
37534
+ /**
37535
+ * Get the last local revision whose root command isn't in the given list of ignored commands
37536
+ * */
37537
+ getLastLocalNonEmptyRevision(ignoredRootCommands) {
37538
+ var _a;
37539
+ const revisions = this.revisions.getRevertedExecution();
37540
+ for (const rev of revisions) {
37541
+ if (rev.rootCommand === "SNAPSHOT")
37542
+ return undefined;
37543
+ if (!rev.rootCommand || rev.rootCommand === "REMOTE")
37544
+ continue;
37545
+ if (!ignoredRootCommands.includes((_a = rev.rootCommand) === null || _a === void 0 ? void 0 : _a.type) && rev.commands.length)
37546
+ return rev;
37547
+ }
37548
+ return undefined;
37549
+ }
36713
37550
  _move(position) {
36714
37551
  var _a;
36715
37552
  // this method is debounced and might be called after the client
@@ -36769,7 +37606,7 @@
36769
37606
  return;
36770
37607
  }
36771
37608
  const { clientId, commands } = message;
36772
- const revision = new Revision(message.nextRevisionId, clientId, commands);
37609
+ const revision = new Revision(message.nextRevisionId, clientId, commands, "REMOTE");
36773
37610
  if (revision.clientId !== this.clientId) {
36774
37611
  this.revisions.insert(revision.id, revision, message.serverRevisionId);
36775
37612
  const pendingCommands = this.pendingMessages
@@ -36782,7 +37619,7 @@
36782
37619
  }
36783
37620
  break;
36784
37621
  case "SNAPSHOT_CREATED": {
36785
- const revision = new Revision(message.nextRevisionId, "server", []);
37622
+ const revision = new Revision(message.nextRevisionId, "server", [], "SNAPSHOT");
36786
37623
  this.revisions.insert(revision.id, revision, message.serverRevisionId);
36787
37624
  this.dropPendingHistoryMessages();
36788
37625
  this.trigger("snapshot");
@@ -37560,6 +38397,324 @@
37560
38397
  "getColRowOffset",
37561
38398
  ];
37562
38399
 
38400
+ const genericRepeatsTransforms = [
38401
+ repeatSheetDependantCommand,
38402
+ repeatTargetDependantCommand,
38403
+ repeatPositionDependantCommand,
38404
+ ];
38405
+ function repeatSheetDependantCommand(getters, command) {
38406
+ if (!("sheetId" in command))
38407
+ return command;
38408
+ return { ...deepCopy(command), sheetId: getters.getActiveSheetId() };
38409
+ }
38410
+ function repeatTargetDependantCommand(getters, command) {
38411
+ if (!("target" in command) || !Array.isArray(command.target))
38412
+ return command;
38413
+ return {
38414
+ ...deepCopy(command),
38415
+ target: getters.getSelectedZones(),
38416
+ };
38417
+ }
38418
+ function repeatPositionDependantCommand(getters, command) {
38419
+ if (!("row" in command) || !("col" in command))
38420
+ return command;
38421
+ const { col, row } = getters.getActivePosition();
38422
+ return { ...deepCopy(command), col, row };
38423
+ }
38424
+
38425
+ const uuidGenerator = new UuidGenerator();
38426
+ function repeatCreateChartCommand(getters, cmd) {
38427
+ return {
38428
+ ...repeatSheetDependantCommand(getters, cmd),
38429
+ id: uuidGenerator.uuidv4(),
38430
+ };
38431
+ }
38432
+ function repeatCreateImageCommand(getters, cmd) {
38433
+ return {
38434
+ ...repeatSheetDependantCommand(getters, cmd),
38435
+ figureId: uuidGenerator.uuidv4(),
38436
+ };
38437
+ }
38438
+ function repeatCreateFigureCommand(getters, cmd) {
38439
+ const newCmd = repeatSheetDependantCommand(getters, cmd);
38440
+ newCmd.figure.id = uuidGenerator.uuidv4();
38441
+ return newCmd;
38442
+ }
38443
+ function repeatCreateSheetCommand(getters, cmd) {
38444
+ var _a;
38445
+ const newCmd = deepCopy(cmd);
38446
+ newCmd.sheetId = uuidGenerator.uuidv4();
38447
+ const sheetName = cmd.name || getters.getSheet(getters.getActiveSheetId()).name;
38448
+ // Extract the prefix of the sheet name (everything before the number at the end of the name)
38449
+ const namePrefix = ((_a = sheetName.match(/(.+?)\d*$/)) === null || _a === void 0 ? void 0 : _a[1]) || sheetName;
38450
+ newCmd.name = getters.getNextSheetName(namePrefix);
38451
+ return newCmd;
38452
+ }
38453
+ function repeatAddColumnsRowsCommand(getters, cmd) {
38454
+ const currentPosition = getters.getActivePosition();
38455
+ return {
38456
+ ...repeatSheetDependantCommand(getters, cmd),
38457
+ base: cmd.dimension === "COL" ? currentPosition.col : currentPosition.row,
38458
+ };
38459
+ }
38460
+ function repeatHeaderElementCommand(getters, cmd) {
38461
+ const currentSelection = getters.getSelectedZone();
38462
+ return {
38463
+ ...repeatSheetDependantCommand(getters, cmd),
38464
+ elements: cmd.dimension === "COL"
38465
+ ? range(currentSelection.left, currentSelection.right + 1)
38466
+ : range(currentSelection.top, currentSelection.bottom + 1),
38467
+ };
38468
+ }
38469
+ function repeatInsertOrDeleteCellCommand(getters, cmd) {
38470
+ const currentSelection = getters.getSelectedZone();
38471
+ return {
38472
+ ...deepCopy(cmd),
38473
+ zone: currentSelection,
38474
+ };
38475
+ }
38476
+ function repeatAutoResizeCommand(getters, cmd) {
38477
+ const newCmd = deepCopy(cmd);
38478
+ const currentSelection = getters.getSelectedZone();
38479
+ const { top, bottom, left, right } = currentSelection;
38480
+ if ("cols" in newCmd) {
38481
+ newCmd.cols = range(left, right + 1);
38482
+ }
38483
+ else if ("rows" in newCmd) {
38484
+ newCmd.rows = range(top, bottom + 1);
38485
+ }
38486
+ return newCmd;
38487
+ }
38488
+ function repeatSortCellsCommand(getters, cmd) {
38489
+ const currentSelection = getters.getSelectedZone();
38490
+ return {
38491
+ ...repeatSheetDependantCommand(getters, cmd),
38492
+ col: currentSelection.left,
38493
+ row: currentSelection.top,
38494
+ zone: currentSelection,
38495
+ };
38496
+ }
38497
+ function repeatPasteCommand(getters, cmd) {
38498
+ /**
38499
+ * Note : we have to store the state of the clipboard in the clipboard plugin, and introduce a
38500
+ * new command REPEAT_PASTE to be able to repeat the paste command.
38501
+ *
38502
+ * We cannot re-dispatch a paste, because the content of the clipboard may have changed in between.
38503
+ *
38504
+ * And we cannot adapt the sub-commands of the paste command, because they are dependant on the state of the sheet,
38505
+ * and may change based on the paste location. A simple example is that paste create new col/rows for the clipboard
38506
+ * content to fit the sheet. So there will be ADD_COL_ROW_COMMANDS in the sub-commands in the history, but repeating
38507
+ * paste might not need them. Or they could only needed for the repeated paste, not for the original.
38508
+ */
38509
+ return {
38510
+ type: "REPEAT_PASTE",
38511
+ pasteOption: deepCopy(cmd.pasteOption),
38512
+ target: getters.getSelectedZones(),
38513
+ };
38514
+ }
38515
+
38516
+ /**
38517
+ * Registry containing all the command that can be repeated on redo, and function to transform them
38518
+ * to the current state of the model.
38519
+ *
38520
+ * If the transform function is undefined, the command will be transformed using generic transformations.
38521
+ * (change the sheetId, the row, the col, the target, the ranges, to the current active sheet & selection)
38522
+ *
38523
+ */
38524
+ const repeatCommandTransformRegistry = new Registry();
38525
+ repeatCommandTransformRegistry.add("UPDATE_CELL", genericRepeat);
38526
+ repeatCommandTransformRegistry.add("CLEAR_CELL", genericRepeat);
38527
+ repeatCommandTransformRegistry.add("DELETE_CONTENT", genericRepeat);
38528
+ repeatCommandTransformRegistry.add("ADD_MERGE", genericRepeat);
38529
+ repeatCommandTransformRegistry.add("REMOVE_MERGE", genericRepeat);
38530
+ repeatCommandTransformRegistry.add("SET_FORMATTING", genericRepeat);
38531
+ repeatCommandTransformRegistry.add("CLEAR_FORMATTING", genericRepeat);
38532
+ repeatCommandTransformRegistry.add("SET_BORDER", genericRepeat);
38533
+ repeatCommandTransformRegistry.add("CREATE_FILTER_TABLE", genericRepeat);
38534
+ repeatCommandTransformRegistry.add("REMOVE_FILTER_TABLE", genericRepeat);
38535
+ repeatCommandTransformRegistry.add("HIDE_SHEET", genericRepeat);
38536
+ repeatCommandTransformRegistry.add("ADD_COLUMNS_ROWS", repeatAddColumnsRowsCommand);
38537
+ repeatCommandTransformRegistry.add("REMOVE_COLUMNS_ROWS", repeatHeaderElementCommand);
38538
+ repeatCommandTransformRegistry.add("HIDE_COLUMNS_ROWS", repeatHeaderElementCommand);
38539
+ repeatCommandTransformRegistry.add("RESIZE_COLUMNS_ROWS", repeatHeaderElementCommand);
38540
+ repeatCommandTransformRegistry.add("CREATE_SHEET", repeatCreateSheetCommand);
38541
+ repeatCommandTransformRegistry.add("CREATE_FIGURE", repeatCreateFigureCommand);
38542
+ repeatCommandTransformRegistry.add("CREATE_CHART", repeatCreateChartCommand);
38543
+ repeatCommandTransformRegistry.add("CREATE_IMAGE", repeatCreateImageCommand);
38544
+ const repeatLocalCommandTransformRegistry = new Registry();
38545
+ repeatLocalCommandTransformRegistry.add("STOP_EDITION", repeatLocalCommandChildren);
38546
+ repeatLocalCommandTransformRegistry.add("PASTE", repeatPasteCommand);
38547
+ repeatLocalCommandTransformRegistry.add("INSERT_CELL", repeatInsertOrDeleteCellCommand);
38548
+ repeatLocalCommandTransformRegistry.add("DELETE_CELL", repeatInsertOrDeleteCellCommand);
38549
+ repeatLocalCommandTransformRegistry.add("AUTORESIZE_COLUMNS", repeatAutoResizeCommand);
38550
+ repeatLocalCommandTransformRegistry.add("AUTORESIZE_ROWS", repeatAutoResizeCommand);
38551
+ repeatLocalCommandTransformRegistry.add("SORT_CELLS", repeatSortCellsCommand);
38552
+ repeatLocalCommandTransformRegistry.add("SUM_SELECTION", genericRepeat);
38553
+ repeatLocalCommandTransformRegistry.add("SET_DECIMAL", genericRepeat);
38554
+ function genericRepeat(getters, command) {
38555
+ let transformedCommand = deepCopy(command);
38556
+ for (const repeatTransform of genericRepeatsTransforms) {
38557
+ transformedCommand = repeatTransform(getters, transformedCommand);
38558
+ }
38559
+ return transformedCommand;
38560
+ }
38561
+ function repeatCoreCommand(getters, command) {
38562
+ if (!command) {
38563
+ return undefined;
38564
+ }
38565
+ const isRepeatable = repeatCommandTransformRegistry.contains(command.type);
38566
+ if (!isRepeatable) {
38567
+ return undefined;
38568
+ }
38569
+ const transform = repeatCommandTransformRegistry.get(command.type);
38570
+ return transform(getters, command);
38571
+ }
38572
+ function repeatLocalCommand(getters, command, childCommands) {
38573
+ const isRepeatable = repeatLocalCommandTransformRegistry.contains(command.type);
38574
+ if (!isRepeatable) {
38575
+ return undefined;
38576
+ }
38577
+ const repeatTransform = repeatLocalCommandTransformRegistry.get(command.type);
38578
+ return repeatTransform(getters, command, childCommands);
38579
+ }
38580
+ function repeatLocalCommandChildren(getters, cmd, childCommands) {
38581
+ return childCommands
38582
+ .map((childCommand) => repeatCoreCommand(getters, childCommand))
38583
+ .filter(isDefined$1);
38584
+ }
38585
+
38586
+ function canRepeatRevision(revision) {
38587
+ if (!revision || !revision.rootCommand || typeof revision.rootCommand !== "object") {
38588
+ return false;
38589
+ }
38590
+ if (isCoreCommand(revision.rootCommand)) {
38591
+ return repeatCommandTransformRegistry.contains(revision.rootCommand.type);
38592
+ }
38593
+ return repeatLocalCommandTransformRegistry.contains(revision.rootCommand.type);
38594
+ }
38595
+ function repeatRevision(revision, getters) {
38596
+ if (!revision.rootCommand || typeof revision.rootCommand !== "object") {
38597
+ return undefined;
38598
+ }
38599
+ if (isCoreCommand(revision.rootCommand)) {
38600
+ return repeatCoreCommand(getters, revision.rootCommand);
38601
+ }
38602
+ return repeatLocalCommand(getters, revision.rootCommand, revision.commands);
38603
+ }
38604
+
38605
+ /**
38606
+ * Local History
38607
+ *
38608
+ * The local history is responsible of tracking the locally state updates
38609
+ * It maintains the local undo and redo stack to allow to undo/redo only local
38610
+ * changes
38611
+ */
38612
+ class HistoryPlugin extends UIPlugin {
38613
+ constructor(config) {
38614
+ super(config);
38615
+ /**
38616
+ * Ids of the revisions which can be undone
38617
+ */
38618
+ this.undoStack = [];
38619
+ /**
38620
+ * Ids of the revisions which can be redone
38621
+ */
38622
+ this.redoStack = [];
38623
+ this.session = config.session;
38624
+ this.session.on("new-local-state-update", this, this.onNewLocalStateUpdate);
38625
+ this.session.on("pending-revisions-dropped", this, ({ revisionIds }) => this.drop(revisionIds));
38626
+ this.session.on("snapshot", this, () => {
38627
+ this.undoStack = [];
38628
+ this.redoStack = [];
38629
+ });
38630
+ }
38631
+ allowDispatch(cmd) {
38632
+ switch (cmd.type) {
38633
+ case "REQUEST_UNDO":
38634
+ if (!this.canUndo()) {
38635
+ return 6 /* CommandResult.EmptyUndoStack */;
38636
+ }
38637
+ break;
38638
+ case "REQUEST_REDO":
38639
+ if (!this.canRedo()) {
38640
+ return 7 /* CommandResult.EmptyRedoStack */;
38641
+ }
38642
+ break;
38643
+ }
38644
+ return 0 /* CommandResult.Success */;
38645
+ }
38646
+ handle(cmd) {
38647
+ switch (cmd.type) {
38648
+ case "REQUEST_UNDO":
38649
+ case "REQUEST_REDO":
38650
+ // History changes (undo & redo) are *not* applied optimistically on the local state.
38651
+ // We wait a global confirmation from the server. The goal is to avoid handling concurrent
38652
+ // history changes on multiple clients which are very hard to manage correctly.
38653
+ this.requestHistoryChange(cmd.type === "REQUEST_UNDO" ? "UNDO" : "REDO");
38654
+ }
38655
+ }
38656
+ finalize() { }
38657
+ requestHistoryChange(type) {
38658
+ const id = type === "UNDO" ? this.undoStack.pop() : this.redoStack.pop();
38659
+ if (!id) {
38660
+ const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
38661
+ if (!lastNonRedoRevision) {
38662
+ return;
38663
+ }
38664
+ const repeatedCommands = repeatRevision(lastNonRedoRevision, this.getters);
38665
+ if (!repeatedCommands) {
38666
+ return;
38667
+ }
38668
+ if (!Array.isArray(repeatedCommands)) {
38669
+ this.dispatch(repeatedCommands.type, repeatedCommands);
38670
+ return;
38671
+ }
38672
+ for (const command of repeatedCommands) {
38673
+ this.dispatch(command.type, command);
38674
+ }
38675
+ return;
38676
+ }
38677
+ if (type === "UNDO") {
38678
+ this.session.undo(id);
38679
+ this.redoStack.push(id);
38680
+ }
38681
+ else {
38682
+ this.session.redo(id);
38683
+ this.undoStack.push(id);
38684
+ }
38685
+ }
38686
+ canUndo() {
38687
+ return this.undoStack.length > 0;
38688
+ }
38689
+ canRedo() {
38690
+ if (this.redoStack.length > 0)
38691
+ return true;
38692
+ const lastNonRedoRevision = this.getPossibleRevisionToRepeat();
38693
+ return canRepeatRevision(lastNonRedoRevision);
38694
+ }
38695
+ drop(revisionIds) {
38696
+ this.undoStack = this.undoStack.filter((id) => !revisionIds.includes(id));
38697
+ this.redoStack = [];
38698
+ }
38699
+ onNewLocalStateUpdate({ id }) {
38700
+ this.undoStack.push(id);
38701
+ this.redoStack = [];
38702
+ if (this.undoStack.length > MAX_HISTORY_STEPS) {
38703
+ this.undoStack.shift();
38704
+ }
38705
+ }
38706
+ /**
38707
+ * Fetch the last revision which is not empty and not a repeated command
38708
+ *
38709
+ * Ignore repeated commands (REQUEST_REDO command as root command)
38710
+ * Ignore standard undo/redo revisions (that are empty)
38711
+ */
38712
+ getPossibleRevisionToRepeat() {
38713
+ return this.session.getLastLocalNonEmptyRevision(["REQUEST_REDO"]);
38714
+ }
38715
+ }
38716
+ HistoryPlugin.getters = ["canUndo", "canRedo"];
38717
+
37563
38718
  /** Abstract state of the clipboard when copying/cutting content that is pasted in cells of the sheet */
37564
38719
  class ClipboardCellsAbstractState {
37565
38720
  constructor(operation, getters, dispatch, selection) {
@@ -38269,7 +39424,7 @@
38269
39424
  return 0 /* CommandResult.Success */;
38270
39425
  }
38271
39426
  handle(cmd) {
38272
- var _a, _b;
39427
+ var _a, _b, _c;
38273
39428
  switch (cmd.type) {
38274
39429
  case "COPY":
38275
39430
  case "CUT":
@@ -38287,6 +39442,7 @@
38287
39442
  if (this.state.operation === "CUT") {
38288
39443
  this.state = undefined;
38289
39444
  }
39445
+ this.lastPasteState = this.state;
38290
39446
  this.status = "invisible";
38291
39447
  break;
38292
39448
  case "CLEAN_CLIPBOARD_HIGHLIGHT":
@@ -38339,10 +39495,19 @@
38339
39495
  break;
38340
39496
  }
38341
39497
  case "PASTE_FROM_OS_CLIPBOARD":
38342
- const state = new ClipboardOsState(cmd.text, this.getters, this.dispatch, this.selection);
38343
- state.paste(cmd.target);
39498
+ this.state = new ClipboardOsState(cmd.text, this.getters, this.dispatch, this.selection);
39499
+ this.state.paste(cmd.target);
39500
+ this.lastPasteState = this.state;
38344
39501
  this.status = "invisible";
38345
39502
  break;
39503
+ case "REPEAT_PASTE": {
39504
+ (_c = this.lastPasteState) === null || _c === void 0 ? void 0 : _c.paste(cmd.target, {
39505
+ pasteOption: cmd.pasteOption,
39506
+ shouldPasteCF: true,
39507
+ selectTarget: true,
39508
+ });
39509
+ break;
39510
+ }
38346
39511
  case "ACTIVATE_PAINT_FORMAT": {
38347
39512
  const zones = this.getters.getSelectedZones();
38348
39513
  this.state = this.getClipboardStateForCopyCells(zones, "COPY");
@@ -39823,7 +40988,8 @@
39823
40988
  .add("automatic_sum", AutomaticSumPlugin)
39824
40989
  .add("format", FormatPlugin)
39825
40990
  .add("cell_popovers", CellPopoverPlugin)
39826
- .add("selection_multiuser", SelectionMultiUserPlugin);
40991
+ .add("selection_multiuser", SelectionMultiUserPlugin)
40992
+ .add("history", HistoryPlugin);
39827
40993
  // Plugins which have a state, but which should not be shared in collaborative
39828
40994
  const statefulUIPluginRegistry = new Registry()
39829
40995
  .add("selection", GridSelectionPlugin)
@@ -39841,7 +41007,7 @@
39841
41007
  const clickableCellRegistry = new Registry();
39842
41008
  clickableCellRegistry.add("link", {
39843
41009
  condition: (position, env) => !!env.model.getters.getEvaluatedCell(position).link,
39844
- action: (position, env) => openLink(env.model.getters.getEvaluatedCell(position).link, env),
41010
+ execute: (position, env) => openLink(env.model.getters.getEvaluatedCell(position).link, env),
39845
41011
  sequence: 5,
39846
41012
  });
39847
41013
 
@@ -40298,7 +41464,7 @@
40298
41464
  name: this.getComposedFnName(fnName, fnValue),
40299
41465
  sequence: i,
40300
41466
  isReadonlyAllowed: true,
40301
- action: () => {
41467
+ execute: () => {
40302
41468
  this.selectedStatisticFn = fnName;
40303
41469
  },
40304
41470
  });
@@ -40466,10 +41632,6 @@
40466
41632
  font-size: 15px;
40467
41633
  border-top: 1px solid lightgrey;
40468
41634
 
40469
- .o-add-sheet.disabled {
40470
- cursor: not-allowed;
40471
- }
40472
-
40473
41635
  .o-sheet-item {
40474
41636
  cursor: pointer;
40475
41637
  &:hover {
@@ -40575,7 +41737,7 @@
40575
41737
  sequence: i,
40576
41738
  isReadonlyAllowed: true,
40577
41739
  textColor: sheet.isVisible ? undefined : "grey",
40578
- action: (env) => {
41740
+ execute: (env) => {
40579
41741
  env.model.dispatch("ACTIVATE_SHEET", { sheetIdFrom: from, sheetIdTo: sheetId });
40580
41742
  },
40581
41743
  });
@@ -40832,7 +41994,7 @@
40832
41994
  getClickableAction(position) {
40833
41995
  for (const items of clickableCellRegistry.getAll().sort((a, b) => a.sequence - b.sequence)) {
40834
41996
  if (items.condition(position, this.env)) {
40835
- return items.action;
41997
+ return items.execute;
40836
41998
  }
40837
41999
  }
40838
42000
  return false;
@@ -41060,21 +42222,66 @@
41060
42222
  onCloseSidePanel: Function,
41061
42223
  };
41062
42224
 
41063
- const AddMergeInteractiveContent = {
41064
- MergeIsDestructive: _lt("Merging these cells will only preserve the top-leftmost value. Merge anyway?"),
41065
- MergeInFilter: _lt("You can't merge cells inside of an existing filter."),
41066
- };
41067
- function interactiveAddMerge(env, sheetId, target) {
41068
- const result = env.model.dispatch("ADD_MERGE", { sheetId, target });
41069
- if (result.isCancelledBecause(80 /* CommandResult.MergeInFilter */)) {
41070
- env.raiseError(AddMergeInteractiveContent.MergeInFilter);
42225
+ css /* scss */ `
42226
+ .o-menu-item-button {
42227
+ display: flex;
42228
+ justify-content: center;
42229
+ align-items: center;
42230
+ margin: 2px;
42231
+ padding: 0px 3px;
42232
+ border-radius: 2px;
42233
+ min-width: 20px;
42234
+ }
42235
+ .o-disabled {
42236
+ opacity: 0.6;
42237
+ cursor: default;
42238
+ }
42239
+ `;
42240
+ class ActionButton extends owl.Component {
42241
+ constructor() {
42242
+ super(...arguments);
42243
+ this.actionButton = createAction(this.props.action);
41071
42244
  }
41072
- else if (result.isCancelledBecause(3 /* CommandResult.MergeIsDestructive */)) {
41073
- env.askConfirmation(AddMergeInteractiveContent.MergeIsDestructive, () => {
41074
- env.model.dispatch("ADD_MERGE", { sheetId, target, force: true });
41075
- });
42245
+ setup() {
42246
+ owl.onWillUpdateProps(() => (this.actionButton = createAction(this.props.action)));
41076
42247
  }
41077
- }
42248
+ get isVisible() {
42249
+ return this.actionButton.isVisible(this.env);
42250
+ }
42251
+ get isEnabled() {
42252
+ return this.actionButton.isEnabled(this.env);
42253
+ }
42254
+ get isActive() {
42255
+ var _a, _b;
42256
+ return (_b = (_a = this.actionButton).isActive) === null || _b === void 0 ? void 0 : _b.call(_a, this.env);
42257
+ }
42258
+ get title() {
42259
+ const name = this.actionButton.name(this.env);
42260
+ const description = this.actionButton.description;
42261
+ return name + (description ? ` (${description})` : "");
42262
+ }
42263
+ get iconTitle() {
42264
+ return this.actionButton.icon;
42265
+ }
42266
+ onClick(ev) {
42267
+ var _a, _b, _c, _d;
42268
+ if (this.isEnabled) {
42269
+ (_b = (_a = this.props).onClick) === null || _b === void 0 ? void 0 : _b.call(_a, ev);
42270
+ (_d = (_c = this.actionButton).execute) === null || _d === void 0 ? void 0 : _d.call(_c, this.env);
42271
+ }
42272
+ }
42273
+ get buttonStyle() {
42274
+ if (this.props.selectedColor) {
42275
+ return cssPropertiesToCss({
42276
+ "border-bottom": `4px solid ${this.props.selectedColor}`,
42277
+ height: "16px",
42278
+ "margin-top": "2px",
42279
+ });
42280
+ }
42281
+ return "";
42282
+ }
42283
+ }
42284
+ ActionButton.template = "o-spreadsheet-ActionButton";
41078
42285
 
41079
42286
  const COMPOSER_MAX_HEIGHT = 100;
41080
42287
  css /* scss */ `
@@ -41136,6 +42343,14 @@
41136
42343
  input::-webkit-inner-spin-button {
41137
42344
  -webkit-appearance: none;
41138
42345
  }
42346
+
42347
+ .o-text-options > div {
42348
+ line-height: 26px;
42349
+ padding: 3px 12px;
42350
+ &:hover {
42351
+ background-color: rgba(0, 0, 0, 0.08);
42352
+ }
42353
+ }
41139
42354
  }
41140
42355
  `;
41141
42356
  class FontSizeEditor extends owl.Component {
@@ -41204,41 +42419,6 @@
41204
42419
  dropdownStyle: String,
41205
42420
  };
41206
42421
 
41207
- const FORMATS = [
41208
- { name: "automatic", text: NumberFormatTerms.Automatic },
41209
- { name: "number", text: NumberFormatTerms.Number, description: "1,000.12", value: "#,##0.00" },
41210
- { name: "percent", text: NumberFormatTerms.Percent, description: "10.12%", value: "0.00%" },
41211
- {
41212
- name: "currency",
41213
- text: NumberFormatTerms.Currency,
41214
- description: "$1,000.12",
41215
- value: "[$$]#,##0.00",
41216
- },
41217
- {
41218
- name: "currency_rounded",
41219
- text: NumberFormatTerms.CurrencyRounded,
41220
- description: "$1,000",
41221
- value: "[$$]#,##0",
41222
- },
41223
- { name: "date", text: NumberFormatTerms.Date, description: "9/26/2008", value: "m/d/yyyy" },
41224
- { name: "time", text: NumberFormatTerms.Time, description: "10:43:00 PM", value: "hh:mm:ss a" },
41225
- {
41226
- name: "datetime",
41227
- text: NumberFormatTerms.DateTime,
41228
- description: "9/26/2008 22:43:00",
41229
- value: "m/d/yyyy hh:mm:ss",
41230
- },
41231
- {
41232
- name: "duration",
41233
- text: NumberFormatTerms.Duration,
41234
- description: "27:51:38",
41235
- value: "hhhh:mm:ss",
41236
- },
41237
- ];
41238
- const CUSTOM_FORMATS = [
41239
- { name: "custom_currency", text: NumberFormatTerms.CustomCurrency, sidePanel: "CustomCurrency" },
41240
- ];
41241
- const ICONS_COLOR = "#4A4F59";
41242
42422
  // If we ever change these colors, make sure the filter tool stays green to match the icon in the grid
41243
42423
  const ACTIVE_BG_COLOR = BACKGROUND_HEADER_FILTER_COLOR;
41244
42424
  const ACTIVE_FONT_COLOR = FILTERS_COLOR;
@@ -41303,23 +42483,10 @@
41303
42483
 
41304
42484
  /* Toolbar */
41305
42485
  .o-toolbar-tools {
41306
- .o-tool {
41307
- display: flex;
41308
- justify-content: center;
41309
- align-items: center;
41310
- margin: 2px;
41311
- padding: 0px 3px;
41312
- border-radius: 2px;
41313
- min-width: 20px;
41314
- }
41315
-
41316
- .o-filter-tool {
41317
- margin-right: 8px;
41318
- }
41319
-
41320
- .o-border-dropdown {
41321
- padding: 4px;
41322
- }
42486
+ display: flex;
42487
+ flex-shrink: 0;
42488
+ margin: 0px 6px 0px 16px;
42489
+ cursor: default;
41323
42490
 
41324
42491
  .o-divider {
41325
42492
  display: inline-block;
@@ -41333,59 +42500,28 @@
41333
42500
  display: flex;
41334
42501
  align-items: center;
41335
42502
 
41336
- .o-dropdown-button {
42503
+ > span {
41337
42504
  height: 30px;
41338
42505
  }
41339
42506
 
41340
- .o-text-options > div {
41341
- line-height: 26px;
41342
- padding: 3px 12px;
41343
- &:hover {
41344
- background-color: rgba(0, 0, 0, 0.08);
41345
- }
41346
- }
41347
-
41348
42507
  .o-dropdown-content {
41349
42508
  position: absolute;
41350
42509
  top: 100%;
41351
42510
  left: 0;
41352
42511
  overflow-y: auto;
41353
42512
  overflow-x: hidden;
42513
+ padding: 2px;
41354
42514
  z-index: ${ComponentsImportance.Dropdown};
41355
42515
  box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
41356
42516
  background-color: white;
41357
42517
 
41358
42518
  .o-dropdown-line {
41359
42519
  display: flex;
41360
- margin: 1px;
41361
42520
 
41362
- .o-line-item {
42521
+ > span {
41363
42522
  padding: 4px;
41364
- width: 18px;
41365
- height: 18px;
41366
42523
  }
41367
42524
  }
41368
-
41369
- &.o-format-tool {
41370
- padding: 5px 0;
41371
- width: 250px;
41372
- font-size: 12px;
41373
- > div {
41374
- padding: 0 20px;
41375
- white-space: nowrap;
41376
-
41377
- &.o-dropdown-active:before {
41378
- content: "✓";
41379
- font-weight: bold;
41380
- position: absolute;
41381
- left: 5px;
41382
- }
41383
- }
41384
- }
41385
-
41386
- .o-dropdown-align-item {
41387
- padding: 7px 10px;
41388
- }
41389
42525
  }
41390
42526
  }
41391
42527
  }
@@ -41395,24 +42531,20 @@
41395
42531
  class TopBar extends owl.Component {
41396
42532
  constructor() {
41397
42533
  super(...arguments);
41398
- this.commonFormats = FORMATS;
41399
- this.customFormats = CUSTOM_FORMATS;
41400
- this.currentFormatName = "automatic";
41401
- this.style = {};
41402
42534
  this.state = owl.useState({
41403
42535
  menuState: { isOpen: false, position: null, menuItems: [] },
41404
42536
  activeTool: "",
42537
+ fillColor: "#ffffff",
42538
+ textColor: "#000000",
41405
42539
  });
41406
42540
  this.isSelectingMenu = false;
41407
42541
  this.openedEl = null;
41408
- this.inMerge = false;
41409
- this.cannotMerge = false;
41410
- this.undoTool = false;
41411
- this.redoTool = false;
41412
- this.paintFormatTool = false;
41413
- this.fillColor = "#ffffff";
41414
- this.textColor = "#000000";
41415
42542
  this.menus = [];
42543
+ this.EDIT = ACTION_EDIT;
42544
+ this.FORMAT = ACTION_FORMAT;
42545
+ this.VIEW = ACTION_VIEW;
42546
+ this.formatNumberMenuItemSpec = formatNumberMenuItemSpec;
42547
+ this.isntToolbarMenu = false;
41416
42548
  }
41417
42549
  get dropdownStyle() {
41418
42550
  return `max-height:${this.props.dropdownMaxHeight}px`;
@@ -41442,28 +42574,8 @@
41442
42574
  this.props.onClick();
41443
42575
  this.closeMenus();
41444
42576
  }
41445
- toggleStyle(style) {
41446
- setStyle(this.env, { [style]: !this.style[style] });
41447
- }
41448
- toggleFormat(formatName) {
41449
- const formatter = FORMATS.find((f) => f.name === formatName);
41450
- const value = (formatter && formatter.value) || "";
41451
- setFormatter(this.env, value);
41452
- }
41453
- toggleHorizontalAlign(align) {
41454
- setStyle(this.env, { align });
41455
- this.onClick();
41456
- }
41457
- toggleVerticalAlign(verticalAlign) {
41458
- setStyle(this.env, { verticalAlign });
41459
- this.onClick();
41460
- }
41461
- toggleTextWrapping(wrapping) {
41462
- setStyle(this.env, { wrapping });
41463
- this.onClick();
41464
- }
41465
42577
  onMenuMouseOver(menu, ev) {
41466
- if (this.isSelectingMenu) {
42578
+ if (this.isSelectingMenu && this.isntToolbarMenu) {
41467
42579
  this.openMenu(menu, ev);
41468
42580
  }
41469
42581
  }
@@ -41474,15 +42586,27 @@
41474
42586
  this.openedEl = isOpen ? null : ev.target;
41475
42587
  }
41476
42588
  toggleContextMenu(menu, ev) {
41477
- if (this.state.menuState.isOpen) {
42589
+ if (this.state.menuState.isOpen && this.isntToolbarMenu) {
42590
+ this.closeMenus();
42591
+ }
42592
+ else {
42593
+ this.openMenu(menu, ev);
42594
+ this.isntToolbarMenu = true;
42595
+ }
42596
+ }
42597
+ toggleToolbarContextMenu(menuSpec, ev) {
42598
+ if (this.state.menuState.isOpen && !this.isntToolbarMenu) {
41478
42599
  this.closeMenus();
41479
42600
  }
41480
42601
  else {
42602
+ const menu = createAction(menuSpec);
41481
42603
  this.openMenu(menu, ev);
42604
+ this.isntToolbarMenu = false;
41482
42605
  }
41483
42606
  }
41484
42607
  openMenu(menu, ev) {
41485
- const { left, top, height } = ev.target.getBoundingClientRect();
42608
+ const { left, top, height } = ev.currentTarget.getBoundingClientRect();
42609
+ this.state.activeTool = "";
41486
42610
  this.state.menuState.isOpen = true;
41487
42611
  this.state.menuState.position = { x: left, y: top + height };
41488
42612
  this.state.menuState.menuItems = menu.children(this.env);
@@ -41499,134 +42623,28 @@
41499
42623
  this.openedEl = null;
41500
42624
  }
41501
42625
  updateCellState() {
41502
- const zones = this.env.model.getters.getSelectedZones();
41503
- const { col, row, sheetId } = this.env.model.getters.getActivePosition();
41504
- this.inMerge = false;
41505
- const { top, left, right, bottom } = this.env.model.getters.getSelectedZone();
41506
- const { xSplit, ySplit } = this.env.model.getters.getPaneDivisions(sheetId);
41507
- this.cannotMerge =
41508
- zones.length > 1 ||
41509
- (top === bottom && left === right) ||
41510
- (left < xSplit && xSplit <= right) ||
41511
- (top < ySplit && ySplit <= bottom);
41512
- if (!this.cannotMerge) {
41513
- const zone = this.env.model.getters.expandZone(sheetId, positionToZone({ col, row }));
41514
- this.inMerge = isEqual(zones[0], zone);
41515
- }
41516
- this.undoTool = this.env.model.getters.canUndo();
41517
- this.redoTool = this.env.model.getters.canRedo();
41518
- this.paintFormatTool = this.env.model.getters.isPaintingFormat();
41519
- const cell = this.env.model.getters.getActiveCell();
41520
- if (cell.format) {
41521
- const currentFormat = this.commonFormats.find((f) => f.value === cell.format);
41522
- this.currentFormatName = currentFormat ? currentFormat.name : "";
41523
- }
41524
- else {
41525
- this.currentFormatName = "automatic";
41526
- }
41527
- this.style = { ...this.env.model.getters.getCurrentStyle() };
41528
- this.style.align = this.style.align || cell.defaultAlign;
41529
- this.fillColor = this.style.fillColor || "#ffffff";
41530
- this.textColor = this.style.textColor || "#000000";
42626
+ const style = this.env.model.getters.getCurrentStyle();
42627
+ this.state.fillColor = style.fillColor || "#ffffff";
42628
+ this.state.textColor = style.textColor || "#000000";
41531
42629
  this.menus = topbarMenuRegistry.getMenuItems();
41532
42630
  }
41533
42631
  getMenuName(menu) {
41534
42632
  return menu.name(this.env);
41535
42633
  }
41536
- toggleMerge() {
41537
- if (this.cannotMerge) {
41538
- return;
41539
- }
41540
- const zones = this.env.model.getters.getSelectedZones();
41541
- const target = [zones[zones.length - 1]];
41542
- const sheetId = this.env.model.getters.getActiveSheetId();
41543
- if (this.inMerge) {
41544
- this.env.model.dispatch("REMOVE_MERGE", { sheetId, target });
41545
- }
41546
- else {
41547
- interactiveAddMerge(this.env, sheetId, target);
41548
- }
41549
- }
41550
42634
  setColor(target, color) {
41551
42635
  setStyle(this.env, { [target]: color });
41552
42636
  this.onClick();
41553
42637
  }
41554
- setBorder(command) {
41555
- this.env.model.dispatch("SET_FORMATTING", {
41556
- sheetId: this.env.model.getters.getActiveSheetId(),
41557
- target: this.env.model.getters.getSelectedZones(),
41558
- border: command,
41559
- });
41560
- this.onClick();
41561
- }
41562
- setFormat(format, custom) {
41563
- if (!custom) {
41564
- this.toggleFormat(format);
41565
- }
41566
- else {
41567
- this.openCustomFormatSidePanel(format);
41568
- }
41569
- this.onClick();
41570
- }
41571
- openCustomFormatSidePanel(custom) {
41572
- const customFormatter = CUSTOM_FORMATS.find((c) => c.name === custom);
41573
- const sidePanel = (customFormatter && customFormatter.sidePanel) || "";
41574
- this.env.openSidePanel(sidePanel);
41575
- }
41576
- setDecimal(step) {
41577
- this.env.model.dispatch("SET_DECIMAL", {
41578
- sheetId: this.env.model.getters.getActiveSheetId(),
41579
- target: this.env.model.getters.getSelectedZones(),
41580
- step: step,
41581
- });
41582
- }
41583
- paintFormat() {
41584
- this.env.model.dispatch("ACTIVATE_PAINT_FORMAT", {
41585
- target: this.env.model.getters.getSelectedZones(),
41586
- });
41587
- }
41588
- clearFormatting() {
41589
- this.env.model.dispatch("CLEAR_FORMATTING", {
41590
- sheetId: this.env.model.getters.getActiveSheetId(),
41591
- target: this.env.model.getters.getSelectedZones(),
41592
- });
41593
- }
41594
- doAction(action) {
41595
- action(this.env);
41596
- this.closeMenus();
41597
- }
41598
- undo() {
41599
- this.env.model.dispatch("REQUEST_UNDO");
41600
- }
41601
- redo() {
41602
- this.env.model.dispatch("REQUEST_REDO");
41603
- }
41604
- get selectionContainsFilter() {
41605
- const sheetId = this.env.model.getters.getActiveSheetId();
41606
- const selectedZones = this.env.model.getters.getSelectedZones();
41607
- return this.env.model.getters.doesZonesContainFilter(sheetId, selectedZones);
41608
- }
41609
- get cannotCreateFilter() {
41610
- return !areZonesContinuous(...this.env.model.getters.getSelectedZones());
41611
- }
41612
- createFilter() {
41613
- if (this.cannotCreateFilter) {
41614
- return;
41615
- }
41616
- this.env.model.selection.selectTableAroundSelection();
41617
- const sheetId = this.env.model.getters.getActiveSheetId();
41618
- const selection = this.env.model.getters.getSelectedZones();
41619
- interactiveAddFilter(this.env, sheetId, selection);
41620
- }
41621
- removeFilter() {
41622
- this.env.model.dispatch("REMOVE_FILTER_TABLE", {
41623
- sheetId: this.env.model.getters.getActiveSheetId(),
41624
- target: this.env.model.getters.getSelectedZones(),
41625
- });
41626
- }
41627
42638
  }
41628
42639
  TopBar.template = "o-spreadsheet-TopBar";
41629
- TopBar.components = { ColorPickerWidget, Menu, TopBarComposer, FontSizeEditor };
42640
+ TopBar.components = {
42641
+ ColorPickerWidget,
42642
+ ColorPicker,
42643
+ Menu,
42644
+ TopBarComposer,
42645
+ FontSizeEditor,
42646
+ ActionButton,
42647
+ };
41630
42648
  TopBar.props = {
41631
42649
  onClick: Function,
41632
42650
  focusComposer: String,
@@ -41736,6 +42754,10 @@
41736
42754
  height: ${CF_ICON_EDGE_LENGTH}px;
41737
42755
  vertical-align: sub;
41738
42756
  }
42757
+
42758
+ .o-text-icon {
42759
+ vertical-align: middle;
42760
+ }
41739
42761
  `;
41740
42762
  // -----------------------------------------------------------------------------
41741
42763
  // GRID STYLE
@@ -42654,6 +43676,14 @@
42654
43676
  this.revertBefore(operationId);
42655
43677
  this.tree.drop(operationId);
42656
43678
  }
43679
+ getRevertedExecution() {
43680
+ const data = [];
43681
+ const operations = this.tree.revertedExecution(this.HEAD_BRANCH);
43682
+ for (const { operation } of operations) {
43683
+ data.push(operation.data);
43684
+ }
43685
+ return data;
43686
+ }
42657
43687
  /**
42658
43688
  * Revert the state as it was *before* the given operation was executed.
42659
43689
  */
@@ -42710,12 +43740,12 @@
42710
43740
  }
42711
43741
  });
42712
43742
  revision.setChanges(changes);
42713
- }, (revision) => revertChanges([revision]), (id) => new Revision(id, "empty", [], []), {
43743
+ }, (revision) => revertChanges([revision]), (id) => new Revision(id, "empty", []), {
42714
43744
  with: (revision) => (toTransform) => {
42715
- return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands));
43745
+ return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands), toTransform.rootCommand);
42716
43746
  },
42717
43747
  without: (revision) => (toTransform) => {
42718
- return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands.map(inverseCommand).flat()));
43748
+ return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands.map(inverseCommand).flat()), toTransform.rootCommand);
42719
43749
  },
42720
43750
  });
42721
43751
  }
@@ -42752,101 +43782,6 @@
42752
43782
  }
42753
43783
  }
42754
43784
 
42755
- /**
42756
- * Local History
42757
- *
42758
- * The local history is responsible of tracking the locally state updates
42759
- * It maintains the local undo and redo stack to allow to undo/redo only local
42760
- * changes
42761
- */
42762
- class LocalHistory extends owl.EventBus {
42763
- constructor(dispatch, session) {
42764
- super();
42765
- this.dispatch = dispatch;
42766
- this.session = session;
42767
- /**
42768
- * Ids of the revisions which can be undone
42769
- */
42770
- this.undoStack = [];
42771
- /**
42772
- * Ids of the revisions which can be redone
42773
- */
42774
- this.redoStack = [];
42775
- this.session.on("new-local-state-update", this, this.onNewLocalStateUpdate);
42776
- this.session.on("revision-undone", this, ({ commands }) => this.selectiveUndo(commands));
42777
- this.session.on("revision-redone", this, ({ commands }) => this.selectiveRedo(commands));
42778
- this.session.on("pending-revisions-dropped", this, ({ revisionIds }) => this.drop(revisionIds));
42779
- this.session.on("snapshot", this, () => {
42780
- this.undoStack = [];
42781
- this.redoStack = [];
42782
- });
42783
- }
42784
- allowDispatch(cmd) {
42785
- switch (cmd.type) {
42786
- case "REQUEST_UNDO":
42787
- if (!this.canUndo()) {
42788
- return 6 /* CommandResult.EmptyUndoStack */;
42789
- }
42790
- break;
42791
- case "REQUEST_REDO":
42792
- if (!this.canRedo()) {
42793
- return 7 /* CommandResult.EmptyRedoStack */;
42794
- }
42795
- break;
42796
- }
42797
- return 0 /* CommandResult.Success */;
42798
- }
42799
- beforeHandle(cmd) { }
42800
- handle(cmd) {
42801
- switch (cmd.type) {
42802
- case "REQUEST_UNDO":
42803
- case "REQUEST_REDO":
42804
- // History changes (undo & redo) are *not* applied optimistically on the local state.
42805
- // We wait a global confirmation from the server. The goal is to avoid handling concurrent
42806
- // history changes on multiple clients which are very hard to manage correctly.
42807
- this.requestHistoryChange(cmd.type === "REQUEST_UNDO" ? "UNDO" : "REDO");
42808
- }
42809
- }
42810
- finalize() { }
42811
- requestHistoryChange(type) {
42812
- const id = type === "UNDO" ? this.undoStack.pop() : this.redoStack.pop();
42813
- if (!id) {
42814
- return;
42815
- }
42816
- if (type === "UNDO") {
42817
- this.session.undo(id);
42818
- this.redoStack.push(id);
42819
- }
42820
- else {
42821
- this.session.redo(id);
42822
- this.undoStack.push(id);
42823
- }
42824
- }
42825
- canUndo() {
42826
- return this.undoStack.length > 0;
42827
- }
42828
- canRedo() {
42829
- return this.redoStack.length > 0;
42830
- }
42831
- drop(revisionIds) {
42832
- this.undoStack = this.undoStack.filter((id) => !revisionIds.includes(id));
42833
- this.redoStack = [];
42834
- }
42835
- onNewLocalStateUpdate({ id }) {
42836
- this.undoStack.push(id);
42837
- this.redoStack = [];
42838
- if (this.undoStack.length > MAX_HISTORY_STEPS) {
42839
- this.undoStack.shift();
42840
- }
42841
- }
42842
- selectiveUndo(commands) {
42843
- this.dispatch("UNDO", { commands });
42844
- }
42845
- selectiveRedo(commands) {
42846
- this.dispatch("REDO", { commands });
42847
- }
42848
- }
42849
-
42850
43785
  /**
42851
43786
  * Stateless sequence of events that can be processed by consumers.
42852
43787
  *
@@ -43247,8 +44182,8 @@
43247
44182
  }
43248
44183
  const { left, right, top, bottom } = zone;
43249
44184
  const sheetId = this.getters.getActiveSheetId();
43250
- const refCol = this.getters.findVisibleHeader(sheetId, "COL", range(left, right + 1));
43251
- const refRow = this.getters.findVisibleHeader(sheetId, "ROW", range(top, bottom + 1));
44185
+ const refCol = this.getters.findVisibleHeader(sheetId, "COL", left, right);
44186
+ const refRow = this.getters.findVisibleHeader(sheetId, "ROW", top, bottom);
43252
44187
  if (refRow === undefined || refCol === undefined) {
43253
44188
  return 17 /* CommandResult.SelectionOutOfBound */;
43254
44189
  }
@@ -43323,10 +44258,10 @@
43323
44258
  const { col: anchorCol, row: anchorRow } = anchor.cell;
43324
44259
  return {
43325
44260
  col: this.getters.isColHidden(sheetId, anchorCol)
43326
- ? this.getters.findVisibleHeader(sheetId, "COL", range(left, right + 1)) || anchorCol
44261
+ ? this.getters.findVisibleHeader(sheetId, "COL", left, right) || anchorCol
43327
44262
  : anchorCol,
43328
44263
  row: this.getters.isRowHidden(sheetId, anchorRow)
43329
- ? this.getters.findVisibleHeader(sheetId, "ROW", range(top, bottom + 1)) || anchorRow
44264
+ ? this.getters.findVisibleHeader(sheetId, "ROW", top, bottom) || anchorRow
43330
44265
  : anchorRow,
43331
44266
  };
43332
44267
  }
@@ -45076,6 +46011,8 @@
45076
46011
  * Internal status of the model. Important for command handling coordination
45077
46012
  */
45078
46013
  this.status = 0 /* Status.Ready */;
46014
+ this.handlers = [];
46015
+ this.coreHandlers = [];
45079
46016
  /**
45080
46017
  * Check if a command can be dispatched, and returns a DispatchResult object with the possible
45081
46018
  * reasons the dispatch failed.
@@ -45120,7 +46057,7 @@
45120
46057
  this.dispatchToHandlers(this.handlers, command);
45121
46058
  this.finalize();
45122
46059
  });
45123
- this.session.save(commands, changes);
46060
+ this.session.save(command, commands, changes);
45124
46061
  this.status = 0 /* Status.Ready */;
45125
46062
  this.trigger("update");
45126
46063
  break;
@@ -45152,9 +46089,7 @@
45152
46089
  const command = { ...payload, type };
45153
46090
  const previousStatus = this.status;
45154
46091
  this.status = 2 /* Status.RunningCore */;
45155
- const handlers = this.isReplayingCommand
45156
- ? [this.range, ...this.corePlugins, ...this.coreViewsPlugins]
45157
- : this.handlers;
46092
+ const handlers = this.isReplayingCommand ? this.coreHandlers : this.handlers;
45158
46093
  this.dispatchToHandlers(handlers, command);
45159
46094
  this.status = previousStatus;
45160
46095
  return DispatchResult.Success;
@@ -45165,7 +46100,6 @@
45165
46100
  this.uuidGenerator = uuidGenerator;
45166
46101
  this.config = this.setupConfig(config);
45167
46102
  this.session = this.setupSession(workbookData.revisionId);
45168
- this.history = new LocalHistory(this.dispatchFromCorePlugin, this.session);
45169
46103
  this.coreGetters = {};
45170
46104
  this.range = new RangeAdapter(this.coreGetters);
45171
46105
  this.coreGetters.getRangeString = this.range.getRangeString.bind(this.range);
@@ -45178,8 +46112,6 @@
45178
46112
  this.getters = {
45179
46113
  isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
45180
46114
  isDashboard: () => this.config.mode === "dashboard",
45181
- canUndo: this.history.canUndo.bind(this.history),
45182
- canRedo: this.history.canRedo.bind(this.history),
45183
46115
  getClient: this.session.getClient.bind(this.session),
45184
46116
  getConnectedClients: this.session.getConnectedClients.bind(this.session),
45185
46117
  isFullySynchronized: this.session.isFullySynchronized.bind(this.session),
@@ -45187,6 +46119,8 @@
45187
46119
  this.uuidGenerator.setIsFastStrategy(true);
45188
46120
  // Initiate stream processor
45189
46121
  this.selection = new SelectionStreamProcessorImpl(this.getters);
46122
+ this.coreHandlers.push(this.range);
46123
+ this.handlers.push(this.range);
45190
46124
  this.corePluginConfig = this.setupCorePluginConfig();
45191
46125
  this.uiPluginConfig = this.setupUiPluginConfig();
45192
46126
  // registering plugins
@@ -45195,13 +46129,20 @@
45195
46129
  }
45196
46130
  Object.assign(this.getters, this.coreGetters);
45197
46131
  for (let Plugin of statefulUIPluginRegistry.getAll()) {
45198
- this.statefulUIPlugins.push(this.setupUiPlugin(Plugin));
46132
+ const plugin = this.setupUiPlugin(Plugin);
46133
+ this.statefulUIPlugins.push(plugin);
46134
+ this.handlers.push(plugin);
45199
46135
  }
45200
46136
  for (let Plugin of coreViewsPluginRegistry.getAll()) {
45201
- this.coreViewsPlugins.push(this.setupUiPlugin(Plugin));
46137
+ const plugin = this.setupUiPlugin(Plugin);
46138
+ this.coreViewsPlugins.push(plugin);
46139
+ this.handlers.push(plugin);
46140
+ this.coreHandlers.push(plugin);
45202
46141
  }
45203
46142
  for (let Plugin of featurePluginRegistry.getAll()) {
45204
- this.featurePlugins.push(this.setupUiPlugin(Plugin));
46143
+ const plugin = this.setupUiPlugin(Plugin);
46144
+ this.featurePlugins.push(plugin);
46145
+ this.handlers.push(plugin);
45205
46146
  }
45206
46147
  this.uuidGenerator.setIsFastStrategy(false);
45207
46148
  // starting plugins
@@ -45225,15 +46166,6 @@
45225
46166
  // by owl, since we do not rely on reactivity
45226
46167
  owl.markRaw(this);
45227
46168
  }
45228
- get handlers() {
45229
- return [...this.coreHandlers, ...this.allUIPlugins, this.history];
45230
- }
45231
- get coreHandlers() {
45232
- return [this.range, ...this.corePlugins];
45233
- }
45234
- get allUIPlugins() {
45235
- return [...this.statefulUIPlugins, ...this.coreViewsPlugins, ...this.featurePlugins];
45236
- }
45237
46169
  joinSession() {
45238
46170
  this.session.join(this.config.client);
45239
46171
  }
@@ -45275,6 +46207,8 @@
45275
46207
  }
45276
46208
  plugin.import(data);
45277
46209
  this.corePlugins.push(plugin);
46210
+ this.coreHandlers.push(plugin);
46211
+ this.handlers.push(plugin);
45278
46212
  }
45279
46213
  onRemoteRevisionReceived({ commands }) {
45280
46214
  for (let command of commands) {
@@ -45292,15 +46226,21 @@
45292
46226
  return;
45293
46227
  }
45294
46228
  this.isReplayingCommand = true;
45295
- this.dispatchToHandlers([this.range, ...this.corePlugins, ...this.coreViewsPlugins], command);
46229
+ this.dispatchToHandlers(this.coreHandlers, command);
45296
46230
  this.isReplayingCommand = false;
45297
46231
  }), this.config.transportService, revisionId);
45298
46232
  return session;
45299
46233
  }
45300
46234
  setupSessionEvents() {
45301
46235
  this.session.on("remote-revision-received", this, this.onRemoteRevisionReceived);
45302
- this.session.on("revision-redone", this, this.finalize);
45303
- this.session.on("revision-undone", this, this.finalize);
46236
+ this.session.on("revision-undone", this, ({ commands }) => {
46237
+ this.dispatchFromCorePlugin("UNDO", { commands });
46238
+ this.finalize();
46239
+ });
46240
+ this.session.on("revision-redone", this, ({ commands }) => {
46241
+ this.dispatchFromCorePlugin("REDO", { commands });
46242
+ this.finalize();
46243
+ });
45304
46244
  // How could we improve communication between the session and UI?
45305
46245
  // It feels weird to have the model piping specific session events to its own bus.
45306
46246
  this.session.on("unexpected-revision-id", this, () => this.trigger("unexpected-revision-id"));
@@ -45348,6 +46288,7 @@
45348
46288
  custom: this.config.custom,
45349
46289
  uiActions: this.config,
45350
46290
  lazyEvaluation: this.config.lazyEvaluation,
46291
+ session: this.session,
45351
46292
  };
45352
46293
  }
45353
46294
  // ---------------------------------------------------------------------------
@@ -45363,7 +46304,8 @@
45363
46304
  return this.checkDispatchAllowedLocalCommand(command);
45364
46305
  }
45365
46306
  checkDispatchAllowedCoreCommand(command) {
45366
- const results = this.coreHandlers.map((handler) => handler.allowDispatch(command));
46307
+ const results = this.corePlugins.map((handler) => handler.allowDispatch(command));
46308
+ results.push(this.range.allowDispatch(command));
45367
46309
  return new DispatchResult(results.flat());
45368
46310
  }
45369
46311
  checkDispatchAllowedLocalCommand(command) {
@@ -45427,7 +46369,7 @@
45427
46369
  }
45428
46370
  }
45429
46371
  data.revisionId = this.session.getRevisionId() || DEFAULT_REVISION_ID;
45430
- data = JSON.parse(JSON.stringify(data));
46372
+ data = deepCopy(data);
45431
46373
  return data;
45432
46374
  }
45433
46375
  updateMode(mode) {
@@ -45455,7 +46397,7 @@
45455
46397
  handler.exportForExcel(data);
45456
46398
  }
45457
46399
  }
45458
- data = JSON.parse(JSON.stringify(data));
46400
+ data = deepCopy(data);
45459
46401
  return getXLSX(data);
45460
46402
  }
45461
46403
  garbageCollectExternalResources() {
@@ -45507,6 +46449,9 @@
45507
46449
  inverseCommandRegistry,
45508
46450
  urlRegistry,
45509
46451
  cellPopoverRegistry,
46452
+ numberFormatMenuRegistry,
46453
+ repeatLocalCommandTransformRegistry,
46454
+ repeatCommandTransformRegistry,
45510
46455
  };
45511
46456
  const helpers = {
45512
46457
  arg,
@@ -45535,6 +46480,7 @@
45535
46480
  positionToZone,
45536
46481
  isDefined: isDefined$1,
45537
46482
  lazy,
46483
+ genericRepeat,
45538
46484
  };
45539
46485
  const links = {
45540
46486
  isMarkdownLink,
@@ -45591,15 +46537,16 @@
45591
46537
  exports.parse = parse;
45592
46538
  exports.readonlyAllowedCommands = readonlyAllowedCommands;
45593
46539
  exports.registries = registries;
46540
+ exports.setDefaultSheetViewSize = setDefaultSheetViewSize;
45594
46541
  exports.setTranslationMethod = setTranslationMethod;
45595
46542
  exports.tokenize = tokenize;
45596
46543
 
45597
46544
  Object.defineProperty(exports, '__esModule', { value: true });
45598
46545
 
45599
46546
 
45600
- __info__.version = '16.3.0-alpha.3';
45601
- __info__.date = '2023-04-13T08:30:41.165Z';
45602
- __info__.hash = '573e679';
46547
+ __info__.version = '16.3.0-alpha.5';
46548
+ __info__.date = '2023-04-21T07:28:52.982Z';
46549
+ __info__.hash = '6304f41';
45603
46550
 
45604
46551
 
45605
46552
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);