@odoo/o-spreadsheet 19.3.13 → 19.3.15

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.13
6
- * @date 2026-07-23T07:41:06.182Z
7
- * @hash 2059bd0
5
+ * @version 19.3.15
6
+ * @date 2026-08-10T12:32:40.247Z
7
+ * @hash 25f760e
8
8
  */
9
9
 
10
10
  import { App, Component, blockDom, markRaw, onMounted, onPatched, onWillPatch, onWillStart, onWillUnmount, onWillUpdateProps, status, toRaw, useChildSubEnv, useComponent, useEffect, useEnv, useExternalListener, useRef, useState, useSubEnv, whenReady, xml } from "@odoo/owl";
@@ -4258,19 +4258,58 @@ function applyVectorization(formula, args, acceptToVectorize = void 0) {
4258
4258
  }
4259
4259
  }
4260
4260
  if (countVectorizedCol === 1 && countVectorizedRow === 1) return formula(...args);
4261
- const getArgOffset = (i, j) => args.map((arg, index) => {
4262
- switch (vectorArgsType?.[index]) {
4263
- case "matrix": return arg[i][j];
4264
- case "horizontal": return arg[i][0];
4265
- case "vertical": return arg[0][j];
4266
- case void 0: return arg;
4261
+ const argsBuffer = new Array(args.length);
4262
+ const argGetters = [];
4263
+ const vectorizedIndices = [];
4264
+ for (let k = 0; k < args.length; k++) {
4265
+ const arg = args[k];
4266
+ switch (vectorArgsType?.[k]) {
4267
+ case "matrix":
4268
+ argGetters.push((i, j) => arg[i][j]);
4269
+ vectorizedIndices.push(k);
4270
+ break;
4271
+ case "horizontal":
4272
+ argGetters.push((i) => arg[i][0]);
4273
+ vectorizedIndices.push(k);
4274
+ break;
4275
+ case "vertical":
4276
+ argGetters.push((_i, j) => arg[0][j]);
4277
+ vectorizedIndices.push(k);
4278
+ break;
4279
+ case void 0:
4280
+ argsBuffer[k] = arg;
4281
+ break;
4267
4282
  }
4268
- });
4269
- return generateMatrix(countVectorizedCol, countVectorizedRow, (col, row) => {
4270
- if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) return new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
4271
- const singleCellComputeResult = formula(...getArgOffset(col, row));
4272
- return isMatrix(singleCellComputeResult) ? singleCellComputeResult[0][0] : singleCellComputeResult;
4273
- });
4283
+ }
4284
+ const nbVectorized = vectorizedIndices.length;
4285
+ let callFormula;
4286
+ switch (argsBuffer.length) {
4287
+ case 1:
4288
+ callFormula = () => formula(argsBuffer[0]);
4289
+ break;
4290
+ case 2:
4291
+ callFormula = () => formula(argsBuffer[0], argsBuffer[1]);
4292
+ break;
4293
+ case 3:
4294
+ callFormula = () => formula(argsBuffer[0], argsBuffer[1], argsBuffer[2]);
4295
+ break;
4296
+ default: callFormula = () => formula(...argsBuffer);
4297
+ }
4298
+ const result = new Array(countVectorizedCol);
4299
+ for (let col = 0; col < countVectorizedCol; col++) {
4300
+ const column = new Array(countVectorizedRow);
4301
+ result[col] = column;
4302
+ for (let row = 0; row < countVectorizedRow; row++) {
4303
+ if (col > vectorizedColLimit - 1 || row > vectorizedRowLimit - 1) {
4304
+ column[row] = new NotAvailableError(_t("Array arguments to [[FUNCTION_NAME]] are of different size."));
4305
+ continue;
4306
+ }
4307
+ for (let k = 0; k < nbVectorized; k++) argsBuffer[vectorizedIndices[k]] = argGetters[k](col, row);
4308
+ const singleCellComputeResult = callFormula();
4309
+ column[row] = isMatrix(singleCellComputeResult) ? singleCellComputeResult[0][0] : singleCellComputeResult;
4310
+ }
4311
+ }
4312
+ return result;
4274
4313
  }
4275
4314
  /**
4276
4315
  * This function allows to visit arguments and stop the visit if necessary.
@@ -4617,12 +4656,15 @@ function emptyDataErrorMessage(argName) {
4617
4656
  //#endregion
4618
4657
  //#region src/functions/create_compute_function.ts
4619
4658
  function createComputeFunction(descr) {
4659
+ let currentArgDefinitions = [];
4620
4660
  function vectorizedCompute(...args) {
4621
4661
  const acceptToVectorize = [];
4662
+ currentArgDefinitions = new Array(args.length);
4622
4663
  const argsToFocus = argTargeting(descr, args.length);
4623
4664
  for (let i = 0; i < args.length; i++) {
4624
4665
  const argIndex = argsToFocus[i].index;
4625
4666
  const argDefinition = descr.args[argIndex];
4667
+ currentArgDefinitions[i] = argDefinition;
4626
4668
  const arg = args[i];
4627
4669
  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()));
4628
4670
  acceptToVectorize.push(!argDefinition.acceptMatrix);
@@ -4635,10 +4677,9 @@ function createComputeFunction(descr) {
4635
4677
  return result;
4636
4678
  }
4637
4679
  function errorHandlingCompute(...args) {
4638
- const argsToFocus = argTargeting(descr, args.length);
4639
4680
  for (let i = 0; i < args.length; i++) {
4640
4681
  const arg = args[i];
4641
- if (!descr.args[argsToFocus[i].index].acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) return arg;
4682
+ if (!currentArgDefinitions[i].acceptErrors && !isMatrix(arg) && isEvaluationError(arg?.value)) return arg;
4642
4683
  }
4643
4684
  try {
4644
4685
  return computeFunctionToObject.apply(this, args);
@@ -8967,6 +9008,25 @@ const funnelTooltipPositioner = function(elements) {
8967
9008
  };
8968
9009
  };
8969
9010
 
9011
+ //#endregion
9012
+ //#region src/components/figures/chart/chartJs/chartjs_geo_projection_plugin.ts
9013
+ /**
9014
+ * ChartJS plugin to apply custom changes to a d3 projection.
9015
+ *
9016
+ * We pass the projection as a string instead of a customized d3 object so
9017
+ * Chart.js creates a fresh projection instance. Custom changes (e.g. rotation)
9018
+ * are then applied in `beforeUpdate`.
9019
+ *
9020
+ * This is important because Chart.js mutates the projection instance at runtime,
9021
+ * and a customize d3 projection object would not be copied during deepCopy.
9022
+ */
9023
+ const geoProjectionPlugin = {
9024
+ id: "geoProjection",
9025
+ beforeUpdate(chart) {
9026
+ if (chart.options?.scales?.projection?.projection === "conicConformal") chart.scales?.projection?.projection?.rotate([100, 0]);
9027
+ }
9028
+ };
9029
+
8970
9030
  //#endregion
8971
9031
  //#region src/components/figures/chart/chartJs/chartjs_minor_grid_plugin.ts
8972
9032
  const chartMinorGridPlugin = {
@@ -10024,7 +10084,7 @@ function getGeoChartScales(definition, args) {
10024
10084
  const format = axisFormats?.y || axisFormats?.y1;
10025
10085
  return {
10026
10086
  projection: {
10027
- projection: getGeoChartProjection(region?.defaultProjection || "mercator"),
10087
+ projection: region?.defaultProjection || "mercator",
10028
10088
  axis: "x"
10029
10089
  },
10030
10090
  color: {
@@ -10076,10 +10136,6 @@ function getFunnelChartScales(definition, args) {
10076
10136
  }
10077
10137
  };
10078
10138
  }
10079
- function getGeoChartProjection(projection) {
10080
- if (projection === "conicConformal") return globalThis.ChartGeo.geoConicConformal().rotate([100, 0]);
10081
- return projection;
10082
- }
10083
10139
  function getChartAxisTitleRuntime(design) {
10084
10140
  if (design?.title?.text) {
10085
10141
  const { text, color, align, italic, bold } = design.title;
@@ -10251,7 +10307,7 @@ function getCalendarChartDatasetAndLabels(definition, args) {
10251
10307
  borderWidth: 1,
10252
10308
  barPercentage: 1,
10253
10309
  categoryPercentage: 1,
10254
- values: dataSetValues.data.map((cell) => isNumberResult(cell) ? cell.value : NaN)
10310
+ values: dataSetValues.data.map((cell) => isNumberResult(cell) ? cell.value : void 0)
10255
10311
  });
10256
10312
  return {
10257
10313
  labels,
@@ -10964,6 +11020,10 @@ chartJsExtensionRegistry.add("chartBackgroundPlugin", {
10964
11020
  register: (Chart) => Chart.register(chartBackgroundPlugin),
10965
11021
  unregister: (Chart) => Chart.unregister(chartBackgroundPlugin)
10966
11022
  });
11023
+ chartJsExtensionRegistry.add("geoProjectionPlugin", {
11024
+ register: (Chart) => Chart.register(geoProjectionPlugin),
11025
+ unregister: (Chart) => Chart.unregister(geoProjectionPlugin)
11026
+ });
10967
11027
  var ChartJsComponent = class extends Component {
10968
11028
  static template = "o-spreadsheet-ChartJsComponent";
10969
11029
  static props = {
@@ -11821,6 +11881,19 @@ function isOtherMobileOS() {
11821
11881
  function isMobileOS() {
11822
11882
  return isAndroid() || isIOS() || isOtherMobileOS();
11823
11883
  }
11884
+ const INTERACTIVE_ELEMENT_SELECTOR = "select, input, textarea, button, .o-select, .os-input, .o-input, .o-button, .o-button-icon, .o-button-link, .o-composer";
11885
+ /** Check if there is an interactive element (input, select, button, ...) between the event.target and event.currentTarget (inclusive)*/
11886
+ function hasInteractiveElementInEventTree(event) {
11887
+ const target = event.target;
11888
+ const root = event.currentTarget;
11889
+ if (!root || !target || !root.contains(target)) return false;
11890
+ let node = target;
11891
+ while (node && node !== root) {
11892
+ if (node.matches(INTERACTIVE_ELEMENT_SELECTOR)) return true;
11893
+ node = node.parentElement;
11894
+ }
11895
+ return root.matches(INTERACTIVE_ELEMENT_SELECTOR);
11896
+ }
11824
11897
 
11825
11898
  //#endregion
11826
11899
  //#region src/components/helpers/zoom.ts
@@ -18278,7 +18351,7 @@ var FigureComponent = class extends Component {
18278
18351
  case "ArrowLeft":
18279
18352
  case "ArrowRight":
18280
18353
  case "ArrowUp":
18281
- const { col, row, offset } = this.postionInBoundary(this.props.figureUI, ev.key);
18354
+ const { col, row, offset } = this.postionInBoundary(this.env.model.getters.getActiveSheetId(), this.props.figureUI, ev.key);
18282
18355
  this.env.model.dispatch("UPDATE_FIGURE", {
18283
18356
  sheetId: this.env.model.getters.getActiveSheetId(),
18284
18357
  figureId: this.props.figureUI.id,
@@ -18302,34 +18375,52 @@ var FigureComponent = class extends Component {
18302
18375
  break;
18303
18376
  }
18304
18377
  }
18305
- postionInBoundary(position, key) {
18306
- const sheetId = this.env.model.getters.getActiveSheetId();
18307
- let { col, row, offset } = position;
18378
+ postionInBoundary(sheetId, figure, key) {
18379
+ let { col, row, offset } = figure;
18308
18380
  offset = { ...offset };
18381
+ const maxAnchor = this.env.model.getters.getMaxAnchorOffset(sheetId, figure.height, figure.width);
18309
18382
  switch (key) {
18310
18383
  case "ArrowUp":
18311
18384
  if (offset.y === 0) {
18312
18385
  row--;
18386
+ while (row > 0 && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row--;
18313
18387
  offset.y = this.env.model.getters.getRowSize(sheetId, row) - 1;
18314
18388
  } else offset.y--;
18315
18389
  break;
18316
18390
  case "ArrowLeft":
18317
18391
  if (offset.x === 0) {
18318
18392
  col--;
18393
+ while (col > 0 && this.env.model.getters.isColHiddenByUser(sheetId, col)) col--;
18319
18394
  offset.x = this.env.model.getters.getColSize(sheetId, col) - 1;
18320
18395
  } else offset.x--;
18321
18396
  break;
18322
18397
  case "ArrowDown":
18323
18398
  if (offset.y === this.env.model.getters.getRowSize(sheetId, row)) {
18324
18399
  row++;
18400
+ while (row <= maxAnchor.row && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row++;
18325
18401
  offset.y = 0;
18326
18402
  } else offset.y++;
18327
18403
  break;
18328
18404
  case "ArrowRight": if (offset.x === this.env.model.getters.getColSize(sheetId, row)) {
18329
18405
  col++;
18406
+ while (col <= maxAnchor.col && this.env.model.getters.isColHiddenByUser(sheetId, col)) col++;
18330
18407
  offset.x = 0;
18331
18408
  } else offset.x++;
18332
18409
  }
18410
+ if (col < 0) {
18411
+ col = 0;
18412
+ offset.x = 0;
18413
+ } else if (col > maxAnchor.col || col === maxAnchor.col && offset.x > maxAnchor.offset.x) {
18414
+ col = maxAnchor.col;
18415
+ offset.x = maxAnchor.offset.x;
18416
+ }
18417
+ if (row < 0) {
18418
+ row = 0;
18419
+ offset.y = 0;
18420
+ } else if (row > maxAnchor.row || row === maxAnchor.row && offset.y > maxAnchor.offset.y) {
18421
+ row = maxAnchor.row;
18422
+ offset.y = maxAnchor.offset.y;
18423
+ }
18333
18424
  return {
18334
18425
  col,
18335
18426
  row,
@@ -38040,13 +38131,9 @@ var PivotLayoutConfigurator = class extends Component {
38040
38131
  dimensionsRef = useRef("pivot-dimensions");
38041
38132
  dragAndDrop = useDragAndDropListItems();
38042
38133
  AGGREGATORS = AGGREGATORS;
38043
- composerFocus;
38044
38134
  isDateOrDatetimeField = isDateOrDatetimeField;
38045
- setup() {
38046
- this.composerFocus = useStore(ComposerFocusStore);
38047
- }
38048
38135
  startDragAndDrop(dimension, event) {
38049
- if (event.button !== 0 || event.target.tagName === "SELECT") return;
38136
+ if (event.button !== 0 || hasInteractiveElementInEventTree(event)) return;
38050
38137
  const rects = this.getDimensionElementsRects();
38051
38138
  const { columns, rows } = this.props.definition;
38052
38139
  const draggableIds = [
@@ -38086,7 +38173,7 @@ var PivotLayoutConfigurator = class extends Component {
38086
38173
  return field.type === "date" ? this.props.dateGranularities : this.props.datetimeGranularities;
38087
38174
  }
38088
38175
  startDragAndDropMeasures(measure, event) {
38089
- if (event.button !== 0 || event.target.tagName === "SELECT" || event.target.tagName === "INPUT" || this.composerFocus.focusMode !== "inactive") return;
38176
+ if (event.button !== 0 || hasInteractiveElementInEventTree(event)) return;
38090
38177
  const rects = this.getDimensionElementsRects();
38091
38178
  const { measures, columns, rows } = this.props.definition;
38092
38179
  const draggableIds = measures.map((m) => m.id);
@@ -44673,7 +44760,13 @@ var CellComposerStore = class extends AbstractComposerStore {
44673
44760
  const cell = this.getters.getEvaluatedCell(position);
44674
44761
  if (cell.link && !isFormula(content)) content = markdownLink(content, cell.link.url);
44675
44762
  const currentFormat = this.getters.getCell(position)?.format;
44676
- const afterFormat = currentFormat === "@" || currentFormat && isDateTimeFormat(currentFormat) ? void 0 : detectDateFormat(content, this.getters.getLocale());
44763
+ const isCurrentFormatDate = currentFormat && isDateTimeFormat(currentFormat);
44764
+ const contentDateFormat = detectDateFormat(content, this.getters.getLocale());
44765
+ let afterFormat;
44766
+ if (currentFormat !== "@") {
44767
+ if (contentDateFormat && !isCurrentFormatDate) afterFormat = contentDateFormat;
44768
+ else if (isCurrentFormatDate && isNumber(content, this.getters.getLocale())) afterFormat = "";
44769
+ }
44677
44770
  this.addHeadersForSpreadingFormula(content);
44678
44771
  result = this.model.dispatch("UPDATE_CELL", {
44679
44772
  ...this.currentEditedCell,
@@ -62380,7 +62473,7 @@ var SheetUIPlugin = class extends UIPlugin {
62380
62473
  if (contentWidth === 0) return 0;
62381
62474
  contentWidth += 2 * 4;
62382
62475
  if (style.wrapping === "wrap") {
62383
- const colWidth = this.getters.getColSize(this.getters.getActiveSheetId(), position.col);
62476
+ const colWidth = this.getters.getColSize(position.sheetId, position.col);
62384
62477
  return Math.min(colWidth, contentWidth);
62385
62478
  }
62386
62479
  return contentWidth;
@@ -66203,6 +66296,10 @@ function inverseCreateFigure(cmd) {
66203
66296
  }
66204
66297
  function inverseCreateChart(cmd) {
66205
66298
  return [{
66299
+ type: "DELETE_CHART",
66300
+ chartId: cmd.chartId,
66301
+ sheetId: cmd.sheetId
66302
+ }, {
66206
66303
  type: "DELETE_FIGURE",
66207
66304
  figureId: cmd.figureId,
66208
66305
  sheetId: cmd.sheetId
@@ -68067,6 +68164,7 @@ var SpreadsheetDashboard = class extends Component {
68067
68164
  return toRaw(this.clickableCellsStore.clickableCells);
68068
68165
  }
68069
68166
  selectClickableCell(ev, clickableCell) {
68167
+ if (![0, 1].includes(ev.button)) return;
68070
68168
  const { position, action } = clickableCell;
68071
68169
  action(position, this.env, isMiddleClickOrCtrlClick(ev));
68072
68170
  }
@@ -84608,6 +84706,6 @@ const chartHelpers = {
84608
84706
  //#endregion
84609
84707
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, ClientDisconnectedError, CommandResult, CompiledFormula, CorePlugin, CoreViewPlugin, DEFAULT_LOCALE, DEFAULT_LOCALES, DispatchResult, EvaluationError, LocalTransportService, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, canExecuteInReadonly, categories, chartHelpers, components, constants, convertAstNodes, coreTypes, createAutocompleteArgumentsProvider, findCellInNewZone, functionCache, getCaretDownSvg, getCaretUpSvg, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, isCoreCommand, isSheetDependent, iterateAstNodes, links, load, lockedSheetAllowedCommands, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
84610
84708
 
84611
- __info__.version = "19.3.13";
84612
- __info__.date = "2026-07-23T07:41:06.182Z";
84613
- __info__.hash = "2059bd0";
84709
+ __info__.version = "19.3.15";
84710
+ __info__.date = "2026-08-10T12:32:40.247Z";
84711
+ __info__.hash = "25f760e";
@@ -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.13
6
- * @date 2026-07-23T07:41:06.182Z
7
- * @hash 2059bd0
5
+ * @version 19.3.15
6
+ * @date 2026-08-10T12:32:40.247Z
7
+ * @hash 25f760e
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);
@@ -8969,6 +9010,25 @@ stores.inject(MyMetaStore, storeInstance);
8969
9010
  };
8970
9011
  };
8971
9012
 
9013
+ //#endregion
9014
+ //#region src/components/figures/chart/chartJs/chartjs_geo_projection_plugin.ts
9015
+ /**
9016
+ * ChartJS plugin to apply custom changes to a d3 projection.
9017
+ *
9018
+ * We pass the projection as a string instead of a customized d3 object so
9019
+ * Chart.js creates a fresh projection instance. Custom changes (e.g. rotation)
9020
+ * are then applied in `beforeUpdate`.
9021
+ *
9022
+ * This is important because Chart.js mutates the projection instance at runtime,
9023
+ * and a customize d3 projection object would not be copied during deepCopy.
9024
+ */
9025
+ const geoProjectionPlugin = {
9026
+ id: "geoProjection",
9027
+ beforeUpdate(chart) {
9028
+ if (chart.options?.scales?.projection?.projection === "conicConformal") chart.scales?.projection?.projection?.rotate([100, 0]);
9029
+ }
9030
+ };
9031
+
8972
9032
  //#endregion
8973
9033
  //#region src/components/figures/chart/chartJs/chartjs_minor_grid_plugin.ts
8974
9034
  const chartMinorGridPlugin = {
@@ -10026,7 +10086,7 @@ stores.inject(MyMetaStore, storeInstance);
10026
10086
  const format = axisFormats?.y || axisFormats?.y1;
10027
10087
  return {
10028
10088
  projection: {
10029
- projection: getGeoChartProjection(region?.defaultProjection || "mercator"),
10089
+ projection: region?.defaultProjection || "mercator",
10030
10090
  axis: "x"
10031
10091
  },
10032
10092
  color: {
@@ -10078,10 +10138,6 @@ stores.inject(MyMetaStore, storeInstance);
10078
10138
  }
10079
10139
  };
10080
10140
  }
10081
- function getGeoChartProjection(projection) {
10082
- if (projection === "conicConformal") return globalThis.ChartGeo.geoConicConformal().rotate([100, 0]);
10083
- return projection;
10084
- }
10085
10141
  function getChartAxisTitleRuntime(design) {
10086
10142
  if (design?.title?.text) {
10087
10143
  const { text, color, align, italic, bold } = design.title;
@@ -10253,7 +10309,7 @@ stores.inject(MyMetaStore, storeInstance);
10253
10309
  borderWidth: 1,
10254
10310
  barPercentage: 1,
10255
10311
  categoryPercentage: 1,
10256
- values: dataSetValues.data.map((cell) => isNumberResult(cell) ? cell.value : NaN)
10312
+ values: dataSetValues.data.map((cell) => isNumberResult(cell) ? cell.value : void 0)
10257
10313
  });
10258
10314
  return {
10259
10315
  labels,
@@ -10966,6 +11022,10 @@ stores.inject(MyMetaStore, storeInstance);
10966
11022
  register: (Chart) => Chart.register(chartBackgroundPlugin),
10967
11023
  unregister: (Chart) => Chart.unregister(chartBackgroundPlugin)
10968
11024
  });
11025
+ chartJsExtensionRegistry.add("geoProjectionPlugin", {
11026
+ register: (Chart) => Chart.register(geoProjectionPlugin),
11027
+ unregister: (Chart) => Chart.unregister(geoProjectionPlugin)
11028
+ });
10969
11029
  var ChartJsComponent = class extends _odoo_owl.Component {
10970
11030
  static template = "o-spreadsheet-ChartJsComponent";
10971
11031
  static props = {
@@ -11823,6 +11883,19 @@ stores.inject(MyMetaStore, storeInstance);
11823
11883
  function isMobileOS() {
11824
11884
  return isAndroid() || isIOS() || isOtherMobileOS();
11825
11885
  }
11886
+ const INTERACTIVE_ELEMENT_SELECTOR = "select, input, textarea, button, .o-select, .os-input, .o-input, .o-button, .o-button-icon, .o-button-link, .o-composer";
11887
+ /** Check if there is an interactive element (input, select, button, ...) between the event.target and event.currentTarget (inclusive)*/
11888
+ function hasInteractiveElementInEventTree(event) {
11889
+ const target = event.target;
11890
+ const root = event.currentTarget;
11891
+ if (!root || !target || !root.contains(target)) return false;
11892
+ let node = target;
11893
+ while (node && node !== root) {
11894
+ if (node.matches(INTERACTIVE_ELEMENT_SELECTOR)) return true;
11895
+ node = node.parentElement;
11896
+ }
11897
+ return root.matches(INTERACTIVE_ELEMENT_SELECTOR);
11898
+ }
11826
11899
 
11827
11900
  //#endregion
11828
11901
  //#region src/components/helpers/zoom.ts
@@ -18280,7 +18353,7 @@ stores.inject(MyMetaStore, storeInstance);
18280
18353
  case "ArrowLeft":
18281
18354
  case "ArrowRight":
18282
18355
  case "ArrowUp":
18283
- const { col, row, offset } = this.postionInBoundary(this.props.figureUI, ev.key);
18356
+ const { col, row, offset } = this.postionInBoundary(this.env.model.getters.getActiveSheetId(), this.props.figureUI, ev.key);
18284
18357
  this.env.model.dispatch("UPDATE_FIGURE", {
18285
18358
  sheetId: this.env.model.getters.getActiveSheetId(),
18286
18359
  figureId: this.props.figureUI.id,
@@ -18304,34 +18377,52 @@ stores.inject(MyMetaStore, storeInstance);
18304
18377
  break;
18305
18378
  }
18306
18379
  }
18307
- postionInBoundary(position, key) {
18308
- const sheetId = this.env.model.getters.getActiveSheetId();
18309
- let { col, row, offset } = position;
18380
+ postionInBoundary(sheetId, figure, key) {
18381
+ let { col, row, offset } = figure;
18310
18382
  offset = { ...offset };
18383
+ const maxAnchor = this.env.model.getters.getMaxAnchorOffset(sheetId, figure.height, figure.width);
18311
18384
  switch (key) {
18312
18385
  case "ArrowUp":
18313
18386
  if (offset.y === 0) {
18314
18387
  row--;
18388
+ while (row > 0 && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row--;
18315
18389
  offset.y = this.env.model.getters.getRowSize(sheetId, row) - 1;
18316
18390
  } else offset.y--;
18317
18391
  break;
18318
18392
  case "ArrowLeft":
18319
18393
  if (offset.x === 0) {
18320
18394
  col--;
18395
+ while (col > 0 && this.env.model.getters.isColHiddenByUser(sheetId, col)) col--;
18321
18396
  offset.x = this.env.model.getters.getColSize(sheetId, col) - 1;
18322
18397
  } else offset.x--;
18323
18398
  break;
18324
18399
  case "ArrowDown":
18325
18400
  if (offset.y === this.env.model.getters.getRowSize(sheetId, row)) {
18326
18401
  row++;
18402
+ while (row <= maxAnchor.row && this.env.model.getters.isRowHiddenByUser(sheetId, row)) row++;
18327
18403
  offset.y = 0;
18328
18404
  } else offset.y++;
18329
18405
  break;
18330
18406
  case "ArrowRight": if (offset.x === this.env.model.getters.getColSize(sheetId, row)) {
18331
18407
  col++;
18408
+ while (col <= maxAnchor.col && this.env.model.getters.isColHiddenByUser(sheetId, col)) col++;
18332
18409
  offset.x = 0;
18333
18410
  } else offset.x++;
18334
18411
  }
18412
+ if (col < 0) {
18413
+ col = 0;
18414
+ offset.x = 0;
18415
+ } else if (col > maxAnchor.col || col === maxAnchor.col && offset.x > maxAnchor.offset.x) {
18416
+ col = maxAnchor.col;
18417
+ offset.x = maxAnchor.offset.x;
18418
+ }
18419
+ if (row < 0) {
18420
+ row = 0;
18421
+ offset.y = 0;
18422
+ } else if (row > maxAnchor.row || row === maxAnchor.row && offset.y > maxAnchor.offset.y) {
18423
+ row = maxAnchor.row;
18424
+ offset.y = maxAnchor.offset.y;
18425
+ }
18335
18426
  return {
18336
18427
  col,
18337
18428
  row,
@@ -38042,13 +38133,9 @@ stores.inject(MyMetaStore, storeInstance);
38042
38133
  dimensionsRef = (0, _odoo_owl.useRef)("pivot-dimensions");
38043
38134
  dragAndDrop = useDragAndDropListItems();
38044
38135
  AGGREGATORS = AGGREGATORS;
38045
- composerFocus;
38046
38136
  isDateOrDatetimeField = isDateOrDatetimeField;
38047
- setup() {
38048
- this.composerFocus = useStore(ComposerFocusStore);
38049
- }
38050
38137
  startDragAndDrop(dimension, event) {
38051
- if (event.button !== 0 || event.target.tagName === "SELECT") return;
38138
+ if (event.button !== 0 || hasInteractiveElementInEventTree(event)) return;
38052
38139
  const rects = this.getDimensionElementsRects();
38053
38140
  const { columns, rows } = this.props.definition;
38054
38141
  const draggableIds = [
@@ -38088,7 +38175,7 @@ stores.inject(MyMetaStore, storeInstance);
38088
38175
  return field.type === "date" ? this.props.dateGranularities : this.props.datetimeGranularities;
38089
38176
  }
38090
38177
  startDragAndDropMeasures(measure, event) {
38091
- if (event.button !== 0 || event.target.tagName === "SELECT" || event.target.tagName === "INPUT" || this.composerFocus.focusMode !== "inactive") return;
38178
+ if (event.button !== 0 || hasInteractiveElementInEventTree(event)) return;
38092
38179
  const rects = this.getDimensionElementsRects();
38093
38180
  const { measures, columns, rows } = this.props.definition;
38094
38181
  const draggableIds = measures.map((m) => m.id);
@@ -44675,7 +44762,13 @@ stores.inject(MyMetaStore, storeInstance);
44675
44762
  const cell = this.getters.getEvaluatedCell(position);
44676
44763
  if (cell.link && !isFormula(content)) content = markdownLink(content, cell.link.url);
44677
44764
  const currentFormat = this.getters.getCell(position)?.format;
44678
- const afterFormat = currentFormat === "@" || currentFormat && isDateTimeFormat(currentFormat) ? void 0 : detectDateFormat(content, this.getters.getLocale());
44765
+ const isCurrentFormatDate = currentFormat && isDateTimeFormat(currentFormat);
44766
+ const contentDateFormat = detectDateFormat(content, this.getters.getLocale());
44767
+ let afterFormat;
44768
+ if (currentFormat !== "@") {
44769
+ if (contentDateFormat && !isCurrentFormatDate) afterFormat = contentDateFormat;
44770
+ else if (isCurrentFormatDate && isNumber(content, this.getters.getLocale())) afterFormat = "";
44771
+ }
44679
44772
  this.addHeadersForSpreadingFormula(content);
44680
44773
  result = this.model.dispatch("UPDATE_CELL", {
44681
44774
  ...this.currentEditedCell,
@@ -62382,7 +62475,7 @@ stores.inject(MyMetaStore, storeInstance);
62382
62475
  if (contentWidth === 0) return 0;
62383
62476
  contentWidth += 2 * 4;
62384
62477
  if (style.wrapping === "wrap") {
62385
- const colWidth = this.getters.getColSize(this.getters.getActiveSheetId(), position.col);
62478
+ const colWidth = this.getters.getColSize(position.sheetId, position.col);
62386
62479
  return Math.min(colWidth, contentWidth);
62387
62480
  }
62388
62481
  return contentWidth;
@@ -66205,6 +66298,10 @@ stores.inject(MyMetaStore, storeInstance);
66205
66298
  }
66206
66299
  function inverseCreateChart(cmd) {
66207
66300
  return [{
66301
+ type: "DELETE_CHART",
66302
+ chartId: cmd.chartId,
66303
+ sheetId: cmd.sheetId
66304
+ }, {
66208
66305
  type: "DELETE_FIGURE",
66209
66306
  figureId: cmd.figureId,
66210
66307
  sheetId: cmd.sheetId
@@ -68069,6 +68166,7 @@ stores.inject(MyMetaStore, storeInstance);
68069
68166
  return (0, _odoo_owl.toRaw)(this.clickableCellsStore.clickableCells);
68070
68167
  }
68071
68168
  selectClickableCell(ev, clickableCell) {
68169
+ if (![0, 1].includes(ev.button)) return;
68072
68170
  const { position, action } = clickableCell;
68073
68171
  action(position, this.env, isMiddleClickOrCtrlClick(ev));
68074
68172
  }
@@ -84668,8 +84766,8 @@ exports.stores = stores;
84668
84766
  exports.tokenColors = tokenColors;
84669
84767
  exports.tokenize = tokenize;
84670
84768
 
84671
- __info__.version = "19.3.13";
84672
- __info__.date = "2026-07-23T07:41:06.182Z";
84673
- __info__.hash = "2059bd0";
84769
+ __info__.version = "19.3.15";
84770
+ __info__.date = "2026-08-10T12:32:40.247Z";
84771
+ __info__.hash = "25f760e";
84674
84772
 
84675
84773
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);