@odoo/o-spreadsheet 17.2.29 → 17.2.31

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.29
7
- * @date 2024-12-05T10:39:14.167Z
8
- * @hash 7b4b898
6
+ * @version 17.2.31
7
+ * @date 2025-01-14T11:31:09.035Z
8
+ * @hash 306dbf7
9
9
  */
10
10
 
11
11
  'use strict';
@@ -626,6 +626,7 @@ function removeFalsyAttributes(obj) {
626
626
  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
627
627
  */
628
628
  const whiteSpaceSpecialCharacters = [
629
+ " ",
629
630
  "\t",
630
631
  "\f",
631
632
  "\v",
@@ -640,17 +641,15 @@ const whiteSpaceSpecialCharacters = [
640
641
  String.fromCharCode(parseInt("3000", 16)),
641
642
  String.fromCharCode(parseInt("feff", 16)),
642
643
  ];
643
- const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|") + "|(\r\n|\r|\n)", "g");
644
+ const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|"), "g");
645
+ const newLineRegexp = /(\r\n|\r)/g;
644
646
  /**
645
- * Replace all the special spaces in a string (non-breaking, tabs, ...) by normal spaces, and all the
646
- * different newlines types by \n.
647
+ * Replace all different newlines characters by \n
647
648
  */
648
- function replaceSpecialSpaces(text) {
649
+ function replaceNewLines(text) {
649
650
  if (!text)
650
651
  return "";
651
- if (!whiteSpaceRegexp.test(text))
652
- return text;
653
- return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
652
+ return text.replace(newLineRegexp, NEWLINE);
654
653
  }
655
654
  /**
656
655
  * Determine if the numbers are consecutive.
@@ -5163,7 +5162,7 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
5163
5162
  const POSTFIX_UNARY_OPERATORS = ["%"];
5164
5163
  const OPERATORS = "+,-,*,/,:,=,<>,>=,>,<=,<,^,&".split(",").concat(POSTFIX_UNARY_OPERATORS);
5165
5164
  function tokenize(str, locale = DEFAULT_LOCALE) {
5166
- str = replaceSpecialSpaces(str);
5165
+ str = replaceNewLines(str);
5167
5166
  const chars = new TokenizingChars(str);
5168
5167
  const result = [];
5169
5168
  while (!chars.isOver()) {
@@ -5310,12 +5309,12 @@ function tokenizeSpace(chars) {
5310
5309
  if (length) {
5311
5310
  return { type: "SPACE", value: NEWLINE.repeat(length) };
5312
5311
  }
5313
- while (chars.current === " ") {
5314
- length++;
5315
- chars.shift();
5312
+ let spaces = "";
5313
+ while (chars.current && chars.current.match(whiteSpaceRegexp)) {
5314
+ spaces += chars.shift();
5316
5315
  }
5317
- if (length) {
5318
- return { type: "SPACE", value: " ".repeat(length) };
5316
+ if (spaces) {
5317
+ return { type: "SPACE", value: spaces };
5319
5318
  }
5320
5319
  return null;
5321
5320
  }
@@ -20246,7 +20245,7 @@ function createGaugeChartRuntime(chart, getters) {
20246
20245
  colors.push(chartColors.upperColor);
20247
20246
  return {
20248
20247
  background: getters.getStyleOfSingleCellChart(chart.background, dataRange).background,
20249
- title: chart.title,
20248
+ title: _t(chart.title),
20250
20249
  minValue: {
20251
20250
  value: minValue,
20252
20251
  label: formatValue(minValue, { locale, format }),
@@ -31583,14 +31582,11 @@ unGroupHeadersMenuRegistry
31583
31582
  });
31584
31583
 
31585
31584
  class DOMFocusableElementStore {
31586
- mutators = ["setFocusableElement", "focus"];
31585
+ mutators = ["setFocusableElement"];
31587
31586
  focusableElement = undefined;
31588
31587
  setFocusableElement(element) {
31589
31588
  this.focusableElement = element;
31590
31589
  }
31591
- focus() {
31592
- this.focusableElement?.focus();
31593
- }
31594
31590
  }
31595
31591
 
31596
31592
  // -----------------------------------------------------------------------------
@@ -32930,7 +32926,7 @@ class GridComposer extends owl.Component {
32930
32926
  this.isEditing = isEditing;
32931
32927
  if (!isEditing) {
32932
32928
  this.rect = this.defaultRect;
32933
- this.DOMFocusableElementStore.focus();
32929
+ this.DOMFocusableElementStore.focusableElement?.focus();
32934
32930
  return;
32935
32931
  }
32936
32932
  const position = this.env.model.getters.getActivePosition();
@@ -33528,6 +33524,7 @@ class FiguresContainer extends owl.Component {
33528
33524
  draggedFigure: undefined,
33529
33525
  horizontalSnap: undefined,
33530
33526
  verticalSnap: undefined,
33527
+ cancelDnd: undefined,
33531
33528
  });
33532
33529
  setup() {
33533
33530
  owl.onMounted(() => {
@@ -33540,12 +33537,28 @@ class FiguresContainer extends owl.Component {
33540
33537
  // new rendering
33541
33538
  this.render();
33542
33539
  });
33540
+ owl.onWillUpdateProps(() => {
33541
+ const sheetId = this.env.model.getters.getActiveSheetId();
33542
+ const draggedFigureId = this.dnd.draggedFigure?.id;
33543
+ if (draggedFigureId && !this.env.model.getters.getFigure(sheetId, draggedFigureId)) {
33544
+ if (this.dnd.cancelDnd) {
33545
+ this.dnd.cancelDnd();
33546
+ }
33547
+ this.dnd.draggedFigure = undefined;
33548
+ this.dnd.horizontalSnap = undefined;
33549
+ this.dnd.verticalSnap = undefined;
33550
+ this.dnd.cancelDnd = undefined;
33551
+ }
33552
+ });
33543
33553
  }
33544
33554
  getVisibleFigures() {
33545
33555
  const visibleFigures = this.env.model.getters.getVisibleFigures();
33546
33556
  if (this.dnd.draggedFigure &&
33547
33557
  !visibleFigures.some((figure) => figure.id === this.dnd.draggedFigure?.id)) {
33548
- visibleFigures.push(this.env.model.getters.getFigure(this.env.model.getters.getActiveSheetId(), this.dnd.draggedFigure?.id));
33558
+ const draggedFigure = this.env.model.getters.getFigure(this.env.model.getters.getActiveSheetId(), this.dnd.draggedFigure?.id);
33559
+ if (draggedFigure) {
33560
+ visibleFigures.push(draggedFigure);
33561
+ }
33549
33562
  }
33550
33563
  return visibleFigures;
33551
33564
  }
@@ -33664,7 +33677,7 @@ class FiguresContainer extends owl.Component {
33664
33677
  this.dnd.verticalSnap = undefined;
33665
33678
  this.env.model.dispatch("UPDATE_FIGURE", { sheetId, id: figure.id, x, y });
33666
33679
  };
33667
- startDnd(onMouseMove, onMouseUp);
33680
+ this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
33668
33681
  }
33669
33682
  /**
33670
33683
  * Initialize the resize of a figure with mouse movements
@@ -33712,7 +33725,7 @@ class FiguresContainer extends owl.Component {
33712
33725
  this.dnd.horizontalSnap = undefined;
33713
33726
  this.dnd.verticalSnap = undefined;
33714
33727
  };
33715
- startDnd(onMouseMove, onMouseUp);
33728
+ this.dnd.cancelDnd = startDnd(onMouseMove, onMouseUp);
33716
33729
  }
33717
33730
  getOtherFigures(figId) {
33718
33731
  return this.getVisibleFigures().filter((f) => f.id !== figId);
@@ -35849,7 +35862,7 @@ class Grid extends owl.Component {
35849
35862
  this.cellPopovers = useStore(CellPopoverStore);
35850
35863
  owl.useEffect(() => {
35851
35864
  if (!this.sidePanel.isOpen) {
35852
- this.DOMFocusableElementStore.focus();
35865
+ this.DOMFocusableElementStore.focusableElement?.focus();
35853
35866
  }
35854
35867
  }, () => [this.sidePanel.isOpen]);
35855
35868
  }
@@ -36053,7 +36066,7 @@ class Grid extends owl.Component {
36053
36066
  focusDefaultElement() {
36054
36067
  if (!this.env.model.getters.getSelectedFigureId() &&
36055
36068
  this.composerStore.editionMode === "inactive") {
36056
- this.DOMFocusableElementStore.focus();
36069
+ this.DOMFocusableElementStore.focusableElement?.focus();
36057
36070
  }
36058
36071
  }
36059
36072
  get gridEl() {
@@ -37672,7 +37685,7 @@ function extractStyle(cell, data) {
37672
37685
  vertical: style.verticalAlign
37673
37686
  ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
37674
37687
  : undefined,
37675
- wrapText: style.wrapping === "wrap",
37688
+ wrapText: style.wrapping === "wrap" || cell.content?.includes(NEWLINE) ? true : undefined,
37676
37689
  },
37677
37690
  };
37678
37691
  styles.font["strike"] = !!style?.strikethrough || undefined;
@@ -37895,7 +37908,7 @@ function convertFigure(figure, id, sheetData) {
37895
37908
  return undefined;
37896
37909
  }
37897
37910
  function isChartData(data) {
37898
- return "dataSets" in data;
37911
+ return "dataSets" in data && data.dataSets.length > 0;
37899
37912
  }
37900
37913
  function isImageData(data) {
37901
37914
  return "imageSrc" in data;
@@ -38124,9 +38137,8 @@ function convertRows(sheet, numberOfRows, headerGroups) {
38124
38137
  }
38125
38138
  return rows;
38126
38139
  }
38127
- /** Remove newlines (\n) in shared strings, We do not support them */
38128
38140
  function convertSharedStrings(xlsxSharedStrings) {
38129
- return xlsxSharedStrings.map((str) => str.replace(/\n/g, ""));
38141
+ return xlsxSharedStrings.map(replaceNewLines);
38130
38142
  }
38131
38143
  function convertCells(sheet, data, sheetDims, warningManager) {
38132
38144
  const cells = {};
@@ -38968,15 +38980,10 @@ class XlsxMiscExtractor extends XlsxBaseExtractor {
38968
38980
  getSharedStrings() {
38969
38981
  return this.mapOnElements({ parent: this.rootFile.file.xml, query: "si" }, (ssElement) => {
38970
38982
  // Shared string can either be a simple text, or a rich text (text with formatting, possibly in multiple parts)
38971
- if (ssElement.children[0].tagName === "t") {
38972
- return this.extractTextContent(ssElement) || "";
38973
- }
38974
38983
  // We don't support rich text formatting, we'll only extract the text
38975
- else {
38976
- return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
38977
- return this.extractTextContent(textElement) || "";
38978
- }).join("");
38979
- }
38984
+ return this.mapOnElements({ parent: ssElement, query: "t" }, (textElement) => {
38985
+ return this.extractTextContent(textElement) || "";
38986
+ }).join("");
38980
38987
  });
38981
38988
  }
38982
38989
  }
@@ -40698,10 +40705,34 @@ class BordersPlugin extends CorePlugin {
40698
40705
  const elements = [...cmd.elements].sort((a, b) => b - a);
40699
40706
  for (const group of groupConsecutive(elements)) {
40700
40707
  if (cmd.dimension === "COL") {
40701
- this.shiftBordersHorizontally(cmd.sheetId, group[group.length - 1] + 1, -group.length);
40708
+ if (group[0] >= this.getters.getNumberCols(cmd.sheetId)) {
40709
+ for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
40710
+ this.history.update("borders", cmd.sheetId, group[0] + 1, row, "vertical", undefined);
40711
+ }
40712
+ }
40713
+ if (group[group.length - 1] === 0) {
40714
+ for (let row = 0; row < this.getters.getNumberRows(cmd.sheetId); row++) {
40715
+ this.history.update("borders", cmd.sheetId, 0, row, "vertical", undefined);
40716
+ }
40717
+ }
40718
+ const zone = this.getters.getColsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
40719
+ this.clearInsideBorders(cmd.sheetId, [zone]);
40720
+ this.shiftBordersHorizontally(cmd.sheetId, group[0] + 1, -group.length);
40702
40721
  }
40703
40722
  else {
40704
- this.shiftBordersVertically(cmd.sheetId, group[group.length - 1] + 1, -group.length);
40723
+ if (group[0] >= this.getters.getNumberRows(cmd.sheetId)) {
40724
+ for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
40725
+ this.history.update("borders", cmd.sheetId, col, group[0] + 1, "horizontal", undefined);
40726
+ }
40727
+ }
40728
+ if (group[group.length - 1] === 0) {
40729
+ for (let col = 0; col < this.getters.getNumberCols(cmd.sheetId); col++) {
40730
+ this.history.update("borders", cmd.sheetId, col, 0, "horizontal", undefined);
40731
+ }
40732
+ }
40733
+ const zone = this.getters.getRowsZone(cmd.sheetId, group[group.length - 1] + 1, group[0]);
40734
+ this.clearInsideBorders(cmd.sheetId, [zone]);
40735
+ this.shiftBordersVertically(cmd.sheetId, group[0] + 1, -group.length);
40705
40736
  }
40706
40737
  }
40707
40738
  break;
@@ -41008,6 +41039,18 @@ class BordersPlugin extends CorePlugin {
41008
41039
  }
41009
41040
  }
41010
41041
  }
41042
+ /**
41043
+ * Remove the borders inside of a zone
41044
+ */
41045
+ clearInsideBorders(sheetId, zones) {
41046
+ for (let zone of zones) {
41047
+ for (let row = zone.top; row <= zone.bottom; row++) {
41048
+ for (let col = zone.left; col <= zone.right; col++) {
41049
+ this.history.update("borders", sheetId, col, row, undefined);
41050
+ }
41051
+ }
41052
+ }
41053
+ }
41011
41054
  /**
41012
41055
  * Add a border to the existing one to a cell
41013
41056
  */
@@ -41870,7 +41913,7 @@ class CellPlugin extends CorePlugin {
41870
41913
  const before = this.getters.getCell({ sheetId, col, row });
41871
41914
  const hasContent = "content" in after || "formula" in after;
41872
41915
  // Compute the new cell properties
41873
- const afterContent = hasContent ? replaceSpecialSpaces(after?.content) : before?.content || "";
41916
+ const afterContent = hasContent ? replaceNewLines(after?.content) : before?.content || "";
41874
41917
  let style;
41875
41918
  if (after.style !== undefined) {
41876
41919
  style = after.style || undefined;
@@ -50589,6 +50632,9 @@ class Session extends EventBus {
50589
50632
  }
50590
50633
  }
50591
50634
  this.acknowledge(message);
50635
+ if (message.type === "REMOTE_REVISION" && message.clientId === this.clientId) {
50636
+ return;
50637
+ }
50592
50638
  this.trigger("collaborative-event-received");
50593
50639
  }
50594
50640
  onClientMoved(message) {
@@ -54192,6 +54238,7 @@ class SheetViewPlugin extends UIPlugin {
54192
54238
  break;
54193
54239
  case "DELETE_SHEET":
54194
54240
  this.cleanViewports();
54241
+ this.sheetsWithDirtyViewports.delete(cmd.sheetId);
54195
54242
  break;
54196
54243
  case "ACTIVATE_SHEET":
54197
54244
  this.sheetsWithDirtyViewports.add(cmd.sheetIdTo);
@@ -55139,11 +55186,6 @@ class BottomBarSheet extends owl.Component {
55139
55186
  editionState = "initializing";
55140
55187
  DOMFocusableElementStore;
55141
55188
  setup() {
55142
- owl.onMounted(() => {
55143
- if (this.isSheetActive) {
55144
- this.scrollToSheet();
55145
- }
55146
- });
55147
55189
  owl.onPatched(() => {
55148
55190
  if (this.sheetNameRef.el && this.state.isEditing && this.editionState === "initializing") {
55149
55191
  this.editionState = "editing";
@@ -55151,6 +55193,11 @@ class BottomBarSheet extends owl.Component {
55151
55193
  }
55152
55194
  });
55153
55195
  this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
55196
+ owl.useEffect((sheetId) => {
55197
+ if (this.props.sheetId === sheetId) {
55198
+ this.scrollToSheet();
55199
+ }
55200
+ }, () => [this.env.model.getters.getActiveSheetId()]);
55154
55201
  }
55155
55202
  focusInputAndSelectContent() {
55156
55203
  if (!this.state.isEditing || !this.sheetNameRef.el)
@@ -55162,7 +55209,10 @@ class BottomBarSheet extends owl.Component {
55162
55209
  }
55163
55210
  }
55164
55211
  scrollToSheet() {
55165
- this.sheetDivRef.el?.scrollIntoView?.();
55212
+ this.sheetDivRef.el?.scrollIntoView?.({
55213
+ behavior: "smooth",
55214
+ inline: "nearest",
55215
+ });
55166
55216
  }
55167
55217
  onFocusOut() {
55168
55218
  if (this.state.isEditing && this.editionState !== "initializing") {
@@ -55192,11 +55242,11 @@ class BottomBarSheet extends owl.Component {
55192
55242
  if (ev.key === "Enter") {
55193
55243
  ev.preventDefault();
55194
55244
  this.stopEdition();
55195
- this.DOMFocusableElementStore.focus();
55245
+ this.DOMFocusableElementStore.focusableElement?.focus();
55196
55246
  }
55197
55247
  if (ev.key === "Escape") {
55198
55248
  this.cancelEdition();
55199
- this.DOMFocusableElementStore.focus();
55249
+ this.DOMFocusableElementStore.focusableElement?.focus();
55200
55250
  }
55201
55251
  }
55202
55252
  onMouseEventSheetName(ev) {
@@ -56429,7 +56479,6 @@ css /* scss */ `
56429
56479
  height: fit-content;
56430
56480
  margin-top: -1px;
56431
56481
  border: 1px solid;
56432
- z-index: ${ComponentsImportance.TopBarComposer};
56433
56482
 
56434
56483
  .o-composer:empty:not(:focus):not(.active)::before {
56435
56484
  content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
@@ -56471,6 +56520,7 @@ class TopBarComposer extends owl.Component {
56471
56520
  }
56472
56521
  return cssPropertiesToCss({
56473
56522
  "border-color": SELECTION_BORDER_COLOR,
56523
+ "z-index": String(ComponentsImportance.TopBarComposer),
56474
56524
  });
56475
56525
  }
56476
56526
  get delimitation() {
@@ -60254,7 +60304,12 @@ function createSharedStrings(strings) {
60254
60304
  ["count", strings.length],
60255
60305
  ["uniqueCount", strings.length],
60256
60306
  ];
60257
- const stringNodes = strings.map((string) => escapeXml /*xml*/ `<si><t>${string}</t></si>`);
60307
+ const stringNodes = strings.map((string) => {
60308
+ if (string.trim() !== string) {
60309
+ return escapeXml /*xml*/ `<si><t xml:space="preserve">${string}</t></si>`;
60310
+ }
60311
+ return escapeXml /*xml*/ `<si><t>${string}</t></si>`;
60312
+ });
60258
60313
  const xml = escapeXml /*xml*/ `
60259
60314
  <sst ${formatAttributes(namespaces)}>
60260
60315
  ${joinXmlNodes(stringNodes)}
@@ -60905,6 +60960,8 @@ const helpers = {
60905
60960
  expandZoneOnInsertion,
60906
60961
  reduceZoneOnDeletion,
60907
60962
  unquote,
60963
+ isNumber,
60964
+ isDateTime,
60908
60965
  };
60909
60966
  const links = {
60910
60967
  isMarkdownLink,
@@ -61019,6 +61076,6 @@ exports.tokenColors = tokenColors;
61019
61076
  exports.tokenize = tokenize;
61020
61077
 
61021
61078
 
61022
- __info__.version = "17.2.29";
61023
- __info__.date = "2024-12-05T10:39:14.167Z";
61024
- __info__.hash = "7b4b898";
61079
+ __info__.version = "17.2.31";
61080
+ __info__.date = "2025-01-14T11:31:09.035Z";
61081
+ __info__.hash = "306dbf7";
@@ -2334,6 +2334,10 @@ declare class BordersPlugin extends CorePlugin<BordersPluginState> implements Bo
2334
2334
  * Remove the borders of a zone
2335
2335
  */
2336
2336
  private clearBorders;
2337
+ /**
2338
+ * Remove the borders inside of a zone
2339
+ */
2340
+ private clearInsideBorders;
2337
2341
  /**
2338
2342
  * Add a border to the existing one to a cell
2339
2343
  */
@@ -4918,6 +4922,7 @@ declare class DateTime {
4918
4922
  setMinutes(minutes: number): number;
4919
4923
  setSeconds(seconds: number): number;
4920
4924
  }
4925
+ declare function isDateTime(str: string, locale: Locale): boolean;
4921
4926
 
4922
4927
  /**
4923
4928
  * Formats a cell value with its format.
@@ -4955,6 +4960,13 @@ declare function lazy<T>(fn: (() => T) | T): Lazy<T>;
4955
4960
  */
4956
4961
  declare function deepEquals(o1: any, o2: any): boolean;
4957
4962
 
4963
+ /**
4964
+ * Return true if the argument is a "number string".
4965
+ *
4966
+ * Note that "" (empty string) does not count as a number string
4967
+ */
4968
+ declare function isNumber(value: string | undefined, locale: Locale): boolean;
4969
+
4958
4970
  interface ConstructorArgs {
4959
4971
  readonly zone: Readonly<Zone | UnboundedZone>;
4960
4972
  readonly parts: readonly RangePart[];
@@ -7311,6 +7323,7 @@ interface DndState {
7311
7323
  draggedFigure?: Figure;
7312
7324
  horizontalSnap?: Snap<HFigureAxisType>;
7313
7325
  verticalSnap?: Snap<VFigureAxisType>;
7326
+ cancelDnd: (() => void) | undefined;
7314
7327
  }
7315
7328
  /**
7316
7329
  * Each figure ⭐ is positioned inside a container `div` placed and sized
@@ -10024,6 +10037,8 @@ declare const helpers: {
10024
10037
  expandZoneOnInsertion: typeof expandZoneOnInsertion;
10025
10038
  reduceZoneOnDeletion: typeof reduceZoneOnDeletion;
10026
10039
  unquote: typeof unquote;
10040
+ isNumber: typeof isNumber;
10041
+ isDateTime: typeof isDateTime;
10027
10042
  };
10028
10043
  declare const links: {
10029
10044
  isMarkdownLink: typeof isMarkdownLink;