@odoo/o-spreadsheet 16.5.0-alpha.11 → 16.5.0-alpha.13

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 16.5.0-alpha.11
6
- * @date 2023-10-19T14:26:01.790Z
7
- * @hash 4b42059
5
+ * @version 16.5.0-alpha.13
6
+ * @date 2023-10-25T10:04:45.428Z
7
+ * @hash 18a08b1
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -2059,6 +2059,7 @@
2059
2059
  CommandResult["InvalidDataValidationCriterionValue"] = "InvalidDataValidationCriterionValue";
2060
2060
  CommandResult["InvalidNumberOfCriterionValues"] = "InvalidNumberOfCriterionValues";
2061
2061
  CommandResult["BlockingValidationRule"] = "BlockingValidationRule";
2062
+ CommandResult["InvalidCopyPasteSelection"] = "InvalidCopyPasteSelection";
2062
2063
  })(exports.CommandResult || (exports.CommandResult = {}));
2063
2064
 
2064
2065
  const DEFAULT_LOCALES = [
@@ -4660,7 +4661,7 @@
4660
4661
  return `background-color: ${this.background}`;
4661
4662
  }
4662
4663
  get chartRuntime() {
4663
- const runtime = this.env.model.getters.getChartRuntime(this.props.figureId);
4664
+ const runtime = this.env.model.getters.getChartRuntime(this.props.figure.id);
4664
4665
  if (!("chartJsConfig" in runtime)) {
4665
4666
  throw new Error("Unsupported chart runtime");
4666
4667
  }
@@ -4704,7 +4705,7 @@
4704
4705
  }
4705
4706
  }
4706
4707
  ChartJsComponent.props = {
4707
- figureId: String,
4708
+ figure: Object,
4708
4709
  };
4709
4710
 
4710
4711
  /**
@@ -5106,6 +5107,8 @@
5106
5107
  ? "InvalidScorecardBaseline" /* CommandResult.InvalidScorecardBaseline */
5107
5108
  : "Success" /* CommandResult.Success */;
5108
5109
  }
5110
+ const arrowDownPath = new window.Path2D("M8.6 4.8a.5.5 0 0 1 0 .75l-3.9 3.9a.5 .5 0 0 1 -.75 0l-3.8 -3.9a.5 .5 0 0 1 0 -.75l.4-.4a.5.5 0 0 1 .75 0l2.3 2.4v-5.7c0-.25.25-.5.5-.5h.6c.25 0 .5.25.5.5v5.8l2.3 -2.4a.5.5 0 0 1 .75 0z");
5111
+ const arrowUpPath = new window.Path2D("M8.7 5.5a.5.5 0 0 0 0-.75l-3.8-4a.5.5 0 0 0-.75 0l-3.8 4a.5.5 0 0 0 0 .75l.4.4a.5.5 0 0 0 .75 0l2.3-2.4v5.8c0 .25.25.5.5.5h.6c.25 0 .5-.25.5-.5v-5.8l2.2 2.4a.5.5 0 0 0 .75 0z");
5109
5112
  let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
5110
5113
  keyValue;
5111
5114
  baseline;
@@ -5226,10 +5229,24 @@
5226
5229
  ctx.fillStyle = structure.baseline.style.color;
5227
5230
  drawDecoratedText(ctx, structure.baseline.text, structure.baseline.position, structure.baseline.style.underline, structure.baseline.style.strikethrough);
5228
5231
  }
5229
- if (structure.baselineArrow) {
5230
- ctx.font = structure.baselineArrow.style.font;
5232
+ if (structure.baselineArrow && structure.baselineArrow.style.size > 0) {
5233
+ ctx.save();
5231
5234
  ctx.fillStyle = structure.baselineArrow.style.color;
5232
- ctx.fillText(structure.baselineArrow.text, structure.baselineArrow.position.x, structure.baselineArrow.position.y);
5235
+ ctx.translate(structure.baselineArrow.position.x, structure.baselineArrow.position.y);
5236
+ // This ratio is computed according to the original svg size and the final size we want
5237
+ const ratio = structure.baselineArrow.style.size / 10;
5238
+ ctx.scale(ratio, ratio);
5239
+ switch (structure.baselineArrow.direction) {
5240
+ case "down": {
5241
+ ctx.fill(arrowDownPath);
5242
+ break;
5243
+ }
5244
+ case "up": {
5245
+ ctx.fill(arrowUpPath);
5246
+ break;
5247
+ }
5248
+ }
5249
+ ctx.restore();
5233
5250
  }
5234
5251
  if (structure.baselineDescr) {
5235
5252
  ctx.font = structure.baselineDescr.style.font;
@@ -5352,25 +5369,29 @@
5352
5369
  },
5353
5370
  };
5354
5371
  }
5355
- const { height: baselineArrowHeight, width: baselineArrowWidth } = this.getTextDimensions(this.baselineArrow, style.baselineArrow.font);
5372
+ const baselineArrowSize = style.baselineArrow?.size ?? 0;
5356
5373
  const { height: baselineHeight, width: baselineWidth } = this.getTextDimensions(this.baseline, style.baselineValue.font);
5357
5374
  const { width: baselineDescrWidth } = this.getTextDimensions(this.baselineDescr, style.baselineDescr.font);
5358
5375
  structure.baseline = {
5359
5376
  text: this.baseline,
5360
5377
  style: style.baselineValue,
5361
5378
  position: {
5362
- x: (this.width - baselineWidth - baselineDescrWidth + baselineArrowWidth) / 2,
5363
- y: this.height - 2 * this.chartPadding,
5364
- },
5365
- };
5366
- structure.baselineArrow = {
5367
- text: this.baselineArrow,
5368
- style: style.baselineArrow,
5369
- position: {
5370
- x: structure.baseline.position.x - baselineArrowWidth,
5371
- y: structure.baseline.position.y - (baselineHeight - baselineArrowHeight) / 2,
5379
+ x: (this.width - baselineWidth - baselineDescrWidth + baselineArrowSize) / 2,
5380
+ y: this.keyValue
5381
+ ? this.height - 2 * this.chartPadding
5382
+ : this.height - (this.height - titleHeight - baselineHeight) / 2 - this.chartPadding,
5372
5383
  },
5373
5384
  };
5385
+ if (style.baselineArrow) {
5386
+ structure.baselineArrow = {
5387
+ direction: this.baselineArrow,
5388
+ style: style.baselineArrow,
5389
+ position: {
5390
+ x: structure.baseline.position.x - baselineArrowSize,
5391
+ y: structure.baseline.position.y - (baselineHeight + baselineArrowSize) / 2,
5392
+ },
5393
+ };
5394
+ }
5374
5395
  if (this.baselineDescr) {
5375
5396
  structure.baselineDescr = {
5376
5397
  text: this.baselineDescr,
@@ -5407,13 +5428,7 @@
5407
5428
  return formatBaselineDescr(this.runtime.baselineDescr, this.baseline);
5408
5429
  }
5409
5430
  get baselineArrow() {
5410
- switch (this.runtime.baselineArrow) {
5411
- case "up":
5412
- return "\u{1F871}";
5413
- case "down":
5414
- return "\u{1F873}";
5415
- }
5416
- return "";
5431
+ return this.runtime.baselineArrow;
5417
5432
  }
5418
5433
  get backgroundColor() {
5419
5434
  return this.runtime.background;
@@ -5465,10 +5480,12 @@
5465
5480
  font: getDefaultContextFont(baselineFontSize * BASELINE_DESCR_FONT_RATIO),
5466
5481
  color: this.secondaryFontColor,
5467
5482
  },
5468
- baselineArrow: {
5469
- font: getDefaultContextFont(0.8 * baselineFontSize),
5470
- color: this.runtime.baselineColor || this.secondaryFontColor,
5471
- },
5483
+ baselineArrow: this.baselineArrow === "neutral"
5484
+ ? undefined
5485
+ : {
5486
+ size: this.keyValue ? 0.8 * baselineFontSize : 0,
5487
+ color: this.runtime.baselineColor || this.secondaryFontColor,
5488
+ },
5472
5489
  };
5473
5490
  }
5474
5491
  /** Get the height of the chart minus all the vertical paddings */
@@ -5505,7 +5522,7 @@
5505
5522
  }
5506
5523
  const baselineStr = chart.baseline;
5507
5524
  // Put mock text to simulate the width of the up/down arrow
5508
- const largeText = chart.baselineArrow !== "" ? "A " + baselineStr : baselineStr;
5525
+ const largeText = chart.baselineArrow !== "neutral" ? "A " + baselineStr : baselineStr;
5509
5526
  let textWidth = this.measureTextWidth(ctx, largeText, fontSize);
5510
5527
  // Baseline descr font size should be smaller than baseline font size
5511
5528
  textWidth += this.measureTextWidth(ctx, chart.baselineDescr, fontSize * BASELINE_DESCR_FONT_RATIO);
@@ -5542,7 +5559,7 @@
5542
5559
  static template = "o-spreadsheet-ScorecardChart";
5543
5560
  canvas = owl.useRef("chartContainer");
5544
5561
  get runtime() {
5545
- return this.env.model.getters.getChartRuntime(this.props.figureId);
5562
+ return this.env.model.getters.getChartRuntime(this.props.figure.id);
5546
5563
  }
5547
5564
  setup() {
5548
5565
  owl.useEffect(this.createChart.bind(this), () => {
@@ -5558,7 +5575,7 @@
5558
5575
  }
5559
5576
  }
5560
5577
  ScorecardChart.props = {
5561
- figureId: String,
5578
+ figure: Object,
5562
5579
  };
5563
5580
 
5564
5581
  /**
@@ -7567,6 +7584,18 @@
7567
7584
  }
7568
7585
  return result;
7569
7586
  }
7587
+ /**
7588
+ * Return the input if it's a scalar or the first element of the input if it's a matrix.
7589
+ */
7590
+ function toScalar(matrix) {
7591
+ if (!isMatrix(matrix)) {
7592
+ return matrix;
7593
+ }
7594
+ if (matrix.length !== 1 || matrix[0].length !== 1) {
7595
+ throw new Error("toScalar: matrix should be a scalar or a 1x1 matrix");
7596
+ }
7597
+ return matrix[0][0];
7598
+ }
7570
7599
 
7571
7600
  // -----------------------------------------------------------------------------
7572
7601
  // ARRAY_CONSTRAIN
@@ -10280,6 +10309,42 @@
10280
10309
  },
10281
10310
  isExported: true,
10282
10311
  };
10312
+ // RANK
10313
+ // -----------------------------------------------------------------------------
10314
+ const RANK = {
10315
+ description: _t("Returns the rank of a specified value in a dataset."),
10316
+ args: [
10317
+ arg("value (number)", _t("The value whose rank will be determined.")),
10318
+ arg("data (range)", _t("The range containing the dataset to consider.")),
10319
+ arg("is_ascending (boolean, default=FALSE)", _t("Whether to consider the values in data in descending or ascending order.")),
10320
+ ],
10321
+ returns: ["ANY"],
10322
+ compute: function (value, data, isAscending = false) {
10323
+ const _isAscending = toBoolean(isAscending);
10324
+ const _value = toNumber(value, this.locale);
10325
+ let rank = 1;
10326
+ let found = false;
10327
+ for (const row of data) {
10328
+ for (const cell of row) {
10329
+ if (typeof cell !== "number") {
10330
+ continue;
10331
+ }
10332
+ const _cell = toNumber(cell, this.locale);
10333
+ if (_cell === _value) {
10334
+ found = true;
10335
+ }
10336
+ else if (_cell > _value !== _isAscending) {
10337
+ rank++;
10338
+ }
10339
+ }
10340
+ }
10341
+ if (!found) {
10342
+ throw new NotAvailableError(_t("Value not found in the given data."));
10343
+ }
10344
+ return rank;
10345
+ },
10346
+ isExported: true,
10347
+ };
10283
10348
  // -----------------------------------------------------------------------------
10284
10349
  // RSQ
10285
10350
  // -----------------------------------------------------------------------------
@@ -10624,6 +10689,7 @@
10624
10689
  QUARTILE: QUARTILE,
10625
10690
  QUARTILE_EXC: QUARTILE_EXC,
10626
10691
  QUARTILE_INC: QUARTILE_INC,
10692
+ RANK: RANK,
10627
10693
  RSQ: RSQ,
10628
10694
  SLOPE: SLOPE,
10629
10695
  SMALL: SMALL,
@@ -11770,6 +11836,172 @@
11770
11836
  DELTA: DELTA
11771
11837
  });
11772
11838
 
11839
+ const SORT_TYPES = [
11840
+ CellValueType.number,
11841
+ CellValueType.error,
11842
+ CellValueType.text,
11843
+ CellValueType.boolean,
11844
+ ];
11845
+ function cellsSortingCriterion(sortingOrder) {
11846
+ const inverse = sortingOrder === "ascending" ? 1 : -1;
11847
+ return (left, right) => {
11848
+ if (left.type === CellValueType.empty) {
11849
+ return right.type === CellValueType.empty ? 0 : 1;
11850
+ }
11851
+ else if (right.type === CellValueType.empty) {
11852
+ return -1;
11853
+ }
11854
+ let typeOrder = SORT_TYPES.indexOf(left.type) - SORT_TYPES.indexOf(right.type);
11855
+ if (typeOrder === 0) {
11856
+ if (left.type === CellValueType.text || left.type === CellValueType.error) {
11857
+ typeOrder = left.value.localeCompare(right.value);
11858
+ }
11859
+ else {
11860
+ typeOrder = left.value - right.value;
11861
+ }
11862
+ }
11863
+ return inverse * typeOrder;
11864
+ };
11865
+ }
11866
+ function sortCells(cells, sortDirection, emptyCellAsZero) {
11867
+ const cellsWithIndex = cells.map((cell, index) => ({
11868
+ index,
11869
+ type: cell.type,
11870
+ value: cell.value,
11871
+ }));
11872
+ const cellsToSort = emptyCellAsZero
11873
+ ? cellsWithIndex.map((cell) => cell.type === CellValueType.empty ? { ...cell, type: CellValueType.number, value: 0 } : cell)
11874
+ : cellsWithIndex;
11875
+ return cellsToSort.sort(cellsSortingCriterion(sortDirection));
11876
+ }
11877
+ function interactiveSortSelection(env, sheetId, anchor, zone, sortDirection) {
11878
+ let result = DispatchResult.Success;
11879
+ //several columns => bypass the contiguity check
11880
+ let multiColumns = zone.right > zone.left;
11881
+ if (env.model.getters.doesIntersectMerge(sheetId, zone)) {
11882
+ multiColumns = false;
11883
+ let table;
11884
+ for (let row = zone.top; row <= zone.bottom; row++) {
11885
+ table = [];
11886
+ for (let col = zone.left; col <= zone.right; col++) {
11887
+ let merge = env.model.getters.getMerge({ sheetId, col, row });
11888
+ if (merge && !table.includes(merge.id.toString())) {
11889
+ table.push(merge.id.toString());
11890
+ }
11891
+ }
11892
+ if (table.length >= 2) {
11893
+ multiColumns = true;
11894
+ break;
11895
+ }
11896
+ }
11897
+ }
11898
+ const { col, row } = anchor;
11899
+ if (multiColumns) {
11900
+ result = env.model.dispatch("SORT_CELLS", { sheetId, col, row, zone, sortDirection });
11901
+ }
11902
+ else {
11903
+ // check contiguity
11904
+ const contiguousZone = env.model.getters.getContiguousZone(sheetId, zone);
11905
+ if (isEqual(contiguousZone, zone)) {
11906
+ // merge as it is
11907
+ result = env.model.dispatch("SORT_CELLS", {
11908
+ sheetId,
11909
+ col,
11910
+ row,
11911
+ zone,
11912
+ sortDirection,
11913
+ });
11914
+ }
11915
+ else {
11916
+ env.askConfirmation(_t("We found data next to your selection. Since this data was not selected, it will not be sorted. Do you want to extend your selection?"), () => {
11917
+ zone = contiguousZone;
11918
+ result = env.model.dispatch("SORT_CELLS", {
11919
+ sheetId,
11920
+ col,
11921
+ row,
11922
+ zone,
11923
+ sortDirection,
11924
+ });
11925
+ }, () => {
11926
+ result = env.model.dispatch("SORT_CELLS", {
11927
+ sheetId,
11928
+ col,
11929
+ row,
11930
+ zone,
11931
+ sortDirection,
11932
+ });
11933
+ });
11934
+ }
11935
+ }
11936
+ if (result.isCancelledBecause("InvalidSortZone" /* CommandResult.InvalidSortZone */)) {
11937
+ const { col, row } = anchor;
11938
+ env.model.selection.selectZone({ cell: { col, row }, zone });
11939
+ env.raiseError(_t("Cannot sort. To sort, select only cells or only merges that have the same size."));
11940
+ }
11941
+ }
11942
+
11943
+ function sortMatrix(matrix, locale, ...criteria) {
11944
+ for (const [i, value] of criteria.entries()) {
11945
+ assert(() => value !== undefined, _t(`Value for parameter %d is missing, while the function [[FUNCTION_NAME]] expect a number or a range.`, i + 1));
11946
+ }
11947
+ const sortingOrders = [];
11948
+ const sortColumns = [];
11949
+ const nRows = matrix.length;
11950
+ for (let i = 0; i < criteria.length; i += 2) {
11951
+ sortingOrders.push(toBoolean(toScalar(criteria[i + 1])?.value) ? "ascending" : "descending");
11952
+ const sortColumn = criteria[i];
11953
+ if (isMatrix(sortColumn) && (sortColumn.length > 1 || sortColumn[0].length > 1)) {
11954
+ assert(() => sortColumn.length === 1 && sortColumn[0].length === nRows, _t(`Wrong size for %s. Expected a range of size 1x%s. Got %sx%s.`, `sort_column{i + 1}`, nRows, sortColumn.length, sortColumn[0].length));
11955
+ sortColumns.push(sortColumn.flat().map((c) => c.value));
11956
+ }
11957
+ else {
11958
+ const colIndex = toNumber(toScalar(sortColumn)?.value, locale);
11959
+ if (colIndex < 1 || colIndex > matrix[0].length) {
11960
+ return matrix;
11961
+ }
11962
+ sortColumns.push(matrix.map((row) => row[colIndex - 1].value));
11963
+ }
11964
+ }
11965
+ if (sortColumns.length === 0) {
11966
+ for (let i = 0; i < matrix[0].length; i++) {
11967
+ sortColumns.push(matrix.map((row) => row[i].value));
11968
+ sortingOrders.push("ascending");
11969
+ }
11970
+ }
11971
+ const sortingCriteria = {
11972
+ descending: cellsSortingCriterion("descending"),
11973
+ ascending: cellsSortingCriterion("ascending"),
11974
+ };
11975
+ const indexes = range(0, matrix.length);
11976
+ indexes.sort((a, b) => {
11977
+ for (const [i, sortColumn] of sortColumns.entries()) {
11978
+ const left = sortColumn[a];
11979
+ const right = sortColumn[b];
11980
+ const leftCell = {
11981
+ value: left,
11982
+ type: left === null
11983
+ ? CellValueType.empty
11984
+ : typeof left === "string"
11985
+ ? CellValueType.text
11986
+ : typeof left,
11987
+ };
11988
+ const rightCell = {
11989
+ value: right,
11990
+ type: right === null
11991
+ ? CellValueType.empty
11992
+ : typeof right === "string"
11993
+ ? CellValueType.text
11994
+ : typeof right,
11995
+ };
11996
+ const result = sortingCriteria[sortingOrders[i]](leftCell, rightCell);
11997
+ if (result !== 0) {
11998
+ return result;
11999
+ }
12000
+ }
12001
+ return 0;
12002
+ });
12003
+ return indexes.map((i) => matrix[i]);
12004
+ }
11773
12005
  // -----------------------------------------------------------------------------
11774
12006
  // FILTER
11775
12007
  // -----------------------------------------------------------------------------
@@ -11806,6 +12038,93 @@
11806
12038
  isExported: true,
11807
12039
  };
11808
12040
  // -----------------------------------------------------------------------------
12041
+ // SORT
12042
+ // -----------------------------------------------------------------------------
12043
+ const SORT = {
12044
+ description: _t("Sorts the rows of a given array or range by the values in one or more columns."),
12045
+ args: [
12046
+ arg("range (range)", _t("The data to be sorted.")),
12047
+ arg("sort_column (any, range<number>, repeating)", _t("The index of the column in range or a range outside of range containing the values by which to sort.")),
12048
+ arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
12049
+ ],
12050
+ returns: ["RANGE"],
12051
+ computeValueAndFormat: function (range, ...sortingCriteria) {
12052
+ const _range = transposeMatrix(range);
12053
+ return transposeMatrix(sortMatrix(_range, this.locale, ...sortingCriteria));
12054
+ },
12055
+ isExported: true,
12056
+ };
12057
+ // -----------------------------------------------------------------------------
12058
+ // SORTN
12059
+ // -----------------------------------------------------------------------------
12060
+ const SORTN = {
12061
+ description: _t("Returns the first n items in a data set after performing a sort."),
12062
+ args: [
12063
+ arg("range (range)", _t("The data to be sorted.")),
12064
+ arg("n (number, default=1)", _t("The number of items to return.")),
12065
+ arg("display_ties_mode (number, default=0)", _t("A number representing the way to display ties.")),
12066
+ arg("sort_column (number, range<number>, repeating)", _t("The index of the column in range or a range outside of range containing the values by which to sort.")),
12067
+ arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
12068
+ ],
12069
+ returns: ["RANGE"],
12070
+ computeValueAndFormat: function (range, n, displayTiesMode, ...sortingCriteria) {
12071
+ const _n = toNumber(n?.value ?? 1, this.locale);
12072
+ assert(() => _n >= 0, _t(`Wrong value of 'n'. Expected a positive number. Got %s.`, _n));
12073
+ const _displayTiesMode = toNumber(displayTiesMode?.value ?? 0, this.locale);
12074
+ assert(() => _displayTiesMode >= 0 && _displayTiesMode <= 3, _t(`Wrong value of 'display_ties_mode'. Expected a positive number between 0 and 3. Got %s.`, _displayTiesMode));
12075
+ const sortedData = sortMatrix(transposeMatrix(range), this.locale, ...sortingCriteria);
12076
+ const sameRows = (i, j) => JSON.stringify(sortedData[i].map((c) => c.value)) ===
12077
+ JSON.stringify(sortedData[j].map((c) => c.value));
12078
+ /*
12079
+ * displayTiesMode determine how ties (equal values) are dealt with:
12080
+ * 0 - ignore ties and show first n rows only
12081
+ * 1 - show first n rows plus any additional ties with nth row
12082
+ * 2 - show n rows but remove duplicates
12083
+ * 3 - show first n unique rows and all duplicates of these rows
12084
+ */
12085
+ switch (_displayTiesMode) {
12086
+ case 0:
12087
+ return transposeMatrix(sortedData.slice(0, _n));
12088
+ case 1:
12089
+ for (let i = _n; i < sortedData.length; i++) {
12090
+ if (!sameRows(i, _n - 1)) {
12091
+ return transposeMatrix(sortedData.slice(0, i));
12092
+ }
12093
+ }
12094
+ return transposeMatrix(sortedData);
12095
+ case 2: {
12096
+ const uniques = [sortedData[0]];
12097
+ for (let i = 1; i < sortedData.length; i++) {
12098
+ for (let j = 0; j < i; j++) {
12099
+ if (sameRows(i, j)) {
12100
+ break;
12101
+ }
12102
+ if (j === i - 1) {
12103
+ uniques.push(sortedData[i]);
12104
+ }
12105
+ }
12106
+ }
12107
+ return transposeMatrix(uniques.slice(0, _n));
12108
+ }
12109
+ case 3: {
12110
+ const uniques = [sortedData[0]];
12111
+ let counter = 1;
12112
+ for (let i = 1; i < sortedData.length; i++) {
12113
+ if (!sameRows(i, i - 1)) {
12114
+ counter++;
12115
+ }
12116
+ if (counter > _n) {
12117
+ break;
12118
+ }
12119
+ uniques.push(sortedData[i]);
12120
+ }
12121
+ return transposeMatrix(uniques);
12122
+ }
12123
+ }
12124
+ },
12125
+ isExported: true,
12126
+ };
12127
+ // -----------------------------------------------------------------------------
11809
12128
  // UNIQUE
11810
12129
  // -----------------------------------------------------------------------------
11811
12130
  const UNIQUE = {
@@ -11853,6 +12172,8 @@
11853
12172
  var filter = /*#__PURE__*/Object.freeze({
11854
12173
  __proto__: null,
11855
12174
  FILTER: FILTER,
12175
+ SORT: SORT,
12176
+ SORTN: SORTN,
11856
12177
  UNIQUE: UNIQUE
11857
12178
  });
11858
12179
 
@@ -17088,7 +17409,7 @@
17088
17409
  wrongPasteSelection: _t("This operation is not allowed with multiple selections."),
17089
17410
  willRemoveExistingMerge: _t("This operation is not possible due to a merge. Please remove the merges first than try again."),
17090
17411
  wrongFigurePasteOption: _t("Cannot do a special paste of a figure."),
17091
- frozenPaneOverlap: _t("Cannot paste merged cells over a frozen pane."),
17412
+ frozenPaneOverlap: _t("This operation is not allowed due to an overlapping frozen pane."),
17092
17413
  };
17093
17414
  function handlePasteResult(env, result) {
17094
17415
  if (!result.isSuccessful) {
@@ -18628,11 +18949,11 @@
18628
18949
  static template = "o-spreadsheet-ChartFigure";
18629
18950
  static components = {};
18630
18951
  onDoubleClick() {
18631
- this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figureId });
18952
+ this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
18632
18953
  this.env.openSidePanel("ChartPanel");
18633
18954
  }
18634
18955
  get chartType() {
18635
- return this.env.model.getters.getChartType(this.props.figureId);
18956
+ return this.env.model.getters.getChartType(this.props.figure.id);
18636
18957
  }
18637
18958
  get chartComponent() {
18638
18959
  const type = this.chartType;
@@ -18644,7 +18965,7 @@
18644
18965
  }
18645
18966
  }
18646
18967
  ChartFigure.props = {
18647
- figureId: String,
18968
+ figure: Object,
18648
18969
  onFigureDeleted: Function,
18649
18970
  };
18650
18971
 
@@ -18655,14 +18976,14 @@
18655
18976
  // Getters
18656
18977
  // ---------------------------------------------------------------------------
18657
18978
  get figureId() {
18658
- return this.props.figureId;
18979
+ return this.props.figure.id;
18659
18980
  }
18660
18981
  get getImagePath() {
18661
18982
  return this.env.model.getters.getImagePath(this.figureId);
18662
18983
  }
18663
18984
  }
18664
18985
  ImageFigure.props = {
18665
- figureId: String,
18986
+ figure: Object,
18666
18987
  onFigureDeleted: Function,
18667
18988
  };
18668
18989
 
@@ -20267,105 +20588,6 @@
20267
20588
  separator: true,
20268
20589
  });
20269
20590
 
20270
- const SORT_TYPES = [
20271
- CellValueType.number,
20272
- CellValueType.error,
20273
- CellValueType.text,
20274
- CellValueType.boolean,
20275
- ];
20276
- function sortCells(cells, sortDirection, emptyCellAsZero) {
20277
- const cellsWithIndex = cells.map((cell, index) => ({
20278
- index,
20279
- type: cell.type,
20280
- value: cell.value,
20281
- }));
20282
- let emptyCells = cellsWithIndex.filter((x) => x.type === CellValueType.empty);
20283
- let nonEmptyCells = cellsWithIndex.filter((x) => x.type !== CellValueType.empty);
20284
- if (emptyCellAsZero) {
20285
- nonEmptyCells.push(...emptyCells.map((emptyCell) => ({ ...emptyCell, type: CellValueType.number, value: 0 })));
20286
- emptyCells = [];
20287
- }
20288
- const inverse = sortDirection === "descending" ? -1 : 1;
20289
- return nonEmptyCells
20290
- .sort((left, right) => {
20291
- let typeOrder = SORT_TYPES.indexOf(left.type) - SORT_TYPES.indexOf(right.type);
20292
- if (typeOrder === 0) {
20293
- if (left.type === CellValueType.text || left.type === CellValueType.error) {
20294
- typeOrder = left.value.localeCompare(right.value);
20295
- }
20296
- else
20297
- typeOrder = left.value - right.value;
20298
- }
20299
- return inverse * typeOrder;
20300
- })
20301
- .concat(emptyCells);
20302
- }
20303
- function interactiveSortSelection(env, sheetId, anchor, zone, sortDirection) {
20304
- let result = DispatchResult.Success;
20305
- //several columns => bypass the contiguity check
20306
- let multiColumns = zone.right > zone.left;
20307
- if (env.model.getters.doesIntersectMerge(sheetId, zone)) {
20308
- multiColumns = false;
20309
- let table;
20310
- for (let row = zone.top; row <= zone.bottom; row++) {
20311
- table = [];
20312
- for (let col = zone.left; col <= zone.right; col++) {
20313
- let merge = env.model.getters.getMerge({ sheetId, col, row });
20314
- if (merge && !table.includes(merge.id.toString())) {
20315
- table.push(merge.id.toString());
20316
- }
20317
- }
20318
- if (table.length >= 2) {
20319
- multiColumns = true;
20320
- break;
20321
- }
20322
- }
20323
- }
20324
- const { col, row } = anchor;
20325
- if (multiColumns) {
20326
- result = env.model.dispatch("SORT_CELLS", { sheetId, col, row, zone, sortDirection });
20327
- }
20328
- else {
20329
- // check contiguity
20330
- const contiguousZone = env.model.getters.getContiguousZone(sheetId, zone);
20331
- if (isEqual(contiguousZone, zone)) {
20332
- // merge as it is
20333
- result = env.model.dispatch("SORT_CELLS", {
20334
- sheetId,
20335
- col,
20336
- row,
20337
- zone,
20338
- sortDirection,
20339
- });
20340
- }
20341
- else {
20342
- env.askConfirmation(_t("We found data next to your selection. Since this data was not selected, it will not be sorted. Do you want to extend your selection?"), () => {
20343
- zone = contiguousZone;
20344
- result = env.model.dispatch("SORT_CELLS", {
20345
- sheetId,
20346
- col,
20347
- row,
20348
- zone,
20349
- sortDirection,
20350
- });
20351
- }, () => {
20352
- result = env.model.dispatch("SORT_CELLS", {
20353
- sheetId,
20354
- col,
20355
- row,
20356
- zone,
20357
- sortDirection,
20358
- });
20359
- });
20360
- }
20361
- }
20362
- if (result.isCancelledBecause("InvalidSortZone" /* CommandResult.InvalidSortZone */)) {
20363
- const { col, row } = anchor;
20364
- env.model.selection.selectZone({ cell: { col, row }, zone });
20365
- env.raiseError(_t("Cannot sort. To sort, select only cells or only merges that have the same size."));
20366
- }
20367
- }
20368
-
20369
20591
  const AddFilterInteractiveContent = {
20370
20592
  filterOverlap: _t("You cannot create overlapping filters."),
20371
20593
  nonContinuousTargets: _t("A filter can only be created on a continuous selection."),
@@ -26548,7 +26770,6 @@
26548
26770
  border-top-right-radius: 4px;
26549
26771
  font-size: ${DEFAULT_FONT_SIZE};
26550
26772
  color: white;
26551
- opacity: 0;
26552
26773
  pointer-events: none;
26553
26774
  }
26554
26775
  `;
@@ -26568,7 +26789,6 @@
26568
26789
  left: `${x - 1}px`,
26569
26790
  border: `1px solid ${color}`,
26570
26791
  "background-color": color,
26571
- opacity: this.props.active ? "opacity:1 !important" : undefined,
26572
26792
  });
26573
26793
  }
26574
26794
  }
@@ -30114,6 +30334,8 @@
30114
30334
  const position = this.env.model.getters.getActivePosition();
30115
30335
  this.env.model.selection.selectZone({ cell: position, zone: newZone });
30116
30336
  },
30337
+ "CTRL+D": async () => this.env.model.dispatch("COPY_PASTE_CELLS_ABOVE"),
30338
+ "CTRL+R": async () => this.env.model.dispatch("COPY_PASTE_CELLS_ON_LEFT"),
30117
30339
  "CTRL+SHIFT+E": () => this.setHorizontalAlign("center"),
30118
30340
  "CTRL+SHIFT+L": () => this.setHorizontalAlign("left"),
30119
30341
  "CTRL+SHIFT+R": () => this.setHorizontalAlign("right"),
@@ -40743,7 +40965,7 @@
40743
40965
  return percentile(rangeValues, Number(threshold.value) / 100, true);
40744
40966
  case "formula":
40745
40967
  const value = threshold.value && this.getters.evaluateFormula(sheetId, threshold.value);
40746
- return !(value instanceof Promise) ? value : null;
40968
+ return typeof value === "number" ? value : null;
40747
40969
  default:
40748
40970
  return null;
40749
40971
  }
@@ -40869,10 +41091,13 @@
40869
41091
  }
40870
41092
  const [value0, value1] = rule.values.map((val) => {
40871
41093
  if (val.startsWith("=")) {
40872
- return this.getters.evaluateFormula(target.sheetId, val);
41094
+ return this.getters.evaluateFormula(target.sheetId, val) ?? "";
40873
41095
  }
40874
41096
  return parseLiteral(val, DEFAULT_LOCALE);
40875
41097
  });
41098
+ if (isMatrix(value0) || isMatrix(value1)) {
41099
+ return false;
41100
+ }
40876
41101
  switch (rule.operator) {
40877
41102
  case "IsEmpty":
40878
41103
  return cell.value.toString().trim() === "";
@@ -41061,7 +41286,7 @@
41061
41286
  const formula = compile(value);
41062
41287
  const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, formula, formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)));
41063
41288
  const evaluated = this.getters.evaluateFormula(sheetId, translatedFormula);
41064
- return evaluated ? evaluated.toString() : "";
41289
+ return evaluated && !isMatrix(evaluated) ? evaluated.toString() : "";
41065
41290
  }
41066
41291
  catch (e) {
41067
41292
  return e instanceof EvaluationError ? e.errorType : CellErrorType.GenericError;
@@ -46516,6 +46741,20 @@
46516
46741
  const state = new ClipboardOsState(cmd.text, this.getters, this.dispatch, this.selection);
46517
46742
  return state.isPasteAllowed(cmd.target, { pasteOption: cmd.pasteOption });
46518
46743
  }
46744
+ case "COPY_PASTE_CELLS_ABOVE": {
46745
+ const zones = this.getters.getSelectedZones();
46746
+ if (zones.length > 1 || (zones[0].top === 0 && zones[0].bottom === 0)) {
46747
+ return "InvalidCopyPasteSelection" /* CommandResult.InvalidCopyPasteSelection */;
46748
+ }
46749
+ break;
46750
+ }
46751
+ case "COPY_PASTE_CELLS_ON_LEFT": {
46752
+ const zones = this.getters.getSelectedZones();
46753
+ if (zones.length > 1 || (zones[0].left === 0 && zones[0].right === 0)) {
46754
+ return "InvalidCopyPasteSelection" /* CommandResult.InvalidCopyPasteSelection */;
46755
+ }
46756
+ break;
46757
+ }
46519
46758
  case "INSERT_CELL": {
46520
46759
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
46521
46760
  const state = this.getClipboardStateForCopyCells(cut, "CUT");
@@ -46555,6 +46794,40 @@
46555
46794
  this.status = "invisible";
46556
46795
  }
46557
46796
  break;
46797
+ case "COPY_PASTE_CELLS_ABOVE":
46798
+ {
46799
+ const zone = this.getters.getSelectedZone();
46800
+ const multipleRowsInSelection = zone.top !== zone.bottom;
46801
+ const copyTarget = {
46802
+ ...zone,
46803
+ bottom: multipleRowsInSelection ? zone.top : zone.top - 1,
46804
+ top: multipleRowsInSelection ? zone.top : zone.top - 1,
46805
+ };
46806
+ const state = this.getClipboardStateForCopyCells([copyTarget], "COPY");
46807
+ state.paste([zone], {
46808
+ pasteOption: undefined,
46809
+ shouldPasteCF: true,
46810
+ selectTarget: true,
46811
+ });
46812
+ }
46813
+ break;
46814
+ case "COPY_PASTE_CELLS_ON_LEFT":
46815
+ {
46816
+ const zone = this.getters.getSelectedZone();
46817
+ const multipleColsInSelection = zone.left !== zone.right;
46818
+ const copyTarget = {
46819
+ ...zone,
46820
+ right: multipleColsInSelection ? zone.left : zone.left - 1,
46821
+ left: multipleColsInSelection ? zone.left : zone.left - 1,
46822
+ };
46823
+ const state = this.getClipboardStateForCopyCells([copyTarget], "COPY");
46824
+ state.paste([zone], {
46825
+ pasteOption: undefined,
46826
+ shouldPasteCF: true,
46827
+ selectTarget: true,
46828
+ });
46829
+ }
46830
+ break;
46558
46831
  case "CLEAN_CLIPBOARD_HIGHLIGHT":
46559
46832
  this.status = "invisible";
46560
46833
  break;
@@ -47508,6 +47781,9 @@
47508
47781
  const cellValue = content.startsWith("=")
47509
47782
  ? this.getters.evaluateFormula(this.sheetId, content)
47510
47783
  : parseLiteral(content, this.getters.getLocale());
47784
+ if (isMatrix(cellValue)) {
47785
+ return "Success" /* CommandResult.Success */;
47786
+ }
47511
47787
  const validationResult = this.getters.getValidationResultForCellValue(cellValue, cellPosition);
47512
47788
  if (!validationResult.isValid && validationResult.rule.isBlocking) {
47513
47789
  return "BlockingValidationRule" /* CommandResult.BlockingValidationRule */;
@@ -48094,11 +48370,19 @@
48094
48370
  }
48095
48371
  }
48096
48372
  getStatisticFnResults() {
48097
- // get deduplicated cells in zones
48098
- const cells = new Set(this.gridSelection.zones
48099
- .map((zone) => this.getters.getEvaluatedCellsInZone(this.getters.getActiveSheetId(), zone))
48100
- .flat()
48101
- .filter((cell) => cell.type !== CellValueType.empty));
48373
+ const sheetId = this.getters.getActiveSheetId();
48374
+ const cells = new Set();
48375
+ for (const zone of this.gridSelection.zones) {
48376
+ for (const { col, row } of positions(zone)) {
48377
+ if (this.getters.isRowHidden(sheetId, row) || this.getters.isColHidden(sheetId, col)) {
48378
+ continue; // Skip hidden cells
48379
+ }
48380
+ const evaluatedCell = this.getters.getEvaluatedCell({ sheetId, col, row });
48381
+ if (evaluatedCell.type !== CellValueType.empty) {
48382
+ cells.add(evaluatedCell);
48383
+ }
48384
+ }
48385
+ }
48102
48386
  let cellsTypes = new Set();
48103
48387
  let cellsValues = [];
48104
48388
  for (let cell of cells) {
@@ -50739,6 +51023,7 @@
50739
51023
  css /* scss */ `
50740
51024
  .o-border-selector {
50741
51025
  padding: 4px;
51026
+ background-color: white;
50742
51027
  }
50743
51028
  .o-divider {
50744
51029
  border-right: 1px solid #e0e2e4;
@@ -55454,9 +55739,9 @@
55454
55739
  exports.tokenize = tokenize;
55455
55740
 
55456
55741
 
55457
- __info__.version = "16.5.0-alpha.11";
55458
- __info__.date = "2023-10-19T14:26:01.790Z";
55459
- __info__.hash = "4b42059";
55742
+ __info__.version = "16.5.0-alpha.13";
55743
+ __info__.date = "2023-10-25T10:04:45.428Z";
55744
+ __info__.hash = "18a08b1";
55460
55745
 
55461
55746
 
55462
55747
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);