@odoo/o-spreadsheet 16.5.0-alpha.12 → 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.12
6
- * @date 2023-10-20T15:12:28.296Z
7
- * @hash 430f090
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) {
@@ -7584,6 +7584,18 @@
7584
7584
  }
7585
7585
  return result;
7586
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
+ }
7587
7599
 
7588
7600
  // -----------------------------------------------------------------------------
7589
7601
  // ARRAY_CONSTRAIN
@@ -10297,6 +10309,42 @@
10297
10309
  },
10298
10310
  isExported: true,
10299
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
+ };
10300
10348
  // -----------------------------------------------------------------------------
10301
10349
  // RSQ
10302
10350
  // -----------------------------------------------------------------------------
@@ -10641,6 +10689,7 @@
10641
10689
  QUARTILE: QUARTILE,
10642
10690
  QUARTILE_EXC: QUARTILE_EXC,
10643
10691
  QUARTILE_INC: QUARTILE_INC,
10692
+ RANK: RANK,
10644
10693
  RSQ: RSQ,
10645
10694
  SLOPE: SLOPE,
10646
10695
  SMALL: SMALL,
@@ -11787,6 +11836,172 @@
11787
11836
  DELTA: DELTA
11788
11837
  });
11789
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
+ }
11790
12005
  // -----------------------------------------------------------------------------
11791
12006
  // FILTER
11792
12007
  // -----------------------------------------------------------------------------
@@ -11823,6 +12038,93 @@
11823
12038
  isExported: true,
11824
12039
  };
11825
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
+ // -----------------------------------------------------------------------------
11826
12128
  // UNIQUE
11827
12129
  // -----------------------------------------------------------------------------
11828
12130
  const UNIQUE = {
@@ -11870,6 +12172,8 @@
11870
12172
  var filter = /*#__PURE__*/Object.freeze({
11871
12173
  __proto__: null,
11872
12174
  FILTER: FILTER,
12175
+ SORT: SORT,
12176
+ SORTN: SORTN,
11873
12177
  UNIQUE: UNIQUE
11874
12178
  });
11875
12179
 
@@ -20284,105 +20588,6 @@
20284
20588
  separator: true,
20285
20589
  });
20286
20590
 
20287
- const SORT_TYPES = [
20288
- CellValueType.number,
20289
- CellValueType.error,
20290
- CellValueType.text,
20291
- CellValueType.boolean,
20292
- ];
20293
- function sortCells(cells, sortDirection, emptyCellAsZero) {
20294
- const cellsWithIndex = cells.map((cell, index) => ({
20295
- index,
20296
- type: cell.type,
20297
- value: cell.value,
20298
- }));
20299
- let emptyCells = cellsWithIndex.filter((x) => x.type === CellValueType.empty);
20300
- let nonEmptyCells = cellsWithIndex.filter((x) => x.type !== CellValueType.empty);
20301
- if (emptyCellAsZero) {
20302
- nonEmptyCells.push(...emptyCells.map((emptyCell) => ({ ...emptyCell, type: CellValueType.number, value: 0 })));
20303
- emptyCells = [];
20304
- }
20305
- const inverse = sortDirection === "descending" ? -1 : 1;
20306
- return nonEmptyCells
20307
- .sort((left, right) => {
20308
- let typeOrder = SORT_TYPES.indexOf(left.type) - SORT_TYPES.indexOf(right.type);
20309
- if (typeOrder === 0) {
20310
- if (left.type === CellValueType.text || left.type === CellValueType.error) {
20311
- typeOrder = left.value.localeCompare(right.value);
20312
- }
20313
- else
20314
- typeOrder = left.value - right.value;
20315
- }
20316
- return inverse * typeOrder;
20317
- })
20318
- .concat(emptyCells);
20319
- }
20320
- function interactiveSortSelection(env, sheetId, anchor, zone, sortDirection) {
20321
- let result = DispatchResult.Success;
20322
- //several columns => bypass the contiguity check
20323
- let multiColumns = zone.right > zone.left;
20324
- if (env.model.getters.doesIntersectMerge(sheetId, zone)) {
20325
- multiColumns = false;
20326
- let table;
20327
- for (let row = zone.top; row <= zone.bottom; row++) {
20328
- table = [];
20329
- for (let col = zone.left; col <= zone.right; col++) {
20330
- let merge = env.model.getters.getMerge({ sheetId, col, row });
20331
- if (merge && !table.includes(merge.id.toString())) {
20332
- table.push(merge.id.toString());
20333
- }
20334
- }
20335
- if (table.length >= 2) {
20336
- multiColumns = true;
20337
- break;
20338
- }
20339
- }
20340
- }
20341
- const { col, row } = anchor;
20342
- if (multiColumns) {
20343
- result = env.model.dispatch("SORT_CELLS", { sheetId, col, row, zone, sortDirection });
20344
- }
20345
- else {
20346
- // check contiguity
20347
- const contiguousZone = env.model.getters.getContiguousZone(sheetId, zone);
20348
- if (isEqual(contiguousZone, zone)) {
20349
- // merge as it is
20350
- result = env.model.dispatch("SORT_CELLS", {
20351
- sheetId,
20352
- col,
20353
- row,
20354
- zone,
20355
- sortDirection,
20356
- });
20357
- }
20358
- else {
20359
- 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?"), () => {
20360
- zone = contiguousZone;
20361
- result = env.model.dispatch("SORT_CELLS", {
20362
- sheetId,
20363
- col,
20364
- row,
20365
- zone,
20366
- sortDirection,
20367
- });
20368
- }, () => {
20369
- result = env.model.dispatch("SORT_CELLS", {
20370
- sheetId,
20371
- col,
20372
- row,
20373
- zone,
20374
- sortDirection,
20375
- });
20376
- });
20377
- }
20378
- }
20379
- if (result.isCancelledBecause("InvalidSortZone" /* CommandResult.InvalidSortZone */)) {
20380
- const { col, row } = anchor;
20381
- env.model.selection.selectZone({ cell: { col, row }, zone });
20382
- env.raiseError(_t("Cannot sort. To sort, select only cells or only merges that have the same size."));
20383
- }
20384
- }
20385
-
20386
20591
  const AddFilterInteractiveContent = {
20387
20592
  filterOverlap: _t("You cannot create overlapping filters."),
20388
20593
  nonContinuousTargets: _t("A filter can only be created on a continuous selection."),
@@ -26565,7 +26770,6 @@
26565
26770
  border-top-right-radius: 4px;
26566
26771
  font-size: ${DEFAULT_FONT_SIZE};
26567
26772
  color: white;
26568
- opacity: 0;
26569
26773
  pointer-events: none;
26570
26774
  }
26571
26775
  `;
@@ -26585,7 +26789,6 @@
26585
26789
  left: `${x - 1}px`,
26586
26790
  border: `1px solid ${color}`,
26587
26791
  "background-color": color,
26588
- opacity: this.props.active ? "opacity:1 !important" : undefined,
26589
26792
  });
26590
26793
  }
26591
26794
  }
@@ -40762,7 +40965,7 @@
40762
40965
  return percentile(rangeValues, Number(threshold.value) / 100, true);
40763
40966
  case "formula":
40764
40967
  const value = threshold.value && this.getters.evaluateFormula(sheetId, threshold.value);
40765
- return !(value instanceof Promise) ? value : null;
40968
+ return typeof value === "number" ? value : null;
40766
40969
  default:
40767
40970
  return null;
40768
40971
  }
@@ -40888,10 +41091,13 @@
40888
41091
  }
40889
41092
  const [value0, value1] = rule.values.map((val) => {
40890
41093
  if (val.startsWith("=")) {
40891
- return this.getters.evaluateFormula(target.sheetId, val);
41094
+ return this.getters.evaluateFormula(target.sheetId, val) ?? "";
40892
41095
  }
40893
41096
  return parseLiteral(val, DEFAULT_LOCALE);
40894
41097
  });
41098
+ if (isMatrix(value0) || isMatrix(value1)) {
41099
+ return false;
41100
+ }
40895
41101
  switch (rule.operator) {
40896
41102
  case "IsEmpty":
40897
41103
  return cell.value.toString().trim() === "";
@@ -41080,7 +41286,7 @@
41080
41286
  const formula = compile(value);
41081
41287
  const translatedFormula = this.getters.getTranslatedCellFormula(sheetId, offset.col, offset.row, formula, formula.dependencies.map((d) => this.getters.getRangeFromSheetXC(sheetId, d)));
41082
41288
  const evaluated = this.getters.evaluateFormula(sheetId, translatedFormula);
41083
- return evaluated ? evaluated.toString() : "";
41289
+ return evaluated && !isMatrix(evaluated) ? evaluated.toString() : "";
41084
41290
  }
41085
41291
  catch (e) {
41086
41292
  return e instanceof EvaluationError ? e.errorType : CellErrorType.GenericError;
@@ -47575,6 +47781,9 @@
47575
47781
  const cellValue = content.startsWith("=")
47576
47782
  ? this.getters.evaluateFormula(this.sheetId, content)
47577
47783
  : parseLiteral(content, this.getters.getLocale());
47784
+ if (isMatrix(cellValue)) {
47785
+ return "Success" /* CommandResult.Success */;
47786
+ }
47578
47787
  const validationResult = this.getters.getValidationResultForCellValue(cellValue, cellPosition);
47579
47788
  if (!validationResult.isValid && validationResult.rule.isBlocking) {
47580
47789
  return "BlockingValidationRule" /* CommandResult.BlockingValidationRule */;
@@ -50814,6 +51023,7 @@
50814
51023
  css /* scss */ `
50815
51024
  .o-border-selector {
50816
51025
  padding: 4px;
51026
+ background-color: white;
50817
51027
  }
50818
51028
  .o-divider {
50819
51029
  border-right: 1px solid #e0e2e4;
@@ -55529,9 +55739,9 @@
55529
55739
  exports.tokenize = tokenize;
55530
55740
 
55531
55741
 
55532
- __info__.version = "16.5.0-alpha.12";
55533
- __info__.date = "2023-10-20T15:12:28.296Z";
55534
- __info__.hash = "430f090";
55742
+ __info__.version = "16.5.0-alpha.13";
55743
+ __info__.date = "2023-10-25T10:04:45.428Z";
55744
+ __info__.hash = "18a08b1";
55535
55745
 
55536
55746
 
55537
55747
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);