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