@odoo/o-spreadsheet 17.2.7 → 17.2.9

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.7
7
- * @date 2024-05-15T09:20:44.429Z
8
- * @hash 57e89fa
6
+ * @version 17.2.9
7
+ * @date 2024-06-03T14:56:21.684Z
8
+ * @hash 086af6d
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();
@@ -2638,7 +2659,7 @@
2638
2659
  return false;
2639
2660
  }
2640
2661
  if (typeof operand === "number" && operator === "=") {
2641
- return toString(value) === toString(operand);
2662
+ return value.toString() === operand.toString();
2642
2663
  }
2643
2664
  if (operator === "<>" || operator === "=") {
2644
2665
  let result;
@@ -2698,14 +2719,13 @@
2698
2719
  if (countArg % 2 === 1) {
2699
2720
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2700
2721
  }
2701
- const dimRow = args[0].length;
2702
- const dimCol = args[0][0].length;
2722
+ const firstArg = toMatrix(args[0]);
2723
+ const dimRow = firstArg.length;
2724
+ const dimCol = firstArg[0].length;
2703
2725
  let predicates = [];
2704
2726
  for (let i = 0; i < countArg - 1; i += 2) {
2705
- const criteriaRange = args[i];
2706
- if (!isMatrix(criteriaRange) ||
2707
- criteriaRange.length !== dimRow ||
2708
- criteriaRange[0].length !== dimCol) {
2727
+ const criteriaRange = toMatrix(args[i]);
2728
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2709
2729
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2710
2730
  }
2711
2731
  const description = toString(args[i + 1]);
@@ -2719,7 +2739,7 @@
2719
2739
  for (let j = 0; j < dimCol; j++) {
2720
2740
  let validatedPredicates = true;
2721
2741
  for (let k = 0; k < countArg - 1; k += 2) {
2722
- const criteriaValue = args[k][i][j].value;
2742
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2723
2743
  const criterion = predicates[k / 2];
2724
2744
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2725
2745
  if (!validatedPredicates) {
@@ -4436,8 +4456,11 @@
4436
4456
  /**
4437
4457
  * Create a range from a xc. If the xc is empty, this function returns undefined.
4438
4458
  */
4439
- function createRange(getters, sheetId, range) {
4440
- return range ? getters.getRangeFromSheetXC(sheetId, range) : undefined;
4459
+ function createValidRange(getters, sheetId, xc) {
4460
+ if (!xc)
4461
+ return;
4462
+ const range = getters.getRangeFromSheetXC(sheetId, xc);
4463
+ return !(range.invalidSheetName || range.invalidXc) ? range : undefined;
4441
4464
  }
4442
4465
  /**
4443
4466
  * Spread multiple colrows zone to one row/col zone and add a many new input range as needed.
@@ -8013,10 +8036,66 @@
8013
8036
  });
8014
8037
  }
8015
8038
 
8039
+ /**
8040
+ * This is a generic event bus based on the Owl event bus.
8041
+ * This bus however ensures type safety across events and subscription callbacks.
8042
+ */
8043
+ class EventBus {
8044
+ subscriptions = {};
8045
+ /**
8046
+ * Add a listener for the 'eventType' events.
8047
+ *
8048
+ * Note that the 'owner' of this event can be anything, but will more likely
8049
+ * be a component or a class. The idea is that the callback will be called with
8050
+ * the proper owner bound.
8051
+ *
8052
+ * Also, the owner should be kind of unique. This will be used to remove the
8053
+ * listener.
8054
+ */
8055
+ on(type, owner, callback) {
8056
+ if (!callback) {
8057
+ throw new Error("Missing callback");
8058
+ }
8059
+ if (!this.subscriptions[type]) {
8060
+ this.subscriptions[type] = [];
8061
+ }
8062
+ this.subscriptions[type].push({
8063
+ owner,
8064
+ callback,
8065
+ });
8066
+ }
8067
+ /**
8068
+ * Emit an event of type 'eventType'. Any extra arguments will be passed to
8069
+ * the listeners callback.
8070
+ */
8071
+ trigger(type, payload) {
8072
+ const subs = this.subscriptions[type] || [];
8073
+ for (let i = 0, iLen = subs.length; i < iLen; i++) {
8074
+ const sub = subs[i];
8075
+ sub.callback.call(sub.owner, payload);
8076
+ }
8077
+ }
8078
+ /**
8079
+ * Remove a listener
8080
+ */
8081
+ off(eventType, owner) {
8082
+ const subs = this.subscriptions[eventType];
8083
+ if (subs) {
8084
+ this.subscriptions[eventType] = subs.filter((s) => s.owner !== owner);
8085
+ }
8086
+ }
8087
+ /**
8088
+ * Remove all subscriptions.
8089
+ */
8090
+ clear() {
8091
+ this.subscriptions = {};
8092
+ }
8093
+ }
8094
+
8016
8095
  /**
8017
8096
  * A type-safe dependency container
8018
8097
  */
8019
- class DependencyContainer {
8098
+ class DependencyContainer extends EventBus {
8020
8099
  dependencies = new Map();
8021
8100
  factory = new StoreFactory(this.get.bind(this));
8022
8101
  /**
@@ -8093,15 +8172,12 @@ stores.inject(MyMetaStore, storeInstance);
8093
8172
  }
8094
8173
  return MetaStore;
8095
8174
  }
8096
- class ReactiveStore {
8175
+ class DisposableStore {
8097
8176
  get;
8177
+ disposeCallbacks = [];
8098
8178
  constructor(get) {
8099
8179
  this.get = get;
8100
- return owl.reactive(this);
8101
8180
  }
8102
- }
8103
- class DisposableStore extends ReactiveStore {
8104
- disposeCallbacks = [];
8105
8181
  onDispose(callback) {
8106
8182
  this.disposeCallbacks.push(callback);
8107
8183
  }
@@ -8121,7 +8197,10 @@ stores.inject(MyMetaStore, storeInstance);
8121
8197
  const container = new DependencyContainer();
8122
8198
  owl.useSubEnv({
8123
8199
  __spreadsheet_stores__: container,
8124
- getStore: container.get.bind(container),
8200
+ getStore: (Store) => {
8201
+ const store = container.get(Store);
8202
+ return proxifyStoreMutation(store, () => container.trigger("store-updated"));
8203
+ },
8125
8204
  });
8126
8205
  return container;
8127
8206
  }
@@ -8131,14 +8210,57 @@ stores.inject(MyMetaStore, storeInstance);
8131
8210
  function useStore(Store) {
8132
8211
  const env = owl.useEnv();
8133
8212
  const container = getDependencyContainer(env);
8134
- return owl.useState(container.get(Store));
8213
+ const store = container.get(Store);
8214
+ return useStoreRenderProxy(container, store);
8135
8215
  }
8136
8216
  function useLocalStore(Store, ...args) {
8137
8217
  const env = owl.useEnv();
8138
8218
  const container = getDependencyContainer(env);
8139
- const store = owl.useState(container.instantiate(Store, ...args));
8219
+ const store = container.instantiate(Store, ...args);
8140
8220
  owl.onWillUnmount(() => store.dispose());
8141
- return store;
8221
+ return useStoreRenderProxy(container, store);
8222
+ }
8223
+ /**
8224
+ * Trigger an event to re-render the app (deep render) when
8225
+ * a store is mutated by invoking one of its mutator methods.
8226
+ */
8227
+ function useStoreRenderProxy(container, store) {
8228
+ const component = owl.useComponent();
8229
+ const proxy = proxifyStoreMutation(store, () => {
8230
+ if (owl.status(component) === "mounted") {
8231
+ container.trigger("store-updated");
8232
+ }
8233
+ });
8234
+ return proxy;
8235
+ }
8236
+ /**
8237
+ * Creates a proxied version of a store object with mutation tracking.
8238
+ * Whenever a mutator method of the store is called, the provided callback function is invoked.
8239
+ */
8240
+ function proxifyStoreMutation(store, callback) {
8241
+ const proxy = new Proxy(store, {
8242
+ get(target, property, receiver) {
8243
+ const thisStore = target;
8244
+ // The third argument is `thisStore` (target) instead of `receiver`.
8245
+ // The goal is to always have the same `this` value in getter functions
8246
+ // (when `target[property]` is an accessor property).
8247
+ // `thisStore` is always the same object reference. `receiver` however is the
8248
+ // object on which the property is called, which is the Proxy object which is different for each component.
8249
+ const value = Reflect.get(target, property, thisStore);
8250
+ if (store.mutators.includes(property)) {
8251
+ const functionProxy = new Proxy(value, {
8252
+ // trap the function call
8253
+ apply(target, thisArg, argArray) {
8254
+ Reflect.apply(target, thisStore, argArray);
8255
+ callback();
8256
+ },
8257
+ });
8258
+ return functionProxy;
8259
+ }
8260
+ return value;
8261
+ },
8262
+ });
8263
+ return proxy;
8142
8264
  }
8143
8265
  function getDependencyContainer(env) {
8144
8266
  const container = env.__spreadsheet_stores__;
@@ -8150,7 +8272,8 @@ stores.inject(MyMetaStore, storeInstance);
8150
8272
 
8151
8273
  const ModelStore = createAbstractStore("Model");
8152
8274
 
8153
- class RendererStore extends ReactiveStore {
8275
+ class RendererStore {
8276
+ mutators = ["register", "unRegister"];
8154
8277
  renderers = {};
8155
8278
  register(renderer) {
8156
8279
  if (!renderer.renderingLayers.length) {
@@ -8184,7 +8307,7 @@ stores.inject(MyMetaStore, storeInstance);
8184
8307
  class SpreadsheetStore extends DisposableStore {
8185
8308
  // cast the model store as Model to allow model.dispatch to return the DispatchResult
8186
8309
  model = this.get(ModelStore);
8187
- getters = owl.markRaw(this.model.getters);
8310
+ getters = this.model.getters;
8188
8311
  renderer = this.get(RendererStore);
8189
8312
  constructor(get) {
8190
8313
  super(get);
@@ -8231,6 +8354,7 @@ stores.inject(MyMetaStore, storeInstance);
8231
8354
  }
8232
8355
 
8233
8356
  class HighlightStore extends SpreadsheetStore {
8357
+ mutators = ["register", "unRegister"];
8234
8358
  providers = [];
8235
8359
  constructor(get) {
8236
8360
  super(get);
@@ -8261,7 +8385,7 @@ stores.inject(MyMetaStore, storeInstance);
8261
8385
  this.providers.push(highlightProvider);
8262
8386
  }
8263
8387
  unRegister(highlightProvider) {
8264
- this.providers = this.providers.filter((h) => owl.toRaw(h) !== owl.toRaw(highlightProvider));
8388
+ this.providers = this.providers.filter((h) => h !== highlightProvider);
8265
8389
  }
8266
8390
  drawLayer(ctx, layer) {
8267
8391
  if (layer === "Highlights") {
@@ -8277,6 +8401,16 @@ stores.inject(MyMetaStore, storeInstance);
8277
8401
 
8278
8402
  const CELL_DELETED_MESSAGE = _t("The cell you are trying to edit has been deleted.");
8279
8403
  class ComposerStore extends SpreadsheetStore {
8404
+ mutators = [
8405
+ "startEdition",
8406
+ "setCurrentContent",
8407
+ "stopEdition",
8408
+ "stopComposerRangeSelection",
8409
+ "cancelEdition",
8410
+ "cycleReferences",
8411
+ "changeComposerCursorSelection",
8412
+ "replaceComposerCursorSelection",
8413
+ ];
8280
8414
  col = 0;
8281
8415
  row = 0;
8282
8416
  editionMode = "inactive";
@@ -8291,9 +8425,9 @@ stores.inject(MyMetaStore, storeInstance);
8291
8425
  highlightStore = this.get(HighlightStore);
8292
8426
  constructor(get) {
8293
8427
  super(get);
8294
- this.highlightStore.register(owl.toRaw(this));
8428
+ this.highlightStore.register(this);
8295
8429
  this.onDispose(() => {
8296
- this.highlightStore.unRegister(owl.toRaw(this));
8430
+ this.highlightStore.unRegister(this);
8297
8431
  });
8298
8432
  }
8299
8433
  canStopEdition() {
@@ -8420,7 +8554,7 @@ stores.inject(MyMetaStore, storeInstance);
8420
8554
  if (this.isSelectingRange) {
8421
8555
  this.editionMode = "editing";
8422
8556
  }
8423
- this.model.selection.resetAnchor(owl.toRaw(this), {
8557
+ this.model.selection.resetAnchor(this, {
8424
8558
  cell: { col: left, row: top },
8425
8559
  zone: cmd.zone,
8426
8560
  });
@@ -8438,7 +8572,7 @@ stores.inject(MyMetaStore, storeInstance);
8438
8572
  row: activePosition.row,
8439
8573
  });
8440
8574
  const zone = this.getters.expandZone(cmd.sheetIdTo, positionToZone({ col, row }));
8441
- this.model.selection.resetAnchor(owl.toRaw(this), { cell: { col, row }, zone });
8575
+ this.model.selection.resetAnchor(this, { cell: { col, row }, zone });
8442
8576
  }
8443
8577
  break;
8444
8578
  case "DELETE_SHEET":
@@ -8537,7 +8671,7 @@ stores.inject(MyMetaStore, storeInstance);
8537
8671
  startComposerRangeSelection() {
8538
8672
  if (this.sheetId === this.getters.getActiveSheetId()) {
8539
8673
  const zone = positionToZone({ col: this.col, row: this.row });
8540
- this.model.selection.resetAnchor(owl.toRaw(this), {
8674
+ this.model.selection.resetAnchor(this, {
8541
8675
  cell: { col: this.col, row: this.row },
8542
8676
  zone,
8543
8677
  });
@@ -8566,7 +8700,7 @@ stores.inject(MyMetaStore, storeInstance);
8566
8700
  this.setContent(str || this.initialContent, selection);
8567
8701
  this.colorIndexByRange = {};
8568
8702
  const zone = positionToZone({ col: this.col, row: this.row });
8569
- this.model.selection.capture(owl.toRaw(this), { cell: { col: this.col, row: this.row }, zone }, {
8703
+ this.model.selection.capture(this, { cell: { col: this.col, row: this.row }, zone }, {
8570
8704
  handleEvent: this.handleEvent.bind(this),
8571
8705
  release: () => {
8572
8706
  this._stopEdition();
@@ -8674,7 +8808,7 @@ stores.inject(MyMetaStore, storeInstance);
8674
8808
  return;
8675
8809
  }
8676
8810
  this.editionMode = "inactive";
8677
- this.model.selection.release(owl.toRaw(this));
8811
+ this.model.selection.release(this);
8678
8812
  }
8679
8813
  /**
8680
8814
  * Reset the current content to the active cell content
@@ -8996,6 +9130,7 @@ stores.inject(MyMetaStore, storeInstance);
8996
9130
  }
8997
9131
 
8998
9132
  class ComposerFocusStore extends SpreadsheetStore {
9133
+ mutators = ["focusTopBarComposer", "focusGridComposerContent", "focusGridComposerCell"];
8999
9134
  composerStore = this.get(ComposerStore);
9000
9135
  topBarFocus = "inactive";
9001
9136
  gridFocusMode = "inactive";
@@ -9512,8 +9647,8 @@ stores.inject(MyMetaStore, storeInstance);
9512
9647
  type = "scorecard";
9513
9648
  constructor(definition, sheetId, getters) {
9514
9649
  super(definition, sheetId, getters);
9515
- this.keyValue = createRange(getters, sheetId, definition.keyValue);
9516
- this.baseline = createRange(getters, sheetId, definition.baseline);
9650
+ this.keyValue = createValidRange(getters, sheetId, definition.keyValue);
9651
+ this.baseline = createValidRange(getters, sheetId, definition.baseline);
9517
9652
  this.baselineMode = definition.baselineMode;
9518
9653
  this.baselineDescr = definition.baselineDescr;
9519
9654
  this.background = definition.background;
@@ -10083,6 +10218,9 @@ stores.inject(MyMetaStore, storeInstance);
10083
10218
  if (types.some((t) => t.startsWith("RANGE"))) {
10084
10219
  result.acceptMatrix = true;
10085
10220
  }
10221
+ if (types.every((t) => t.startsWith("RANGE"))) {
10222
+ result.acceptMatrixOnly = true;
10223
+ }
10086
10224
  return result;
10087
10225
  }
10088
10226
  /**
@@ -10364,11 +10502,16 @@ stores.inject(MyMetaStore, storeInstance);
10364
10502
  compute: function (array, ...columns) {
10365
10503
  const _array = toMatrix(array);
10366
10504
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
10367
- assert(() => _columns.every((col) => col > 0 && col <= _array.length), _t("The columns arguments must be between 1 and %s (got %s).", _array.length.toString(), (_columns.find((col) => col <= 0 || col > _array.length) || 0).toString()));
10505
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
10506
+ assert(() => argOutOfRange.length === 0, _t("The columns arguments must be between -%s and %s (got %s), excluding 0.", _array.length.toString(), _array.length.toString(), argOutOfRange.join(",")));
10368
10507
  const result = Array(_columns.length);
10369
10508
  for (let col = 0; col < _columns.length; col++) {
10370
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
10371
- result[col] = _array[colIndex];
10509
+ if (_columns[col] > 0) {
10510
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
10511
+ }
10512
+ else {
10513
+ result[col] = _array[_array.length + _columns[col]];
10514
+ }
10372
10515
  }
10373
10516
  return result;
10374
10517
  },
@@ -10389,8 +10532,14 @@ stores.inject(MyMetaStore, storeInstance);
10389
10532
  const _array = toMatrix(array);
10390
10533
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
10391
10534
  const _nbColumns = _array.length;
10392
- assert(() => _rows.every((row) => row > 0 && row <= _array[0].length), _t("The rows arguments must be between 1 and %s (got %s).", _array[0].length.toString(), (_rows.find((row) => row <= 0 || row > _array[0].length) || 0).toString()));
10393
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
10535
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
10536
+ assert(() => argOutOfRange.length === 0, _t("The rows arguments must be between -%s and %s (got %s), excluding 0.", _array[0].length.toString(), _array[0].length.toString(), argOutOfRange.join(",")));
10537
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
10538
+ if (_rows[row] > 0) {
10539
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
10540
+ }
10541
+ return _array[col][_array[col].length + _rows[row]];
10542
+ });
10394
10543
  },
10395
10544
  isExported: true,
10396
10545
  };
@@ -11298,7 +11447,7 @@ stores.inject(MyMetaStore, storeInstance);
11298
11447
  compute: function (range, ...args) {
11299
11448
  let uniqueValues = new Set();
11300
11449
  visitMatchingRanges(args, (i, j) => {
11301
- const data = range[i][j];
11450
+ const data = range[i]?.[j];
11302
11451
  if (isDefined(data)) {
11303
11452
  uniqueValues.add(data.value);
11304
11453
  }
@@ -11928,7 +12077,7 @@ stores.inject(MyMetaStore, storeInstance);
11928
12077
  }
11929
12078
  let sum = 0;
11930
12079
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
11931
- const value = sumRange[i][j].value;
12080
+ const value = sumRange[i]?.[j]?.value;
11932
12081
  if (typeof value === "number") {
11933
12082
  sum += value;
11934
12083
  }
@@ -11953,7 +12102,7 @@ stores.inject(MyMetaStore, storeInstance);
11953
12102
  compute: function (sumRange, ...criters) {
11954
12103
  let sum = 0;
11955
12104
  visitMatchingRanges(criters, (i, j) => {
11956
- const value = sumRange[i][j].value;
12105
+ const value = sumRange[i]?.[j]?.value;
11957
12106
  if (typeof value === "number") {
11958
12107
  sum += value;
11959
12108
  }
@@ -12500,7 +12649,7 @@ stores.inject(MyMetaStore, storeInstance);
12500
12649
  let count = 0;
12501
12650
  let sum = 0;
12502
12651
  visitMatchingRanges([criteriaRange, criterion], (i, j) => {
12503
- const value = _averageRange[i][j].value;
12652
+ const value = _averageRange[i]?.[j]?.value;
12504
12653
  if (typeof value === "number") {
12505
12654
  count += 1;
12506
12655
  sum += value;
@@ -12529,7 +12678,7 @@ stores.inject(MyMetaStore, storeInstance);
12529
12678
  let count = 0;
12530
12679
  let sum = 0;
12531
12680
  visitMatchingRanges(args, (i, j) => {
12532
- const value = _averageRange[i][j].value;
12681
+ const value = _averageRange[i]?.[j]?.value;
12533
12682
  if (typeof value === "number") {
12534
12683
  count += 1;
12535
12684
  sum += value;
@@ -12834,7 +12983,7 @@ stores.inject(MyMetaStore, storeInstance);
12834
12983
  compute: function (range, ...args) {
12835
12984
  let result = -Infinity;
12836
12985
  visitMatchingRanges(args, (i, j) => {
12837
- const value = range[i][j].value;
12986
+ const value = range[i]?.[j]?.value;
12838
12987
  if (typeof value === "number") {
12839
12988
  result = result < value ? value : result;
12840
12989
  }
@@ -12917,7 +13066,7 @@ stores.inject(MyMetaStore, storeInstance);
12917
13066
  compute: function (range, ...args) {
12918
13067
  let result = Infinity;
12919
13068
  visitMatchingRanges(args, (i, j) => {
12920
- const value = range[i][j].value;
13069
+ const value = range[i]?.[j]?.value;
12921
13070
  if (typeof value === "number") {
12922
13071
  result = result > value ? value : result;
12923
13072
  }
@@ -18669,6 +18818,9 @@ stores.inject(MyMetaStore, storeInstance);
18669
18818
  }
18670
18819
  args[i] = arg[0][0];
18671
18820
  }
18821
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
18822
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
18823
+ }
18672
18824
  }
18673
18825
  return descr.compute.apply(this, args);
18674
18826
  }
@@ -19671,7 +19823,7 @@ stores.inject(MyMetaStore, storeInstance);
19671
19823
  constructor(definition, sheetId, getters) {
19672
19824
  super(definition, sheetId, getters);
19673
19825
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
19674
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
19826
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
19675
19827
  this.background = definition.background;
19676
19828
  this.verticalAxisPosition = definition.verticalAxisPosition;
19677
19829
  this.legendPosition = definition.legendPosition;
@@ -19915,7 +20067,7 @@ stores.inject(MyMetaStore, storeInstance);
19915
20067
  type = "gauge";
19916
20068
  constructor(definition, sheetId, getters) {
19917
20069
  super(definition, sheetId, getters);
19918
- this.dataRange = createRange(this.getters, this.sheetId, definition.dataRange);
20070
+ this.dataRange = createValidRange(this.getters, this.sheetId, definition.dataRange);
19919
20071
  this.sectionRule = definition.sectionRule;
19920
20072
  this.background = definition.background;
19921
20073
  }
@@ -20436,7 +20588,7 @@ stores.inject(MyMetaStore, storeInstance);
20436
20588
  constructor(definition, sheetId, getters) {
20437
20589
  super(definition, sheetId, getters);
20438
20590
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20439
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
20591
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
20440
20592
  this.background = definition.background;
20441
20593
  this.verticalAxisPosition = definition.verticalAxisPosition;
20442
20594
  this.legendPosition = definition.legendPosition;
@@ -20551,7 +20703,7 @@ stores.inject(MyMetaStore, storeInstance);
20551
20703
  constructor(definition, sheetId, getters) {
20552
20704
  super(definition, sheetId, getters);
20553
20705
  this.dataSets = createDataSets(getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20554
- this.labelRange = createRange(getters, sheetId, definition.labelRange);
20706
+ this.labelRange = createValidRange(getters, sheetId, definition.labelRange);
20555
20707
  this.background = definition.background;
20556
20708
  this.legendPosition = definition.legendPosition;
20557
20709
  this.aggregated = definition.aggregated;
@@ -20753,7 +20905,7 @@ stores.inject(MyMetaStore, storeInstance);
20753
20905
  constructor(definition, sheetId, getters) {
20754
20906
  super(definition, sheetId, getters);
20755
20907
  this.dataSets = createDataSets(this.getters, definition.dataSets, sheetId, definition.dataSetsHaveTitle);
20756
- this.labelRange = createRange(this.getters, sheetId, definition.labelRange);
20908
+ this.labelRange = createValidRange(this.getters, sheetId, definition.labelRange);
20757
20909
  this.background = definition.background;
20758
20910
  this.verticalAxisPosition = definition.verticalAxisPosition;
20759
20911
  this.legendPosition = definition.legendPosition;
@@ -20839,13 +20991,6 @@ stores.inject(MyMetaStore, storeInstance);
20839
20991
  // have less options than the line chart (it only works with linear labels)
20840
20992
  chartJsConfig.type = "line";
20841
20993
  const configOptions = chartJsConfig.options;
20842
- configOptions.elements = {
20843
- point: {
20844
- radius: 3,
20845
- hoverRadius: 3,
20846
- hitRadius: 8,
20847
- },
20848
- };
20849
20994
  const locale = getters.getLocale();
20850
20995
  configOptions.plugins.tooltip.callbacks.title = () => "";
20851
20996
  configOptions.plugins.tooltip.callbacks.label = (tooltipItem) => {
@@ -21452,6 +21597,7 @@ stores.inject(MyMetaStore, storeInstance);
21452
21597
  }
21453
21598
 
21454
21599
  class HoveredCellStore extends SpreadsheetStore {
21600
+ mutators = ["clear", "hover"];
21455
21601
  col;
21456
21602
  row;
21457
21603
  handle(cmd) {
@@ -21471,6 +21617,7 @@ stores.inject(MyMetaStore, storeInstance);
21471
21617
  }
21472
21618
 
21473
21619
  class CellPopoverStore extends SpreadsheetStore {
21620
+ mutators = ["open", "close"];
21474
21621
  persistentPopover;
21475
21622
  hoveredCell = this.get(HoveredCellStore);
21476
21623
  handle(cmd) {
@@ -25962,12 +26109,13 @@ stores.inject(MyMetaStore, storeInstance);
25962
26109
 
25963
26110
  // The name is misleading and can be confused with the DOM focus.
25964
26111
  class FocusStore {
26112
+ mutators = ["focus", "unfocus"];
25965
26113
  focusedElement = null;
25966
26114
  focus(element) {
25967
26115
  this.focusedElement = element;
25968
26116
  }
25969
26117
  unfocus(element) {
25970
- if (this.focusedElement && owl.toRaw(this.focusedElement) === owl.toRaw(element)) {
26118
+ if (this.focusedElement && this.focusedElement === element) {
25971
26119
  this.focusedElement = null;
25972
26120
  }
25973
26121
  }
@@ -25983,6 +26131,16 @@ stores.inject(MyMetaStore, storeInstance);
25983
26131
  class SelectionInputStore extends SpreadsheetStore {
25984
26132
  initialRanges;
25985
26133
  inputHasSingleRange;
26134
+ mutators = [
26135
+ "resetWithRanges",
26136
+ "focusById",
26137
+ "unfocus",
26138
+ "addEmptyRange",
26139
+ "removeRange",
26140
+ "changeRange",
26141
+ "reset",
26142
+ "confirm",
26143
+ ];
25986
26144
  ranges = [];
25987
26145
  focusedRangeIndex = null;
25988
26146
  inputSheetId;
@@ -26042,7 +26200,7 @@ stores.inject(MyMetaStore, storeInstance);
26042
26200
  row: 0,
26043
26201
  });
26044
26202
  const zone = this.getters.expandZone(cmd.sheetIdTo, positionToZone({ col, row }));
26045
- this.model.selection.resetAnchor(owl.toRaw(this), { cell: { col, row }, zone });
26203
+ this.model.selection.resetAnchor(this, { cell: { col, row }, zone });
26046
26204
  }
26047
26205
  break;
26048
26206
  }
@@ -26061,7 +26219,7 @@ stores.inject(MyMetaStore, storeInstance);
26061
26219
  if (focusIndex !== -1) {
26062
26220
  this.focus(focusIndex);
26063
26221
  const { left, top } = newZone;
26064
- this.model.selection.resetAnchor(owl.toRaw(this), {
26222
+ this.model.selection.resetAnchor(this, {
26065
26223
  cell: { col: left, row: top },
26066
26224
  zone: newZone,
26067
26225
  });
@@ -26152,7 +26310,7 @@ stores.inject(MyMetaStore, storeInstance);
26152
26310
  }
26153
26311
  get hasMainFocus() {
26154
26312
  const focusedElement = this.focusStore.focusedElement;
26155
- return !!focusedElement && owl.toRaw(focusedElement) === owl.toRaw(this);
26313
+ return !!focusedElement && focusedElement === this;
26156
26314
  }
26157
26315
  get highlights() {
26158
26316
  if (!this.hasMainFocus) {
@@ -26181,7 +26339,7 @@ stores.inject(MyMetaStore, storeInstance);
26181
26339
  unfocus() {
26182
26340
  this.focusedRangeIndex = null;
26183
26341
  this.focusStore.unfocus(this);
26184
- this.model.selection.release(owl.toRaw(this));
26342
+ this.model.selection.release(this);
26185
26343
  }
26186
26344
  captureSelection() {
26187
26345
  if (this.focusedRangeIndex === null) {
@@ -26190,7 +26348,7 @@ stores.inject(MyMetaStore, storeInstance);
26190
26348
  const range = this.ranges[this.focusedRangeIndex];
26191
26349
  const sheetId = this.getters.getActiveSheetId();
26192
26350
  const zone = this.getters.getRangeFromSheetXC(sheetId, range?.xc || "A1").zone;
26193
- this.model.selection.capture(owl.toRaw(this), { cell: { col: zone.left, row: zone.top }, zone }, {
26351
+ this.model.selection.capture(this, { cell: { col: zone.left, row: zone.top }, zone }, {
26194
26352
  handleEvent: this.handleEvent.bind(this),
26195
26353
  release: this.unfocus.bind(this),
26196
26354
  });
@@ -26666,7 +26824,7 @@ stores.inject(MyMetaStore, storeInstance);
26666
26824
  }
26667
26825
  const getters = this.env.model.getters;
26668
26826
  const sheetId = getters.getActiveSheetId();
26669
- const labelRange = createRange(getters, sheetId, this.labelRange);
26827
+ const labelRange = createValidRange(getters, sheetId, this.labelRange);
26670
26828
  const dataSets = createDataSets(getters, this.dataSeriesRanges, sheetId, this.props.definition.dataSetsHaveTitle);
26671
26829
  if (dataSets.length) {
26672
26830
  return dataSets[0].dataRange.zone.top + 1;
@@ -26695,15 +26853,23 @@ stores.inject(MyMetaStore, storeInstance);
26695
26853
  }
26696
26854
  }
26697
26855
 
26856
+ /**
26857
+ * Start listening to pointer events and apply the given callbacks.
26858
+ *
26859
+ * @returns A function to remove the listeners.
26860
+ */
26698
26861
  function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
26699
- const _onMouseUp = (ev) => {
26700
- onMouseUp(ev);
26862
+ const removeListeners = () => {
26701
26863
  window.removeEventListener("pointerdown", onMouseDown);
26702
26864
  window.removeEventListener("pointerup", _onMouseUp);
26703
26865
  window.removeEventListener("dragstart", _onDragStart);
26704
26866
  window.removeEventListener("pointermove", onMouseMove);
26705
26867
  window.removeEventListener("wheel", onMouseMove);
26706
26868
  };
26869
+ const _onMouseUp = (ev) => {
26870
+ onMouseUp(ev);
26871
+ removeListeners();
26872
+ };
26707
26873
  function _onDragStart(ev) {
26708
26874
  ev.preventDefault();
26709
26875
  }
@@ -26715,6 +26881,7 @@ stores.inject(MyMetaStore, storeInstance);
26715
26881
  // preventDefault() is not allowed in passive event handler.
26716
26882
  // https://chromestatus.com/feature/6662647093133312
26717
26883
  window.addEventListener("wheel", onMouseMove, { passive: false });
26884
+ return removeListeners;
26718
26885
  }
26719
26886
  /**
26720
26887
  * Function to be used during a pointerdown event, this function allows to
@@ -27658,6 +27825,7 @@ stores.inject(MyMetaStore, storeInstance);
27658
27825
  });
27659
27826
 
27660
27827
  class MainChartPanelStore extends SpreadsheetStore {
27828
+ mutators = ["activatePanel"];
27661
27829
  panel = "configuration";
27662
27830
  activatePanel(panel) {
27663
27831
  this.panel = panel;
@@ -27908,6 +28076,7 @@ stores.inject(MyMetaStore, storeInstance);
27908
28076
  state.itemsStyle = {};
27909
28077
  document.body.style.cursor = previousCursor;
27910
28078
  args.onCancel?.();
28079
+ cleanUp();
27911
28080
  };
27912
28081
  const onDragEnd = (itemId, indexAtEnd) => {
27913
28082
  state.draggedItemId = undefined;
@@ -27928,7 +28097,8 @@ stores.inject(MyMetaStore, storeInstance);
27928
28097
  onDragEnd,
27929
28098
  onCancel: state.cancel,
27930
28099
  });
27931
- startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
28100
+ const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
28101
+ cleanupFns.push(stopListening);
27932
28102
  const onScroll = dndHelper.onScroll.bind(dndHelper);
27933
28103
  args.containerEl.addEventListener("scroll", onScroll);
27934
28104
  cleanupFns.push(() => args.containerEl.removeEventListener("scroll", onScroll));
@@ -28005,7 +28175,7 @@ stores.inject(MyMetaStore, storeInstance);
28005
28175
  this.moveDraggedItemToPosition(this.currentMousePosition + this.scrollOffset);
28006
28176
  }
28007
28177
  onMouseMove(ev) {
28008
- if (ev.button !== -1) {
28178
+ if (ev.button > 1) {
28009
28179
  this.onCancel();
28010
28180
  return;
28011
28181
  }
@@ -28196,14 +28366,14 @@ stores.inject(MyMetaStore, storeInstance);
28196
28366
 
28197
28367
  function useHighlightsOnHover(ref, highlightProvider) {
28198
28368
  const hoverState = useHoveredElement(ref);
28199
- const env = owl.useEnv();
28369
+ const stores = useStoreProvider();
28200
28370
  useHighlights({
28201
28371
  get highlights() {
28202
28372
  return hoverState.hovered ? highlightProvider.highlights : [];
28203
28373
  },
28204
28374
  });
28205
28375
  owl.useEffect(() => {
28206
- env.model.dispatch("RENDER_CANVAS");
28376
+ stores.trigger("store-updated");
28207
28377
  }, () => [hoverState.hovered]);
28208
28378
  }
28209
28379
  function useHighlights(highlightProvider) {
@@ -29659,6 +29829,14 @@ stores.inject(MyMetaStore, storeInstance);
29659
29829
  Direction[Direction["next"] = 1] = "next";
29660
29830
  })(Direction || (Direction = {}));
29661
29831
  class FindAndReplaceStore extends SpreadsheetStore {
29832
+ mutators = [
29833
+ "updateSearchOptions",
29834
+ "updateSearchContent",
29835
+ "searchFormulas",
29836
+ "selectPreviousMatch",
29837
+ "selectNextMatch",
29838
+ "replace",
29839
+ ];
29662
29840
  allSheetsMatches = [];
29663
29841
  activeSheetMatches = [];
29664
29842
  specificRangeMatches = [];
@@ -29683,11 +29861,11 @@ stores.inject(MyMetaStore, storeInstance);
29683
29861
  this.initialShowFormulaState = this.model.getters.shouldShowFormulas();
29684
29862
  this.searchOptions.searchFormulas = this.initialShowFormulaState;
29685
29863
  const highlightStore = get(HighlightStore);
29686
- highlightStore.register(owl.toRaw(this));
29864
+ highlightStore.register(this);
29687
29865
  this.onDispose(() => {
29688
29866
  this.model.dispatch("SET_FORMULA_VISIBILITY", { show: this.initialShowFormulaState });
29689
29867
  this.updateSearchContent.stopDebounce();
29690
- highlightStore.unRegister(owl.toRaw(this));
29868
+ highlightStore.unRegister(this);
29691
29869
  });
29692
29870
  }
29693
29871
  get searchMatches() {
@@ -31167,14 +31345,14 @@ stores.inject(MyMetaStore, storeInstance);
31167
31345
  }
31168
31346
  onKeyDown(ev) {
31169
31347
  const figure = this.props.figure;
31170
- switch (ev.key) {
31348
+ const keyDownShortcut = keyboardEventToShortcutString(ev);
31349
+ switch (keyDownShortcut) {
31171
31350
  case "Delete":
31172
31351
  this.env.model.dispatch("DELETE_FIGURE", {
31173
31352
  sheetId: this.env.model.getters.getActiveSheetId(),
31174
31353
  id: figure.id,
31175
31354
  });
31176
31355
  this.props.onFigureDeleted();
31177
- ev.stopPropagation();
31178
31356
  ev.preventDefault();
31179
31357
  ev.stopPropagation();
31180
31358
  break;
@@ -31195,7 +31373,22 @@ stores.inject(MyMetaStore, storeInstance);
31195
31373
  x: figure.x + delta[0],
31196
31374
  y: figure.y + delta[1],
31197
31375
  });
31376
+ ev.preventDefault();
31377
+ ev.stopPropagation();
31378
+ break;
31379
+ case "Ctrl+A":
31380
+ // Maybe in the future we will implement a way to select all figures
31381
+ ev.preventDefault();
31198
31382
  ev.stopPropagation();
31383
+ break;
31384
+ case "Ctrl+Y":
31385
+ case "Ctrl+Z":
31386
+ if (keyDownShortcut === "Ctrl+Y") {
31387
+ this.env.model.dispatch("REQUEST_REDO");
31388
+ }
31389
+ else if (keyDownShortcut === "Ctrl+Z") {
31390
+ this.env.model.dispatch("REQUEST_UNDO");
31391
+ }
31199
31392
  ev.preventDefault();
31200
31393
  ev.stopPropagation();
31201
31394
  break;
@@ -31330,6 +31523,7 @@ stores.inject(MyMetaStore, storeInstance);
31330
31523
  });
31331
31524
 
31332
31525
  class DOMFocusableElementStore {
31526
+ mutators = ["setFocusableElement", "focus"];
31333
31527
  focusableElement = undefined;
31334
31528
  setFocusableElement(element) {
31335
31529
  this.focusableElement = element;
@@ -32066,7 +32260,7 @@ stores.inject(MyMetaStore, storeInstance);
32066
32260
  "Ctrl+Enter": this.processNewLineEvent,
32067
32261
  Escape: this.processEscapeKey,
32068
32262
  F2: () => console.warn("Not implemented"),
32069
- F4: this.processF4Key,
32263
+ F4: (ev) => this.processF4Key(ev),
32070
32264
  Tab: (ev) => this.processTabKey(ev, "right"),
32071
32265
  "Shift+Tab": (ev) => this.processTabKey(ev, "left"),
32072
32266
  };
@@ -32188,7 +32382,8 @@ stores.inject(MyMetaStore, storeInstance);
32188
32382
  processEscapeKey() {
32189
32383
  this.composerStore.cancelEdition();
32190
32384
  }
32191
- processF4Key() {
32385
+ processF4Key(ev) {
32386
+ ev.stopPropagation();
32192
32387
  this.composerStore.cycleReferences();
32193
32388
  this.processContent();
32194
32389
  }
@@ -34391,13 +34586,6 @@ stores.inject(MyMetaStore, storeInstance);
34391
34586
  this.getters = get(ModelStore).getters;
34392
34587
  this.renderer = get(RendererStore);
34393
34588
  this.renderer.register(this);
34394
- /**
34395
- * Mark the instance as raw to avoid reactivity as this class is instanciated
34396
- * as a Store by `useGridDrawing` (which casts it as reactive).
34397
- *
34398
- * Calling `this.` on a reactive instance is significantly slower than on a raw object.
34399
- */
34400
- owl.markRaw(this);
34401
34589
  }
34402
34590
  get renderingLayers() {
34403
34591
  return ["Background", "Headers"];
@@ -35027,7 +35215,7 @@ stores.inject(MyMetaStore, storeInstance);
35027
35215
  function useGridDrawing(refName, model, canvasSize) {
35028
35216
  const canvasRef = owl.useRef(refName);
35029
35217
  owl.useEffect(drawGrid);
35030
- const rendererManager = useStore(RendererStore);
35218
+ const rendererStore = useStore(RendererStore);
35031
35219
  useStore(GridRenderer);
35032
35220
  function drawGrid() {
35033
35221
  const canvas = canvasRef.el;
@@ -35055,7 +35243,11 @@ stores.inject(MyMetaStore, storeInstance);
35055
35243
  ctx.scale(dpr, dpr);
35056
35244
  for (const layer of OrderedLayers()) {
35057
35245
  model.drawLayer(renderingContext, layer);
35058
- rendererManager.drawLayer(renderingContext, layer);
35246
+ // @ts-ignore 'drawLayer' is not declated as a mutator because:
35247
+ // it does not mutate anything. Most importantly it's used
35248
+ // during rendering. Invoking a mutator during rendering would
35249
+ // trigger another rendering, ultimately resulting in an infinite loop.
35250
+ rendererStore.drawLayer(renderingContext, layer);
35059
35251
  }
35060
35252
  }
35061
35253
  }
@@ -35457,6 +35649,7 @@ stores.inject(MyMetaStore, storeInstance);
35457
35649
  }
35458
35650
 
35459
35651
  class SidePanelStore extends SpreadsheetStore {
35652
+ mutators = ["open", "toggle", "close"];
35460
35653
  initialPanelProps = {};
35461
35654
  componentTag = "";
35462
35655
  get isOpen() {
@@ -40983,12 +41176,6 @@ stores.inject(MyMetaStore, storeInstance);
40983
41176
  // detect when an argument need to be evaluated as a meta argument
40984
41177
  const isMeta = argTypes.includes("META");
40985
41178
  const hasRange = argTypes.some((t) => isRangeType(t));
40986
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
40987
- if (isRangeOnly) {
40988
- if (!isRangeInput(currentArg)) {
40989
- throw new BadExpressionError(_t("Function %s expects the parameter %s to be reference to a cell or range, not a %s.", functionName, (i + 1).toString(), currentArg.type.toLowerCase()));
40990
- }
40991
- }
40992
41179
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange, {
40993
41180
  functionName,
40994
41181
  paramIndex: i + 1,
@@ -41159,16 +41346,6 @@ stores.inject(MyMetaStore, storeInstance);
41159
41346
  function isRangeType(type) {
41160
41347
  return type.startsWith("RANGE");
41161
41348
  }
41162
- function isRangeInput(arg) {
41163
- if (arg.type === "REFERENCE") {
41164
- return true;
41165
- }
41166
- if (arg.type === "FUNCALL") {
41167
- const fnDef = functions$1[arg.value.toUpperCase()];
41168
- return fnDef && isRangeType(fnDef.returns[0]);
41169
- }
41170
- return false;
41171
- }
41172
41349
 
41173
41350
  const functions = functionRegistry.content;
41174
41351
  function isExportableToExcel(tokens) {
@@ -43285,7 +43462,12 @@ stores.inject(MyMetaStore, storeInstance);
43285
43462
  * if they have at least a common cell
43286
43463
  */
43287
43464
  doesIntersectMerge(sheetId, zone) {
43288
- return positions(zone).some(({ col, row }) => this.getMerge({ sheetId, col, row }) !== undefined);
43465
+ for (const merge of this.getMerges(sheetId)) {
43466
+ if (overlap(zone, merge)) {
43467
+ return true;
43468
+ }
43469
+ }
43470
+ return false;
43289
43471
  }
43290
43472
  /**
43291
43473
  * Returns true if two columns have at least one merge in common
@@ -43901,6 +44083,9 @@ stores.inject(MyMetaStore, storeInstance);
43901
44083
  if (range.invalidXc) {
43902
44084
  return range.invalidXc;
43903
44085
  }
44086
+ if (!this.getters.tryGetSheet(range.sheetId)) {
44087
+ return CellErrorType.InvalidReference;
44088
+ }
43904
44089
  if (range.zone.bottom - range.zone.top < 0 || range.zone.right - range.zone.left < 0) {
43905
44090
  return CellErrorType.InvalidReference;
43906
44091
  }
@@ -47285,7 +47470,6 @@ stores.inject(MyMetaStore, storeInstance);
47285
47470
  *
47286
47471
  */
47287
47472
  class SpreadingRelation {
47288
- createEmptyPositionSet;
47289
47473
  /**
47290
47474
  * Internal structure:
47291
47475
  * For something like
@@ -47316,9 +47500,6 @@ stores.inject(MyMetaStore, storeInstance);
47316
47500
  */
47317
47501
  resultsToArrayFormulas = new PositionMap();
47318
47502
  arrayFormulasToResults = new PositionMap();
47319
- constructor(createEmptyPositionSet) {
47320
- this.createEmptyPositionSet = createEmptyPositionSet;
47321
- }
47322
47503
  getFormulaPositionsSpreadingOn(resultPosition) {
47323
47504
  return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
47324
47505
  }
@@ -47337,13 +47518,13 @@ stores.inject(MyMetaStore, storeInstance);
47337
47518
  */
47338
47519
  addRelation({ arrayFormulaPosition, resultPosition, }) {
47339
47520
  if (!this.resultsToArrayFormulas.has(resultPosition)) {
47340
- this.resultsToArrayFormulas.set(resultPosition, this.createEmptyPositionSet());
47521
+ this.resultsToArrayFormulas.set(resultPosition, []);
47341
47522
  }
47342
- this.resultsToArrayFormulas.get(resultPosition)?.add(arrayFormulaPosition);
47523
+ this.resultsToArrayFormulas.get(resultPosition)?.push(arrayFormulaPosition);
47343
47524
  if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
47344
- this.arrayFormulasToResults.set(arrayFormulaPosition, this.createEmptyPositionSet());
47525
+ this.arrayFormulasToResults.set(arrayFormulaPosition, []);
47345
47526
  }
47346
- this.arrayFormulasToResults.get(arrayFormulaPosition)?.add(resultPosition);
47527
+ this.arrayFormulasToResults.get(arrayFormulaPosition)?.push(resultPosition);
47347
47528
  }
47348
47529
  hasArrayFormulaResult(position) {
47349
47530
  return this.resultsToArrayFormulas.has(position);
@@ -47364,7 +47545,7 @@ stores.inject(MyMetaStore, storeInstance);
47364
47545
  evaluatedCells = new PositionMap();
47365
47546
  formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
47366
47547
  blockedArrayFormulas = new PositionSet({});
47367
- spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
47548
+ spreadingRelations = new SpreadingRelation();
47368
47549
  constructor(context, getters) {
47369
47550
  this.context = context;
47370
47551
  this.getters = getters;
@@ -47441,7 +47622,7 @@ stores.inject(MyMetaStore, storeInstance);
47441
47622
  }
47442
47623
  buildDependencyGraph() {
47443
47624
  this.blockedArrayFormulas = this.createEmptyPositionSet();
47444
- this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
47625
+ this.spreadingRelations = new SpreadingRelation();
47445
47626
  this.formulaDependencies = lazy(() => {
47446
47627
  const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position)
47447
47628
  .filter((range) => !range.invalidSheetName && !range.invalidXc)
@@ -47930,16 +48111,22 @@ stores.inject(MyMetaStore, storeInstance);
47930
48111
  let newContent = undefined;
47931
48112
  let newFormat = undefined;
47932
48113
  let isExported = true;
48114
+ const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
47933
48115
  const formulaCell = this.getCorrespondingFormulaCell(position);
47934
48116
  if (formulaCell) {
47935
48117
  isExported = isExportableToExcel(formulaCell.compiledFormula.tokens);
47936
48118
  isFormula = isExported;
47937
48119
  if (!isExported) {
47938
- newContent = (value ?? "").toString();
47939
- newFormat = evaluatedCell.format;
48120
+ // If the cell contains a non-exported formula and that is evaluates to
48121
+ // nothing* ,we don't export it.
48122
+ // * non-falsy value are relevant and so are 0 and FALSE, which only leaves
48123
+ // the empty string.
48124
+ if (value !== "") {
48125
+ newContent = (value ?? "").toString();
48126
+ newFormat = evaluatedCell.format;
48127
+ }
47940
48128
  }
47941
48129
  }
47942
- const exportedSheetData = data.sheets.find((sheet) => sheet.id === position.sheetId);
47943
48130
  const exportedCellData = exportedSheetData.cells[xc] || {};
47944
48131
  const format = newFormat
47945
48132
  ? getItemId(newFormat, data.formats)
@@ -49605,62 +49792,6 @@ stores.inject(MyMetaStore, storeInstance);
49605
49792
  }
49606
49793
  }
49607
49794
 
49608
- /**
49609
- * This is a generic event bus based on the Owl event bus.
49610
- * This bus however ensures type safety across events and subscription callbacks.
49611
- */
49612
- class EventBus {
49613
- subscriptions = {};
49614
- /**
49615
- * Add a listener for the 'eventType' events.
49616
- *
49617
- * Note that the 'owner' of this event can be anything, but will more likely
49618
- * be a component or a class. The idea is that the callback will be called with
49619
- * the proper owner bound.
49620
- *
49621
- * Also, the owner should be kind of unique. This will be used to remove the
49622
- * listener.
49623
- */
49624
- on(type, owner, callback) {
49625
- if (!callback) {
49626
- throw new Error("Missing callback");
49627
- }
49628
- if (!this.subscriptions[type]) {
49629
- this.subscriptions[type] = [];
49630
- }
49631
- this.subscriptions[type].push({
49632
- owner,
49633
- callback,
49634
- });
49635
- }
49636
- /**
49637
- * Emit an event of type 'eventType'. Any extra arguments will be passed to
49638
- * the listeners callback.
49639
- */
49640
- trigger(type, payload) {
49641
- const subs = this.subscriptions[type] || [];
49642
- for (let i = 0, iLen = subs.length; i < iLen; i++) {
49643
- const sub = subs[i];
49644
- sub.callback.call(sub.owner, payload);
49645
- }
49646
- }
49647
- /**
49648
- * Remove a listener
49649
- */
49650
- off(eventType, owner) {
49651
- const subs = this.subscriptions[eventType];
49652
- if (subs) {
49653
- this.subscriptions[eventType] = subs.filter((s) => s.owner !== owner);
49654
- }
49655
- }
49656
- /**
49657
- * Remove all subscriptions.
49658
- */
49659
- clear() {
49660
- this.subscriptions = {};
49661
- }
49662
- }
49663
-
49664
49795
  /*
49665
49796
  * This file contains the specifics transformations
49666
49797
  */
@@ -51985,7 +52116,7 @@ stores.inject(MyMetaStore, storeInstance);
51985
52116
  paintFormatStatus = "inactive";
51986
52117
  originSheetId;
51987
52118
  copiedData;
51988
- _isCutOperation;
52119
+ _isCutOperation = false;
51989
52120
  // ---------------------------------------------------------------------------
51990
52121
  // Command Handling
51991
52122
  // ---------------------------------------------------------------------------
@@ -51997,14 +52128,17 @@ stores.inject(MyMetaStore, storeInstance);
51997
52128
  case "PASTE_FROM_OS_CLIPBOARD": {
51998
52129
  const copiedData = this.convertOSClipboardData(cmd.text);
51999
52130
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52000
- return this.isPasteAllowed(cmd.target, copiedData, { pasteOption });
52131
+ return this.isPasteAllowed(cmd.target, copiedData, { pasteOption, isCutOperation: false });
52001
52132
  }
52002
52133
  case "PASTE": {
52003
52134
  if (!this.copiedData) {
52004
52135
  return "EmptyClipboard" /* CommandResult.EmptyClipboard */;
52005
52136
  }
52006
52137
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52007
- return this.isPasteAllowed(cmd.target, this.copiedData, { pasteOption });
52138
+ return this.isPasteAllowed(cmd.target, this.copiedData, {
52139
+ pasteOption: pasteOption,
52140
+ isCutOperation: this._isCutOperation,
52141
+ });
52008
52142
  }
52009
52143
  case "COPY_PASTE_CELLS_ABOVE": {
52010
52144
  const zones = this.getters.getSelectedZones();
@@ -52022,13 +52156,13 @@ stores.inject(MyMetaStore, storeInstance);
52022
52156
  }
52023
52157
  case "INSERT_CELL": {
52024
52158
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
52025
- const copiedData = this.copy("CUT", cut);
52026
- return this.isPasteAllowed(paste, copiedData, {});
52159
+ const copiedData = this.copy(cut);
52160
+ return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
52027
52161
  }
52028
52162
  case "DELETE_CELL": {
52029
52163
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
52030
- const copiedData = this.copy("CUT", cut);
52031
- return this.isPasteAllowed(paste, copiedData, {});
52164
+ const copiedData = this.copy(cut);
52165
+ return this.isPasteAllowed(paste, copiedData, { isCutOperation: true });
52032
52166
  }
52033
52167
  case "ACTIVATE_PAINT_FORMAT": {
52034
52168
  if (this.paintFormatStatus !== "inactive") {
@@ -52046,23 +52180,27 @@ stores.inject(MyMetaStore, storeInstance);
52046
52180
  const zones = this.getters.getSelectedZones();
52047
52181
  this.status = "visible";
52048
52182
  this.originSheetId = this.getters.getActiveSheetId();
52049
- this.copiedData = this.copy(cmd.type, zones);
52183
+ this.copiedData = this.copy(zones);
52184
+ this._isCutOperation = cmd.type === "CUT";
52050
52185
  break;
52051
52186
  case "PASTE_FROM_OS_CLIPBOARD": {
52187
+ this._isCutOperation = false;
52052
52188
  this.copiedData = this.convertOSClipboardData(cmd.text);
52053
52189
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52054
- this.paste(cmd.target, {
52190
+ this.paste(cmd.target, this.copiedData, {
52055
52191
  pasteOption,
52056
52192
  selectTarget: true,
52193
+ isCutOperation: false,
52057
52194
  });
52058
52195
  this.status = "invisible";
52059
52196
  break;
52060
52197
  }
52061
52198
  case "PASTE": {
52062
52199
  const pasteOption = cmd.pasteOption || (this.paintFormatStatus !== "inactive" ? "onlyFormat" : undefined);
52063
- this.paste(cmd.target, {
52200
+ this.paste(cmd.target, this.copiedData, {
52064
52201
  pasteOption,
52065
52202
  selectTarget: true,
52203
+ isCutOperation: this._isCutOperation,
52066
52204
  });
52067
52205
  if (this.paintFormatStatus === "oneOff") {
52068
52206
  this.paintFormatStatus = "inactive";
@@ -52083,9 +52221,9 @@ stores.inject(MyMetaStore, storeInstance);
52083
52221
  top: multipleRowsInSelection ? zone.top : zone.top - 1,
52084
52222
  };
52085
52223
  this.originSheetId = this.getters.getActiveSheetId();
52086
- this.copiedData = this.copy("COPY", [copyTarget]);
52087
- this.paste([zone], {
52088
- pasteOption: undefined,
52224
+ const copiedData = this.copy([copyTarget]);
52225
+ this.paste([zone], copiedData, {
52226
+ isCutOperation: false,
52089
52227
  selectTarget: true,
52090
52228
  });
52091
52229
  }
@@ -52100,9 +52238,9 @@ stores.inject(MyMetaStore, storeInstance);
52100
52238
  left: multipleColsInSelection ? zone.left : zone.left - 1,
52101
52239
  };
52102
52240
  this.originSheetId = this.getters.getActiveSheetId();
52103
- this.copiedData = this.copy("COPY", [copyTarget]);
52104
- this.paste([zone], {
52105
- pasteOption: undefined,
52241
+ const copiedData = this.copy([copyTarget]);
52242
+ this.paste([zone], copiedData, {
52243
+ isCutOperation: false,
52106
52244
  selectTarget: true,
52107
52245
  });
52108
52246
  }
@@ -52118,20 +52256,20 @@ stores.inject(MyMetaStore, storeInstance);
52118
52256
  }
52119
52257
  break;
52120
52258
  }
52121
- this.copiedData = this.copy("CUT", cut);
52122
- this.paste(paste, {});
52259
+ const copiedData = this.copy(cut);
52260
+ this.paste(paste, copiedData, { isCutOperation: true });
52123
52261
  break;
52124
52262
  }
52125
52263
  case "INSERT_CELL": {
52126
52264
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
52127
- this.copiedData = this.copy("CUT", cut);
52128
- this.paste(paste, {});
52265
+ const copiedData = this.copy(cut);
52266
+ this.paste(paste, copiedData, { isCutOperation: true });
52129
52267
  break;
52130
52268
  }
52131
52269
  case "ADD_COLUMNS_ROWS": {
52132
52270
  this.status = "invisible";
52133
52271
  // If we add a col/row inside or before the cut area, we invalidate the clipboard
52134
- if (this._isCutOperation !== true) {
52272
+ if (this._isCutOperation !== true || cmd.sheetId !== this.copiedData?.sheetId) {
52135
52273
  return;
52136
52274
  }
52137
52275
  const isClipboardDirty = this.isColRowDirtyingClipboard(cmd.position === "before" ? cmd.base : cmd.base + 1, cmd.dimension);
@@ -52143,7 +52281,7 @@ stores.inject(MyMetaStore, storeInstance);
52143
52281
  case "REMOVE_COLUMNS_ROWS": {
52144
52282
  this.status = "invisible";
52145
52283
  // If we remove a col/row inside or before the cut area, we invalidate the clipboard
52146
- if (this._isCutOperation !== true) {
52284
+ if (this._isCutOperation !== true || cmd.sheetId !== this.copiedData?.sheetId) {
52147
52285
  return;
52148
52286
  }
52149
52287
  for (let el of cmd.elements) {
@@ -52157,7 +52295,8 @@ stores.inject(MyMetaStore, storeInstance);
52157
52295
  break;
52158
52296
  }
52159
52297
  case "REPEAT_PASTE": {
52160
- this.paste(cmd.target, {
52298
+ this.paste(cmd.target, this.copiedData, {
52299
+ isCutOperation: false,
52161
52300
  pasteOption: cmd.pasteOption,
52162
52301
  selectTarget: true,
52163
52302
  });
@@ -52165,7 +52304,7 @@ stores.inject(MyMetaStore, storeInstance);
52165
52304
  }
52166
52305
  case "ACTIVATE_PAINT_FORMAT": {
52167
52306
  const zones = this.getters.getSelectedZones();
52168
- this.copiedData = this.copy("COPY", zones);
52307
+ this.copiedData = this.copy(zones);
52169
52308
  this.status = "visible";
52170
52309
  if (cmd.persistent) {
52171
52310
  this.paintFormatStatus = "persistent";
@@ -52196,7 +52335,6 @@ stores.inject(MyMetaStore, storeInstance);
52196
52335
  }
52197
52336
  }
52198
52337
  convertOSClipboardData(clipboardData) {
52199
- this._isCutOperation = false;
52200
52338
  const handlers = clipboardHandlersRegistries.figureHandlers
52201
52339
  .getAll()
52202
52340
  .map((handler) => new handler(this.getters, this.dispatch));
@@ -52234,7 +52372,6 @@ stores.inject(MyMetaStore, storeInstance);
52234
52372
  for (const handler of this.selectClipboardHandlers(copiedData)) {
52235
52373
  const result = handler.isPasteAllowed(this.getters.getActiveSheetId(), target, copiedData, {
52236
52374
  ...options,
52237
- isCutOperation: this.isCutOperation(),
52238
52375
  });
52239
52376
  if (result !== "Success" /* CommandResult.Success */) {
52240
52377
  return result;
@@ -52257,9 +52394,8 @@ stores.inject(MyMetaStore, storeInstance);
52257
52394
  }
52258
52395
  return false;
52259
52396
  }
52260
- copy(operation, zones) {
52397
+ copy(zones) {
52261
52398
  let copiedData = {};
52262
- this._isCutOperation = operation === "CUT";
52263
52399
  const clipboardData = this.getClipboardData(zones);
52264
52400
  for (const handler of this.selectClipboardHandlers(clipboardData)) {
52265
52401
  const data = handler.copy(clipboardData);
@@ -52267,8 +52403,8 @@ stores.inject(MyMetaStore, storeInstance);
52267
52403
  }
52268
52404
  return copiedData;
52269
52405
  }
52270
- paste(zones, options) {
52271
- if (!this.copiedData) {
52406
+ paste(zones, copiedData, options) {
52407
+ if (!copiedData) {
52272
52408
  return;
52273
52409
  }
52274
52410
  let zone = undefined;
@@ -52276,12 +52412,9 @@ stores.inject(MyMetaStore, storeInstance);
52276
52412
  let target = {
52277
52413
  zones,
52278
52414
  };
52279
- const handlers = this.selectClipboardHandlers(this.copiedData);
52415
+ const handlers = this.selectClipboardHandlers(copiedData);
52280
52416
  for (const handler of handlers) {
52281
- const currentTarget = handler.getPasteTarget(zones, this.copiedData, {
52282
- ...options,
52283
- isCutOperation: this.isCutOperation(),
52284
- });
52417
+ const currentTarget = handler.getPasteTarget(zones, copiedData, options);
52285
52418
  if (currentTarget.figureId) {
52286
52419
  target.figureId = currentTarget.figureId;
52287
52420
  }
@@ -52297,7 +52430,7 @@ stores.inject(MyMetaStore, storeInstance);
52297
52430
  if (zone !== undefined) {
52298
52431
  this.addMissingDimensions(this.getters.getActiveSheetId(), zone.right - zone.left + 1, zone.bottom - zone.top + 1, zone.left, zone.top);
52299
52432
  }
52300
- handlers.forEach((handler) => handler.paste(target, this.copiedData, { ...options, isCutOperation: this.isCutOperation() }));
52433
+ handlers.forEach((handler) => handler.paste(target, copiedData, options));
52301
52434
  if (!options?.selectTarget) {
52302
52435
  return;
52303
52436
  }
@@ -54767,6 +54900,7 @@ stores.inject(MyMetaStore, storeInstance);
54767
54900
  sheetDivRef = owl.useRef("sheetDiv");
54768
54901
  sheetNameRef = owl.useRef("sheetNameSpan");
54769
54902
  editionState = "initializing";
54903
+ DOMFocusableElementStore;
54770
54904
  setup() {
54771
54905
  owl.onMounted(() => {
54772
54906
  if (this.isSheetActive) {
@@ -54779,6 +54913,7 @@ stores.inject(MyMetaStore, storeInstance);
54779
54913
  this.focusInputAndSelectContent();
54780
54914
  }
54781
54915
  });
54916
+ this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
54782
54917
  }
54783
54918
  focusInputAndSelectContent() {
54784
54919
  if (!this.state.isEditing || !this.sheetNameRef.el)
@@ -54820,9 +54955,11 @@ stores.inject(MyMetaStore, storeInstance);
54820
54955
  if (ev.key === "Enter") {
54821
54956
  ev.preventDefault();
54822
54957
  this.stopEdition();
54958
+ this.DOMFocusableElementStore.focus();
54823
54959
  }
54824
54960
  if (ev.key === "Escape") {
54825
54961
  this.cancelEdition();
54962
+ this.DOMFocusableElementStore.focus();
54826
54963
  }
54827
54964
  }
54828
54965
  onClickSheetName(ev) {
@@ -56778,16 +56915,25 @@ stores.inject(MyMetaStore, storeInstance);
56778
56915
  }
56779
56916
  }, () => [this.env.model.getters.getActiveSheetId()]);
56780
56917
  owl.useExternalListener(window, "resize", () => this.render(true));
56918
+ // For some reason, the wheel event is not properly registered inside templates
56919
+ // in Chromium-based browsers based on chromium 125
56920
+ // This hack ensures the event declared in the template is properly registered/working
56921
+ owl.useExternalListener(document.body, "wheel", () => { });
56781
56922
  this.bindModelEvents();
56782
56923
  owl.onWillUpdateProps((nextProps) => {
56783
56924
  if (nextProps.model !== this.props.model) {
56784
56925
  throw new Error("Changing the props model is not supported at the moment.");
56785
56926
  }
56786
56927
  });
56928
+ const render = batched(this.render.bind(this, true));
56787
56929
  owl.onMounted(() => {
56788
56930
  this.checkViewportSize();
56931
+ stores.on("store-updated", this, render);
56932
+ });
56933
+ owl.onWillUnmount(() => {
56934
+ this.unbindModelEvents();
56935
+ stores.off("store-updated", this);
56789
56936
  });
56790
- owl.onWillUnmount(() => this.unbindModelEvents());
56791
56937
  owl.onPatched(() => {
56792
56938
  this.checkViewportSize();
56793
56939
  });
@@ -59536,7 +59682,11 @@ stores.inject(MyMetaStore, storeInstance);
59536
59682
  let cellNode = escapeXml ``;
59537
59683
  // Either formula or static value inside the cell
59538
59684
  if (cell.isFormula) {
59539
- ({ attrs: additionalAttrs, node: cellNode } = addFormula(cell));
59685
+ const res = addFormula(cell);
59686
+ if (!res) {
59687
+ continue;
59688
+ }
59689
+ ({ attrs: additionalAttrs, node: cellNode } = res);
59540
59690
  }
59541
59691
  else if (cell.content && isMarkdownLink(cell.content)) {
59542
59692
  const { label } = parseMarkdownLink(cell.content);
@@ -60616,9 +60766,9 @@ stores.inject(MyMetaStore, storeInstance);
60616
60766
  exports.tokenize = tokenize;
60617
60767
 
60618
60768
 
60619
- __info__.version = "17.2.7";
60620
- __info__.date = "2024-05-15T09:20:44.429Z";
60621
- __info__.hash = "57e89fa";
60769
+ __info__.version = "17.2.9";
60770
+ __info__.date = "2024-06-03T14:56:21.684Z";
60771
+ __info__.hash = "086af6d";
60622
60772
 
60623
60773
 
60624
60774
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);