@odoo/o-spreadsheet 17.4.2 → 17.4.3

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 17.4.2
6
- * @date 2024-07-24T10:26:00.237Z
7
- * @hash f5ede5b
5
+ * @version 17.4.3
6
+ * @date 2024-08-02T08:23:56.573Z
7
+ * @hash 40ecd1e
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -2765,13 +2765,16 @@ const wildcardToRegExp = memoize(function wildcardToRegExp(operand) {
2765
2765
  }
2766
2766
  return new RegExp("^" + exp + "$", "i");
2767
2767
  });
2768
- function evaluatePredicate(value = "", criterion) {
2768
+ function evaluatePredicate(value = "", criterion, locale) {
2769
2769
  const { operator, operand } = criterion;
2770
2770
  if (operand === undefined || value === null || operand === null) {
2771
2771
  return false;
2772
2772
  }
2773
2773
  if (typeof operand === "number" && operator === "=") {
2774
- return value.toString() === operand.toString();
2774
+ if (typeof value === "string" && (isNumber(value, locale) || isDateTime(value, locale))) {
2775
+ return toNumber(value, locale) === operand;
2776
+ }
2777
+ return value === operand;
2775
2778
  }
2776
2779
  if (operator === "<>" || operator === "=") {
2777
2780
  let result;
@@ -2853,7 +2856,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2853
2856
  for (let k = 0; k < countArg - 1; k += 2) {
2854
2857
  const criteriaValue = toMatrix(args[k])[i][j].value;
2855
2858
  const criterion = predicates[k / 2];
2856
- validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2859
+ validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion, locale);
2857
2860
  if (!validatedPredicates) {
2858
2861
  break;
2859
2862
  }
@@ -6544,6 +6547,9 @@ function toNormalizedPivotValue(dimension, groupValue) {
6544
6547
  const groupValueString = typeof groupValue === "boolean"
6545
6548
  ? toString(groupValue).toLocaleLowerCase()
6546
6549
  : toString(groupValue);
6550
+ if (groupValueString === "null") {
6551
+ return null;
6552
+ }
6547
6553
  if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
6548
6554
  throw new EvaluationError(_t("Field %(field)s is not supported because of its type (%(type)s)", {
6549
6555
  field: dimension.displayName,
@@ -6564,6 +6570,9 @@ function normalizeDateTime(value, granularity) {
6564
6570
  return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
6565
6571
  }
6566
6572
  function toFunctionPivotValue(value, dimension) {
6573
+ if (value === null) {
6574
+ return `"null"`;
6575
+ }
6567
6576
  if (!pivotToFunctionValueRegistry.contains(dimension.type)) {
6568
6577
  return `"${value}"`;
6569
6578
  }
@@ -20779,6 +20788,78 @@ function isCtrlKey(ev) {
20779
20788
  return isMacOS() ? ev.metaKey : ev.ctrlKey;
20780
20789
  }
20781
20790
 
20791
+ /**
20792
+ * Return the o-spreadsheet element position relative
20793
+ * to the browser viewport.
20794
+ */
20795
+ function useSpreadsheetRect() {
20796
+ const position = useState({ x: 0, y: 0, width: 0, height: 0 });
20797
+ let spreadsheetElement = null;
20798
+ function updatePosition() {
20799
+ if (!spreadsheetElement) {
20800
+ spreadsheetElement = document.querySelector(".o-spreadsheet");
20801
+ }
20802
+ if (spreadsheetElement) {
20803
+ const { top, left, width, height } = spreadsheetElement.getBoundingClientRect();
20804
+ position.x = left;
20805
+ position.y = top;
20806
+ position.width = width;
20807
+ position.height = height;
20808
+ }
20809
+ }
20810
+ onMounted(updatePosition);
20811
+ onPatched(updatePosition);
20812
+ return position;
20813
+ }
20814
+ /**
20815
+ * Return the component (or ref's component) BoundingRect, relative
20816
+ * to the upper left corner of the screen (<body> element).
20817
+ *
20818
+ * Note: when used with a <Portal/> component, it will
20819
+ * return the portal position, not the teleported position.
20820
+ */
20821
+ function useAbsoluteBoundingRect(ref) {
20822
+ const rect = useState({ x: 0, y: 0, width: 0, height: 0 });
20823
+ function updateElRect() {
20824
+ const el = ref.el;
20825
+ if (el === null) {
20826
+ return;
20827
+ }
20828
+ const { top, left, width, height } = el.getBoundingClientRect();
20829
+ rect.x = left;
20830
+ rect.y = top;
20831
+ rect.width = width;
20832
+ rect.height = height;
20833
+ }
20834
+ onMounted(updateElRect);
20835
+ onPatched(updateElRect);
20836
+ return rect;
20837
+ }
20838
+ /**
20839
+ * Get the rectangle inside which a popover should stay when being displayed.
20840
+ * It's the value defined in `env.getPopoverContainerRect`, or the Rect of the "o-spreadsheet"
20841
+ * element by default.
20842
+ *
20843
+ * Coordinates are expressed expressed as absolute DOM position.
20844
+ */
20845
+ function usePopoverContainer() {
20846
+ const container = useState({ x: 0, y: 0, width: 0, height: 0 });
20847
+ const component = useComponent();
20848
+ const spreadsheetRect = useSpreadsheetRect();
20849
+ function updateRect() {
20850
+ const env = component.env;
20851
+ const newRect = "getPopoverContainerRect" in env ? env.getPopoverContainerRect() : spreadsheetRect;
20852
+ container.x = newRect.x;
20853
+ container.y = newRect.y;
20854
+ container.width = newRect.width;
20855
+ container.height = newRect.height;
20856
+ }
20857
+ updateRect();
20858
+ onMounted(updateRect);
20859
+ onPatched(updateRect);
20860
+ return container;
20861
+ }
20862
+
20782
20863
  const arrowMap = {
20783
20864
  ArrowDown: "down",
20784
20865
  ArrowLeft: "left",
@@ -21368,7 +21449,9 @@ class Composer extends Component {
21368
21449
  argToFocus: 0,
21369
21450
  });
21370
21451
  compositionActive = false;
21452
+ spreadsheetRect = useSpreadsheetRect();
21371
21453
  get assistantStyle() {
21454
+ const composerRect = this.composerRef.el.getBoundingClientRect();
21372
21455
  const assistantStyle = {};
21373
21456
  assistantStyle["min-width"] = `${this.props.rect?.width || ASSISTANT_WIDTH}px`;
21374
21457
  const proposals = this.autoCompleteState.provider?.proposals;
@@ -21395,6 +21478,9 @@ class Composer extends Component {
21395
21478
  }
21396
21479
  else if (this.props.delimitation) {
21397
21480
  assistantStyle["max-height"] = `${this.props.delimitation.height}px`;
21481
+ if (composerRect.left + ASSISTANT_WIDTH > this.spreadsheetRect.width) {
21482
+ assistantStyle.right = `0px`;
21483
+ }
21398
21484
  }
21399
21485
  return cssPropertiesToCss(assistantStyle);
21400
21486
  }
@@ -26237,78 +26323,6 @@ function zoneToRect(zone) {
26237
26323
  };
26238
26324
  }
26239
26325
 
26240
- /**
26241
- * Return the o-spreadsheet element position relative
26242
- * to the browser viewport.
26243
- */
26244
- function useSpreadsheetRect() {
26245
- const position = useState({ x: 0, y: 0, width: 0, height: 0 });
26246
- let spreadsheetElement = null;
26247
- function updatePosition() {
26248
- if (!spreadsheetElement) {
26249
- spreadsheetElement = document.querySelector(".o-spreadsheet");
26250
- }
26251
- if (spreadsheetElement) {
26252
- const { top, left, width, height } = spreadsheetElement.getBoundingClientRect();
26253
- position.x = left;
26254
- position.y = top;
26255
- position.width = width;
26256
- position.height = height;
26257
- }
26258
- }
26259
- onMounted(updatePosition);
26260
- onPatched(updatePosition);
26261
- return position;
26262
- }
26263
- /**
26264
- * Return the component (or ref's component) BoundingRect, relative
26265
- * to the upper left corner of the screen (<body> element).
26266
- *
26267
- * Note: when used with a <Portal/> component, it will
26268
- * return the portal position, not the teleported position.
26269
- */
26270
- function useAbsoluteBoundingRect(ref) {
26271
- const rect = useState({ x: 0, y: 0, width: 0, height: 0 });
26272
- function updateElRect() {
26273
- const el = ref.el;
26274
- if (el === null) {
26275
- return;
26276
- }
26277
- const { top, left, width, height } = el.getBoundingClientRect();
26278
- rect.x = left;
26279
- rect.y = top;
26280
- rect.width = width;
26281
- rect.height = height;
26282
- }
26283
- onMounted(updateElRect);
26284
- onPatched(updateElRect);
26285
- return rect;
26286
- }
26287
- /**
26288
- * Get the rectangle inside which a popover should stay when being displayed.
26289
- * It's the value defined in `env.getPopoverContainerRect`, or the Rect of the "o-spreadsheet"
26290
- * element by default.
26291
- *
26292
- * Coordinates are expressed expressed as absolute DOM position.
26293
- */
26294
- function usePopoverContainer() {
26295
- const container = useState({ x: 0, y: 0, width: 0, height: 0 });
26296
- const component = useComponent();
26297
- const spreadsheetRect = useSpreadsheetRect();
26298
- function updateRect() {
26299
- const env = component.env;
26300
- const newRect = "getPopoverContainerRect" in env ? env.getPopoverContainerRect() : spreadsheetRect;
26301
- container.x = newRect.x;
26302
- container.y = newRect.y;
26303
- container.width = newRect.width;
26304
- container.height = newRect.height;
26305
- }
26306
- updateRect();
26307
- onMounted(updateRect);
26308
- onPatched(updateRect);
26309
- return container;
26310
- }
26311
-
26312
26326
  css /* scss */ `
26313
26327
  .o-popover {
26314
26328
  position: absolute;
@@ -35807,6 +35821,14 @@ css /* scss */ `
35807
35821
  .pivot-dim-operator-label {
35808
35822
  min-width: 120px;
35809
35823
  }
35824
+
35825
+ &.pivot-dimension-invalid {
35826
+ background-color: #ffdddd;
35827
+ border-color: red !important;
35828
+ select {
35829
+ background-color: #ffdddd;
35830
+ }
35831
+ }
35810
35832
  }
35811
35833
  `;
35812
35834
  class PivotDimension extends Component {
@@ -47214,12 +47236,13 @@ class BordersPlugin extends CorePlugin {
47214
47236
  this.clearBorders(cmd.sheetId, cmd.target);
47215
47237
  break;
47216
47238
  case "REMOVE_COLUMNS_ROWS":
47217
- for (let el of [...cmd.elements].sort((a, b) => b - a)) {
47239
+ const elements = [...cmd.elements].sort((a, b) => b - a);
47240
+ for (const group of groupConsecutive(elements)) {
47218
47241
  if (cmd.dimension === "COL") {
47219
- this.shiftBordersHorizontally(cmd.sheetId, el + 1, -1);
47242
+ this.shiftBordersHorizontally(cmd.sheetId, group[group.length - 1] + 1, -group.length);
47220
47243
  }
47221
47244
  else {
47222
- this.shiftBordersVertically(cmd.sheetId, el + 1, -1);
47245
+ this.shiftBordersVertically(cmd.sheetId, group[group.length - 1] + 1, -group.length);
47223
47246
  }
47224
47247
  }
47225
47248
  break;
@@ -51280,12 +51303,7 @@ class SheetPlugin extends CorePlugin {
51280
51303
  });
51281
51304
  }
51282
51305
  if (colIndex > deletedColumn) {
51283
- this.dispatch("UPDATE_CELL_POSITION", {
51284
- sheetId: sheet.id,
51285
- cellId: cellId,
51286
- col: colIndex - 1,
51287
- row: rowIndex,
51288
- });
51306
+ this.setNewPosition(cellId, sheet.id, colIndex - 1, rowIndex);
51289
51307
  }
51290
51308
  }
51291
51309
  }
@@ -51295,7 +51313,7 @@ class SheetPlugin extends CorePlugin {
51295
51313
  * Move the cells after a column or rows insertion
51296
51314
  */
51297
51315
  moveCellsOnAddition(sheet, addedElement, quantity, dimension) {
51298
- const commands = [];
51316
+ const updates = [];
51299
51317
  for (let rowIndex = 0; rowIndex < sheet.rows.length; rowIndex++) {
51300
51318
  const row = sheet.rows[rowIndex];
51301
51319
  if (dimension !== "rows" || rowIndex >= addedElement) {
@@ -51304,20 +51322,20 @@ class SheetPlugin extends CorePlugin {
51304
51322
  const cellId = row.cells[i];
51305
51323
  if (cellId) {
51306
51324
  if (dimension === "rows" || colIndex >= addedElement) {
51307
- commands.push({
51308
- type: "UPDATE_CELL_POSITION",
51325
+ updates.push({
51309
51326
  sheetId: sheet.id,
51310
51327
  cellId: cellId,
51311
51328
  col: colIndex + (dimension === "columns" ? quantity : 0),
51312
51329
  row: rowIndex + (dimension === "rows" ? quantity : 0),
51330
+ type: "UPDATE_CELL_POSITION",
51313
51331
  });
51314
51332
  }
51315
51333
  }
51316
51334
  }
51317
51335
  }
51318
51336
  }
51319
- for (let cmd of commands.reverse()) {
51320
- this.dispatch(cmd.type, cmd);
51337
+ for (let update of updates.reverse()) {
51338
+ this.updateCellPosition(update);
51321
51339
  }
51322
51340
  }
51323
51341
  /**
@@ -51350,12 +51368,7 @@ class SheetPlugin extends CorePlugin {
51350
51368
  const colIndex = Number(i);
51351
51369
  const cellId = row.cells[i];
51352
51370
  if (cellId) {
51353
- this.dispatch("UPDATE_CELL_POSITION", {
51354
- sheetId: sheet.id,
51355
- cellId: cellId,
51356
- col: colIndex,
51357
- row: rowIndex - numberRows,
51358
- });
51371
+ this.setNewPosition(cellId, sheet.id, colIndex, rowIndex - numberRows);
51359
51372
  }
51360
51373
  }
51361
51374
  }
@@ -54121,6 +54134,9 @@ class Evaluator {
54121
54134
  if (!this.blockedArrayFormulas.has(position)) {
54122
54135
  this.invalidateSpreading(position);
54123
54136
  }
54137
+ if (this.spreadingRelations.isArrayFormula(position)) {
54138
+ this.spreadingRelations.removeNode(position);
54139
+ }
54124
54140
  const cell = this.getters.getCell(position);
54125
54141
  if (cell === undefined) {
54126
54142
  return EMPTY_CELL;
@@ -54163,7 +54179,6 @@ class Evaluator {
54163
54179
  this.assertSheetHasEnoughSpaceToSpreadFormulaResult(formulaPosition, formulaReturn);
54164
54180
  const nbColumns = formulaReturn.length;
54165
54181
  const nbRows = formulaReturn[0].length;
54166
- this.spreadingRelations.removeNode(formulaPosition);
54167
54182
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.updateSpreadRelation(formulaPosition));
54168
54183
  this.assertNoMergedCellsInSpreadZone(formulaPosition, formulaReturn);
54169
54184
  forEachSpreadPositionInMatrix(nbColumns, nbRows, this.checkCollision(formulaPosition));
@@ -63088,6 +63103,8 @@ css /* scss */ `
63088
63103
 
63089
63104
  .o-sidePanel-handle-container {
63090
63105
  width: 8px;
63106
+ position: fixed;
63107
+ top: 50%;
63091
63108
  }
63092
63109
  .o-sidePanel-handle {
63093
63110
  cursor: col-resize;
@@ -65707,7 +65724,7 @@ function createEmptyStructure(node) {
65707
65724
  }
65708
65725
 
65709
65726
  class StateObserver {
65710
- changes = [];
65727
+ changes;
65711
65728
  commands = [];
65712
65729
  /**
65713
65730
  * Record the changes which could happen in the given callback, save them in a
@@ -65739,7 +65756,7 @@ class StateObserver {
65739
65756
  if (value[key] === val) {
65740
65757
  return;
65741
65758
  }
65742
- this.changes.push({
65759
+ this.changes?.push({
65743
65760
  key,
65744
65761
  target: value,
65745
65762
  before: value[key],
@@ -68362,6 +68379,6 @@ const constants = {
68362
68379
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
68363
68380
 
68364
68381
 
68365
- __info__.version = "17.4.2";
68366
- __info__.date = "2024-07-24T10:26:00.237Z";
68367
- __info__.hash = "f5ede5b";
68382
+ __info__.version = "17.4.3";
68383
+ __info__.date = "2024-08-02T08:23:56.573Z";
68384
+ __info__.hash = "40ecd1e";