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