@odoo/o-spreadsheet 17.1.17 → 17.1.19

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.1.17
6
- * @date 2024-06-03T14:54:06.711Z
7
- * @hash 7dedb2f
5
+ * @version 17.1.19
6
+ * @date 2024-06-14T10:03:04.850Z
7
+ * @hash 8a74f95
8
8
  */
9
9
 
10
10
  'use strict';
@@ -295,7 +295,10 @@ function deepCopy(obj) {
295
295
  * Check if the object is a plain old javascript object.
296
296
  */
297
297
  function isPlainObject(obj) {
298
- return typeof obj === "object" && obj?.constructor === Object;
298
+ return (typeof obj === "object" &&
299
+ obj !== null &&
300
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
301
+ (obj?.constructor === Object || obj?.constructor === undefined));
299
302
  }
300
303
  /**
301
304
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -6841,8 +6844,7 @@ function isCtrlKey(ev) {
6841
6844
  */
6842
6845
  function useSpreadsheetRect() {
6843
6846
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
6844
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
6845
- updatePosition();
6847
+ let spreadsheetElement = null;
6846
6848
  function updatePosition() {
6847
6849
  if (!spreadsheetElement) {
6848
6850
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -6993,7 +6995,7 @@ class Popover extends owl.Component {
6993
6995
  if (!anchor)
6994
6996
  return;
6995
6997
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
6996
- const elDims = {
6998
+ let elDims = {
6997
6999
  width: el.getBoundingClientRect().width,
6998
7000
  height: el.getBoundingClientRect().height,
6999
7001
  };
@@ -7001,7 +7003,14 @@ class Popover extends owl.Component {
7001
7003
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
7002
7004
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
7003
7005
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
7004
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
7006
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
7007
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
7008
+ // Re-compute the dimensions after setting the max-width and max-height
7009
+ elDims = {
7010
+ width: el.getBoundingClientRect().width,
7011
+ height: el.getBoundingClientRect().height,
7012
+ };
7013
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
7005
7014
  for (const property of Object.keys(style)) {
7006
7015
  el.style[property] = style[property];
7007
7016
  }
@@ -7064,8 +7073,6 @@ class PopoverPositionContext {
7064
7073
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
7065
7074
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
7066
7075
  const cssProperties = {
7067
- "max-height": maxHeight + "px",
7068
- "max-width": maxWidth + "px",
7069
7076
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
7070
7077
  this.spreadsheetOffset.y -
7071
7078
  verticalOffset +
@@ -8606,7 +8613,7 @@ function chartToImage(runtime, figure, type) {
8606
8613
  if ("chartJsConfig" in runtime) {
8607
8614
  runtime.chartJsConfig.plugins = [backgroundColorChartJSPlugin];
8608
8615
  // @ts-ignore
8609
- const chart = new window.Chart(canvas, runtime.chartJsConfig);
8616
+ const chart = new window.Chart(canvas, deepCopy(runtime.chartJsConfig));
8610
8617
  const imgContent = chart.toBase64Image();
8611
8618
  chart.destroy();
8612
8619
  div.remove();
@@ -25471,13 +25478,17 @@ class SelectMenu extends owl.Component {
25471
25478
  class: { type: String, optional: true },
25472
25479
  };
25473
25480
  static components = { Menu };
25481
+ menuId = new UuidGenerator().uuidv4();
25474
25482
  selectRef = owl.useRef("select");
25475
25483
  selectRect = useAbsoluteBoundingRect(this.selectRef);
25476
25484
  state = owl.useState({
25477
25485
  isMenuOpen: false,
25478
25486
  });
25479
- onClick() {
25480
- this.state.isMenuOpen = true;
25487
+ onClick(ev) {
25488
+ if (ev.closedMenuId === this.menuId) {
25489
+ return;
25490
+ }
25491
+ this.state.isMenuOpen = !this.state.isMenuOpen;
25481
25492
  }
25482
25493
  onMenuClosed() {
25483
25494
  this.state.isMenuOpen = false;
@@ -25485,7 +25496,7 @@ class SelectMenu extends owl.Component {
25485
25496
  get menuPosition() {
25486
25497
  return {
25487
25498
  x: this.selectRect.x,
25488
- y: this.selectRect.y,
25499
+ y: this.selectRect.y + this.selectRect.height,
25489
25500
  };
25490
25501
  }
25491
25502
  }
@@ -27375,8 +27386,15 @@ class Composer extends owl.Component {
27375
27386
  }
27376
27387
  onPaste(ev) {
27377
27388
  if (this.env.model.getters.getEditionMode() !== "inactive") {
27389
+ // let the browser clipboard work
27378
27390
  ev.stopPropagation();
27379
27391
  }
27392
+ else {
27393
+ // the user meant to paste in the sheet, not open the composer with the pasted content
27394
+ // While we're not editing, we still have the focus and should therefore prevent
27395
+ // the native "paste" to occur.
27396
+ ev.preventDefault();
27397
+ }
27380
27398
  }
27381
27399
  /*
27382
27400
  * Triggered automatically by the content-editable between the keydown and key up
@@ -27385,10 +27403,6 @@ class Composer extends owl.Component {
27385
27403
  if (!this.shouldProcessInputEvents) {
27386
27404
  return;
27387
27405
  }
27388
- if (ev.inputType === "insertFromPaste" &&
27389
- this.env.model.getters.getEditionMode() === "inactive") {
27390
- return;
27391
- }
27392
27406
  ev.stopPropagation();
27393
27407
  let content;
27394
27408
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -27829,10 +27843,7 @@ class GridComposer extends owl.Component {
27829
27843
  }
27830
27844
  get containerStyle() {
27831
27845
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27832
- return `
27833
- position: absolute;
27834
- z-index: -1000;
27835
- `;
27846
+ return `z-index: -1000;`;
27836
27847
  }
27837
27848
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27838
27849
  const cell = this.env.model.getters.getActiveCell();
@@ -28523,7 +28534,7 @@ class FiguresContainer extends owl.Component {
28523
28534
  });
28524
28535
  }
28525
28536
  getContainerRect(container) {
28526
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
28537
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
28527
28538
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
28528
28539
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
28529
28540
  const width = viewWidth - x;
@@ -44796,7 +44807,10 @@ class Session extends EventBus {
44796
44807
  /**
44797
44808
  * Notify the server that the user client left the collaborative session
44798
44809
  */
44799
- leave() {
44810
+ leave(data) {
44811
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
44812
+ this.snapshot(data);
44813
+ }
44800
44814
  delete this.clients[this.clientId];
44801
44815
  this.transportService.leave(this.clientId);
44802
44816
  this.transportService.sendMessage({
@@ -44809,6 +44823,9 @@ class Session extends EventBus {
44809
44823
  * Send a snapshot of the spreadsheet to the collaboration server
44810
44824
  */
44811
44825
  snapshot(data) {
44826
+ if (this.pendingMessages.length !== 0) {
44827
+ return;
44828
+ }
44812
44829
  const snapshotId = this.uuidGenerator.uuidv4();
44813
44830
  this.transportService.sendMessage({
44814
44831
  type: "SNAPSHOT",
@@ -49508,10 +49525,8 @@ class EditionPlugin extends UIPlugin {
49508
49525
  const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
49509
49526
  return isEqual(this.getters.expandZone(activeSheetId, refRange.zone), oldZone);
49510
49527
  });
49511
- // this function assumes that the previous range is always found because
49512
- // it's called when changing a highlight, which exists by definition
49513
49528
  if (!previousRefToken) {
49514
- throw new Error("Previous range not found");
49529
+ return;
49515
49530
  }
49516
49531
  const previousRange = this.getters.getRangeFromSheetXC(activeSheetId, previousRefToken.value);
49517
49532
  this.selectionStart = previousRefToken.start;
@@ -57264,7 +57279,7 @@ class Model extends EventBus {
57264
57279
  this.session.join(this.config.client);
57265
57280
  }
57266
57281
  leaveSession() {
57267
- this.session.leave();
57282
+ this.session.leave(this.exportData());
57268
57283
  }
57269
57284
  setupUiPlugin(Plugin) {
57270
57285
  const plugin = new Plugin(this.uiPluginConfig);
@@ -57688,6 +57703,7 @@ const helpers = {
57688
57703
  createAction,
57689
57704
  createActions,
57690
57705
  transformRangeData,
57706
+ deepEquals,
57691
57707
  };
57692
57708
  const links = {
57693
57709
  isMarkdownLink,
@@ -57775,6 +57791,6 @@ exports.setTranslationMethod = setTranslationMethod;
57775
57791
  exports.tokenize = tokenize;
57776
57792
 
57777
57793
 
57778
- __info__.version = "17.1.17";
57779
- __info__.date = "2024-06-03T14:54:06.711Z";
57780
- __info__.hash = "7dedb2f";
57794
+ __info__.version = "17.1.19";
57795
+ __info__.date = "2024-06-14T10:03:04.850Z";
57796
+ __info__.hash = "8a74f95";
@@ -841,7 +841,7 @@ declare class Session extends EventBus<CollaborativeEvent> {
841
841
  /**
842
842
  * Notify the server that the user client left the collaborative session
843
843
  */
844
- leave(): void;
844
+ leave(data: WorkbookData): void;
845
845
  /**
846
846
  * Send a snapshot of the spreadsheet to the collaboration server
847
847
  */
@@ -982,6 +982,10 @@ declare function isDefined<T>(argument: T | undefined): argument is T;
982
982
  * Lazy value computed by the provided function.
983
983
  */
984
984
  declare function lazy<T>(fn: (() => T) | T): Lazy<T>;
985
+ /**
986
+ * Compares two objects.
987
+ */
988
+ declare function deepEquals(o1: any, o2: any, ignoreFunctions?: "ignoreFunctions"): boolean;
985
989
 
986
990
  interface ConstructorArgs {
987
991
  readonly zone: Readonly<Zone | UnboundedZone>;
@@ -8691,6 +8695,7 @@ declare const helpers: {
8691
8695
  createAction: typeof createAction;
8692
8696
  createActions: typeof createActions;
8693
8697
  transformRangeData: typeof transformRangeData;
8698
+ deepEquals: typeof deepEquals;
8694
8699
  };
8695
8700
  declare const links: {
8696
8701
  isMarkdownLink: typeof isMarkdownLink;
@@ -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.1.17
6
- * @date 2024-06-03T14:54:06.711Z
7
- * @hash 7dedb2f
5
+ * @version 17.1.19
6
+ * @date 2024-06-14T10:03:04.850Z
7
+ * @hash 8a74f95
8
8
  */
9
9
 
10
10
  import { Component, useRef, onMounted, onWillUnmount, useEffect, onWillPatch, useState, onWillUpdateProps, onPatched, useComponent, useExternalListener, onWillStart, xml, useChildSubEnv, useSubEnv, markRaw } from '@odoo/owl';
@@ -293,7 +293,10 @@ function deepCopy(obj) {
293
293
  * Check if the object is a plain old javascript object.
294
294
  */
295
295
  function isPlainObject(obj) {
296
- return typeof obj === "object" && obj?.constructor === Object;
296
+ return (typeof obj === "object" &&
297
+ obj !== null &&
298
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
299
+ (obj?.constructor === Object || obj?.constructor === undefined));
297
300
  }
298
301
  /**
299
302
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -6839,8 +6842,7 @@ function isCtrlKey(ev) {
6839
6842
  */
6840
6843
  function useSpreadsheetRect() {
6841
6844
  const position = useState({ x: 0, y: 0, width: 0, height: 0 });
6842
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
6843
- updatePosition();
6845
+ let spreadsheetElement = null;
6844
6846
  function updatePosition() {
6845
6847
  if (!spreadsheetElement) {
6846
6848
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -6991,7 +6993,7 @@ class Popover extends Component {
6991
6993
  if (!anchor)
6992
6994
  return;
6993
6995
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
6994
- const elDims = {
6996
+ let elDims = {
6995
6997
  width: el.getBoundingClientRect().width,
6996
6998
  height: el.getBoundingClientRect().height,
6997
6999
  };
@@ -6999,7 +7001,14 @@ class Popover extends Component {
6999
7001
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
7000
7002
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
7001
7003
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
7002
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
7004
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
7005
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
7006
+ // Re-compute the dimensions after setting the max-width and max-height
7007
+ elDims = {
7008
+ width: el.getBoundingClientRect().width,
7009
+ height: el.getBoundingClientRect().height,
7010
+ };
7011
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
7003
7012
  for (const property of Object.keys(style)) {
7004
7013
  el.style[property] = style[property];
7005
7014
  }
@@ -7062,8 +7071,6 @@ class PopoverPositionContext {
7062
7071
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
7063
7072
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
7064
7073
  const cssProperties = {
7065
- "max-height": maxHeight + "px",
7066
- "max-width": maxWidth + "px",
7067
7074
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
7068
7075
  this.spreadsheetOffset.y -
7069
7076
  verticalOffset +
@@ -8604,7 +8611,7 @@ function chartToImage(runtime, figure, type) {
8604
8611
  if ("chartJsConfig" in runtime) {
8605
8612
  runtime.chartJsConfig.plugins = [backgroundColorChartJSPlugin];
8606
8613
  // @ts-ignore
8607
- const chart = new window.Chart(canvas, runtime.chartJsConfig);
8614
+ const chart = new window.Chart(canvas, deepCopy(runtime.chartJsConfig));
8608
8615
  const imgContent = chart.toBase64Image();
8609
8616
  chart.destroy();
8610
8617
  div.remove();
@@ -25469,13 +25476,17 @@ class SelectMenu extends Component {
25469
25476
  class: { type: String, optional: true },
25470
25477
  };
25471
25478
  static components = { Menu };
25479
+ menuId = new UuidGenerator().uuidv4();
25472
25480
  selectRef = useRef("select");
25473
25481
  selectRect = useAbsoluteBoundingRect(this.selectRef);
25474
25482
  state = useState({
25475
25483
  isMenuOpen: false,
25476
25484
  });
25477
- onClick() {
25478
- this.state.isMenuOpen = true;
25485
+ onClick(ev) {
25486
+ if (ev.closedMenuId === this.menuId) {
25487
+ return;
25488
+ }
25489
+ this.state.isMenuOpen = !this.state.isMenuOpen;
25479
25490
  }
25480
25491
  onMenuClosed() {
25481
25492
  this.state.isMenuOpen = false;
@@ -25483,7 +25494,7 @@ class SelectMenu extends Component {
25483
25494
  get menuPosition() {
25484
25495
  return {
25485
25496
  x: this.selectRect.x,
25486
- y: this.selectRect.y,
25497
+ y: this.selectRect.y + this.selectRect.height,
25487
25498
  };
25488
25499
  }
25489
25500
  }
@@ -27373,8 +27384,15 @@ class Composer extends Component {
27373
27384
  }
27374
27385
  onPaste(ev) {
27375
27386
  if (this.env.model.getters.getEditionMode() !== "inactive") {
27387
+ // let the browser clipboard work
27376
27388
  ev.stopPropagation();
27377
27389
  }
27390
+ else {
27391
+ // the user meant to paste in the sheet, not open the composer with the pasted content
27392
+ // While we're not editing, we still have the focus and should therefore prevent
27393
+ // the native "paste" to occur.
27394
+ ev.preventDefault();
27395
+ }
27378
27396
  }
27379
27397
  /*
27380
27398
  * Triggered automatically by the content-editable between the keydown and key up
@@ -27383,10 +27401,6 @@ class Composer extends Component {
27383
27401
  if (!this.shouldProcessInputEvents) {
27384
27402
  return;
27385
27403
  }
27386
- if (ev.inputType === "insertFromPaste" &&
27387
- this.env.model.getters.getEditionMode() === "inactive") {
27388
- return;
27389
- }
27390
27404
  ev.stopPropagation();
27391
27405
  let content;
27392
27406
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -27827,10 +27841,7 @@ class GridComposer extends Component {
27827
27841
  }
27828
27842
  get containerStyle() {
27829
27843
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27830
- return `
27831
- position: absolute;
27832
- z-index: -1000;
27833
- `;
27844
+ return `z-index: -1000;`;
27834
27845
  }
27835
27846
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27836
27847
  const cell = this.env.model.getters.getActiveCell();
@@ -28521,7 +28532,7 @@ class FiguresContainer extends Component {
28521
28532
  });
28522
28533
  }
28523
28534
  getContainerRect(container) {
28524
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
28535
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
28525
28536
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
28526
28537
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
28527
28538
  const width = viewWidth - x;
@@ -44794,7 +44805,10 @@ class Session extends EventBus {
44794
44805
  /**
44795
44806
  * Notify the server that the user client left the collaborative session
44796
44807
  */
44797
- leave() {
44808
+ leave(data) {
44809
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
44810
+ this.snapshot(data);
44811
+ }
44798
44812
  delete this.clients[this.clientId];
44799
44813
  this.transportService.leave(this.clientId);
44800
44814
  this.transportService.sendMessage({
@@ -44807,6 +44821,9 @@ class Session extends EventBus {
44807
44821
  * Send a snapshot of the spreadsheet to the collaboration server
44808
44822
  */
44809
44823
  snapshot(data) {
44824
+ if (this.pendingMessages.length !== 0) {
44825
+ return;
44826
+ }
44810
44827
  const snapshotId = this.uuidGenerator.uuidv4();
44811
44828
  this.transportService.sendMessage({
44812
44829
  type: "SNAPSHOT",
@@ -49506,10 +49523,8 @@ class EditionPlugin extends UIPlugin {
49506
49523
  const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
49507
49524
  return isEqual(this.getters.expandZone(activeSheetId, refRange.zone), oldZone);
49508
49525
  });
49509
- // this function assumes that the previous range is always found because
49510
- // it's called when changing a highlight, which exists by definition
49511
49526
  if (!previousRefToken) {
49512
- throw new Error("Previous range not found");
49527
+ return;
49513
49528
  }
49514
49529
  const previousRange = this.getters.getRangeFromSheetXC(activeSheetId, previousRefToken.value);
49515
49530
  this.selectionStart = previousRefToken.start;
@@ -57262,7 +57277,7 @@ class Model extends EventBus {
57262
57277
  this.session.join(this.config.client);
57263
57278
  }
57264
57279
  leaveSession() {
57265
- this.session.leave();
57280
+ this.session.leave(this.exportData());
57266
57281
  }
57267
57282
  setupUiPlugin(Plugin) {
57268
57283
  const plugin = new Plugin(this.uiPluginConfig);
@@ -57686,6 +57701,7 @@ const helpers = {
57686
57701
  createAction,
57687
57702
  createActions,
57688
57703
  transformRangeData,
57704
+ deepEquals,
57689
57705
  };
57690
57706
  const links = {
57691
57707
  isMarkdownLink,
@@ -57737,6 +57753,6 @@ const constants = {
57737
57753
  export { AbstractChart, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, tokenize };
57738
57754
 
57739
57755
 
57740
- __info__.version = "17.1.17";
57741
- __info__.date = "2024-06-03T14:54:06.711Z";
57742
- __info__.hash = "7dedb2f";
57756
+ __info__.version = "17.1.19";
57757
+ __info__.date = "2024-06-14T10:03:04.850Z";
57758
+ __info__.hash = "8a74f95";
@@ -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.1.17
6
- * @date 2024-06-03T14:54:06.711Z
7
- * @hash 7dedb2f
5
+ * @version 17.1.19
6
+ * @date 2024-06-14T10:03:04.850Z
7
+ * @hash 8a74f95
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -294,7 +294,10 @@
294
294
  * Check if the object is a plain old javascript object.
295
295
  */
296
296
  function isPlainObject(obj) {
297
- return typeof obj === "object" && obj?.constructor === Object;
297
+ return (typeof obj === "object" &&
298
+ obj !== null &&
299
+ // obj.constructor can be undefined when there's no prototype (`Object.create(null, {})`)
300
+ (obj?.constructor === Object || obj?.constructor === undefined));
298
301
  }
299
302
  /**
300
303
  * Sanitize the name of a sheet, by eventually removing quotes
@@ -6840,8 +6843,7 @@
6840
6843
  */
6841
6844
  function useSpreadsheetRect() {
6842
6845
  const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
6843
- let spreadsheetElement = document.querySelector(".o-spreadsheet");
6844
- updatePosition();
6846
+ let spreadsheetElement = null;
6845
6847
  function updatePosition() {
6846
6848
  if (!spreadsheetElement) {
6847
6849
  spreadsheetElement = document.querySelector(".o-spreadsheet");
@@ -6992,7 +6994,7 @@
6992
6994
  if (!anchor)
6993
6995
  return;
6994
6996
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
6995
- const elDims = {
6997
+ let elDims = {
6996
6998
  width: el.getBoundingClientRect().width,
6997
6999
  height: el.getBoundingClientRect().height,
6998
7000
  };
@@ -7000,7 +7002,14 @@
7000
7002
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
7001
7003
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
7002
7004
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
7003
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
7005
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
7006
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
7007
+ // Re-compute the dimensions after setting the max-width and max-height
7008
+ elDims = {
7009
+ width: el.getBoundingClientRect().width,
7010
+ height: el.getBoundingClientRect().height,
7011
+ };
7012
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
7004
7013
  for (const property of Object.keys(style)) {
7005
7014
  el.style[property] = style[property];
7006
7015
  }
@@ -7063,8 +7072,6 @@
7063
7072
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
7064
7073
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
7065
7074
  const cssProperties = {
7066
- "max-height": maxHeight + "px",
7067
- "max-width": maxWidth + "px",
7068
7075
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
7069
7076
  this.spreadsheetOffset.y -
7070
7077
  verticalOffset +
@@ -8605,7 +8612,7 @@
8605
8612
  if ("chartJsConfig" in runtime) {
8606
8613
  runtime.chartJsConfig.plugins = [backgroundColorChartJSPlugin];
8607
8614
  // @ts-ignore
8608
- const chart = new window.Chart(canvas, runtime.chartJsConfig);
8615
+ const chart = new window.Chart(canvas, deepCopy(runtime.chartJsConfig));
8609
8616
  const imgContent = chart.toBase64Image();
8610
8617
  chart.destroy();
8611
8618
  div.remove();
@@ -25470,13 +25477,17 @@
25470
25477
  class: { type: String, optional: true },
25471
25478
  };
25472
25479
  static components = { Menu };
25480
+ menuId = new UuidGenerator().uuidv4();
25473
25481
  selectRef = owl.useRef("select");
25474
25482
  selectRect = useAbsoluteBoundingRect(this.selectRef);
25475
25483
  state = owl.useState({
25476
25484
  isMenuOpen: false,
25477
25485
  });
25478
- onClick() {
25479
- this.state.isMenuOpen = true;
25486
+ onClick(ev) {
25487
+ if (ev.closedMenuId === this.menuId) {
25488
+ return;
25489
+ }
25490
+ this.state.isMenuOpen = !this.state.isMenuOpen;
25480
25491
  }
25481
25492
  onMenuClosed() {
25482
25493
  this.state.isMenuOpen = false;
@@ -25484,7 +25495,7 @@
25484
25495
  get menuPosition() {
25485
25496
  return {
25486
25497
  x: this.selectRect.x,
25487
- y: this.selectRect.y,
25498
+ y: this.selectRect.y + this.selectRect.height,
25488
25499
  };
25489
25500
  }
25490
25501
  }
@@ -27374,8 +27385,15 @@
27374
27385
  }
27375
27386
  onPaste(ev) {
27376
27387
  if (this.env.model.getters.getEditionMode() !== "inactive") {
27388
+ // let the browser clipboard work
27377
27389
  ev.stopPropagation();
27378
27390
  }
27391
+ else {
27392
+ // the user meant to paste in the sheet, not open the composer with the pasted content
27393
+ // While we're not editing, we still have the focus and should therefore prevent
27394
+ // the native "paste" to occur.
27395
+ ev.preventDefault();
27396
+ }
27379
27397
  }
27380
27398
  /*
27381
27399
  * Triggered automatically by the content-editable between the keydown and key up
@@ -27384,10 +27402,6 @@
27384
27402
  if (!this.shouldProcessInputEvents) {
27385
27403
  return;
27386
27404
  }
27387
- if (ev.inputType === "insertFromPaste" &&
27388
- this.env.model.getters.getEditionMode() === "inactive") {
27389
- return;
27390
- }
27391
27405
  ev.stopPropagation();
27392
27406
  let content;
27393
27407
  if (this.env.model.getters.getEditionMode() === "inactive") {
@@ -27828,10 +27842,7 @@
27828
27842
  }
27829
27843
  get containerStyle() {
27830
27844
  if (this.env.model.getters.getEditionMode() === "inactive" || !this.rect) {
27831
- return `
27832
- position: absolute;
27833
- z-index: -1000;
27834
- `;
27845
+ return `z-index: -1000;`;
27835
27846
  }
27836
27847
  const isFormula = this.env.model.getters.getCurrentContent().startsWith("=");
27837
27848
  const cell = this.env.model.getters.getActiveCell();
@@ -28522,7 +28533,7 @@
28522
28533
  });
28523
28534
  }
28524
28535
  getContainerRect(container) {
28525
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
28536
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
28526
28537
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
28527
28538
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
28528
28539
  const width = viewWidth - x;
@@ -44795,7 +44806,10 @@
44795
44806
  /**
44796
44807
  * Notify the server that the user client left the collaborative session
44797
44808
  */
44798
- leave() {
44809
+ leave(data) {
44810
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
44811
+ this.snapshot(data);
44812
+ }
44799
44813
  delete this.clients[this.clientId];
44800
44814
  this.transportService.leave(this.clientId);
44801
44815
  this.transportService.sendMessage({
@@ -44808,6 +44822,9 @@
44808
44822
  * Send a snapshot of the spreadsheet to the collaboration server
44809
44823
  */
44810
44824
  snapshot(data) {
44825
+ if (this.pendingMessages.length !== 0) {
44826
+ return;
44827
+ }
44811
44828
  const snapshotId = this.uuidGenerator.uuidv4();
44812
44829
  this.transportService.sendMessage({
44813
44830
  type: "SNAPSHOT",
@@ -49507,10 +49524,8 @@
49507
49524
  const refRange = this.getters.getRangeFromSheetXC(activeSheetId, xc);
49508
49525
  return isEqual(this.getters.expandZone(activeSheetId, refRange.zone), oldZone);
49509
49526
  });
49510
- // this function assumes that the previous range is always found because
49511
- // it's called when changing a highlight, which exists by definition
49512
49527
  if (!previousRefToken) {
49513
- throw new Error("Previous range not found");
49528
+ return;
49514
49529
  }
49515
49530
  const previousRange = this.getters.getRangeFromSheetXC(activeSheetId, previousRefToken.value);
49516
49531
  this.selectionStart = previousRefToken.start;
@@ -57263,7 +57278,7 @@
57263
57278
  this.session.join(this.config.client);
57264
57279
  }
57265
57280
  leaveSession() {
57266
- this.session.leave();
57281
+ this.session.leave(this.exportData());
57267
57282
  }
57268
57283
  setupUiPlugin(Plugin) {
57269
57284
  const plugin = new Plugin(this.uiPluginConfig);
@@ -57687,6 +57702,7 @@
57687
57702
  createAction,
57688
57703
  createActions,
57689
57704
  transformRangeData,
57705
+ deepEquals,
57690
57706
  };
57691
57707
  const links = {
57692
57708
  isMarkdownLink,
@@ -57774,9 +57790,9 @@
57774
57790
  exports.tokenize = tokenize;
57775
57791
 
57776
57792
 
57777
- __info__.version = "17.1.17";
57778
- __info__.date = "2024-06-03T14:54:06.711Z";
57779
- __info__.hash = "7dedb2f";
57793
+ __info__.version = "17.1.19";
57794
+ __info__.date = "2024-06-14T10:03:04.850Z";
57795
+ __info__.hash = "8a74f95";
57780
57796
 
57781
57797
 
57782
57798
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);