@odoo/o-spreadsheet 19.3.14 → 19.3.16

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 19.3.14
6
- * @date 2026-07-30T06:55:43.749Z
7
- * @hash 3dd5632
5
+ * @version 19.3.16
6
+ * @date 2026-08-12T09:15:31.627Z
7
+ * @hash 464be42
8
8
  */
9
9
 
10
10
  (function(exports, _odoo_owl) {
@@ -4260,19 +4260,58 @@ stores.inject(MyMetaStore, storeInstance);
4260
4260
  }
4261
4261
  }
4262
4262
  if (countVectorizedCol === 1 && countVectorizedRow === 1) return formula(...args);
4263
- const getArgOffset = (i, j) => args.map((arg, index) => {
4264
- switch (vectorArgsType?.[index]) {
4265
- case "matrix": return arg[i][j];
4266
- case "horizontal": return arg[i][0];
4267
- case "vertical": return arg[0][j];
4268
- case void 0: return arg;
4263
+ const argsBuffer = new Array(args.length);
4264
+ const argGetters = [];
4265
+ const vectorizedIndices = [];
4266
+ for (let k = 0; k < args.length; k++) {
4267
+ const arg = args[k];
4268
+ switch (vectorArgsType?.[k]) {
4269
+ case "matrix":
4270
+ argGetters.push((i, j) => arg[i][j]);
4271
+ vectorizedIndices.push(k);
4272
+ break;
4273
+ case "horizontal":
4274
+ argGetters.push((i) => arg[i][0]);
4275
+ vectorizedIndices.push(k);
4276
+ break;
4277
+ case "vertical":
4278
+ argGetters.push((_i, j) => arg[0][j]);
4279
+ vectorizedIndices.push(k);
4280
+ break;
4281
+ case void 0:
4282
+ argsBuffer[k] = arg;
4283
+ break;
4269
4284
  }
4270
- });
4271
- return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
4272
- if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
4273
- const singleCellComputeResult = formula(...getArgOffset(col, row));
4274
- return isMatrix(singleCellComputeResult) ? singleCellComputeResult[0][0] : singleCellComputeResult;
4275
- });
4285
+ }
4286
+ const nbVectorized = vectorizedIndices.length;
4287
+ let callFormula;
4288
+ switch (argsBuffer.length) {
4289
+ case 1:
4290
+ callFormula = () => formula(argsBuffer[0]);
4291
+ break;
4292
+ case 2:
4293
+ callFormula = () => formula(argsBuffer[0], argsBuffer[1]);
4294
+ break;
4295
+ case 3:
4296
+ callFormula = () => formula(argsBuffer[0], argsBuffer[1], argsBuffer[2]);
4297
+ break;
4298
+ default: callFormula = () => formula(...argsBuffer);
4299
+ }
4300
+ const result = new Array(countVectorizedCol);
4301
+ for (let col = 0; col < countVectorizedCol; col++) {
4302
+ const column = new Array(countVectorizedRow);
4303
+ result[col] = column;
4304
+ for (let row = 0; row < countVectorizedRow; row++) {
4305
+ if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
4306
+ column[row] = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
4307
+ continue;
4308
+ }
4309
+ for (let k = 0; k < nbVectorized; k++) argsBuffer[vectorizedIndices[k]] = argGetters[k](col, row);
4310
+ const singleCellComputeResult = callFormula();
4311
+ column[row] = isMatrix(singleCellComputeResult) ? singleCellComputeResult[0][0] : singleCellComputeResult;
4312
+ }
4313
+ }
4314
+ return result;
4276
4315
  }
4277
4316
  /**
4278
4317
  * This function allows to visit arguments and stop the visit if necessary.
@@ -4619,12 +4658,15 @@ stores.inject(MyMetaStore, storeInstance);
4619
4658
  //#endregion
4620
4659
  //#region src/functions/create_compute_function.ts
4621
4660
  function createComputeFunction(descr) {
4661
+ let currentArgDefinitions = [];
4622
4662
  function vectorizedCompute(...args) {
4623
4663
  const acceptToVectorize = [];
4664
+ currentArgDefinitions = new Array(args.length);
4624
4665
  const argsToFocus = argTargeting(descr, args.length);
4625
4666
  for (let i = 0; i < args.length; i++) {
4626
4667
  const argIndex = argsToFocus[i].index;
4627
4668
  const argDefinition = descr.args[argIndex];
4669
+ currentArgDefinitions[i] = argDefinition;
4628
4670
  const arg = args[i];
4629
4671
  if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) throw new BadExpressionError(_t("Function %s expects the parameter '%s' to be reference to a cell or range.", descr.name, (i + 1).toString()));
4630
4672
  acceptToVectorize.push(!argDefinition.acceptMatrix);
@@ -4637,10 +4679,9 @@ stores.inject(MyMetaStore, storeInstance);
4637
4679
  return result;
4638
4680
  }
4639
4681
  function errorHandlingCompute(...args) {
4640
- const argsToFocus = argTargeting(descr, args.length);
4641
4682
  for (let i = 0; i < args.length; i++) {
4642
4683
  const arg = args[i];
4643
- if (!descr.args[argsToFocus[i].index].acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) return arg;
4684
+ if (!currentArgDefinitions[i].acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) return arg;
4644
4685
  }
4645
4686
  try {
4646
4687
  return computeFunctionToObject.apply(this, args);
@@ -4704,6 +4745,9 @@ stores.inject(MyMetaStore, storeInstance);
4704
4745
  }
4705
4746
  };
4706
4747
  const functionRegistry = new FunctionRegistry();
4748
+ /** Formulas using one of these functions are never squished: they are always exported
4749
+ * as a full formula string, and they don't become the base formula of the next cells. */
4750
+ const NonSquishableFunctionRegistry = new Registry();
4707
4751
 
4708
4752
  //#endregion
4709
4753
  //#region src/types/locale.ts
@@ -8969,6 +9013,25 @@ stores.inject(MyMetaStore, storeInstance);
8969
9013
  };
8970
9014
  };
8971
9015
 
9016
+ //#endregion
9017
+ //#region src/components/figures/chart/chartJs/chartjs_geo_projection_plugin.ts
9018
+ /**
9019
+ * ChartJS plugin to apply custom changes to a d3 projection.
9020
+ *
9021
+ * We pass the projection as a string instead of a customized d3 object so
9022
+ * Chart.js creates a fresh projection instance. Custom changes (e.g. rotation)
9023
+ * are then applied in `beforeUpdate`.
9024
+ *
9025
+ * This is important because Chart.js mutates the projection instance at runtime,
9026
+ * and a customize d3 projection object would not be copied during deepCopy.
9027
+ */
9028
+ const geoProjectionPlugin = {
9029
+ id: "geoProjection",
9030
+ beforeUpdate(chart) {
9031
+ if (chart.options?.scales?.projection?.projection === "conicConformal") chart.scales?.projection?.projection?.rotate([100, 0]);
9032
+ }
9033
+ };
9034
+
8972
9035
  //#endregion
8973
9036
  //#region src/components/figures/chart/chartJs/chartjs_minor_grid_plugin.ts
8974
9037
  const chartMinorGridPlugin = {
@@ -10026,7 +10089,7 @@ stores.inject(MyMetaStore, storeInstance);
10026
10089
  const format = axisFormats?.y || axisFormats?.y1;
10027
10090
  return {
10028
10091
  projection: {
10029
- projection: getGeoChartProjection(region?.defaultProjection || "mercator"),
10092
+ projection: region?.defaultProjection || "mercator",
10030
10093
  axis: "x"
10031
10094
  },
10032
10095
  color: {
@@ -10078,10 +10141,6 @@ stores.inject(MyMetaStore, storeInstance);
10078
10141
  }
10079
10142
  };
10080
10143
  }
10081
- function getGeoChartProjection(projection) {
10082
- if (projection === "conicConformal") return globalThis.ChartGeo.geoConicConformal().rotate([100, 0]);
10083
- return projection;
10084
- }
10085
10144
  function getChartAxisTitleRuntime(design) {
10086
10145
  if (design?.title?.text) {
10087
10146
  const { text, color, align, italic, bold } = design.title;
@@ -10966,6 +11025,10 @@ stores.inject(MyMetaStore, storeInstance);
10966
11025
  register: (Chart) => Chart.register(chartBackgroundPlugin),
10967
11026
  unregister: (Chart) => Chart.unregister(chartBackgroundPlugin)
10968
11027
  });
11028
+ chartJsExtensionRegistry.add("geoProjectionPlugin", {
11029
+ register: (Chart) => Chart.register(geoProjectionPlugin),
11030
+ unregister: (Chart) => Chart.unregister(geoProjectionPlugin)
11031
+ });
10969
11032
  var ChartJsComponent = class extends _odoo_owl.Component {
10970
11033
  static template = "o-spreadsheet-ChartJsComponent";
10971
11034
  static props = {
@@ -18293,7 +18356,7 @@ stores.inject(MyMetaStore, storeInstance);
18293
18356
  case "ArrowLeft":
18294
18357
  case "ArrowRight":
18295
18358
  case "ArrowUp":
18296
- const { col, row, offset } = this.postionInBoundary(this.props.figureUI, ev.key);
18359
+ const { col, row, offset } = this.postionInBoundary(this.env.model.getters.getActiveSheetId(), this.props.figureUI, ev.key);
18297
18360
  this.env.model.dispatch("UPDATE_FIGURE", {
18298
18361
  sheetId: this.env.model.getters.getActiveSheetId(),
18299
18362
  figureId: this.props.figureUI.id,
@@ -18317,34 +18380,52 @@ stores.inject(MyMetaStore, storeInstance);
18317
18380
  break;
18318
18381
  }
18319
18382
  }
18320
- postionInBoundary(position, key) {
18321
- const sheetId = this.env.model.getters.getActiveSheetId();
18322
- let { col, row, offset } = position;
18383
+ postionInBoundary(sheetId, figure, key) {
18384
+ let { col, row, offset } = figure;
18323
18385
  offset = { ...offset };
18386
+ const maxAnchor = this.env.model.getters.getMaxAnchorOffset(sheetId, figure.height, figure.width);
18324
18387
  switch (key) {
18325
18388
  case "ArrowUp":
18326
18389
  if (offset.y === 0) {
18327
18390
  row--;
18391
+ while (row > 0 && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row--;
18328
18392
  offset.y = this.env.model.getters.getRowSize(sheetId, row) - 1;
18329
18393
  } else offset.y--;
18330
18394
  break;
18331
18395
  case "ArrowLeft":
18332
18396
  if (offset.x === 0) {
18333
18397
  col--;
18398
+ while (col > 0 && this.env.model.getters.isColHiddenByUser(sheetId, col)) col--;
18334
18399
  offset.x = this.env.model.getters.getColSize(sheetId, col) - 1;
18335
18400
  } else offset.x--;
18336
18401
  break;
18337
18402
  case "ArrowDown":
18338
18403
  if (offset.y === this.env.model.getters.getRowSize(sheetId, row)) {
18339
18404
  row++;
18405
+ while (row <= maxAnchor.row && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row++;
18340
18406
  offset.y = 0;
18341
18407
  } else offset.y++;
18342
18408
  break;
18343
18409
  case "ArrowRight": if (offset.x === this.env.model.getters.getColSize(sheetId, row)) {
18344
18410
  col++;
18411
+ while (col <= maxAnchor.col && this.env.model.getters.isColHiddenByUser(sheetId, col)) col++;
18345
18412
  offset.x = 0;
18346
18413
  } else offset.x++;
18347
18414
  }
18415
+ if (col < 0) {
18416
+ col = 0;
18417
+ offset.x = 0;
18418
+ } else if (col > maxAnchor.col || col === maxAnchor.col && offset.x > maxAnchor.offset.x) {
18419
+ col = maxAnchor.col;
18420
+ offset.x = maxAnchor.offset.x;
18421
+ }
18422
+ if (row < 0) {
18423
+ row = 0;
18424
+ offset.y = 0;
18425
+ } else if (row > maxAnchor.row || row === maxAnchor.row && offset.y > maxAnchor.offset.y) {
18426
+ row = maxAnchor.row;
18427
+ offset.y = maxAnchor.offset.y;
18428
+ }
18348
18429
  return {
18349
18430
  col,
18350
18431
  row,
@@ -44684,7 +44765,13 @@ stores.inject(MyMetaStore, storeInstance);
44684
44765
  const cell = this.getters.getEvaluatedCell(position);
44685
44766
  if (cell.link && !isFormula(content)) content = markdownLink(content, cell.link.url);
44686
44767
  const currentFormat = this.getters.getCell(position)?.format;
44687
- const afterFormat = currentFormat === "@" || currentFormat && isDateTimeFormat(currentFormat) ? void 0 : detectDateFormat(content, this.getters.getLocale());
44768
+ const isCurrentFormatDate = currentFormat && isDateTimeFormat(currentFormat);
44769
+ const contentDateFormat = detectDateFormat(content, this.getters.getLocale());
44770
+ let afterFormat;
44771
+ if (currentFormat !== "@") {
44772
+ if (contentDateFormat && !isCurrentFormatDate) afterFormat = contentDateFormat;
44773
+ else if (isCurrentFormatDate && isNumber(content, this.getters.getLocale())) afterFormat = "";
44774
+ }
44688
44775
  this.addHeadersForSpreadingFormula(content);
44689
44776
  result = this.model.dispatch("UPDATE_CELL", {
44690
44777
  ...this.currentEditedCell,
@@ -49781,7 +49868,8 @@ stores.inject(MyMetaStore, storeInstance);
49781
49868
  * The result of this method is:
49782
49869
  * - if the cell is not a formula, returns the content as is and resets the base formula
49783
49870
  * - if the cell is a formula:
49784
- * - if there is no previous formula, or the normalized formula is different from the previous one, resets the base formula to this one and returns the full formula string
49871
+ * - if there is no previous formula, or the normalized formula is different from the previous one or it contains blacklisted functions (see NonSquishableFunctionRegistry),
49872
+ * resets the base formula to this one and returns the full formula string
49785
49873
  * - else, compares the literal values and range dependencies to the previous formula, and for each parameter:
49786
49874
  * - for numbers: returns a relative change (+N or -N) if possible, else the full number or "=" if unchanged
49787
49875
  * - for strings: returns the full string if changed, else "="
@@ -49789,6 +49877,10 @@ stores.inject(MyMetaStore, storeInstance);
49789
49877
  * */
49790
49878
  squish(cell, forSheetId) {
49791
49879
  if (cell.isFormula) {
49880
+ if (NonSquishableFunctionRegistry.getAll().some((functionName) => cell.compiledFormula.usesSymbol(functionName))) {
49881
+ this.resetBaseFormula();
49882
+ return cell.compiledFormula.toFormulaString(this.getters, this.rangeToStringOptions);
49883
+ }
49792
49884
  let numbers = [];
49793
49885
  let strings = [];
49794
49886
  let references = [];
@@ -60970,7 +61062,7 @@ stores.inject(MyMetaStore, storeInstance);
60970
61062
  }
60971
61063
  message = {
60972
61064
  ...message,
60973
- commands: this.commandSquisher.squish(revision.commands)
61065
+ commands: revision.commands
60974
61066
  };
60975
61067
  }
60976
61068
  if (this.isReplayingInitialRevisions) throw new Error(`Trying to send a new revision while replaying initial revision. This can lead to endless dispatches every time the spreadsheet is open.
@@ -66214,6 +66306,10 @@ stores.inject(MyMetaStore, storeInstance);
66214
66306
  }
66215
66307
  function inverseCreateChart(cmd) {
66216
66308
  return [{
66309
+ type: "DELETE_CHART",
66310
+ chartId: cmd.chartId,
66311
+ sheetId: cmd.sheetId
66312
+ }, {
66217
66313
  type: "DELETE_FIGURE",
66218
66314
  figureId: cmd.figureId,
66219
66315
  sheetId: cmd.sheetId
@@ -84425,7 +84521,8 @@ stores.inject(MyMetaStore, storeInstance);
84425
84521
  supportedPivotPositionalFormulaRegistry,
84426
84522
  pivotToFunctionValueRegistry,
84427
84523
  migrationStepRegistry,
84428
- chartJsExtensionRegistry
84524
+ chartJsExtensionRegistry,
84525
+ NonSquishableFunctionRegistry
84429
84526
  };
84430
84527
  const helpers = {
84431
84528
  arg,
@@ -84678,8 +84775,8 @@ exports.stores = stores;
84678
84775
  exports.tokenColors = tokenColors;
84679
84776
  exports.tokenize = tokenize;
84680
84777
 
84681
- __info__.version = "19.3.14";
84682
- __info__.date = "2026-07-30T06:55:43.749Z";
84683
- __info__.hash = "3dd5632";
84778
+ __info__.version = "19.3.16";
84779
+ __info__.date = "2026-08-12T09:15:31.627Z";
84780
+ __info__.hash = "464be42";
84684
84781
 
84685
84782
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);