@odoo/o-spreadsheet 18.2.0-alpha.4 → 18.2.0-alpha.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 18.2.0-alpha.4
6
- * @date 2025-01-29T06:30:12.773Z
7
- * @hash 6838c26
5
+ * @version 18.2.0-alpha.5
6
+ * @date 2025-01-31T07:59:30.667Z
7
+ * @hash efce841
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -3360,11 +3360,11 @@
3360
3360
  * number from the point of view of the isNumber function.
3361
3361
  */
3362
3362
  function parseNumber(str, locale) {
3363
+ // remove invaluable characters
3364
+ str = str.replace(getInvaluableSymbolsRegexp(locale), "");
3363
3365
  if (locale.decimalSeparator !== ".") {
3364
3366
  str = str.replace(locale.decimalSeparator, ".");
3365
3367
  }
3366
- // remove invaluable characters
3367
- str = str.replace(getInvaluableSymbolsRegexp(locale), "");
3368
3368
  let n = Number(str);
3369
3369
  if (isNaN(n) && str.includes("%")) {
3370
3370
  n = Number(str.split("%")[0]);
@@ -32537,36 +32537,58 @@ stores.inject(MyMetaStore, storeInstance);
32537
32537
  static maxSize = { maxHeight: ERROR_TOOLTIP_MAX_HEIGHT };
32538
32538
  static template = "o-spreadsheet-ErrorToolTip";
32539
32539
  static props = {
32540
- errors: Array,
32540
+ cellPosition: Object,
32541
32541
  onClosed: { type: Function, optional: true },
32542
32542
  };
32543
+ get dataValidationErrorMessage() {
32544
+ return this.env.model.getters.getInvalidDataValidationMessage(this.props.cellPosition);
32545
+ }
32546
+ get evaluationError() {
32547
+ const cell = this.env.model.getters.getEvaluatedCell(this.props.cellPosition);
32548
+ if (cell.message) {
32549
+ return cell;
32550
+ }
32551
+ return undefined;
32552
+ }
32553
+ get errorOriginPositionString() {
32554
+ const evaluationError = this.evaluationError;
32555
+ const position = evaluationError?.errorOriginPosition;
32556
+ if (!position || deepEquals(position, this.props.cellPosition)) {
32557
+ return "";
32558
+ }
32559
+ const sheetId = position.sheetId;
32560
+ return this.env.model.getters.getRangeString(this.env.model.getters.getRangeFromZone(sheetId, positionToZone(position)), this.env.model.getters.getActiveSheetId());
32561
+ }
32562
+ selectCell() {
32563
+ const position = this.evaluationError?.errorOriginPosition;
32564
+ if (!position) {
32565
+ return;
32566
+ }
32567
+ const activeSheetId = this.env.model.getters.getActiveSheetId();
32568
+ if (position.sheetId !== activeSheetId) {
32569
+ this.env.model.dispatch("ACTIVATE_SHEET", {
32570
+ sheetIdFrom: activeSheetId,
32571
+ sheetIdTo: position.sheetId,
32572
+ });
32573
+ }
32574
+ this.env.model.selection.selectCell(position.col, position.row);
32575
+ }
32543
32576
  }
32544
32577
  const ErrorToolTipPopoverBuilder = {
32545
32578
  onHover: (position, getters) => {
32546
32579
  const cell = getters.getEvaluatedCell(position);
32547
- const errors = [];
32548
- if (cell.type === CellValueType.error && !!cell.message) {
32549
- errors.push({
32550
- title: _t("Error"),
32551
- message: cell.message,
32552
- });
32553
- }
32554
- const validationErrorMessage = getters.getInvalidDataValidationMessage(position);
32555
- if (validationErrorMessage) {
32556
- errors.push({
32557
- title: _t("Invalid"),
32558
- message: validationErrorMessage,
32559
- });
32560
- }
32561
- if (!errors.length) {
32562
- return { isOpen: false };
32580
+ if ((cell.type === CellValueType.error && !!cell.message) ||
32581
+ getters.getInvalidDataValidationMessage(position)) {
32582
+ return {
32583
+ isOpen: true,
32584
+ props: {
32585
+ cellPosition: position,
32586
+ },
32587
+ Component: ErrorToolTip,
32588
+ cellCorner: "TopRight",
32589
+ };
32563
32590
  }
32564
- return {
32565
- isOpen: true,
32566
- props: { errors: errors },
32567
- Component: ErrorToolTip,
32568
- cellCorner: "TopRight",
32569
- };
32591
+ return { isOpen: false };
32570
32592
  },
32571
32593
  };
32572
32594
 
@@ -33130,6 +33152,100 @@ stores.inject(MyMetaStore, storeInstance);
33130
33152
  function getOpenedMenus() {
33131
33153
  return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
33132
33154
  }
33155
+ function getCurrentSelection(el) {
33156
+ let { startElement, endElement, startSelectionOffset, endSelectionOffset } = getStartAndEndSelection(el);
33157
+ let startSizeBefore = findSelectionIndex(el, startElement, startSelectionOffset);
33158
+ let endSizeBefore = findSelectionIndex(el, endElement, endSelectionOffset);
33159
+ return {
33160
+ start: startSizeBefore,
33161
+ end: endSizeBefore,
33162
+ };
33163
+ }
33164
+ function getStartAndEndSelection(el) {
33165
+ const selection = document.getSelection();
33166
+ return {
33167
+ startElement: selection.anchorNode || el,
33168
+ startSelectionOffset: selection.anchorOffset,
33169
+ endElement: selection.focusNode || el,
33170
+ endSelectionOffset: selection.focusOffset,
33171
+ };
33172
+ }
33173
+ /**
33174
+ * Computes the text 'index' inside this.el based on the currently selected node and its offset.
33175
+ * The selected node is either a Text node or an Element node.
33176
+ *
33177
+ * case 1 -Text node:
33178
+ * the offset is the number of characters from the start of the node. We have to add this offset to the
33179
+ * content length of all previous nodes.
33180
+ *
33181
+ * case 2 - Element node:
33182
+ * the offset is the number of child nodes before the selected node. We have to add the content length of
33183
+ * all the nodes prior to the selected node as well as the content of the child node before the offset.
33184
+ *
33185
+ * See the MDN documentation for more details.
33186
+ * https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
33187
+ * https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
33188
+ *
33189
+ */
33190
+ function findSelectionIndex(el, nodeToFind, nodeOffset) {
33191
+ let usedCharacters = 0;
33192
+ let it = iterateChildren(el);
33193
+ let current = it.next();
33194
+ let isFirstParagraph = true;
33195
+ while (!current.done && current.value !== nodeToFind) {
33196
+ if (!current.value.hasChildNodes()) {
33197
+ if (current.value.textContent) {
33198
+ usedCharacters += current.value.textContent.length;
33199
+ }
33200
+ }
33201
+ // One new paragraph = one new line character, except for the first paragraph
33202
+ if (current.value.nodeName === "P" ||
33203
+ (current.value.nodeName === "DIV" && current.value !== el) // On paste, the HTML may contain <div> instead of <p>
33204
+ ) {
33205
+ if (isFirstParagraph) {
33206
+ isFirstParagraph = false;
33207
+ }
33208
+ else {
33209
+ usedCharacters++;
33210
+ }
33211
+ }
33212
+ current = it.next();
33213
+ }
33214
+ if (current.value !== nodeToFind) {
33215
+ /** This situation can happen if the code is called while the selection is not currently on the element.
33216
+ * In this case, we return 0 because we don't know the size of the text before the selection.
33217
+ *
33218
+ * A known occurrence is triggered since the introduction of commit d4663158 (PR #2038).
33219
+ */
33220
+ return 0;
33221
+ }
33222
+ else {
33223
+ if (!current.value.hasChildNodes()) {
33224
+ usedCharacters += nodeOffset;
33225
+ }
33226
+ else {
33227
+ const children = [...current.value.childNodes].slice(0, nodeOffset);
33228
+ usedCharacters += children.reduce((acc, child, index) => {
33229
+ if (child.textContent !== null) {
33230
+ // need to account for paragraph nodes that implicitly add a new line
33231
+ // except for the last paragraph
33232
+ let chars = child.textContent.length;
33233
+ if (child.nodeName === "P" && index !== children.length - 1) {
33234
+ chars++;
33235
+ }
33236
+ return acc + chars;
33237
+ }
33238
+ else {
33239
+ return acc;
33240
+ }
33241
+ }, 0);
33242
+ }
33243
+ }
33244
+ if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
33245
+ usedCharacters++;
33246
+ }
33247
+ return usedCharacters;
33248
+ }
33133
33249
  const letterRegex = /^[a-zA-Z]$/;
33134
33250
  /**
33135
33251
  * Transform a keyboard event into a shortcut string that represent this event. The letters keys will be uppercased.
@@ -40337,6 +40453,10 @@ stores.inject(MyMetaStore, storeInstance);
40337
40453
  if (currentStart === start && currentEnd === end) {
40338
40454
  return;
40339
40455
  }
40456
+ if (selection.rangeCount === 0) {
40457
+ const range = document.createRange();
40458
+ selection.addRange(range);
40459
+ }
40340
40460
  const currentRange = selection.getRangeAt(0);
40341
40461
  let range;
40342
40462
  if (this.el.contains(currentRange.startContainer)) {
@@ -40499,7 +40619,7 @@ stores.inject(MyMetaStore, storeInstance);
40499
40619
  if (!focusedNode || !this.el.contains(focusedNode))
40500
40620
  return;
40501
40621
  const element = focusedNode instanceof HTMLElement ? focusedNode : focusedNode.parentElement;
40502
- element?.scrollIntoView({ block: "nearest" });
40622
+ element?.scrollIntoView?.({ block: "nearest" });
40503
40623
  }
40504
40624
  /**
40505
40625
  * remove the current selection of the user
@@ -40519,100 +40639,7 @@ stores.inject(MyMetaStore, storeInstance);
40519
40639
  * finds the indexes of the current selection.
40520
40640
  * */
40521
40641
  getCurrentSelection() {
40522
- let { startElement, endElement, startSelectionOffset, endSelectionOffset } = this.getStartAndEndSelection();
40523
- let startSizeBefore = this.findSelectionIndex(startElement, startSelectionOffset);
40524
- let endSizeBefore = this.findSelectionIndex(endElement, endSelectionOffset);
40525
- return {
40526
- start: startSizeBefore,
40527
- end: endSizeBefore,
40528
- };
40529
- }
40530
- /**
40531
- * Computes the text 'index' inside this.el based on the currently selected node and its offset.
40532
- * The selected node is either a Text node or an Element node.
40533
- *
40534
- * case 1 -Text node:
40535
- * the offset is the number of characters from the start of the node. We have to add this offset to the
40536
- * content length of all previous nodes.
40537
- *
40538
- * case 2 - Element node:
40539
- * the offset is the number of child nodes before the selected node. We have to add the content length of
40540
- * all the bnodes prior to the selected node as well as the content of the child node before the offset.
40541
- *
40542
- * See the MDN documentation for more details.
40543
- * https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
40544
- * https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
40545
- *
40546
- */
40547
- findSelectionIndex(nodeToFind, nodeOffset) {
40548
- let usedCharacters = 0;
40549
- let it = iterateChildren(this.el);
40550
- let current = it.next();
40551
- let isFirstParagraph = true;
40552
- while (!current.done && current.value !== nodeToFind) {
40553
- if (!current.value.hasChildNodes()) {
40554
- if (current.value.textContent) {
40555
- usedCharacters += current.value.textContent.length;
40556
- }
40557
- }
40558
- // One new paragraph = one new line character, except for the first paragraph
40559
- if (current.value.nodeName === "P" ||
40560
- (current.value.nodeName === "DIV" && current.value !== this.el) // On paste, the HTML may contain <div> instead of <p>
40561
- ) {
40562
- if (isFirstParagraph) {
40563
- isFirstParagraph = false;
40564
- }
40565
- else {
40566
- usedCharacters++;
40567
- }
40568
- }
40569
- current = it.next();
40570
- }
40571
- if (current.value !== nodeToFind) {
40572
- /** This situation can happen if the code is called while the selection is not currently on the ContentEditableHelper.
40573
- * In this case, we return 0 because we don't know the size of the text before the selection.
40574
- *
40575
- * A known occurence is triggered since the introduction of commit d4663158 (PR #2038).
40576
- *
40577
- * FIXME: find a way to test eventhough the selection API is not available in jsDOM.
40578
- */
40579
- return 0;
40580
- }
40581
- else {
40582
- if (!current.value.hasChildNodes()) {
40583
- usedCharacters += nodeOffset;
40584
- }
40585
- else {
40586
- const children = [...current.value.childNodes].slice(0, nodeOffset);
40587
- usedCharacters += children.reduce((acc, child, index) => {
40588
- if (child.textContent !== null) {
40589
- // need to account for paragraph nodes that implicitely add a new line
40590
- // except for the last paragraph
40591
- let chars = child.textContent.length;
40592
- if (child.nodeName === "P" && index !== children.length - 1) {
40593
- chars++;
40594
- }
40595
- return acc + chars;
40596
- }
40597
- else {
40598
- return acc;
40599
- }
40600
- }, 0);
40601
- }
40602
- }
40603
- if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent === "") {
40604
- usedCharacters++;
40605
- }
40606
- return usedCharacters;
40607
- }
40608
- getStartAndEndSelection() {
40609
- const selection = document.getSelection();
40610
- return {
40611
- startElement: selection.anchorNode || this.el,
40612
- startSelectionOffset: selection.anchorOffset,
40613
- endElement: selection.focusNode || this.el,
40614
- endSelectionOffset: selection.focusOffset,
40615
- };
40642
+ return getCurrentSelection(this.el);
40616
40643
  }
40617
40644
  getText() {
40618
40645
  let text = "";
@@ -40876,6 +40903,12 @@ stores.inject(MyMetaStore, storeInstance);
40876
40903
  }
40877
40904
  this.contentHelper.updateEl(el);
40878
40905
  });
40906
+ this.env.model.selection.observe(this, {
40907
+ handleEvent: () => this.autoCompleteState.hide(),
40908
+ });
40909
+ owl.onWillUnmount(() => {
40910
+ this.env.model.selection.detachObserver(this);
40911
+ });
40879
40912
  owl.useEffect(() => {
40880
40913
  this.processContent();
40881
40914
  if (document.activeElement === this.contentHelper.el &&
@@ -49215,7 +49248,7 @@ stores.inject(MyMetaStore, storeInstance);
49215
49248
  axisStartEndPositions.push({ x: axis.position, y: figure.y + figure.height });
49216
49249
  break;
49217
49250
  }
49218
- return axisStartEndPositions.some(getters.isPositionVisible);
49251
+ return axisStartEndPositions.some(getters.isPixelPositionVisible);
49219
49252
  }
49220
49253
  /**
49221
49254
  * Get a snap line for the given figure, if the figure can snap to any other figure
@@ -51242,8 +51275,8 @@ stores.inject(MyMetaStore, storeInstance);
51242
51275
  previousColIndex = col;
51243
51276
  }
51244
51277
  else {
51245
- nextColIndex = this.findNextEmptyCol(col, right, row);
51246
- previousColIndex = this.findPreviousEmptyCol(col, left, row);
51278
+ nextColIndex = box.border?.right ? zone.right : this.findNextEmptyCol(col, right, row);
51279
+ previousColIndex = box.border?.left ? zone.left : this.findPreviousEmptyCol(col, left, row);
51247
51280
  box.isOverflow = true;
51248
51281
  }
51249
51282
  switch (align) {
@@ -52716,7 +52749,7 @@ stores.inject(MyMetaStore, storeInstance);
52716
52749
  // map and slice preserve empty values and do not set `undefined` instead
52717
52750
  const bordersCopy = borders
52718
52751
  .slice()
52719
- .map((col) => col?.slice().map((border) => ({ ...border })));
52752
+ .map((col) => col?.slice().map((border) => deepCopy(border)));
52720
52753
  this.history.update("borders", cmd.sheetIdTo, bordersCopy);
52721
52754
  }
52722
52755
  break;
@@ -52746,32 +52779,12 @@ stores.inject(MyMetaStore, storeInstance);
52746
52779
  const elements = [...cmd.elements].sort((a, b) => b - a);
52747
52780
  for (const group of groupConsecutive(elements)) {
52748
52781
  if (cmd.dimension === "COL") {
52749
- if (group[0] >= this.getters.getNumberCols(cmd.sheetId)) {
52750
- for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
52751
- this.history.update("borders", cmd.sheetId, group[0] + 1, row, "vertical", undefined);
52752
- }
52753
- }
52754
- if (group[group.length - 1] === 0) {
52755
- for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
52756
- this.history.update("borders", cmd.sheetId, 0, row, "vertical", undefined);
52757
- }
52758
- }
52759
- const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
52782
+ const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1], group[0]);
52760
52783
  this.clearInsideBorders(cmd.sheetId, [zone]);
52761
52784
  this.shiftBordersHorizontally(cmd.sheetId, group[0] + 1, -group.length);
52762
52785
  }
52763
52786
  else {
52764
- if (group[0] >= this.getters.getNumberRows(cmd.sheetId)) {
52765
- for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
52766
- this.history.update("borders", cmd.sheetId, col, group[0] + 1, "horizontal", undefined);
52767
- }
52768
- }
52769
- if (group[group.length - 1] === 0) {
52770
- for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
52771
- this.history.update("borders", cmd.sheetId, col, 0, "horizontal", undefined);
52772
- }
52773
- }
52774
- const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
52787
+ const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1], group[0]);
52775
52788
  this.clearInsideBorders(cmd.sheetId, [zone]);
52776
52789
  this.shiftBordersVertically(cmd.sheetId, group[0] + 1, -group.length);
52777
52790
  }
@@ -52796,16 +52809,12 @@ stores.inject(MyMetaStore, storeInstance);
52796
52809
  let colLeftOfInsertion;
52797
52810
  let colRightOfInsertion;
52798
52811
  if (cmd.position === "before") {
52799
- this.shiftBordersHorizontally(cmd.sheetId, cmd.base, cmd.quantity, {
52800
- moveFirstLeftBorder: true,
52801
- });
52812
+ this.shiftBordersHorizontally(cmd.sheetId, cmd.base, cmd.quantity);
52802
52813
  colLeftOfInsertion = cmd.base - 1;
52803
52814
  colRightOfInsertion = cmd.base + cmd.quantity;
52804
52815
  }
52805
52816
  else {
52806
- this.shiftBordersHorizontally(cmd.sheetId, cmd.base + 1, cmd.quantity, {
52807
- moveFirstLeftBorder: false,
52808
- });
52817
+ this.shiftBordersHorizontally(cmd.sheetId, cmd.base + 1, cmd.quantity);
52809
52818
  colLeftOfInsertion = cmd.base;
52810
52819
  colRightOfInsertion = cmd.base + cmd.quantity + 1;
52811
52820
  }
@@ -52820,16 +52829,12 @@ stores.inject(MyMetaStore, storeInstance);
52820
52829
  let rowAboveInsertion;
52821
52830
  let rowBelowInsertion;
52822
52831
  if (cmd.position === "before") {
52823
- this.shiftBordersVertically(cmd.sheetId, cmd.base, cmd.quantity, {
52824
- moveFirstTopBorder: true,
52825
- });
52832
+ this.shiftBordersVertically(cmd.sheetId, cmd.base, cmd.quantity);
52826
52833
  rowAboveInsertion = cmd.base - 1;
52827
52834
  rowBelowInsertion = cmd.base + cmd.quantity;
52828
52835
  }
52829
52836
  else {
52830
- this.shiftBordersVertically(cmd.sheetId, cmd.base + 1, cmd.quantity, {
52831
- moveFirstTopBorder: false,
52832
- });
52837
+ this.shiftBordersVertically(cmd.sheetId, cmd.base + 1, cmd.quantity);
52833
52838
  rowAboveInsertion = cmd.base;
52834
52839
  rowBelowInsertion = cmd.base + cmd.quantity + 1;
52835
52840
  }
@@ -52839,16 +52844,8 @@ stores.inject(MyMetaStore, storeInstance);
52839
52844
  // Getters
52840
52845
  // ---------------------------------------------------------------------------
52841
52846
  getCellBorder({ sheetId, col, row }) {
52842
- const border = {
52843
- top: this.borders[sheetId]?.[col]?.[row]?.horizontal,
52844
- bottom: this.borders[sheetId]?.[col]?.[row + 1]?.horizontal,
52845
- left: this.borders[sheetId]?.[col]?.[row]?.vertical,
52846
- right: this.borders[sheetId]?.[col + 1]?.[row]?.vertical,
52847
- };
52848
- if (!border.bottom && !border.left && !border.right && !border.top) {
52849
- return null;
52850
- }
52851
- return border;
52847
+ const border = this.borders[sheetId]?.[col]?.[row];
52848
+ return border?.top || border?.bottom || border?.left || border?.right ? deepCopy(border) : null;
52852
52849
  }
52853
52850
  getBordersColors(sheetId) {
52854
52851
  const colors = [];
@@ -52856,11 +52853,13 @@ stores.inject(MyMetaStore, storeInstance);
52856
52853
  if (sheetBorders) {
52857
52854
  for (const borders of sheetBorders.filter(isDefined)) {
52858
52855
  for (const cellBorder of borders) {
52859
- if (cellBorder?.horizontal) {
52860
- colors.push(cellBorder.horizontal.color);
52861
- }
52862
- if (cellBorder?.vertical) {
52863
- colors.push(cellBorder.vertical.color);
52856
+ if (cellBorder) {
52857
+ for (const direction of ["top", "bottom", "left", "right"]) {
52858
+ const color = cellBorder[direction]?.color;
52859
+ if (color) {
52860
+ colors.push(color);
52861
+ }
52862
+ }
52864
52863
  }
52865
52864
  }
52866
52865
  }
@@ -52913,7 +52912,7 @@ stores.inject(MyMetaStore, storeInstance);
52913
52912
  getCommonSides(border1, border2) {
52914
52913
  const commonBorder = {};
52915
52914
  for (let side of ["top", "bottom", "left", "right"]) {
52916
- if (border1[side] && border1[side] === border2[side]) {
52915
+ if (border1[side] && deepEquals(border1[side], border2[side])) {
52917
52916
  commonBorder[side] = border1[side];
52918
52917
  }
52919
52918
  }
@@ -52958,23 +52957,15 @@ stores.inject(MyMetaStore, storeInstance);
52958
52957
  * @param start starting column (included)
52959
52958
  * @param delta how much borders will be moved (negative if moved to the left)
52960
52959
  */
52961
- shiftBordersHorizontally(sheetId, start, delta, { moveFirstLeftBorder } = {}) {
52960
+ shiftBordersHorizontally(sheetId, start, delta) {
52962
52961
  const borders = this.borders[sheetId];
52963
52962
  if (!borders)
52964
52963
  return;
52965
- if (delta < 0) {
52966
- this.moveBordersOfColumn(sheetId, start, delta, "vertical", {
52967
- destructive: false,
52968
- });
52969
- }
52970
52964
  this.getColumnsWithBorders(sheetId)
52971
52965
  .filter((col) => col >= start)
52972
52966
  .sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
52973
52967
  .forEach((col) => {
52974
- if ((col === start && moveFirstLeftBorder) || col !== start) {
52975
- this.moveBordersOfColumn(sheetId, col, delta, "vertical");
52976
- }
52977
- this.moveBordersOfColumn(sheetId, col, delta, "horizontal");
52968
+ this.moveBordersOfColumn(sheetId, col, delta);
52978
52969
  });
52979
52970
  }
52980
52971
  /**
@@ -52983,12 +52974,12 @@ stores.inject(MyMetaStore, storeInstance);
52983
52974
  * @param start starting row (included)
52984
52975
  * @param delta how much borders will be moved (negative if moved to the above)
52985
52976
  */
52986
- shiftBordersVertically(sheetId, start, delta, { moveFirstTopBorder } = {}) {
52977
+ shiftBordersVertically(sheetId, start, delta) {
52987
52978
  const borders = this.borders[sheetId];
52988
52979
  if (!borders)
52989
52980
  return;
52990
52981
  if (delta < 0) {
52991
- this.moveBordersOfRow(sheetId, start, delta, "horizontal", {
52982
+ this.moveBordersOfRow(sheetId, start, delta, {
52992
52983
  destructive: false,
52993
52984
  });
52994
52985
  }
@@ -52996,10 +52987,7 @@ stores.inject(MyMetaStore, storeInstance);
52996
52987
  .filter((row) => row >= start)
52997
52988
  .sort((a, b) => (delta < 0 ? a - b : b - a)) // start by the end when moving up
52998
52989
  .forEach((row) => {
52999
- if ((row === start && moveFirstTopBorder) || row !== start) {
53000
- this.moveBordersOfRow(sheetId, row, delta, "horizontal");
53001
- }
53002
- this.moveBordersOfRow(sheetId, row, delta, "vertical");
52990
+ this.moveBordersOfRow(sheetId, row, delta);
53003
52991
  });
53004
52992
  }
53005
52993
  /**
@@ -53013,15 +53001,15 @@ stores.inject(MyMetaStore, storeInstance);
53013
53001
  * argument `destructive` is given false, the target border is preserved if
53014
53002
  * the moved border is empty
53015
53003
  */
53016
- moveBordersOfRow(sheetId, row, delta, borderDirection, { destructive } = { destructive: true }) {
53004
+ moveBordersOfRow(sheetId, row, delta, { destructive } = { destructive: true }) {
53017
53005
  const borders = this.borders[sheetId];
53018
53006
  if (!borders)
53019
53007
  return;
53020
53008
  this.getColumnsWithBorders(sheetId).forEach((col) => {
53021
- const targetBorder = borders[col]?.[row + delta]?.[borderDirection];
53022
- const movedBorder = borders[col]?.[row]?.[borderDirection];
53023
- this.history.update("borders", sheetId, col, row + delta, borderDirection, destructive ? movedBorder : movedBorder || targetBorder);
53024
- this.history.update("borders", sheetId, col, row, borderDirection, undefined);
53009
+ const targetBorder = borders[col]?.[row + delta];
53010
+ const movedBorder = borders[col]?.[row];
53011
+ this.history.update("borders", sheetId, col, row + delta, destructive ? movedBorder : movedBorder || targetBorder);
53012
+ this.history.update("borders", sheetId, col, row, undefined);
53025
53013
  });
53026
53014
  }
53027
53015
  /**
@@ -53035,15 +53023,17 @@ stores.inject(MyMetaStore, storeInstance);
53035
53023
  * argument `destructive` is given false, the target border is preserved if
53036
53024
  * the moved border is empty
53037
53025
  */
53038
- moveBordersOfColumn(sheetId, col, delta, borderDirection, { destructive } = { destructive: true }) {
53026
+ moveBordersOfColumn(sheetId, col, delta, { destructive } = { destructive: true }) {
53039
53027
  const borders = this.borders[sheetId];
53040
53028
  if (!borders)
53041
53029
  return;
53042
53030
  this.getRowsRange(sheetId).forEach((row) => {
53043
- const targetBorder = borders[col + delta]?.[row]?.[borderDirection];
53044
- const movedBorder = borders[col]?.[row]?.[borderDirection];
53045
- this.history.update("borders", sheetId, col + delta, row, borderDirection, destructive ? movedBorder : movedBorder || targetBorder);
53046
- this.history.update("borders", sheetId, col, row, borderDirection, undefined);
53031
+ const targetBorder = borders[col + delta]?.[row];
53032
+ const movedBorder = borders[col]?.[row];
53033
+ this.history.update("borders", sheetId, col + delta, row, destructive ? movedBorder : movedBorder || targetBorder);
53034
+ if (destructive) {
53035
+ this.history.update("borders", sheetId, col, row, undefined);
53036
+ }
53047
53037
  });
53048
53038
  }
53049
53039
  /**
@@ -53051,33 +53041,69 @@ stores.inject(MyMetaStore, storeInstance);
53051
53041
  * It overrides the current border if override === true.
53052
53042
  */
53053
53043
  setBorder(sheetId, col, row, border, override = true) {
53054
- if (override || !this.borders?.[sheetId]?.[col]?.[row]?.vertical) {
53055
- this.history.update("borders", sheetId, col, row, "vertical", border?.left);
53044
+ const maxCol = this.getters.getNumberCols(sheetId) - 1;
53045
+ const maxRow = this.getters.getNumberRows(sheetId) - 1;
53046
+ if (override || !this.borders[sheetId]?.[col]?.[row]?.left) {
53047
+ this.history.update("borders", sheetId, col, row, "left", border?.left);
53048
+ if (border?.left &&
53049
+ col > 0 &&
53050
+ !deepEquals(this.getCellBorder({ sheetId, col: col - 1, row })?.right, border?.left)) {
53051
+ this.history.update("borders", sheetId, col - 1, row, "right", undefined);
53052
+ }
53056
53053
  }
53057
- if (override || !this.borders?.[sheetId]?.[col]?.[row]?.horizontal) {
53058
- this.history.update("borders", sheetId, col, row, "horizontal", border?.top);
53054
+ if (override || !this.borders[sheetId]?.[col]?.[row]?.top) {
53055
+ this.history.update("borders", sheetId, col, row, "top", border?.top);
53056
+ if (border?.top &&
53057
+ row > 0 &&
53058
+ !deepEquals(this.getCellBorder({ sheetId, col, row: row - 1 })?.bottom, border?.top)) {
53059
+ this.history.update("borders", sheetId, col, row - 1, "bottom", undefined);
53060
+ }
53059
53061
  }
53060
- if (override || !this.borders?.[sheetId]?.[col + 1]?.[row]?.vertical) {
53061
- this.history.update("borders", sheetId, col + 1, row, "vertical", border?.right);
53062
+ if (override || !this.borders[sheetId]?.[col]?.[row]?.right) {
53063
+ this.history.update("borders", sheetId, col, row, "right", border?.right);
53064
+ if (border?.right &&
53065
+ col < maxCol &&
53066
+ !deepEquals(this.getCellBorder({ sheetId, col: col + 1, row })?.left, border?.right)) {
53067
+ this.history.update("borders", sheetId, col + 1, row, "left", undefined);
53068
+ }
53062
53069
  }
53063
- if (override || !this.borders?.[sheetId]?.[col]?.[row + 1]?.horizontal) {
53064
- this.history.update("borders", sheetId, col, row + 1, "horizontal", border?.bottom);
53070
+ if (override || !this.borders[sheetId]?.[col]?.[row]?.bottom) {
53071
+ this.history.update("borders", sheetId, col, row, "bottom", border?.bottom);
53072
+ if (border?.bottom &&
53073
+ row < maxRow &&
53074
+ !deepEquals(this.getCellBorder({ sheetId, col, row: row + 1 })?.top, border?.bottom)) {
53075
+ this.history.update("borders", sheetId, col, row + 1, "top", undefined);
53076
+ }
53065
53077
  }
53066
53078
  }
53067
53079
  /**
53068
53080
  * Remove the borders of a zone
53069
53081
  */
53070
- clearBorders(sheetId, zones) {
53082
+ clearBorders(sheetId, zones, eraseBoundaries = false) {
53083
+ const maxCol = this.getters.getNumberCols(sheetId) - 1;
53084
+ const maxRow = this.getters.getNumberRows(sheetId) - 1;
53071
53085
  for (let zone of recomputeZones(zones)) {
53072
53086
  for (let row = zone.top; row <= zone.bottom; row++) {
53073
- this.history.update("borders", sheetId, zone.right + 1, row, "vertical", undefined);
53087
+ if (eraseBoundaries) {
53088
+ if (zone.left > 0) {
53089
+ this.history.update("borders", sheetId, zone.left - 1, row, "right", undefined);
53090
+ }
53091
+ if (zone.right < maxCol) {
53092
+ this.history.update("borders", sheetId, zone.right + 1, row, "left", undefined);
53093
+ }
53094
+ }
53074
53095
  for (let col = zone.left; col <= zone.right; col++) {
53075
53096
  this.history.update("borders", sheetId, col, row, undefined);
53097
+ if (eraseBoundaries) {
53098
+ if (zone.top > 0) {
53099
+ this.history.update("borders", sheetId, col, zone.top - 1, "bottom", undefined);
53100
+ }
53101
+ if (zone.bottom < maxRow) {
53102
+ this.history.update("borders", sheetId, col, zone.bottom + 1, "top", undefined);
53103
+ }
53104
+ }
53076
53105
  }
53077
53106
  }
53078
- for (let col = zone.left; col <= zone.right; col++) {
53079
- this.history.update("borders", sheetId, col, zone.bottom + 1, "horizontal", undefined);
53080
- }
53081
53107
  }
53082
53108
  }
53083
53109
  /**
@@ -53107,41 +53133,63 @@ stores.inject(MyMetaStore, storeInstance);
53107
53133
  */
53108
53134
  setBorders(sheetId, zones, position, border) {
53109
53135
  if (position === "clear") {
53110
- return this.clearBorders(sheetId, zones);
53136
+ return this.clearBorders(sheetId, zones, true);
53111
53137
  }
53112
53138
  for (let zone of recomputeZones(zones)) {
53113
- if (position === "h" || position === "hv" || position === "all") {
53114
- for (let row = zone.top + 1; row <= zone.bottom; row++) {
53139
+ if (position === "all") {
53140
+ for (let row = zone.top; row <= zone.bottom; row++) {
53115
53141
  for (let col = zone.left; col <= zone.right; col++) {
53116
- this.addBorder(sheetId, col, row, { top: border });
53142
+ this.addBorder(sheetId, col, row, {
53143
+ top: border,
53144
+ right: border,
53145
+ bottom: border,
53146
+ left: border,
53147
+ });
53117
53148
  }
53118
53149
  }
53119
53150
  }
53120
- if (position === "v" || position === "hv" || position === "all") {
53151
+ if (position === "h" || position === "hv") {
53152
+ if (zone.top === zone.bottom) {
53153
+ continue;
53154
+ }
53155
+ for (let col = zone.left; col <= zone.right; col++) {
53156
+ this.addBorder(sheetId, col, zone.top, { bottom: border });
53157
+ for (let row = zone.top + 1; row < zone.bottom; row++) {
53158
+ this.addBorder(sheetId, col, row, { top: border, bottom: border });
53159
+ }
53160
+ this.addBorder(sheetId, col, zone.bottom, { top: border });
53161
+ }
53162
+ }
53163
+ if (position === "v" || position === "hv") {
53164
+ if (zone.left === zone.right) {
53165
+ continue;
53166
+ }
53121
53167
  for (let row = zone.top; row <= zone.bottom; row++) {
53122
- for (let col = zone.left + 1; col <= zone.right; col++) {
53123
- this.addBorder(sheetId, col, row, { left: border });
53168
+ this.addBorder(sheetId, zone.left, row, { right: border });
53169
+ for (let col = zone.left + 1; col < zone.right; col++) {
53170
+ this.addBorder(sheetId, col, row, { left: border, right: border });
53124
53171
  }
53172
+ this.addBorder(sheetId, zone.right, row, { left: border });
53125
53173
  }
53126
53174
  }
53127
- if (position === "left" || position === "all" || position === "external") {
53175
+ if (position === "left" || position === "external") {
53128
53176
  for (let row = zone.top; row <= zone.bottom; row++) {
53129
53177
  this.addBorder(sheetId, zone.left, row, { left: border });
53130
53178
  }
53131
53179
  }
53132
- if (position === "right" || position === "all" || position === "external") {
53180
+ if (position === "right" || position === "external") {
53133
53181
  for (let row = zone.top; row <= zone.bottom; row++) {
53134
- this.addBorder(sheetId, zone.right + 1, row, { left: border });
53182
+ this.addBorder(sheetId, zone.right, row, { right: border });
53135
53183
  }
53136
53184
  }
53137
- if (position === "top" || position === "all" || position === "external") {
53185
+ if (position === "top" || position === "external") {
53138
53186
  for (let col = zone.left; col <= zone.right; col++) {
53139
53187
  this.addBorder(sheetId, col, zone.top, { top: border });
53140
53188
  }
53141
53189
  }
53142
- if (position === "bottom" || position === "all" || position === "external") {
53190
+ if (position === "bottom" || position === "external") {
53143
53191
  for (let col = zone.left; col <= zone.right; col++) {
53144
- this.addBorder(sheetId, col, zone.bottom + 1, { top: border });
53192
+ this.addBorder(sheetId, col, zone.bottom, { bottom: border });
53145
53193
  }
53146
53194
  }
53147
53195
  }
@@ -59886,7 +59934,11 @@ stores.inject(MyMetaStore, storeInstance);
59886
59934
  computeFormulaCell(formulaPosition, cellData) {
59887
59935
  const formulaReturn = updateEvalContextAndExecute(cellData.compiledFormula, this.compilationParams, formulaPosition.sheetId, this.buildSafeGetSymbolValue(), formulaPosition);
59888
59936
  if (!isMatrix(formulaReturn)) {
59889
- return createEvaluatedCell(nullValueToZeroValue(formulaReturn), this.getters.getLocale(), cellData);
59937
+ const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(formulaReturn), this.getters.getLocale(), cellData);
59938
+ if (evaluatedCell.type === CellValueType.error) {
59939
+ evaluatedCell.errorOriginPosition = formulaReturn.errorOriginPosition ?? formulaPosition;
59940
+ }
59941
+ return evaluatedCell;
59890
59942
  }
59891
59943
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
59892
59944
  const nbColumns = formulaReturn.length;
@@ -59959,6 +60011,9 @@ stores.inject(MyMetaStore, storeInstance);
59959
60011
  const position = { sheetId, col: i + col, row: j + row };
59960
60012
  const cell = this.getters.getCell(position);
59961
60013
  const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(matrixResult[i][j]), this.getters.getLocale(), cell);
60014
+ if (evaluatedCell.type === CellValueType.error) {
60015
+ evaluatedCell.errorOriginPosition = matrixResult[i][j].errorOriginPosition ?? position;
60016
+ }
59962
60017
  this.evaluatedCells.set(position, evaluatedCell);
59963
60018
  };
59964
60019
  return spreadValues;
@@ -61517,7 +61572,7 @@ stores.inject(MyMetaStore, storeInstance);
61517
61572
  const symbolIndex = rowDomain.findIndex((row) => row.field === symbolName);
61518
61573
  return this.getPivotHeaderValueAndFormat(rowDomain.slice(0, symbolIndex + 1));
61519
61574
  }
61520
- return this._getPivotCellValueAndFormat(symbolName, domain);
61575
+ return this.getPivotCellValueAndFormat(symbolName, domain);
61521
61576
  };
61522
61577
  const result = this.getters.evaluateCompiledFormula(measure.computedBy.sheetId, formula, getSymbolValue);
61523
61578
  if (isMatrix(result)) {
@@ -64703,14 +64758,12 @@ stores.inject(MyMetaStore, storeInstance);
64703
64758
  }
64704
64759
  break;
64705
64760
  case "AUTORESIZE_ROWS":
64706
- for (let row of cmd.rows) {
64707
- this.dispatch("RESIZE_COLUMNS_ROWS", {
64708
- elements: [row],
64709
- dimension: "ROW",
64710
- size: null,
64711
- sheetId: cmd.sheetId,
64712
- });
64713
- }
64761
+ this.dispatch("RESIZE_COLUMNS_ROWS", {
64762
+ elements: cmd.rows,
64763
+ dimension: "ROW",
64764
+ size: null,
64765
+ sheetId: cmd.sheetId,
64766
+ });
64714
64767
  break;
64715
64768
  }
64716
64769
  }
@@ -67461,7 +67514,7 @@ stores.inject(MyMetaStore, storeInstance);
67461
67514
  "getSheetViewVisibleCols",
67462
67515
  "getSheetViewVisibleRows",
67463
67516
  "getFrozenSheetViewRatio",
67464
- "isPositionVisible",
67517
+ "isPixelPositionVisible",
67465
67518
  "getColDimensionsInViewport",
67466
67519
  "getRowDimensionsInViewport",
67467
67520
  "getAllActiveViewportsZones",
@@ -68085,7 +68138,7 @@ stores.inject(MyMetaStore, storeInstance);
68085
68138
  }
68086
68139
  return result;
68087
68140
  }
68088
- isPositionVisible(position) {
68141
+ isPixelPositionVisible(position) {
68089
68142
  const { scrollX, scrollY } = this.getters.getActiveSheetScrollInfo();
68090
68143
  const { x: mainViewportX, y: mainViewportY } = this.getters.getMainViewportCoordinates();
68091
68144
  const { width, height } = this.getters.getSheetViewDimension();
@@ -70480,12 +70533,8 @@ stores.inject(MyMetaStore, storeInstance);
70480
70533
  .o-spreadsheet {
70481
70534
  position: relative;
70482
70535
  display: grid;
70483
- color: ${TEXT_BODY};
70484
70536
  font-size: 14px;
70485
70537
 
70486
- input {
70487
- background-color: white;
70488
- }
70489
70538
  .text-muted {
70490
70539
  color: ${TEXT_BODY_MUTED} !important;
70491
70540
  }
@@ -71732,6 +71781,9 @@ stores.inject(MyMetaStore, storeInstance);
71732
71781
  observe(owner, callbacks) {
71733
71782
  this.observers.set(owner, { owner, callbacks });
71734
71783
  }
71784
+ detachObserver(owner) {
71785
+ this.observers.delete(owner);
71786
+ }
71735
71787
  /**
71736
71788
  * Capture the stream for yourself
71737
71789
  */
@@ -71824,6 +71876,9 @@ stores.inject(MyMetaStore, storeInstance);
71824
71876
  observe(owner, callbacks) {
71825
71877
  this.stream.observe(owner, callbacks);
71826
71878
  }
71879
+ detachObserver(owner) {
71880
+ this.stream.detachObserver(owner);
71881
+ }
71827
71882
  release(owner) {
71828
71883
  if (this.stream.isListening(owner)) {
71829
71884
  this.stream.release(owner);
@@ -75273,9 +75328,9 @@ stores.inject(MyMetaStore, storeInstance);
75273
75328
  exports.tokenize = tokenize;
75274
75329
 
75275
75330
 
75276
- __info__.version = "18.2.0-alpha.4";
75277
- __info__.date = "2025-01-29T06:30:12.773Z";
75278
- __info__.hash = "6838c26";
75331
+ __info__.version = "18.2.0-alpha.5";
75332
+ __info__.date = "2025-01-31T07:59:30.667Z";
75333
+ __info__.hash = "efce841";
75279
75334
 
75280
75335
 
75281
75336
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);