@odoo/o-spreadsheet 16.5.0-alpha.7 → 16.5.0-alpha.8

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.
@@ -1,3 +1,12 @@
1
+
2
+ /**
3
+ * This file is generated by o-spreadsheet build tools. Do not edit it.
4
+ * @see https://github.com/odoo/o-spreadsheet
5
+ * @version 16.5.0-alpha.8
6
+ * @date 2023-09-21T15:59:10.959Z
7
+ * @hash 0b7527d
8
+ */
9
+
1
10
  'use strict';
2
11
 
3
12
  var owl = require('@odoo/owl');
@@ -233,13 +242,26 @@ const MENU_ITEM_PADDING_HORIZONTAL = 11;
233
242
  const MENU_ITEM_PADDING_VERTICAL = 4;
234
243
  const MENU_SEPARATOR_BORDER_WIDTH = 1;
235
244
  const MENU_SEPARATOR_PADDING = 5;
245
+ // Style
246
+ const DEFAULT_STYLE = {
247
+ align: "left",
248
+ verticalAlign: "bottom",
249
+ wrapping: "overflow",
250
+ bold: false,
251
+ italic: false,
252
+ strikethrough: false,
253
+ underline: false,
254
+ fontSize: 10,
255
+ fillColor: "",
256
+ textColor: "#000000",
257
+ };
258
+ const DEFAULT_VERTICAL_ALIGN = DEFAULT_STYLE.verticalAlign;
259
+ const DEFAULT_WRAPPING_MODE = DEFAULT_STYLE.wrapping;
236
260
  // Fonts
237
261
  const DEFAULT_FONT_WEIGHT = "400";
238
- const DEFAULT_FONT_SIZE = 10;
262
+ const DEFAULT_FONT_SIZE = DEFAULT_STYLE.fontSize;
239
263
  const HEADER_FONT_SIZE = 11;
240
264
  const DEFAULT_FONT = "'Roboto', arial";
241
- const DEFAULT_VERTICAL_ALIGN = "bottom";
242
- const DEFAULT_WRAPPING_MODE = "overflow";
243
265
  // Borders
244
266
  const DEFAULT_BORDER_DESC = { style: "thin", color: "#000000" };
245
267
  const DEFAULT_FILTER_BORDER_DESC = { style: "thin", color: FILTERS_COLOR };
@@ -617,13 +639,17 @@ function getAddHeaderStartIndex(position, base) {
617
639
  return position === "after" ? base + 1 : base;
618
640
  }
619
641
  /**
620
- * Compare two objects.
642
+ * Compares two objects.
621
643
  */
622
644
  function deepEquals(o1, o2) {
623
645
  if (o1 === o2)
624
646
  return true;
625
647
  if ((o1 && !o2) || (o2 && !o1))
626
648
  return false;
649
+ if (typeof o1 !== typeof o2)
650
+ return false;
651
+ if (typeof o1 !== "object")
652
+ return o1 === o2;
627
653
  // Objects can have different keys if the values are undefined
628
654
  const keys = new Set();
629
655
  Object.keys(o1).forEach((key) => keys.add(key));
@@ -739,6 +765,10 @@ function insertItemsAtIndex(array, items, index) {
739
765
  newArray.splice(index, 0, ...items);
740
766
  return newArray;
741
767
  }
768
+ function trimContent(content) {
769
+ const contentLines = content.split("\n");
770
+ return contentLines.map((line) => line.replace(/\s+/g, " ").trim()).join("\n");
771
+ }
742
772
 
743
773
  const RBA_REGEX = /rgba?\(|\s+|\)/gi;
744
774
  const HEX_MATCH = /^#([A-F\d]{2}){3,4}$/;
@@ -4405,6 +4435,16 @@ function toNumber(value, locale) {
4405
4435
  return 0;
4406
4436
  }
4407
4437
  }
4438
+ function tryCastAsNumberMatrix(data, argName) {
4439
+ data.forEach((row) => {
4440
+ row.forEach((cell) => {
4441
+ if (typeof cell !== "number") {
4442
+ throw new Error(_t("Function [[FUNCTION_NAME]] expects number values for %s, but got a %s.", typeof cell, argName));
4443
+ }
4444
+ });
4445
+ });
4446
+ return data;
4447
+ }
4408
4448
  function strictToNumber(value, locale) {
4409
4449
  if (value === "") {
4410
4450
  throw new Error(expectNumberValueError(value));
@@ -5349,6 +5389,7 @@ css /* scss */ `
5349
5389
  padding: 10px;
5350
5390
  width: ${ERROR_TOOLTIP_WIDTH}px;
5351
5391
  box-sizing: border-box !important;
5392
+ overflow-wrap: break-word;
5352
5393
  }
5353
5394
  `;
5354
5395
  class ErrorToolTip extends owl.Component {
@@ -8354,43 +8395,53 @@ var math = /*#__PURE__*/Object.freeze({
8354
8395
  TRUNC: TRUNC
8355
8396
  });
8356
8397
 
8357
- // Note: dataY and dataX may not have the same dimension
8358
- function covariance(dataY, dataX, isSample) {
8359
- let flatDataY = [];
8360
- let flatDataX = [];
8398
+ function assertSameNumberOfElements(...args) {
8399
+ const dims = args[0].length;
8400
+ args.forEach((arg, i) => assert(() => arg.length === dims, _t("[[FUNCTION_NAME]] has mismatched dimensions for argument %s (%s vs %s).", i.toString(), dims.toString(), arg.length.toString())));
8401
+ }
8402
+
8403
+ function filterAndFlatData(dataY, dataX) {
8404
+ const _flatDataY = [];
8405
+ const _flatDataX = [];
8361
8406
  let lenY = 0;
8362
8407
  let lenX = 0;
8363
8408
  visitAny([dataY], (y) => {
8364
- flatDataY.push(y);
8409
+ _flatDataY.push(y);
8365
8410
  lenY += 1;
8366
8411
  });
8367
8412
  visitAny([dataX], (x) => {
8368
- flatDataX.push(x);
8413
+ _flatDataX.push(x);
8369
8414
  lenX += 1;
8370
8415
  });
8371
- assert(() => lenY === lenX, _t("[[FUNCTION_NAME]] has mismatched argument count %s vs %s.", lenY.toString(), lenX.toString()));
8372
- let count = 0;
8373
- let sumY = 0;
8374
- let sumX = 0;
8416
+ assert(() => lenY === lenX, _t("[[FUNCTION_NAME]] has mismatched argument count %s vs %s.", lenY, lenX));
8417
+ const flatDataX = [];
8418
+ const flatDataY = [];
8375
8419
  for (let i = 0; i < lenY; i++) {
8376
- const valueY = flatDataY[i];
8377
- const valueX = flatDataX[i];
8420
+ const valueY = _flatDataY[i];
8421
+ const valueX = _flatDataX[i];
8378
8422
  if (typeof valueY === "number" && typeof valueX === "number") {
8379
- count += 1;
8380
- sumY += valueY;
8381
- sumX += valueX;
8423
+ flatDataY.push(valueY);
8424
+ flatDataX.push(valueX);
8382
8425
  }
8383
8426
  }
8427
+ return { flatDataX, flatDataY };
8428
+ }
8429
+ // Note: dataY and dataX may not have the same dimension
8430
+ function covariance(dataY, dataX, isSample) {
8431
+ const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
8432
+ const count = flatDataY.length;
8384
8433
  assert(() => count !== 0 && (!isSample || count !== 1), _t(`Evaluation of function [[FUNCTION_NAME]] caused a divide by zero error.`));
8434
+ let sumY = 0;
8435
+ let sumX = 0;
8436
+ for (let i = 0; i < count; i++) {
8437
+ sumY += flatDataY[i];
8438
+ sumX += flatDataX[i];
8439
+ }
8385
8440
  const averageY = sumY / count;
8386
8441
  const averageX = sumX / count;
8387
8442
  let acc = 0;
8388
- for (let i = 0; i < lenY; i++) {
8389
- const valueY = flatDataY[i];
8390
- const valueX = flatDataX[i];
8391
- if (typeof valueY === "number" && typeof valueX === "number") {
8392
- acc += (valueY - averageY) * (valueX - averageX);
8393
- }
8443
+ for (let i = 0; i < count; i++) {
8444
+ acc += (flatDataY[i] - averageY) * (flatDataX[i] - averageX);
8394
8445
  }
8395
8446
  return acc / (count - (isSample ? 1 : 0));
8396
8447
  }
@@ -8427,6 +8478,161 @@ function centile(data, percent, isInclusive, locale) {
8427
8478
  }
8428
8479
  return percentile(sortedArray, _percent, isInclusive);
8429
8480
  }
8481
+ function prepareDataForRegression(X, Y, newX) {
8482
+ const _X = X.length ? X : [range(1, Y.flat().length + 1)];
8483
+ const nVar = _X.length;
8484
+ let _newX = newX.length ? newX : _X;
8485
+ _newX = _newX.length === nVar ? transposeMatrix(_newX) : _newX;
8486
+ return { _X, _newX };
8487
+ }
8488
+ /*
8489
+ * This function performs a linear regression on the data set. It returns an array with two elements.
8490
+ * The first element is the slope, and the second element is the intercept.
8491
+ * The linear regression line is: y = slope*x + intercept
8492
+ * The function use the least squares method to find the best fit for the data set :
8493
+ * see https://www.mathsisfun.com/data/least-squares-regression.html
8494
+ * https://www.statology.org/standard-error-of-estimate/
8495
+ * https://agronomy4future.org/?p=16670
8496
+ * https://vitalflux.com/interpreting-f-statistics-in-linear-regression-formula-examples/
8497
+ * https://web.ist.utl.pt/~ist11038/compute/errtheory/,regression/regrthroughorigin.pdf
8498
+ */
8499
+ function fullLinearRegression(X, Y, computeIntercept = true, verbose = false) {
8500
+ const y = Y.flat();
8501
+ const n = y.length;
8502
+ let { _X } = prepareDataForRegression(X, Y, []);
8503
+ _X = _X.length === n ? transposeMatrix(_X) : _X.slice();
8504
+ assertSameNumberOfElements(_X[0], y);
8505
+ const nVar = _X.length;
8506
+ const nDeg = n - nVar - (computeIntercept ? 1 : 0);
8507
+ const yMatrix = [y];
8508
+ const xMatrix = transposeMatrix(_X.reverse());
8509
+ let avgX = [];
8510
+ for (let i = 0; i < nVar; i++) {
8511
+ avgX.push(0);
8512
+ if (computeIntercept) {
8513
+ for (const xij of _X[i]) {
8514
+ avgX[i] += xij;
8515
+ }
8516
+ avgX[i] /= n;
8517
+ }
8518
+ }
8519
+ let avgY = 0;
8520
+ if (computeIntercept) {
8521
+ for (const yi of y) {
8522
+ avgY += yi;
8523
+ }
8524
+ avgY /= n;
8525
+ }
8526
+ const redX = xMatrix.map((row) => row.map((value, i) => value - avgX[i]));
8527
+ if (computeIntercept) {
8528
+ xMatrix.forEach((row) => row.push(1));
8529
+ }
8530
+ const coeffs = getLMSCoefficients(xMatrix, yMatrix);
8531
+ if (!computeIntercept) {
8532
+ coeffs.push([0]);
8533
+ }
8534
+ if (!verbose) {
8535
+ return coeffs;
8536
+ }
8537
+ const dot1 = multiplyMatrices(redX, transposeMatrix(redX));
8538
+ const { inverted: dotInv } = invertMatrix(dot1);
8539
+ if (dotInv === undefined) {
8540
+ throw new Error(_t("Matrix is not invertible"));
8541
+ }
8542
+ let SSE = 0, SSR = 0;
8543
+ for (let i = 0; i < n; i++) {
8544
+ const yi = y[i] - avgY;
8545
+ let temp = 0;
8546
+ for (let j = 0; j < nVar; j++) {
8547
+ const xi = redX[i][j];
8548
+ temp += xi * coeffs[j][0];
8549
+ }
8550
+ const ei = yi - temp;
8551
+ SSE += ei * ei;
8552
+ SSR += temp * temp;
8553
+ }
8554
+ const RMSE = Math.sqrt(SSE / nDeg);
8555
+ const r2 = SSR / (SSR + SSE);
8556
+ const f_stat = SSR / nVar / (SSE / nDeg);
8557
+ const deltaCoeffs = [];
8558
+ for (let i = 0; i < nVar; i++) {
8559
+ deltaCoeffs.push(RMSE * Math.sqrt(dotInv[i][i]));
8560
+ }
8561
+ if (computeIntercept) {
8562
+ const dot2 = multiplyMatrices(dotInv, [avgX]);
8563
+ const dot3 = multiplyMatrices(transposeMatrix([avgX]), dot2);
8564
+ deltaCoeffs.push(RMSE * Math.sqrt(dot3[0][0] + 1 / y.length));
8565
+ }
8566
+ const returned = [
8567
+ [coeffs[0][0], deltaCoeffs[0], r2, f_stat, SSR],
8568
+ [coeffs[1][0], deltaCoeffs[1], RMSE, nDeg, SSE],
8569
+ ];
8570
+ for (let i = 2; i < nVar; i++) {
8571
+ returned.push([coeffs[i][0], deltaCoeffs[i], "", "", ""]);
8572
+ }
8573
+ if (computeIntercept) {
8574
+ returned.push([coeffs[nVar][0], deltaCoeffs[nVar], "", "", ""]);
8575
+ }
8576
+ else {
8577
+ returned.push([0, "", "", "", ""]);
8578
+ }
8579
+ return returned;
8580
+ }
8581
+ /*
8582
+ This function performs a polynomial regression on the data set. It returns the coefficients of
8583
+ the polynomial function that best fits the data set.
8584
+ The polynomial function is: y = c0 + c1*x + c2*x^2 + ... + cn*x^n, where n is the order (degree)
8585
+ of the polynomial. The returned coefficients are then in the form: [c0, c1, c2, ..., cn]
8586
+ The function is based on the method of least squares :
8587
+ see: https://mathworld.wolfram.com/LeastSquaresFittingPolynomial.html
8588
+ */
8589
+ function polynomialRegression(flatY, flatX, order, intercept) {
8590
+ assertSameNumberOfElements(flatX, flatY);
8591
+ assert(() => order >= 1, _t(`Function [[FUNCTION_NAME]] A regression of order less than 1 cannot be possible.`));
8592
+ const yMatrix = [flatY];
8593
+ const xMatrix = flatX.map((x) => range(0, order).map((i) => Math.pow(x, order - i)));
8594
+ if (intercept) {
8595
+ xMatrix.forEach((row) => row.push(1));
8596
+ }
8597
+ const coeffs = getLMSCoefficients(xMatrix, yMatrix);
8598
+ if (!intercept) {
8599
+ coeffs.push([0]);
8600
+ }
8601
+ return coeffs;
8602
+ }
8603
+ function getLMSCoefficients(xMatrix, yMatrix) {
8604
+ const xMatrixT = transposeMatrix(xMatrix);
8605
+ const dot1 = multiplyMatrices(xMatrix, xMatrixT);
8606
+ const { inverted: dotInv } = invertMatrix(dot1);
8607
+ if (dotInv === undefined) {
8608
+ throw new Error(_t("Matrix is not invertible"));
8609
+ }
8610
+ const dot2 = multiplyMatrices(xMatrix, yMatrix);
8611
+ return transposeMatrix(multiplyMatrices(dotInv, dot2));
8612
+ }
8613
+ function evaluatePolynomial(coeffs, x, order) {
8614
+ return coeffs.reduce((acc, coeff, i) => acc + coeff * Math.pow(x, order - i), 0);
8615
+ }
8616
+ function expM(M) {
8617
+ return M.map((col) => col.map((cell) => Math.exp(cell)));
8618
+ }
8619
+ function logM(M) {
8620
+ return M.map((col) => col.map((cell) => Math.log(cell)));
8621
+ }
8622
+ function predictLinearValues(Y, X, newX, computeIntercept) {
8623
+ const { _X, _newX } = prepareDataForRegression(X, Y, newX);
8624
+ const coeffs = fullLinearRegression(_X, Y, computeIntercept, false);
8625
+ const nVar = coeffs.length - 1;
8626
+ const newY = _newX.map((col) => {
8627
+ let value = 0;
8628
+ for (let i = 0; i < nVar; i++) {
8629
+ value += coeffs[i][0] * col[nVar - i - 1];
8630
+ }
8631
+ value += coeffs[nVar][0];
8632
+ return [value];
8633
+ });
8634
+ return newY.length === newX.length ? newY : transposeMatrix(newY);
8635
+ }
8430
8636
  // -----------------------------------------------------------------------------
8431
8637
  // AVEDEV
8432
8638
  // -----------------------------------------------------------------------------
@@ -8711,6 +8917,56 @@ const COVARIANCE_S = {
8711
8917
  isExported: true,
8712
8918
  };
8713
8919
  // -----------------------------------------------------------------------------
8920
+ // FORECAST
8921
+ // -----------------------------------------------------------------------------
8922
+ const FORECAST = {
8923
+ description: _t("Calculates the expected y-value for a specified x based on a linear regression of a dataset."),
8924
+ args: [
8925
+ arg("x (number, range<number>)", _t("The value(s) on the x-axis to forecast.")),
8926
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
8927
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
8928
+ ],
8929
+ returns: ["NUMBER"],
8930
+ compute: function (x, dataY, dataX) {
8931
+ const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
8932
+ return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
8933
+ },
8934
+ isExported: true,
8935
+ };
8936
+ // -----------------------------------------------------------------------------
8937
+ // GROWTH
8938
+ // -----------------------------------------------------------------------------
8939
+ const GROWTH = {
8940
+ description: _t("Fits points to exponential growth trend."),
8941
+ args: [
8942
+ arg("known_data_y (range<number>)", _t("The array or range containing dependent (y) values that are already known, used to curve fit an ideal exponential growth curve.")),
8943
+ arg("known_data_x (range<number>, default={1;2;3;...})", _t("The values of the independent variable(s) corresponding with known_data_y.")),
8944
+ arg("new_data_x (any, range, default=known_data_x)", _t("The data points to return the y values for on the ideal curve fit.")),
8945
+ arg("b (boolean, default=TRUE)", _t("Given a general exponential form of y = b*m^x for a curve fit, calculates b if TRUE or forces b to be 1 and only calculates the m values if FALSE.")),
8946
+ ],
8947
+ returns: ["NUMBER"],
8948
+ compute: function (knownDataY, knownDataX = [], newDataX = [], b = true) {
8949
+ return expM(predictLinearValues(logM(tryCastAsNumberMatrix(knownDataY, "the first argument (known_data_y)")), tryCastAsNumberMatrix(knownDataX, "the second argument (known_data_x)"), tryCastAsNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b)));
8950
+ },
8951
+ };
8952
+ // -----------------------------------------------------------------------------
8953
+ // INTERCEPT
8954
+ // -----------------------------------------------------------------------------
8955
+ const INTERCEPT = {
8956
+ description: _t("Compute the intercept of the linear regression."),
8957
+ args: [
8958
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
8959
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
8960
+ ],
8961
+ returns: ["NUMBER"],
8962
+ compute: function (dataY, dataX) {
8963
+ const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
8964
+ const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
8965
+ return intercept;
8966
+ },
8967
+ isExported: true,
8968
+ };
8969
+ // -----------------------------------------------------------------------------
8714
8970
  // LARGE
8715
8971
  // -----------------------------------------------------------------------------
8716
8972
  const LARGE = {
@@ -8738,12 +8994,94 @@ const LARGE = {
8738
8994
  });
8739
8995
  const result = largests.shift();
8740
8996
  assert(() => result !== undefined, _t(`[[FUNCTION_NAME]] has no valid input data.`));
8741
- assert(() => count >= _n, _t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n.toString()));
8997
+ assert(() => count >= _n, _t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n));
8742
8998
  return result;
8743
8999
  },
8744
9000
  isExported: true,
8745
9001
  };
8746
9002
  // -----------------------------------------------------------------------------
9003
+ // LINEST
9004
+ // -----------------------------------------------------------------------------
9005
+ const LINEST = {
9006
+ description: _t("Compute the intercept of the linear regression."),
9007
+ args: [
9008
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9009
+ arg("data_x (range<number>, default={1;2;3;...})", _t("The range representing the array or matrix of independent data.")),
9010
+ arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
9011
+ arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
9012
+ ],
9013
+ returns: ["NUMBER"],
9014
+ compute: function (dataY, dataX = [], calculateB = true, verbose = false) {
9015
+ return fullLinearRegression(tryCastAsNumberMatrix(dataX, "the first argument (data_y)"), tryCastAsNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
9016
+ },
9017
+ isExported: true,
9018
+ };
9019
+ // -----------------------------------------------------------------------------
9020
+ // LOGEST
9021
+ // -----------------------------------------------------------------------------
9022
+ const LOGEST = {
9023
+ description: _t("Compute the intercept of the linear regression."),
9024
+ args: [
9025
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9026
+ arg("data_x (range<number>, optional, default={1;2;3;...})", _t("The range representing the array or matrix of independent data.")),
9027
+ arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
9028
+ arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
9029
+ ],
9030
+ returns: ["NUMBER"],
9031
+ compute: function (dataY, dataX = [], calculateB = true, verbose = false) {
9032
+ const coeffs = fullLinearRegression(tryCastAsNumberMatrix(dataX, "the second argument (data_x)"), logM(tryCastAsNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
9033
+ for (let i = 0; i < coeffs.length; i++) {
9034
+ coeffs[i][0] = Math.exp(coeffs[i][0]);
9035
+ }
9036
+ return coeffs;
9037
+ },
9038
+ isExported: true,
9039
+ };
9040
+ // -----------------------------------------------------------------------------
9041
+ // MATTHEWS
9042
+ // -----------------------------------------------------------------------------
9043
+ const MATTHEWS = {
9044
+ description: _t("Compute the Matthews correlation coefficient of a dataset."),
9045
+ args: [
9046
+ arg("data_x (range)", _t("The range representing the array or matrix of observed data.")),
9047
+ arg("data_y (range)", _t("The range representing the array or matrix of predicted data.")),
9048
+ ],
9049
+ returns: ["NUMBER"],
9050
+ compute: function (dataX, dataY) {
9051
+ const flatX = dataX.flat();
9052
+ const flatY = dataY.flat();
9053
+ assertSameNumberOfElements(flatX, flatY);
9054
+ if (flatX.length === 0) {
9055
+ throw new Error(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
9056
+ }
9057
+ const n = flatX.length;
9058
+ let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
9059
+ for (let i = 0; i < n; ++i) {
9060
+ const isTrue1 = toBoolean(flatX[i]);
9061
+ const isTrue2 = toBoolean(flatY[i]);
9062
+ if (isTrue1 === isTrue2) {
9063
+ if (isTrue1) {
9064
+ trueP++;
9065
+ }
9066
+ else {
9067
+ trueN++;
9068
+ }
9069
+ }
9070
+ else {
9071
+ if (isTrue1) {
9072
+ falseN++;
9073
+ }
9074
+ else {
9075
+ falseP++;
9076
+ }
9077
+ }
9078
+ }
9079
+ return ((trueP * trueN - falseP * falseN) /
9080
+ Math.sqrt((trueP + falseP) * (trueP + falseN) * (trueN + falseP) * (trueN + falseN)));
9081
+ },
9082
+ isExported: false,
9083
+ };
9084
+ // -----------------------------------------------------------------------------
8747
9085
  // MAX
8748
9086
  // -----------------------------------------------------------------------------
8749
9087
  const MAX = {
@@ -8898,6 +9236,41 @@ const MINIFS = {
8898
9236
  isExported: true,
8899
9237
  };
8900
9238
  // -----------------------------------------------------------------------------
9239
+ // PEARSON
9240
+ // -----------------------------------------------------------------------------
9241
+ const PEARSON = {
9242
+ description: _t("Compute the Pearson product-moment correlation coefficient of a dataset."),
9243
+ args: [
9244
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9245
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
9246
+ ],
9247
+ returns: ["NUMBER"],
9248
+ compute: function (dataY, dataX) {
9249
+ const { flatDataX, flatDataY } = filterAndFlatData(dataX, dataY);
9250
+ if (flatDataX.length === 0) {
9251
+ throw new Error(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
9252
+ }
9253
+ if (flatDataX.length < 2) {
9254
+ throw new Error(_t("[[FUNCTION_NAME]] needs at least two values for both parameters"));
9255
+ }
9256
+ const n = flatDataX.length;
9257
+ let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0, sumYY = 0;
9258
+ for (let i = 0; i < n; i++) {
9259
+ const xij = flatDataX[i];
9260
+ const yij = flatDataY[i];
9261
+ sumX += xij;
9262
+ sumY += yij;
9263
+ sumXY += xij * yij;
9264
+ sumXX += xij * xij;
9265
+ sumYY += yij * yij;
9266
+ }
9267
+ return ((n * sumXY - sumX * sumY) / Math.sqrt((n * sumXX - sumX * sumX) * (n * sumYY - sumY * sumY)));
9268
+ },
9269
+ isExported: true,
9270
+ };
9271
+ // In GSheet, CORREL is just an alias to PEARSON
9272
+ const CORREL = PEARSON;
9273
+ // -----------------------------------------------------------------------------
8901
9274
  // PERCENTILE
8902
9275
  // -----------------------------------------------------------------------------
8903
9276
  const PERCENTILE = {
@@ -8952,6 +9325,45 @@ const PERCENTILE_INC = {
8952
9325
  isExported: true,
8953
9326
  };
8954
9327
  // -----------------------------------------------------------------------------
9328
+ // POLYFIT
9329
+ // -----------------------------------------------------------------------------
9330
+ const POLYFIT_COEFFS = {
9331
+ description: _t("Compute the coefficients of polynomial regression of the dataset."),
9332
+ args: [
9333
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9334
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
9335
+ arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
9336
+ arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
9337
+ ],
9338
+ returns: ["RANGE<NUMBER>"],
9339
+ compute: function (dataY, dataX, order, intercept = true) {
9340
+ const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
9341
+ return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
9342
+ },
9343
+ isExported: false,
9344
+ };
9345
+ // -----------------------------------------------------------------------------
9346
+ // POLYFIT.FORECAST
9347
+ // -----------------------------------------------------------------------------
9348
+ const POLYFIT_FORECAST = {
9349
+ description: _t("Predict value by computing a polynomial regression of the dataset."),
9350
+ args: [
9351
+ arg("x (number, range<number>)", _t("The value(s) on the x-axis to forecast.")),
9352
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9353
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
9354
+ arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
9355
+ arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
9356
+ ],
9357
+ returns: ["NUMBER"],
9358
+ compute: function (x, dataY, dataX, order, intercept = true) {
9359
+ const _order = toNumber(order, this.locale);
9360
+ const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
9361
+ const coeffs = polynomialRegression(flatDataY, flatDataX, _order, toBoolean(intercept)).flat();
9362
+ return matrixMap(toMatrix(x), (xij) => evaluatePolynomial(coeffs, toNumber(xij, this.locale), _order));
9363
+ },
9364
+ isExported: false,
9365
+ };
9366
+ // -----------------------------------------------------------------------------
8955
9367
  // QUARTILE
8956
9368
  // -----------------------------------------------------------------------------
8957
9369
  const QUARTILE = {
@@ -9008,6 +9420,39 @@ const QUARTILE_INC = {
9008
9420
  isExported: true,
9009
9421
  };
9010
9422
  // -----------------------------------------------------------------------------
9423
+ // RSQ
9424
+ // -----------------------------------------------------------------------------
9425
+ const RSQ = {
9426
+ description: _t("Compute the square of r, the Pearson product-moment correlation coefficient of a dataset."),
9427
+ args: [
9428
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9429
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
9430
+ ],
9431
+ returns: ["NUMBER"],
9432
+ compute: function (dataY, dataX) {
9433
+ const pearson = PEARSON.compute.bind(this);
9434
+ return Math.pow(pearson(dataX, dataY), 2.0);
9435
+ },
9436
+ isExported: true,
9437
+ };
9438
+ // -----------------------------------------------------------------------------
9439
+ // SLOPE
9440
+ // -----------------------------------------------------------------------------
9441
+ const SLOPE = {
9442
+ description: _t("Compute the slope of the linear regression."),
9443
+ args: [
9444
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9445
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
9446
+ ],
9447
+ returns: ["NUMBER"],
9448
+ compute: function (dataY, dataX) {
9449
+ const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
9450
+ const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
9451
+ return slope;
9452
+ },
9453
+ isExported: true,
9454
+ };
9455
+ // -----------------------------------------------------------------------------
9011
9456
  // SMALL
9012
9457
  // -----------------------------------------------------------------------------
9013
9458
  const SMALL = {
@@ -9035,12 +9480,39 @@ const SMALL = {
9035
9480
  });
9036
9481
  const result = largests.pop();
9037
9482
  assert(() => result !== undefined, _t(`[[FUNCTION_NAME]] has no valid input data.`));
9038
- assert(() => count >= _n, _t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n.toString()));
9483
+ assert(() => count >= _n, _t("Function [[FUNCTION_NAME]] parameter 2 value (%s) is out of range.", _n));
9039
9484
  return result;
9040
9485
  },
9041
9486
  isExported: true,
9042
9487
  };
9043
9488
  // -----------------------------------------------------------------------------
9489
+ // SPEARMAN
9490
+ // -----------------------------------------------------------------------------
9491
+ const SPEARMAN = {
9492
+ description: _t("Compute the Spearman rank correlation coefficient of a dataset."),
9493
+ args: [
9494
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9495
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
9496
+ ],
9497
+ returns: ["NUMBER"],
9498
+ compute: function (dataX, dataY) {
9499
+ const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
9500
+ const n = flatDataX.length;
9501
+ const order = flatDataX.map((e, i) => [e, flatDataY[i]]);
9502
+ order.sort((a, b) => a[0] - b[0]);
9503
+ for (let i = 0; i < n; ++i) {
9504
+ order[i][0] = i;
9505
+ }
9506
+ order.sort((a, b) => a[1] - b[1]);
9507
+ let sum = 0.0;
9508
+ for (let i = 0; i < n; ++i) {
9509
+ sum += (order[i][0] - i) ** 2;
9510
+ }
9511
+ return 1 - (6 * sum) / (n ** 3 - n);
9512
+ },
9513
+ isExported: false,
9514
+ };
9515
+ // -----------------------------------------------------------------------------
9044
9516
  // STDEV
9045
9517
  // -----------------------------------------------------------------------------
9046
9518
  const STDEV = {
@@ -9131,6 +9603,39 @@ const STDEVPA = {
9131
9603
  isExported: true,
9132
9604
  };
9133
9605
  // -----------------------------------------------------------------------------
9606
+ // STEYX
9607
+ // -----------------------------------------------------------------------------
9608
+ const STEYX = {
9609
+ description: _t("Calculates the standard error of the predicted y-value for each x in the regression of a dataset."),
9610
+ args: [
9611
+ arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
9612
+ arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
9613
+ ],
9614
+ returns: ["NUMBER"],
9615
+ compute: function (dataY, dataX) {
9616
+ const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
9617
+ const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
9618
+ return data[1][2];
9619
+ },
9620
+ isExported: true,
9621
+ };
9622
+ // -----------------------------------------------------------------------------
9623
+ // TREND
9624
+ // -----------------------------------------------------------------------------
9625
+ const TREND = {
9626
+ description: _t("Fits points to linear trend derived via least-squares."),
9627
+ args: [
9628
+ arg("known_data_y (number, range<number>)", _t("The array or range containing dependent (y) values that are already known, used to curve fit an ideal linear trend.")),
9629
+ arg("known_data_x (number, range<number>, optional, default={1;2;3;...})", _t("The values of the independent variable(s) corresponding with known_data_y.")),
9630
+ arg("new_data_x (number, range<number>, optional, default=known_data_x)", _t("The data points to return the y values for on the ideal curve fit.")),
9631
+ arg("b (boolean, optional, default=TRUE)", _t("Given a general linear form of y = m*x+b for a curve fit, calculates b if TRUE or forces b to be 0 and only calculates the m values if FALSE, i.e. forces the curve fit to pass through the origin.")),
9632
+ ],
9633
+ returns: ["NUMBER"],
9634
+ compute: function (knownDataY, knownDataX = [], newDataX = [], b = true) {
9635
+ return predictLinearValues(tryCastAsNumberMatrix(knownDataY, "the first argument (known_data_y)"), tryCastAsNumberMatrix(knownDataX, "the second argument (known_data_x)"), tryCastAsNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b));
9636
+ },
9637
+ };
9638
+ // -----------------------------------------------------------------------------
9134
9639
  // VAR
9135
9640
  // -----------------------------------------------------------------------------
9136
9641
  const VAR = {
@@ -9229,12 +9734,19 @@ var statistical = /*#__PURE__*/Object.freeze({
9229
9734
  AVERAGEIF: AVERAGEIF,
9230
9735
  AVERAGEIFS: AVERAGEIFS,
9231
9736
  AVERAGE_WEIGHTED: AVERAGE_WEIGHTED,
9737
+ CORREL: CORREL,
9232
9738
  COUNT: COUNT,
9233
9739
  COUNTA: COUNTA,
9234
9740
  COVAR: COVAR,
9235
9741
  COVARIANCE_P: COVARIANCE_P,
9236
9742
  COVARIANCE_S: COVARIANCE_S,
9743
+ FORECAST: FORECAST,
9744
+ GROWTH: GROWTH,
9745
+ INTERCEPT: INTERCEPT,
9237
9746
  LARGE: LARGE,
9747
+ LINEST: LINEST,
9748
+ LOGEST: LOGEST,
9749
+ MATTHEWS: MATTHEWS,
9238
9750
  MAX: MAX,
9239
9751
  MAXA: MAXA,
9240
9752
  MAXIFS: MAXIFS,
@@ -9242,19 +9754,27 @@ var statistical = /*#__PURE__*/Object.freeze({
9242
9754
  MIN: MIN,
9243
9755
  MINA: MINA,
9244
9756
  MINIFS: MINIFS,
9757
+ PEARSON: PEARSON,
9245
9758
  PERCENTILE: PERCENTILE,
9246
9759
  PERCENTILE_EXC: PERCENTILE_EXC,
9247
9760
  PERCENTILE_INC: PERCENTILE_INC,
9761
+ POLYFIT_COEFFS: POLYFIT_COEFFS,
9762
+ POLYFIT_FORECAST: POLYFIT_FORECAST,
9248
9763
  QUARTILE: QUARTILE,
9249
9764
  QUARTILE_EXC: QUARTILE_EXC,
9250
9765
  QUARTILE_INC: QUARTILE_INC,
9766
+ RSQ: RSQ,
9767
+ SLOPE: SLOPE,
9251
9768
  SMALL: SMALL,
9769
+ SPEARMAN: SPEARMAN,
9252
9770
  STDEV: STDEV,
9253
9771
  STDEVA: STDEVA,
9254
9772
  STDEVP: STDEVP,
9255
9773
  STDEVPA: STDEVPA,
9256
9774
  STDEV_P: STDEV_P,
9257
9775
  STDEV_S: STDEV_S,
9776
+ STEYX: STEYX,
9777
+ TREND: TREND,
9258
9778
  VAR: VAR,
9259
9779
  VARA: VARA,
9260
9780
  VARP: VARP,
@@ -13889,7 +14409,7 @@ const TRIM = {
13889
14409
  ],
13890
14410
  returns: ["STRING"],
13891
14411
  compute: function (text) {
13892
- return toString(text).trim();
14412
+ return trimContent(toString(text));
13893
14413
  },
13894
14414
  isExported: true,
13895
14415
  };
@@ -19438,6 +19958,12 @@ const removeDuplicates = {
19438
19958
  env.openSidePanel("RemoveDuplicates", {});
19439
19959
  },
19440
19960
  };
19961
+ const trimWhitespace = {
19962
+ name: _t("Trim whitespace"),
19963
+ execute: (env) => {
19964
+ env.model.dispatch("TRIM_WHITESPACE");
19965
+ },
19966
+ };
19441
19967
  const sortDescending = {
19442
19968
  name: _t("Descending (Z ⟶ A)"),
19443
19969
  execute: (env) => {
@@ -20797,6 +21323,10 @@ topbarMenuRegistry
20797
21323
  .addChild("remove_duplicates", ["data", "data_cleanup"], {
20798
21324
  ...removeDuplicates,
20799
21325
  sequence: 10,
21326
+ })
21327
+ .addChild("trim_whitespace", ["data", "data_cleanup"], {
21328
+ ...trimWhitespace,
21329
+ sequence: 20,
20800
21330
  })
20801
21331
  .addChild("split_to_columns", ["data"], {
20802
21332
  ...splitToColumns,
@@ -25972,9 +26502,11 @@ function useCellHovered(env, gridRef, callback) {
25972
26502
  }
25973
26503
  }
25974
26504
  function updateMousePosition(e) {
25975
- x = e.offsetX;
25976
- y = e.offsetY;
25977
- lastMoved = Date.now();
26505
+ if (gridRef.el === e.target) {
26506
+ x = e.offsetX;
26507
+ y = e.offsetY;
26508
+ lastMoved = Date.now();
26509
+ }
25978
26510
  }
25979
26511
  function recompute() {
25980
26512
  const { col, row } = getPosition();
@@ -32456,8 +32988,9 @@ class CellPlugin extends CorePlugin {
32456
32988
  for (const position of positions) {
32457
32989
  const cell = this.getters.getCell(position);
32458
32990
  const xc = toXC(position.col, position.row);
32991
+ const style = this.removeDefaultStyleValues(cell.style);
32459
32992
  cells[xc] = {
32460
- style: cell.style ? getItemId(cell.style, styles) : undefined,
32993
+ style: Object.keys(style).length ? getItemId(style, styles) : undefined,
32461
32994
  format: cell.format ? getItemId(cell.format, formats) : undefined,
32462
32995
  content: cell.content || undefined,
32463
32996
  };
@@ -32476,6 +33009,15 @@ class CellPlugin extends CorePlugin {
32476
33009
  exportForExcel(data) {
32477
33010
  this.export(data);
32478
33011
  }
33012
+ removeDefaultStyleValues(style) {
33013
+ const cleanedStyle = { ...style };
33014
+ for (const [property, defaultValue] of Object.entries(DEFAULT_STYLE)) {
33015
+ if (cleanedStyle[property] === defaultValue) {
33016
+ delete cleanedStyle[property];
33017
+ }
33018
+ }
33019
+ return cleanedStyle;
33020
+ }
32479
33021
  // ---------------------------------------------------------------------------
32480
33022
  // GETTERS
32481
33023
  // ---------------------------------------------------------------------------
@@ -39814,6 +40356,7 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
39814
40356
  cells;
39815
40357
  copiedTables;
39816
40358
  zones;
40359
+ uuidGenerator = new UuidGenerator();
39817
40360
  constructor(zones, operation, getters, dispatch, selection) {
39818
40361
  super(operation, getters, dispatch, selection);
39819
40362
  if (!zones.length) {
@@ -40266,8 +40809,9 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
40266
40809
  this.adaptCFRules(origin.sheetId, cf, [xc], toRemoveRange);
40267
40810
  }
40268
40811
  else {
40269
- this.adaptCFRules(target.sheetId, cf, [xc], []);
40270
40812
  this.adaptCFRules(origin.sheetId, cf, [], toRemoveRange);
40813
+ const cfToCopyTo = this.getCFToCopyTo(target.sheetId, cf);
40814
+ this.adaptCFRules(target.sheetId, cfToCopyTo, [xc], []);
40271
40815
  }
40272
40816
  }
40273
40817
  }
@@ -40291,6 +40835,12 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
40291
40835
  sheetId,
40292
40836
  });
40293
40837
  }
40838
+ getCFToCopyTo(targetSheetId, originCF) {
40839
+ const cfInTarget = this.getters
40840
+ .getConditionalFormats(targetSheetId)
40841
+ .find((cf) => cf.stopIfTrue === originCF.stopIfTrue && deepEquals(cf.rule, originCF.rule));
40842
+ return cfInTarget ? cfInTarget : { ...originCF, id: this.uuidGenerator.uuidv4(), ranges: [] };
40843
+ }
40294
40844
  }
40295
40845
 
40296
40846
  class DataCleanupPlugin extends UIPlugin {
@@ -40309,6 +40859,9 @@ class DataCleanupPlugin extends UIPlugin {
40309
40859
  case "REMOVE_DUPLICATES":
40310
40860
  this.removeDuplicates(cmd.columns, cmd.hasHeader);
40311
40861
  break;
40862
+ case "TRIM_WHITESPACE":
40863
+ this.trimWhitespace();
40864
+ break;
40312
40865
  }
40313
40866
  }
40314
40867
  // ---------------------------------------------------------------------------
@@ -40429,6 +40982,35 @@ class DataCleanupPlugin extends UIPlugin {
40429
40982
  }
40430
40983
  return "Success" /* CommandResult.Success */;
40431
40984
  }
40985
+ trimWhitespace() {
40986
+ const zones = this.getters.getSelectedZones();
40987
+ const sheetId = this.getters.getActiveSheetId();
40988
+ let count = 0;
40989
+ for (const { col, row } of zones.map(positions).flat()) {
40990
+ const cell = this.getters.getCell({ col, row, sheetId });
40991
+ if (!cell) {
40992
+ continue;
40993
+ }
40994
+ const trimmedContent = trimContent(cell.content);
40995
+ if (trimmedContent !== cell.content) {
40996
+ count += 1;
40997
+ this.dispatch("UPDATE_CELL", {
40998
+ sheetId,
40999
+ col,
41000
+ row,
41001
+ content: trimmedContent,
41002
+ });
41003
+ }
41004
+ }
41005
+ const text = count
41006
+ ? _t("Trimmed whitespace from %s cells.", count)
41007
+ : _t("No selected cells had whitespace trimmed.");
41008
+ this.ui.notifyUI({
41009
+ type: "info",
41010
+ text: text,
41011
+ sticky: false,
41012
+ });
41013
+ }
40432
41014
  }
40433
41015
 
40434
41016
  const BORDER_COLOR = "#8B008B";
@@ -43227,7 +43809,7 @@ class ClipboardPlugin extends UIPlugin {
43227
43809
  allowDispatch(cmd) {
43228
43810
  switch (cmd.type) {
43229
43811
  case "CUT":
43230
- const zones = cmd.cutTarget || this.getters.getSelectedZones();
43812
+ const zones = this.getters.getSelectedZones();
43231
43813
  const state = this.getClipboardState(zones, cmd.type);
43232
43814
  return state.isCutAllowed(zones);
43233
43815
  case "PASTE":
@@ -43262,7 +43844,7 @@ class ClipboardPlugin extends UIPlugin {
43262
43844
  switch (cmd.type) {
43263
43845
  case "COPY":
43264
43846
  case "CUT":
43265
- const zones = ("cutTarget" in cmd && cmd.cutTarget) || this.getters.getSelectedZones();
43847
+ const zones = this.getters.getSelectedZones();
43266
43848
  this.state = this.getClipboardState(zones, cmd.type);
43267
43849
  this.status = "visible";
43268
43850
  this.originSheetId = this.getters.getActiveSheetId();
@@ -44926,26 +45508,24 @@ class GridSelectionPlugin extends UIPlugin {
44926
45508
  const isBasedBefore = cmd.base < start;
44927
45509
  const deltaCol = isBasedBefore && isCol ? thickness : 0;
44928
45510
  const deltaRow = isBasedBefore && !isCol ? thickness : 0;
44929
- this.dispatch("CUT", {
44930
- cutTarget: [
44931
- {
44932
- left: isCol ? start + deltaCol : 0,
44933
- right: isCol ? end + deltaCol : this.getters.getNumberCols(cmd.sheetId) - 1,
44934
- top: !isCol ? start + deltaRow : 0,
44935
- bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
44936
- },
44937
- ],
44938
- });
44939
- this.dispatch("PASTE", {
44940
- target: [
44941
- {
44942
- left: isCol ? cmd.base : 0,
44943
- right: isCol ? cmd.base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
44944
- top: !isCol ? cmd.base : 0,
44945
- bottom: !isCol ? cmd.base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
44946
- },
44947
- ],
44948
- });
45511
+ const target = [
45512
+ {
45513
+ left: isCol ? start + deltaCol : 0,
45514
+ right: isCol ? end + deltaCol : this.getters.getNumberCols(cmd.sheetId) - 1,
45515
+ top: !isCol ? start + deltaRow : 0,
45516
+ bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
45517
+ },
45518
+ ];
45519
+ const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
45520
+ const pasteTarget = [
45521
+ {
45522
+ left: isCol ? cmd.base : 0,
45523
+ right: isCol ? cmd.base + thickness - 1 : this.getters.getNumberCols(cmd.sheetId) - 1,
45524
+ top: !isCol ? cmd.base : 0,
45525
+ bottom: !isCol ? cmd.base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
45526
+ },
45527
+ ];
45528
+ state.paste(pasteTarget, { selectTarget: true });
44949
45529
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
44950
45530
  let currentIndex = cmd.base;
44951
45531
  for (const element of toRemove) {
@@ -52294,6 +52874,6 @@ exports.setTranslationMethod = setTranslationMethod;
52294
52874
  exports.tokenize = tokenize;
52295
52875
 
52296
52876
 
52297
- __info__.version = '16.5.0-alpha.7';
52298
- __info__.date = '2023-09-12T11:43:41.584Z';
52299
- __info__.hash = '';
52877
+ __info__.version = "16.5.0-alpha.8";
52878
+ __info__.date = "2023-09-21T15:59:10.959Z";
52879
+ __info__.hash = "0b7527d";