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