@odoo/o-spreadsheet 17.2.6 → 17.2.8

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.
@@ -3,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.6
7
- * @date 2024-05-07T10:41:20.332Z
8
- * @hash a4f800c
6
+ * @version 17.2.8
7
+ * @date 2024-05-24T11:29:49.320Z
8
+ * @hash bfbcaa0
9
9
  */
10
10
 
11
11
  (function (exports, owl) {
@@ -503,6 +503,26 @@
503
503
  };
504
504
  return debounced;
505
505
  }
506
+ /**
507
+ * Creates a batched version of a callback so that all calls to it in the same
508
+ * microtick will only call the original callback once.
509
+ *
510
+ * @param callback the callback to batch
511
+ * @returns a batched version of the original callback
512
+ *
513
+ * Copied from odoo/owl repo.
514
+ */
515
+ function batched(callback) {
516
+ let scheduled = false;
517
+ return async (...args) => {
518
+ if (!scheduled) {
519
+ scheduled = true;
520
+ await Promise.resolve();
521
+ scheduled = false;
522
+ callback(...args);
523
+ }
524
+ };
525
+ }
506
526
  /*
507
527
  * Concatenate an array of strings.
508
528
  */
@@ -577,8 +597,9 @@
577
597
  return false;
578
598
  }
579
599
  else {
580
- if (ignoreFunctions && typeOfO1Key === "function")
581
- return true;
600
+ if (ignoreFunctions && typeOfO1Key === "function") {
601
+ continue;
602
+ }
582
603
  if (o1[key] !== o2[key])
583
604
  return false;
584
605
  }
@@ -1829,7 +1850,7 @@
1829
1850
  }
1830
1851
  valueOf() {
1831
1852
  const str = super.valueOf();
1832
- return _loaded() ? sprintf(_translate(str), ...this.values) : str;
1853
+ return _loaded() ? sprintf(_translate(str), ...this.values) : sprintf(str, ...this.values);
1833
1854
  }
1834
1855
  toString() {
1835
1856
  return this.valueOf();
@@ -5202,7 +5223,7 @@
5202
5223
  }
5203
5224
  return null;
5204
5225
  }
5205
- const separatorRegexp = /^[\w\.!\$]+/;
5226
+ const SYMBOL_CHARS = new Set("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_.!$");
5206
5227
  /**
5207
5228
  * A "Symbol" is just basically any word-like element that can appear in a
5208
5229
  * formula, which is not a string. So:
@@ -5242,11 +5263,8 @@
5242
5263
  };
5243
5264
  }
5244
5265
  }
5245
- const match = chars.remaining().match(separatorRegexp);
5246
- if (match) {
5247
- const value = match[0];
5248
- result += value;
5249
- chars.advanceBy(value.length);
5266
+ while (chars.current && SYMBOL_CHARS.has(chars.current)) {
5267
+ result += chars.shift();
5250
5268
  }
5251
5269
  if (result.length) {
5252
5270
  const value = result;
@@ -6798,7 +6816,7 @@
6798
6816
  function matchReference(tokens) {
6799
6817
  let head = 0;
6800
6818
  let transitions = machine[State.LeftRef];
6801
- const matchedTokens = [];
6819
+ let matchedTokens = "";
6802
6820
  while (transitions !== undefined) {
6803
6821
  const token = tokens[head++];
6804
6822
  if (!token) {
@@ -6810,15 +6828,15 @@
6810
6828
  case undefined:
6811
6829
  return null;
6812
6830
  case State.Found:
6813
- matchedTokens.push(token);
6831
+ matchedTokens += token.value;
6814
6832
  tokens.splice(0, head);
6815
6833
  return {
6816
6834
  type: "REFERENCE",
6817
- value: concat(matchedTokens.map((token) => token.value)),
6835
+ value: matchedTokens,
6818
6836
  };
6819
6837
  default:
6820
6838
  transitions = machine[nextState];
6821
- matchedTokens.push(token);
6839
+ matchedTokens += token.value;
6822
6840
  break;
6823
6841
  }
6824
6842
  }
@@ -8016,10 +8034,66 @@
8016
8034
  });
8017
8035
  }
8018
8036
 
8037
+ /**
8038
+ * This is a generic event bus based on the Owl event bus.
8039
+ * This bus however ensures type safety across events and subscription callbacks.
8040
+ */
8041
+ class EventBus {
8042
+ subscriptions = {};
8043
+ /**
8044
+ * Add a listener for the 'eventType' events.
8045
+ *
8046
+ * Note that the 'owner' of this event can be anything, but will more likely
8047
+ * be a component or a class. The idea is that the callback will be called with
8048
+ * the proper owner bound.
8049
+ *
8050
+ * Also, the owner should be kind of unique. This will be used to remove the
8051
+ * listener.
8052
+ */
8053
+ on(type, owner, callback) {
8054
+ if (!callback) {
8055
+ throw new Error("Missing callback");
8056
+ }
8057
+ if (!this.subscriptions[type]) {
8058
+ this.subscriptions[type] = [];
8059
+ }
8060
+ this.subscriptions[type].push({
8061
+ owner,
8062
+ callback,
8063
+ });
8064
+ }
8065
+ /**
8066
+ * Emit an event of type 'eventType'. Any extra arguments will be passed to
8067
+ * the listeners callback.
8068
+ */
8069
+ trigger(type, payload) {
8070
+ const subs = this.subscriptions[type] || [];
8071
+ for (let i = 0, iLen = subs.length; i < iLen; i++) {
8072
+ const sub = subs[i];
8073
+ sub.callback.call(sub.owner, payload);
8074
+ }
8075
+ }
8076
+ /**
8077
+ * Remove a listener
8078
+ */
8079
+ off(eventType, owner) {
8080
+ const subs = this.subscriptions[eventType];
8081
+ if (subs) {
8082
+ this.subscriptions[eventType] = subs.filter((s) => s.owner !== owner);
8083
+ }
8084
+ }
8085
+ /**
8086
+ * Remove all subscriptions.
8087
+ */
8088
+ clear() {
8089
+ this.subscriptions = {};
8090
+ }
8091
+ }
8092
+
8019
8093
  /**
8020
8094
  * A type-safe dependency container
8021
8095
  */
8022
- class DependencyContainer {
8096
+ class DependencyContainer extends EventBus {
8023
8097
  dependencies = new Map();
8024
8098
  factory = new StoreFactory(this.get.bind(this));
8025
8099
  /**
@@ -8096,15 +8170,12 @@ stores.inject(MyMetaStore, storeInstance);
8096
8170
  }
8097
8171
  return MetaStore;
8098
8172
  }
8099
- class ReactiveStore {
8173
+ class DisposableStore {
8100
8174
  get;
8175
+ disposeCallbacks = [];
8101
8176
  constructor(get) {
8102
8177
  this.get = get;
8103
- return owl.reactive(this);
8104
8178
  }
8105
- }
8106
- class DisposableStore extends ReactiveStore {
8107
- disposeCallbacks = [];
8108
8179
  onDispose(callback) {
8109
8180
  this.disposeCallbacks.push(callback);
8110
8181
  }
@@ -8124,7 +8195,10 @@ stores.inject(MyMetaStore, storeInstance);
8124
8195
  const container = new DependencyContainer();
8125
8196
  owl.useSubEnv({
8126
8197
  __spreadsheet_stores__: container,
8127
- getStore: container.get.bind(container),
8198
+ getStore: (Store) => {
8199
+ const store = container.get(Store);
8200
+ return proxifyStoreMutation(store, () => container.trigger("store-updated"));
8201
+ },
8128
8202
  });
8129
8203
  return container;
8130
8204
  }
@@ -8134,14 +8208,57 @@ stores.inject(MyMetaStore, storeInstance);
8134
8208
  function useStore(Store) {
8135
8209
  const env = owl.useEnv();
8136
8210
  const container = getDependencyContainer(env);
8137
- return owl.useState(container.get(Store));
8211
+ const store = container.get(Store);
8212
+ return useStoreRenderProxy(container, store);
8138
8213
  }
8139
8214
  function useLocalStore(Store, ...args) {
8140
8215
  const env = owl.useEnv();
8141
8216
  const container = getDependencyContainer(env);
8142
- const store = owl.useState(container.instantiate(Store, ...args));
8217
+ const store = container.instantiate(Store, ...args);
8143
8218
  owl.onWillUnmount(() => store.dispose());
8144
- return store;
8219
+ return useStoreRenderProxy(container, store);
8220
+ }
8221
+ /**
8222
+ * Trigger an event to re-render the app (deep render) when
8223
+ * a store is mutated by invoking one of its mutator methods.
8224
+ */
8225
+ function useStoreRenderProxy(container, store) {
8226
+ const component = owl.useComponent();
8227
+ const proxy = proxifyStoreMutation(store, () => {
8228
+ if (owl.status(component) === "mounted") {
8229
+ container.trigger("store-updated");
8230
+ }
8231
+ });
8232
+ return proxy;
8233
+ }
8234
+ /**
8235
+ * Creates a proxied version of a store object with mutation tracking.
8236
+ * Whenever a mutator method of the store is called, the provided callback function is invoked.
8237
+ */
8238
+ function proxifyStoreMutation(store, callback) {
8239
+ const proxy = new Proxy(store, {
8240
+ get(target, property, receiver) {
8241
+ const thisStore = target;
8242
+ // The third argument is `thisStore` (target) instead of `receiver`.
8243
+ // The goal is to always have the same `this` value in getter functions
8244
+ // (when `target[property]` is an accessor property).
8245
+ // `thisStore` is always the same object reference. `receiver` however is the
8246
+ // object on which the property is called, which is the Proxy object which is different for each component.
8247
+ const value = Reflect.get(target, property, thisStore);
8248
+ if (store.mutators.includes(property)) {
8249
+ const functionProxy = new Proxy(value, {
8250
+ // trap the function call
8251
+ apply(target, thisArg, argArray) {
8252
+ Reflect.apply(target, thisStore, argArray);
8253
+ callback();
8254
+ },
8255
+ });
8256
+ return functionProxy;
8257
+ }
8258
+ return value;
8259
+ },
8260
+ });
8261
+ return proxy;
8145
8262
  }
8146
8263
  function getDependencyContainer(env) {
8147
8264
  const container = env.__spreadsheet_stores__;
@@ -8153,7 +8270,8 @@ stores.inject(MyMetaStore, storeInstance);
8153
8270
 
8154
8271
  const ModelStore = createAbstractStore("Model");
8155
8272
 
8156
- class RendererStore extends ReactiveStore {
8273
+ class RendererStore {
8274
+ mutators = ["register", "unRegister"];
8157
8275
  renderers = {};
8158
8276
  register(renderer) {
8159
8277
  if (!renderer.renderingLayers.length) {
@@ -8187,7 +8305,7 @@ stores.inject(MyMetaStore, storeInstance);
8187
8305
  class SpreadsheetStore extends DisposableStore {
8188
8306
  // cast the model store as Model to allow model.dispatch to return the DispatchResult
8189
8307
  model = this.get(ModelStore);
8190
- getters = owl.markRaw(this.model.getters);
8308
+ getters = this.model.getters;
8191
8309
  renderer = this.get(RendererStore);
8192
8310
  constructor(get) {
8193
8311
  super(get);
@@ -8234,6 +8352,7 @@ stores.inject(MyMetaStore, storeInstance);
8234
8352
  }
8235
8353
 
8236
8354
  class HighlightStore extends SpreadsheetStore {
8355
+ mutators = ["register", "unRegister"];
8237
8356
  providers = [];
8238
8357
  constructor(get) {
8239
8358
  super(get);
@@ -8264,7 +8383,7 @@ stores.inject(MyMetaStore, storeInstance);
8264
8383
  this.providers.push(highlightProvider);
8265
8384
  }
8266
8385
  unRegister(highlightProvider) {
8267
- this.providers = this.providers.filter((h) => owl.toRaw(h) !== owl.toRaw(highlightProvider));
8386
+ this.providers = this.providers.filter((h) => h !== highlightProvider);
8268
8387
  }
8269
8388
  drawLayer(ctx, layer) {
8270
8389
  if (layer === "Highlights") {
@@ -8280,6 +8399,16 @@ stores.inject(MyMetaStore, storeInstance);
8280
8399
 
8281
8400
  const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
8282
8401
  class ComposerStore extends SpreadsheetStore {
8402
+ mutators = [
8403
+ "startEdition",
8404
+ "setCurrentContent",
8405
+ "stopEdition",
8406
+ "stopComposerRangeSelection",
8407
+ "cancelEdition",
8408
+ "cycleReferences",
8409
+ "changeComposerCursorSelection",
8410
+ "replaceComposerCursorSelection",
8411
+ ];
8283
8412
  col = 0;
8284
8413
  row = 0;
8285
8414
  editionMode = "inactive";
@@ -8294,9 +8423,9 @@ stores.inject(MyMetaStore, storeInstance);
8294
8423
  highlightStore = this.get(HighlightStore);
8295
8424
  constructor(get) {
8296
8425
  super(get);
8297
- this.highlightStore.register(owl.toRaw(this));
8426
+ this.highlightStore.register(this);
8298
8427
  this.onDispose(() => {
8299
- this.highlightStore.unRegister(owl.toRaw(this));
8428
+ this.highlightStore.unRegister(this);
8300
8429
  });
8301
8430
  }
8302
8431
  canStopEdition() {
@@ -8423,7 +8552,7 @@ stores.inject(MyMetaStore, storeInstance);
8423
8552
  if (this.isSelectingRange) {
8424
8553
  this.editionMode = "editing";
8425
8554
  }
8426
- this.model.selection.resetAnchor(owl.toRaw(this), {
8555
+ this.model.selection.resetAnchor(this, {
8427
8556
  cell: { col: left, row: top },
8428
8557
  zone: cmd.zone,
8429
8558
  });
@@ -8441,7 +8570,7 @@ stores.inject(MyMetaStore, storeInstance);
8441
8570
  row: activePosition.row,
8442
8571
  });
8443
8572
  const zone = this.getters.expandZone(cmd.sheetIdTo, positionToZone({ col, row }));
8444
- this.model.selection.resetAnchor(owl.toRaw(this), { cell: { col, row }, zone });
8573
+ this.model.selection.resetAnchor(this, { cell: { col, row }, zone });
8445
8574
  }
8446
8575
  break;
8447
8576
  case "DELETE_SHEET":
@@ -8540,7 +8669,7 @@ stores.inject(MyMetaStore, storeInstance);
8540
8669
  startComposerRangeSelection() {
8541
8670
  if (this.sheetId === this.getters.getActiveSheetId()) {
8542
8671
  const zone = positionToZone({ col: this.col, row: this.row });
8543
- this.model.selection.resetAnchor(owl.toRaw(this), {
8672
+ this.model.selection.resetAnchor(this, {
8544
8673
  cell: { col: this.col, row: this.row },
8545
8674
  zone,
8546
8675
  });
@@ -8569,7 +8698,7 @@ stores.inject(MyMetaStore, storeInstance);
8569
8698
  this.setContent(str || this.initialContent, selection);
8570
8699
  this.colorIndexByRange = {};
8571
8700
  const zone = positionToZone({ col: this.col, row: this.row });
8572
- this.model.selection.capture(owl.toRaw(this), { cell: { col: this.col, row: this.row }, zone }, {
8701
+ this.model.selection.capture(this, { cell: { col: this.col, row: this.row }, zone }, {
8573
8702
  handleEvent: this.handleEvent.bind(this),
8574
8703
  release: () => {
8575
8704
  this._stopEdition();
@@ -8677,7 +8806,7 @@ stores.inject(MyMetaStore, storeInstance);
8677
8806
  return;
8678
8807
  }
8679
8808
  this.editionMode = "inactive";
8680
- this.model.selection.release(owl.toRaw(this));
8809
+ this.model.selection.release(this);
8681
8810
  }
8682
8811
  /**
8683
8812
  * Reset the current content to the active cell content
@@ -8999,6 +9128,7 @@ stores.inject(MyMetaStore, storeInstance);
8999
9128
  }
9000
9129
 
9001
9130
  class ComposerFocusStore extends SpreadsheetStore {
9131
+ mutators = ["focusTopBarComposer", "focusGridComposerContent", "focusGridComposerCell"];
9002
9132
  composerStore = this.get(ComposerStore);
9003
9133
  topBarFocus = "inactive";
9004
9134
  gridFocusMode = "inactive";
@@ -21455,6 +21585,7 @@ stores.inject(MyMetaStore, storeInstance);
21455
21585
  }
21456
21586
 
21457
21587
  class HoveredCellStore extends SpreadsheetStore {
21588
+ mutators = ["clear", "hover"];
21458
21589
  col;
21459
21590
  row;
21460
21591
  handle(cmd) {
@@ -21474,6 +21605,7 @@ stores.inject(MyMetaStore, storeInstance);
21474
21605
  }
21475
21606
 
21476
21607
  class CellPopoverStore extends SpreadsheetStore {
21608
+ mutators = ["open", "close"];
21477
21609
  persistentPopover;
21478
21610
  hoveredCell = this.get(HoveredCellStore);
21479
21611
  handle(cmd) {
@@ -25965,12 +26097,13 @@ stores.inject(MyMetaStore, storeInstance);
25965
26097
 
25966
26098
  // The name is misleading and can be confused with the DOM focus.
25967
26099
  class FocusStore {
26100
+ mutators = ["focus", "unfocus"];
25968
26101
  focusedElement = null;
25969
26102
  focus(element) {
25970
26103
  this.focusedElement = element;
25971
26104
  }
25972
26105
  unfocus(element) {
25973
- if (this.focusedElement && owl.toRaw(this.focusedElement) === owl.toRaw(element)) {
26106
+ if (this.focusedElement && this.focusedElement === element) {
25974
26107
  this.focusedElement = null;
25975
26108
  }
25976
26109
  }
@@ -25986,6 +26119,16 @@ stores.inject(MyMetaStore, storeInstance);
25986
26119
  class SelectionInputStore extends SpreadsheetStore {
25987
26120
  initialRanges;
25988
26121
  inputHasSingleRange;
26122
+ mutators = [
26123
+ "resetWithRanges",
26124
+ "focusById",
26125
+ "unfocus",
26126
+ "addEmptyRange",
26127
+ "removeRange",
26128
+ "changeRange",
26129
+ "reset",
26130
+ "confirm",
26131
+ ];
25989
26132
  ranges = [];
25990
26133
  focusedRangeIndex = null;
25991
26134
  inputSheetId;
@@ -26045,7 +26188,7 @@ stores.inject(MyMetaStore, storeInstance);
26045
26188
  row: 0,
26046
26189
  });
26047
26190
  const zone = this.getters.expandZone(cmd.sheetIdTo, positionToZone({ col, row }));
26048
- this.model.selection.resetAnchor(owl.toRaw(this), { cell: { col, row }, zone });
26191
+ this.model.selection.resetAnchor(this, { cell: { col, row }, zone });
26049
26192
  }
26050
26193
  break;
26051
26194
  }
@@ -26064,7 +26207,7 @@ stores.inject(MyMetaStore, storeInstance);
26064
26207
  if (focusIndex !== -1) {
26065
26208
  this.focus(focusIndex);
26066
26209
  const { left, top } = newZone;
26067
- this.model.selection.resetAnchor(owl.toRaw(this), {
26210
+ this.model.selection.resetAnchor(this, {
26068
26211
  cell: { col: left, row: top },
26069
26212
  zone: newZone,
26070
26213
  });
@@ -26155,7 +26298,7 @@ stores.inject(MyMetaStore, storeInstance);
26155
26298
  }
26156
26299
  get hasMainFocus() {
26157
26300
  const focusedElement = this.focusStore.focusedElement;
26158
- return !!focusedElement && owl.toRaw(focusedElement) === owl.toRaw(this);
26301
+ return !!focusedElement && focusedElement === this;
26159
26302
  }
26160
26303
  get highlights() {
26161
26304
  if (!this.hasMainFocus) {
@@ -26184,7 +26327,7 @@ stores.inject(MyMetaStore, storeInstance);
26184
26327
  unfocus() {
26185
26328
  this.focusedRangeIndex = null;
26186
26329
  this.focusStore.unfocus(this);
26187
- this.model.selection.release(owl.toRaw(this));
26330
+ this.model.selection.release(this);
26188
26331
  }
26189
26332
  captureSelection() {
26190
26333
  if (this.focusedRangeIndex === null) {
@@ -26193,7 +26336,7 @@ stores.inject(MyMetaStore, storeInstance);
26193
26336
  const range = this.ranges[this.focusedRangeIndex];
26194
26337
  const sheetId = this.getters.getActiveSheetId();
26195
26338
  const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
26196
- this.model.selection.capture(owl.toRaw(this), { cell: { col: zone.left, row: zone.top }, zone }, {
26339
+ this.model.selection.capture(this, { cell: { col: zone.left, row: zone.top }, zone }, {
26197
26340
  handleEvent: this.handleEvent.bind(this),
26198
26341
  release: this.unfocus.bind(this),
26199
26342
  });
@@ -27661,6 +27804,7 @@ stores.inject(MyMetaStore, storeInstance);
27661
27804
  });
27662
27805
 
27663
27806
  class MainChartPanelStore extends SpreadsheetStore {
27807
+ mutators = ["activatePanel"];
27664
27808
  panel = "configuration";
27665
27809
  activatePanel(panel) {
27666
27810
  this.panel = panel;
@@ -28199,14 +28343,14 @@ stores.inject(MyMetaStore, storeInstance);
28199
28343
 
28200
28344
  function useHighlightsOnHover(ref, highlightProvider) {
28201
28345
  const hoverState = useHoveredElement(ref);
28202
- const env = owl.useEnv();
28346
+ const stores = useStoreProvider();
28203
28347
  useHighlights({
28204
28348
  get highlights() {
28205
28349
  return hoverState.hovered ? highlightProvider.highlights : [];
28206
28350
  },
28207
28351
  });
28208
28352
  owl.useEffect(() => {
28209
- env.model.dispatch("RENDER_CANVAS");
28353
+ stores.trigger("store-updated");
28210
28354
  }, () => [hoverState.hovered]);
28211
28355
  }
28212
28356
  function useHighlights(highlightProvider) {
@@ -29662,6 +29806,14 @@ stores.inject(MyMetaStore, storeInstance);
29662
29806
  Direction[Direction["next"] = 1] = "next";
29663
29807
  })(Direction || (Direction = {}));
29664
29808
  class FindAndReplaceStore extends SpreadsheetStore {
29809
+ mutators = [
29810
+ "updateSearchOptions",
29811
+ "updateSearchContent",
29812
+ "searchFormulas",
29813
+ "selectPreviousMatch",
29814
+ "selectNextMatch",
29815
+ "replace",
29816
+ ];
29665
29817
  allSheetsMatches = [];
29666
29818
  activeSheetMatches = [];
29667
29819
  specificRangeMatches = [];
@@ -29686,11 +29838,11 @@ stores.inject(MyMetaStore, storeInstance);
29686
29838
  this.initialShowFormulaState = this.model.getters.shouldShowFormulas();
29687
29839
  this.searchOptions.searchFormulas = this.initialShowFormulaState;
29688
29840
  const highlightStore = get(HighlightStore);
29689
- highlightStore.register(owl.toRaw(this));
29841
+ highlightStore.register(this);
29690
29842
  this.onDispose(() => {
29691
29843
  this.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.initialShowFormulaState });
29692
29844
  this.updateSearchContent.stopDebounce();
29693
- highlightStore.unRegister(owl.toRaw(this));
29845
+ highlightStore.unRegister(this);
29694
29846
  });
29695
29847
  }
29696
29848
  get searchMatches() {
@@ -31333,6 +31485,7 @@ stores.inject(MyMetaStore, storeInstance);
31333
31485
  });
31334
31486
 
31335
31487
  class DOMFocusableElementStore {
31488
+ mutators = ["setFocusableElement", "focus"];
31336
31489
  focusableElement = undefined;
31337
31490
  setFocusableElement(element) {
31338
31491
  this.focusableElement = element;
@@ -32069,7 +32222,7 @@ stores.inject(MyMetaStore, storeInstance);
32069
32222
  "Ctrl+Enter": this.processNewLineEvent,
32070
32223
  Escape: this.processEscapeKey,
32071
32224
  F2: () => console.warn("Not implemented"),
32072
- F4: this.processF4Key,
32225
+ F4: (ev) => this.processF4Key(ev),
32073
32226
  Tab: (ev) => this.processTabKey(ev, "right"),
32074
32227
  "Shift+Tab": (ev) => this.processTabKey(ev, "left"),
32075
32228
  };
@@ -32191,7 +32344,8 @@ stores.inject(MyMetaStore, storeInstance);
32191
32344
  processEscapeKey() {
32192
32345
  this.composerStore.cancelEdition();
32193
32346
  }
32194
- processF4Key() {
32347
+ processF4Key(ev) {
32348
+ ev.stopPropagation();
32195
32349
  this.composerStore.cycleReferences();
32196
32350
  this.processContent();
32197
32351
  }
@@ -34394,13 +34548,6 @@ stores.inject(MyMetaStore, storeInstance);
34394
34548
  this.getters = get(ModelStore).getters;
34395
34549
  this.renderer = get(RendererStore);
34396
34550
  this.renderer.register(this);
34397
- /**
34398
- * Mark the instance as raw to avoid reactivity as this class is instanciated
34399
- * as a Store by `useGridDrawing` (which casts it as reactive).
34400
- *
34401
- * Calling `this.` on a reactive instance is significantly slower than on a raw object.
34402
- */
34403
- owl.markRaw(this);
34404
34551
  }
34405
34552
  get renderingLayers() {
34406
34553
  return ["Background", "Headers"];
@@ -35030,7 +35177,7 @@ stores.inject(MyMetaStore, storeInstance);
35030
35177
  function useGridDrawing(refName, model, canvasSize) {
35031
35178
  const canvasRef = owl.useRef(refName);
35032
35179
  owl.useEffect(drawGrid);
35033
- const rendererManager = useStore(RendererStore);
35180
+ const rendererStore = useStore(RendererStore);
35034
35181
  useStore(GridRenderer);
35035
35182
  function drawGrid() {
35036
35183
  const canvas = canvasRef.el;
@@ -35058,7 +35205,11 @@ stores.inject(MyMetaStore, storeInstance);
35058
35205
  ctx.scale(dpr, dpr);
35059
35206
  for (const layer of OrderedLayers()) {
35060
35207
  model.drawLayer(renderingContext, layer);
35061
- rendererManager.drawLayer(renderingContext, layer);
35208
+ // @ts-ignore 'drawLayer' is not declated as a mutator because:
35209
+ // it does not mutate anything. Most importantly it's used
35210
+ // during rendering. Invoking a mutator during rendering would
35211
+ // trigger another rendering, ultimately resulting in an infinite loop.
35212
+ rendererStore.drawLayer(renderingContext, layer);
35062
35213
  }
35063
35214
  }
35064
35215
  }
@@ -35460,6 +35611,7 @@ stores.inject(MyMetaStore, storeInstance);
35460
35611
  }
35461
35612
 
35462
35613
  class SidePanelStore extends SpreadsheetStore {
35614
+ mutators = ["open", "toggle", "close"];
35463
35615
  initialPanelProps = {};
35464
35616
  componentTag = "";
35465
35617
  get isOpen() {
@@ -43288,7 +43440,12 @@ stores.inject(MyMetaStore, storeInstance);
43288
43440
  * if they have at least a common cell
43289
43441
  */
43290
43442
  doesIntersectMerge(sheetId, zone) {
43291
- return positions(zone).some(({ col, row }) => this.getMerge({ sheetId, col, row }) !== undefined);
43443
+ for (const merge of this.getMerges(sheetId)) {
43444
+ if (overlap(zone, merge)) {
43445
+ return true;
43446
+ }
43447
+ }
43448
+ return false;
43292
43449
  }
43293
43450
  /**
43294
43451
  * Returns true if two columns have at least one merge in common
@@ -47436,9 +47593,10 @@ stores.inject(MyMetaStore, storeInstance);
47436
47593
  }
47437
47594
  if (!content) {
47438
47595
  // The previous content could have blocked some array formulas
47439
- impactedPositions.addMany(this.getArrayFormulasBlockedBy(position));
47596
+ impactedPositions.add(position);
47440
47597
  }
47441
47598
  }
47599
+ impactedPositions.addMany(this.getArrayFormulasBlockedBy(impactedPositions));
47442
47600
  return impactedPositions;
47443
47601
  }
47444
47602
  buildDependencyGraph() {
@@ -47480,23 +47638,25 @@ stores.inject(MyMetaStore, storeInstance);
47480
47638
  return positions;
47481
47639
  }
47482
47640
  /**
47483
- * Return the position of formulas blocked by the given position
47641
+ * Return the position of formulas blocked by the given positions
47484
47642
  * as well as all their dependencies.
47485
47643
  */
47486
- getArrayFormulasBlockedBy(position) {
47487
- if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
47488
- return [];
47489
- }
47490
- const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
47491
- const positions = this.createEmptyPositionSet();
47492
- positions.addMany(arrayFormulas);
47493
- const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
47494
- if (arrayFormulaPosition) {
47495
- // ignore the formula spreading on the position. Keep only the blocked ones
47496
- positions.delete(arrayFormulaPosition);
47644
+ getArrayFormulasBlockedBy(positions) {
47645
+ const arrayFormulaPositions = this.createEmptyPositionSet();
47646
+ for (const position of positions) {
47647
+ if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
47648
+ continue;
47649
+ }
47650
+ const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
47651
+ arrayFormulaPositions.addMany(arrayFormulas);
47652
+ const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
47653
+ if (arrayFormulaPosition) {
47654
+ // ignore the formula spreading on the position. Keep only the blocked ones
47655
+ arrayFormulaPositions.delete(arrayFormulaPosition);
47656
+ }
47497
47657
  }
47498
- positions.addMany(this.getCellsDependingOn(positions));
47499
- return positions;
47658
+ arrayFormulaPositions.addMany(this.getCellsDependingOn(arrayFormulaPositions));
47659
+ return arrayFormulaPositions;
47500
47660
  }
47501
47661
  nextPositionsToUpdate = new PositionSet({});
47502
47662
  cellsBeingComputed = new Set();
@@ -47626,6 +47786,7 @@ stores.inject(MyMetaStore, storeInstance);
47626
47786
  if (!this.spreadingRelations.isArrayFormula(position)) {
47627
47787
  return;
47628
47788
  }
47789
+ const invalidated = this.createEmptyPositionSet();
47629
47790
  for (const child of this.spreadingRelations.getArrayResultPositions(position)) {
47630
47791
  const content = this.getters.getCell(child)?.content;
47631
47792
  if (content) {
@@ -47633,10 +47794,11 @@ stores.inject(MyMetaStore, storeInstance);
47633
47794
  // there's still a collision
47634
47795
  continue;
47635
47796
  }
47797
+ invalidated.add(child);
47636
47798
  this.evaluatedCells.delete(child);
47637
- this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
47638
- this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedBy(child));
47639
47799
  }
47800
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn(invalidated));
47801
+ this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedBy(invalidated));
47640
47802
  this.spreadingRelations.removeNode(position);
47641
47803
  }
47642
47804
  // ----------------------------------------------------------
@@ -49603,62 +49765,6 @@ stores.inject(MyMetaStore, storeInstance);
49603
49765
  }
49604
49766
  }
49605
49767
 
49606
- /**
49607
- * This is a generic event bus based on the Owl event bus.
49608
- * This bus however ensures type safety across events and subscription callbacks.
49609
- */
49610
- class EventBus {
49611
- subscriptions = {};
49612
- /**
49613
- * Add a listener for the 'eventType' events.
49614
- *
49615
- * Note that the 'owner' of this event can be anything, but will more likely
49616
- * be a component or a class. The idea is that the callback will be called with
49617
- * the proper owner bound.
49618
- *
49619
- * Also, the owner should be kind of unique. This will be used to remove the
49620
- * listener.
49621
- */
49622
- on(type, owner, callback) {
49623
- if (!callback) {
49624
- throw new Error("Missing callback");
49625
- }
49626
- if (!this.subscriptions[type]) {
49627
- this.subscriptions[type] = [];
49628
- }
49629
- this.subscriptions[type].push({
49630
- owner,
49631
- callback,
49632
- });
49633
- }
49634
- /**
49635
- * Emit an event of type 'eventType'. Any extra arguments will be passed to
49636
- * the listeners callback.
49637
- */
49638
- trigger(type, payload) {
49639
- const subs = this.subscriptions[type] || [];
49640
- for (let i = 0, iLen = subs.length; i < iLen; i++) {
49641
- const sub = subs[i];
49642
- sub.callback.call(sub.owner, payload);
49643
- }
49644
- }
49645
- /**
49646
- * Remove a listener
49647
- */
49648
- off(eventType, owner) {
49649
- const subs = this.subscriptions[eventType];
49650
- if (subs) {
49651
- this.subscriptions[eventType] = subs.filter((s) => s.owner !== owner);
49652
- }
49653
- }
49654
- /**
49655
- * Remove all subscriptions.
49656
- */
49657
- clear() {
49658
- this.subscriptions = {};
49659
- }
49660
- }
49661
-
49662
49768
  /*
49663
49769
  * This file contains the specifics transformations
49664
49770
  */
@@ -52129,7 +52235,7 @@ stores.inject(MyMetaStore, storeInstance);
52129
52235
  case "ADD_COLUMNS_ROWS": {
52130
52236
  this.status = "invisible";
52131
52237
  // If we add a col/row inside or before the cut area, we invalidate the clipboard
52132
- if (this._isCutOperation !== true) {
52238
+ if (this._isCutOperation !== true || cmd.sheetId !== this.copiedData?.sheetId) {
52133
52239
  return;
52134
52240
  }
52135
52241
  const isClipboardDirty = this.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
@@ -52141,7 +52247,7 @@ stores.inject(MyMetaStore, storeInstance);
52141
52247
  case "REMOVE_COLUMNS_ROWS": {
52142
52248
  this.status = "invisible";
52143
52249
  // If we remove a col/row inside or before the cut area, we invalidate the clipboard
52144
- if (this._isCutOperation !== true) {
52250
+ if (this._isCutOperation !== true || cmd.sheetId !== this.copiedData?.sheetId) {
52145
52251
  return;
52146
52252
  }
52147
52253
  for (let el of cmd.elements) {
@@ -56776,16 +56882,25 @@ stores.inject(MyMetaStore, storeInstance);
56776
56882
  }
56777
56883
  }, () => [this.env.model.getters.getActiveSheetId()]);
56778
56884
  owl.useExternalListener(window, "resize", () => this.render(true));
56885
+ // For some reason, the wheel event is not properly registered inside templates
56886
+ // in Chromium-based browsers based on chromium 125
56887
+ // This hack ensures the event declared in the template is properly registered/working
56888
+ owl.useExternalListener(document.body, "wheel", () => { });
56779
56889
  this.bindModelEvents();
56780
56890
  owl.onWillUpdateProps((nextProps) => {
56781
56891
  if (nextProps.model !== this.props.model) {
56782
56892
  throw new Error("Changing the props model is not supported at the moment.");
56783
56893
  }
56784
56894
  });
56895
+ const render = batched(this.render.bind(this, true));
56785
56896
  owl.onMounted(() => {
56786
56897
  this.checkViewportSize();
56898
+ stores.on("store-updated", this, render);
56899
+ });
56900
+ owl.onWillUnmount(() => {
56901
+ this.unbindModelEvents();
56902
+ stores.off("store-updated", this);
56787
56903
  });
56788
- owl.onWillUnmount(() => this.unbindModelEvents());
56789
56904
  owl.onPatched(() => {
56790
56905
  this.checkViewportSize();
56791
56906
  });
@@ -60614,9 +60729,9 @@ stores.inject(MyMetaStore, storeInstance);
60614
60729
  exports.tokenize = tokenize;
60615
60730
 
60616
60731
 
60617
- __info__.version = "17.2.6";
60618
- __info__.date = "2024-05-07T10:41:20.332Z";
60619
- __info__.hash = "a4f800c";
60732
+ __info__.version = "17.2.8";
60733
+ __info__.date = "2024-05-24T11:29:49.320Z";
60734
+ __info__.hash = "bfbcaa0";
60620
60735
 
60621
60736
 
60622
60737
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);