@odoo/o-spreadsheet 18.3.16 → 18.3.18

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 18.3.16
6
- * @date 2025-08-18T08:15:07.809Z
7
- * @hash 68ef497
5
+ * @version 18.3.18
6
+ * @date 2025-08-26T10:14:21.408Z
7
+ * @hash ec2777d
8
8
  */
9
9
 
10
10
  'use strict';
@@ -3634,6 +3634,7 @@ exports.CommandResult = void 0;
3634
3634
  CommandResult["Success"] = "Success";
3635
3635
  CommandResult["CancelledForUnknownReason"] = "CancelledForUnknownReason";
3636
3636
  CommandResult["WillRemoveExistingMerge"] = "WillRemoveExistingMerge";
3637
+ CommandResult["CannotMoveTableHeader"] = "CannotMoveTableHeader";
3637
3638
  CommandResult["MergeIsDestructive"] = "MergeIsDestructive";
3638
3639
  CommandResult["CellIsMerged"] = "CellIsMerged";
3639
3640
  CommandResult["InvalidTarget"] = "InvalidTarget";
@@ -7104,29 +7105,40 @@ function getPasteZones(target, content) {
7104
7105
  const width = content[0].length, height = content.length;
7105
7106
  return target.map((t) => splitZoneForPaste(t, width, height)).flat();
7106
7107
  }
7107
- function parseOSClipboardContent(content, clipboardId) {
7108
+ function parseOSClipboardContent(content) {
7108
7109
  let spreadsheetContent = undefined;
7109
7110
  if (content[ClipboardMIMEType.Html]) {
7110
7111
  const htmlDocument = new DOMParser().parseFromString(content[ClipboardMIMEType.Html], "text/html");
7111
- const oSheetClipboardData = htmlDocument
7112
- .querySelector("div")
7113
- ?.getAttribute("data-osheet-clipboard");
7114
- spreadsheetContent = oSheetClipboardData && JSON.parse(oSheetClipboardData);
7112
+ spreadsheetContent = getOSheetDataFromHTML(htmlDocument);
7115
7113
  }
7114
+ const textContent = content[ClipboardMIMEType.PlainText] || "";
7116
7115
  let imageBlob = undefined;
7117
- for (const type of AllowedImageMimeTypes) {
7118
- if (content[type]) {
7119
- imageBlob = content[type];
7120
- break;
7116
+ if (!textContent.trim()) {
7117
+ for (const type of AllowedImageMimeTypes) {
7118
+ if (content[type]) {
7119
+ imageBlob = content[type];
7120
+ break;
7121
+ }
7121
7122
  }
7122
7123
  }
7123
7124
  const osClipboardContent = {
7124
- text: content[ClipboardMIMEType.PlainText],
7125
+ text: textContent,
7125
7126
  data: spreadsheetContent,
7126
7127
  imageBlob,
7127
7128
  };
7128
7129
  return osClipboardContent;
7129
7130
  }
7131
+ function getOSheetDataFromHTML(htmlDocument) {
7132
+ const attributes = [...htmlDocument.documentElement.attributes];
7133
+ // Check if it's a Microsoft Office clipboard data (it will have some namespaces defined in the root element)
7134
+ if (attributes.some((attr) => attr.value.includes("microsoft"))) {
7135
+ return undefined;
7136
+ }
7137
+ const oSheetClipboardData = htmlDocument
7138
+ .querySelector("div")
7139
+ ?.getAttribute("data-osheet-clipboard");
7140
+ return oSheetClipboardData && JSON.parse(oSheetClipboardData);
7141
+ }
7130
7142
  /**
7131
7143
  * Applies each clipboard handler to paste its corresponding data into the target.
7132
7144
  */
@@ -24952,6 +24964,7 @@ const CustomCurrencyTerms = {
24952
24964
  Custom: _t("Custom"),
24953
24965
  };
24954
24966
  const MergeErrorMessage = _t("Merged cells are preventing this operation. Unmerge those cells and try again.");
24967
+ const TableHeaderMoveErrorMessage = _t("The header row of a table can't be moved.");
24955
24968
  const SplitToColumnsTerms = {
24956
24969
  Errors: {
24957
24970
  Unexpected: _t("Cannot split the selection for an unknown reason"),
@@ -27197,10 +27210,6 @@ class ComboChart extends AbstractChart {
27197
27210
  };
27198
27211
  }
27199
27212
  getDefinitionForExcel() {
27200
- // Excel does not support aggregating labels
27201
- if (this.aggregated) {
27202
- return undefined;
27203
- }
27204
27213
  const dataSets = this.dataSets
27205
27214
  .map((ds) => toExcelDataset(this.getters, ds))
27206
27215
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -28354,9 +28363,6 @@ class RadarChart extends AbstractChart {
28354
28363
  };
28355
28364
  }
28356
28365
  getDefinitionForExcel() {
28357
- if (this.aggregated) {
28358
- return undefined;
28359
- }
28360
28366
  const dataSets = this.dataSets
28361
28367
  .map((ds) => toExcelDataset(this.getters, ds))
28362
28368
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -28501,10 +28507,6 @@ class ScatterChart extends AbstractChart {
28501
28507
  return new ScatterChart(definition, this.sheetId, this.getters);
28502
28508
  }
28503
28509
  getDefinitionForExcel() {
28504
- // Excel does not support aggregating labels
28505
- if (this.aggregated) {
28506
- return undefined;
28507
- }
28508
28510
  const dataSets = this.dataSets
28509
28511
  .map((ds) => toExcelDataset(this.getters, ds))
28510
28512
  .filter((ds) => ds.range !== "");
@@ -43758,6 +43760,9 @@ class Composer extends owl.Component {
43758
43760
  this.contentHelper.removeSelection();
43759
43761
  }
43760
43762
  onMouseup() {
43763
+ if (this.env.model.getters.isReadonly()) {
43764
+ return;
43765
+ }
43761
43766
  const selection = this.contentHelper.getCurrentSelection();
43762
43767
  if (selection.start !== selection.end) {
43763
43768
  this.props.composerStore.hoverToken(undefined);
@@ -54693,8 +54698,13 @@ class RowResizer extends AbstractResizer {
54693
54698
  elements,
54694
54699
  position: this.state.position,
54695
54700
  });
54696
- if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
54697
- this.env.raiseError(MergeErrorMessage);
54701
+ if (!result.isSuccessful) {
54702
+ if (result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
54703
+ this.env.raiseError(MergeErrorMessage);
54704
+ }
54705
+ else if (result.reasons.includes("CannotMoveTableHeader" /* CommandResult.CannotMoveTableHeader */)) {
54706
+ this.env.raiseError(TableHeaderMoveErrorMessage);
54707
+ }
54698
54708
  }
54699
54709
  }
54700
54710
  _selectElement(index, addDistinctHeader) {
@@ -66668,7 +66678,7 @@ function withPivotPresentationLayer (PivotClass) {
66668
66678
  return PivotPresentationLayer;
66669
66679
  }
66670
66680
 
66671
- const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT"];
66681
+ const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT", "REMOVE_PIVOT"];
66672
66682
  function isPivotCommand(cmd) {
66673
66683
  return UNDO_REDO_PIVOT_COMMANDS.includes(cmd.type);
66674
66684
  }
@@ -72100,8 +72110,33 @@ class GridSelectionPlugin extends UIPlugin {
72100
72110
  if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
72101
72111
  return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
72102
72112
  }
72113
+ if (!isCol && !this.isTableRowMoveAllowed(id, cmd.elements)) {
72114
+ return "CannotMoveTableHeader" /* CommandResult.CannotMoveTableHeader */;
72115
+ }
72103
72116
  return "Success" /* CommandResult.Success */;
72104
72117
  }
72118
+ isTableRowMoveAllowed(sheetId, selectedRows) {
72119
+ const tables = this.getters.getCoreTables(sheetId);
72120
+ if (tables.length === 0) {
72121
+ return true;
72122
+ }
72123
+ const selectedRowSet = new Set(selectedRows);
72124
+ return tables.every(({ range: { zone }, config }) => {
72125
+ const { top, bottom } = zone;
72126
+ if (config.numberOfHeaders === 0) {
72127
+ return true;
72128
+ }
72129
+ const headerRowEnd = top + config.numberOfHeaders - 1;
72130
+ // Moving the table is allowed if table header rows are not part of the selection
72131
+ // Or if the entire table (including header) is selected
72132
+ const isHeaderSelected = selectedRows.some((row) => row >= top && row <= headerRowEnd);
72133
+ if (!isHeaderSelected) {
72134
+ return true;
72135
+ }
72136
+ const isWholeTableSelected = range(top, bottom + 1).every((r) => selectedRowSet.has(r));
72137
+ return isWholeTableSelected;
72138
+ });
72139
+ }
72105
72140
  fallbackToVisibleSheet() {
72106
72141
  if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
72107
72142
  const currentSheetIds = this.getters.getVisibleSheetIds();
@@ -80920,6 +80955,6 @@ exports.tokenColors = tokenColors;
80920
80955
  exports.tokenize = tokenize;
80921
80956
 
80922
80957
 
80923
- __info__.version = "18.3.16";
80924
- __info__.date = "2025-08-18T08:15:07.809Z";
80925
- __info__.hash = "68ef497";
80958
+ __info__.version = "18.3.18";
80959
+ __info__.date = "2025-08-26T10:14:21.408Z";
80960
+ __info__.hash = "ec2777d";
@@ -2254,6 +2254,7 @@ declare class GridSelectionPlugin extends UIPlugin {
2254
2254
  private getFiguresUpdates;
2255
2255
  private applyFigureUpdates;
2256
2256
  private isMoveElementAllowed;
2257
+ private isTableRowMoveAllowed;
2257
2258
  private fallbackToVisibleSheet;
2258
2259
  /**
2259
2260
  * Clip the selection if it spans outside the sheet
@@ -3265,6 +3266,7 @@ declare const enum CommandResult {
3265
3266
  Success = "Success",
3266
3267
  CancelledForUnknownReason = "CancelledForUnknownReason",
3267
3268
  WillRemoveExistingMerge = "WillRemoveExistingMerge",
3269
+ CannotMoveTableHeader = "CannotMoveTableHeader",
3268
3270
  MergeIsDestructive = "MergeIsDestructive",
3269
3271
  CellIsMerged = "CellIsMerged",
3270
3272
  InvalidTarget = "InvalidTarget",
@@ -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 18.3.16
6
- * @date 2025-08-18T08:15:07.809Z
7
- * @hash 68ef497
5
+ * @version 18.3.18
6
+ * @date 2025-08-26T10:14:21.408Z
7
+ * @hash ec2777d
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -3632,6 +3632,7 @@ var CommandResult;
3632
3632
  CommandResult["Success"] = "Success";
3633
3633
  CommandResult["CancelledForUnknownReason"] = "CancelledForUnknownReason";
3634
3634
  CommandResult["WillRemoveExistingMerge"] = "WillRemoveExistingMerge";
3635
+ CommandResult["CannotMoveTableHeader"] = "CannotMoveTableHeader";
3635
3636
  CommandResult["MergeIsDestructive"] = "MergeIsDestructive";
3636
3637
  CommandResult["CellIsMerged"] = "CellIsMerged";
3637
3638
  CommandResult["InvalidTarget"] = "InvalidTarget";
@@ -7102,29 +7103,40 @@ function getPasteZones(target, content) {
7102
7103
  const width = content[0].length, height = content.length;
7103
7104
  return target.map((t) => splitZoneForPaste(t, width, height)).flat();
7104
7105
  }
7105
- function parseOSClipboardContent(content, clipboardId) {
7106
+ function parseOSClipboardContent(content) {
7106
7107
  let spreadsheetContent = undefined;
7107
7108
  if (content[ClipboardMIMEType.Html]) {
7108
7109
  const htmlDocument = new DOMParser().parseFromString(content[ClipboardMIMEType.Html], "text/html");
7109
- const oSheetClipboardData = htmlDocument
7110
- .querySelector("div")
7111
- ?.getAttribute("data-osheet-clipboard");
7112
- spreadsheetContent = oSheetClipboardData && JSON.parse(oSheetClipboardData);
7110
+ spreadsheetContent = getOSheetDataFromHTML(htmlDocument);
7113
7111
  }
7112
+ const textContent = content[ClipboardMIMEType.PlainText] || "";
7114
7113
  let imageBlob = undefined;
7115
- for (const type of AllowedImageMimeTypes) {
7116
- if (content[type]) {
7117
- imageBlob = content[type];
7118
- break;
7114
+ if (!textContent.trim()) {
7115
+ for (const type of AllowedImageMimeTypes) {
7116
+ if (content[type]) {
7117
+ imageBlob = content[type];
7118
+ break;
7119
+ }
7119
7120
  }
7120
7121
  }
7121
7122
  const osClipboardContent = {
7122
- text: content[ClipboardMIMEType.PlainText],
7123
+ text: textContent,
7123
7124
  data: spreadsheetContent,
7124
7125
  imageBlob,
7125
7126
  };
7126
7127
  return osClipboardContent;
7127
7128
  }
7129
+ function getOSheetDataFromHTML(htmlDocument) {
7130
+ const attributes = [...htmlDocument.documentElement.attributes];
7131
+ // Check if it's a Microsoft Office clipboard data (it will have some namespaces defined in the root element)
7132
+ if (attributes.some((attr) => attr.value.includes("microsoft"))) {
7133
+ return undefined;
7134
+ }
7135
+ const oSheetClipboardData = htmlDocument
7136
+ .querySelector("div")
7137
+ ?.getAttribute("data-osheet-clipboard");
7138
+ return oSheetClipboardData && JSON.parse(oSheetClipboardData);
7139
+ }
7128
7140
  /**
7129
7141
  * Applies each clipboard handler to paste its corresponding data into the target.
7130
7142
  */
@@ -24950,6 +24962,7 @@ const CustomCurrencyTerms = {
24950
24962
  Custom: _t("Custom"),
24951
24963
  };
24952
24964
  const MergeErrorMessage = _t("Merged cells are preventing this operation. Unmerge those cells and try again.");
24965
+ const TableHeaderMoveErrorMessage = _t("The header row of a table can't be moved.");
24953
24966
  const SplitToColumnsTerms = {
24954
24967
  Errors: {
24955
24968
  Unexpected: _t("Cannot split the selection for an unknown reason"),
@@ -27195,10 +27208,6 @@ class ComboChart extends AbstractChart {
27195
27208
  };
27196
27209
  }
27197
27210
  getDefinitionForExcel() {
27198
- // Excel does not support aggregating labels
27199
- if (this.aggregated) {
27200
- return undefined;
27201
- }
27202
27211
  const dataSets = this.dataSets
27203
27212
  .map((ds) => toExcelDataset(this.getters, ds))
27204
27213
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -28352,9 +28361,6 @@ class RadarChart extends AbstractChart {
28352
28361
  };
28353
28362
  }
28354
28363
  getDefinitionForExcel() {
28355
- if (this.aggregated) {
28356
- return undefined;
28357
- }
28358
28364
  const dataSets = this.dataSets
28359
28365
  .map((ds) => toExcelDataset(this.getters, ds))
28360
28366
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -28499,10 +28505,6 @@ class ScatterChart extends AbstractChart {
28499
28505
  return new ScatterChart(definition, this.sheetId, this.getters);
28500
28506
  }
28501
28507
  getDefinitionForExcel() {
28502
- // Excel does not support aggregating labels
28503
- if (this.aggregated) {
28504
- return undefined;
28505
- }
28506
28508
  const dataSets = this.dataSets
28507
28509
  .map((ds) => toExcelDataset(this.getters, ds))
28508
28510
  .filter((ds) => ds.range !== "");
@@ -43756,6 +43758,9 @@ class Composer extends Component {
43756
43758
  this.contentHelper.removeSelection();
43757
43759
  }
43758
43760
  onMouseup() {
43761
+ if (this.env.model.getters.isReadonly()) {
43762
+ return;
43763
+ }
43759
43764
  const selection = this.contentHelper.getCurrentSelection();
43760
43765
  if (selection.start !== selection.end) {
43761
43766
  this.props.composerStore.hoverToken(undefined);
@@ -54691,8 +54696,13 @@ class RowResizer extends AbstractResizer {
54691
54696
  elements,
54692
54697
  position: this.state.position,
54693
54698
  });
54694
- if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
54695
- this.env.raiseError(MergeErrorMessage);
54699
+ if (!result.isSuccessful) {
54700
+ if (result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
54701
+ this.env.raiseError(MergeErrorMessage);
54702
+ }
54703
+ else if (result.reasons.includes("CannotMoveTableHeader" /* CommandResult.CannotMoveTableHeader */)) {
54704
+ this.env.raiseError(TableHeaderMoveErrorMessage);
54705
+ }
54696
54706
  }
54697
54707
  }
54698
54708
  _selectElement(index, addDistinctHeader) {
@@ -66666,7 +66676,7 @@ function withPivotPresentationLayer (PivotClass) {
66666
66676
  return PivotPresentationLayer;
66667
66677
  }
66668
66678
 
66669
- const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT"];
66679
+ const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT", "REMOVE_PIVOT"];
66670
66680
  function isPivotCommand(cmd) {
66671
66681
  return UNDO_REDO_PIVOT_COMMANDS.includes(cmd.type);
66672
66682
  }
@@ -72098,8 +72108,33 @@ class GridSelectionPlugin extends UIPlugin {
72098
72108
  if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
72099
72109
  return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
72100
72110
  }
72111
+ if (!isCol && !this.isTableRowMoveAllowed(id, cmd.elements)) {
72112
+ return "CannotMoveTableHeader" /* CommandResult.CannotMoveTableHeader */;
72113
+ }
72101
72114
  return "Success" /* CommandResult.Success */;
72102
72115
  }
72116
+ isTableRowMoveAllowed(sheetId, selectedRows) {
72117
+ const tables = this.getters.getCoreTables(sheetId);
72118
+ if (tables.length === 0) {
72119
+ return true;
72120
+ }
72121
+ const selectedRowSet = new Set(selectedRows);
72122
+ return tables.every(({ range: { zone }, config }) => {
72123
+ const { top, bottom } = zone;
72124
+ if (config.numberOfHeaders === 0) {
72125
+ return true;
72126
+ }
72127
+ const headerRowEnd = top + config.numberOfHeaders - 1;
72128
+ // Moving the table is allowed if table header rows are not part of the selection
72129
+ // Or if the entire table (including header) is selected
72130
+ const isHeaderSelected = selectedRows.some((row) => row >= top && row <= headerRowEnd);
72131
+ if (!isHeaderSelected) {
72132
+ return true;
72133
+ }
72134
+ const isWholeTableSelected = range(top, bottom + 1).every((r) => selectedRowSet.has(r));
72135
+ return isWholeTableSelected;
72136
+ });
72137
+ }
72103
72138
  fallbackToVisibleSheet() {
72104
72139
  if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
72105
72140
  const currentSheetIds = this.getters.getVisibleSheetIds();
@@ -80872,6 +80907,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
80872
80907
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateChartEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
80873
80908
 
80874
80909
 
80875
- __info__.version = "18.3.16";
80876
- __info__.date = "2025-08-18T08:15:07.809Z";
80877
- __info__.hash = "68ef497";
80910
+ __info__.version = "18.3.18";
80911
+ __info__.date = "2025-08-26T10:14:21.408Z";
80912
+ __info__.hash = "ec2777d";
@@ -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 18.3.16
6
- * @date 2025-08-18T08:15:07.809Z
7
- * @hash 68ef497
5
+ * @version 18.3.18
6
+ * @date 2025-08-26T10:14:21.408Z
7
+ * @hash ec2777d
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -3633,6 +3633,7 @@
3633
3633
  CommandResult["Success"] = "Success";
3634
3634
  CommandResult["CancelledForUnknownReason"] = "CancelledForUnknownReason";
3635
3635
  CommandResult["WillRemoveExistingMerge"] = "WillRemoveExistingMerge";
3636
+ CommandResult["CannotMoveTableHeader"] = "CannotMoveTableHeader";
3636
3637
  CommandResult["MergeIsDestructive"] = "MergeIsDestructive";
3637
3638
  CommandResult["CellIsMerged"] = "CellIsMerged";
3638
3639
  CommandResult["InvalidTarget"] = "InvalidTarget";
@@ -7103,29 +7104,40 @@
7103
7104
  const width = content[0].length, height = content.length;
7104
7105
  return target.map((t) => splitZoneForPaste(t, width, height)).flat();
7105
7106
  }
7106
- function parseOSClipboardContent(content, clipboardId) {
7107
+ function parseOSClipboardContent(content) {
7107
7108
  let spreadsheetContent = undefined;
7108
7109
  if (content[ClipboardMIMEType.Html]) {
7109
7110
  const htmlDocument = new DOMParser().parseFromString(content[ClipboardMIMEType.Html], "text/html");
7110
- const oSheetClipboardData = htmlDocument
7111
- .querySelector("div")
7112
- ?.getAttribute("data-osheet-clipboard");
7113
- spreadsheetContent = oSheetClipboardData && JSON.parse(oSheetClipboardData);
7111
+ spreadsheetContent = getOSheetDataFromHTML(htmlDocument);
7114
7112
  }
7113
+ const textContent = content[ClipboardMIMEType.PlainText] || "";
7115
7114
  let imageBlob = undefined;
7116
- for (const type of AllowedImageMimeTypes) {
7117
- if (content[type]) {
7118
- imageBlob = content[type];
7119
- break;
7115
+ if (!textContent.trim()) {
7116
+ for (const type of AllowedImageMimeTypes) {
7117
+ if (content[type]) {
7118
+ imageBlob = content[type];
7119
+ break;
7120
+ }
7120
7121
  }
7121
7122
  }
7122
7123
  const osClipboardContent = {
7123
- text: content[ClipboardMIMEType.PlainText],
7124
+ text: textContent,
7124
7125
  data: spreadsheetContent,
7125
7126
  imageBlob,
7126
7127
  };
7127
7128
  return osClipboardContent;
7128
7129
  }
7130
+ function getOSheetDataFromHTML(htmlDocument) {
7131
+ const attributes = [...htmlDocument.documentElement.attributes];
7132
+ // Check if it's a Microsoft Office clipboard data (it will have some namespaces defined in the root element)
7133
+ if (attributes.some((attr) => attr.value.includes("microsoft"))) {
7134
+ return undefined;
7135
+ }
7136
+ const oSheetClipboardData = htmlDocument
7137
+ .querySelector("div")
7138
+ ?.getAttribute("data-osheet-clipboard");
7139
+ return oSheetClipboardData && JSON.parse(oSheetClipboardData);
7140
+ }
7129
7141
  /**
7130
7142
  * Applies each clipboard handler to paste its corresponding data into the target.
7131
7143
  */
@@ -24951,6 +24963,7 @@ stores.inject(MyMetaStore, storeInstance);
24951
24963
  Custom: _t("Custom"),
24952
24964
  };
24953
24965
  const MergeErrorMessage = _t("Merged cells are preventing this operation. Unmerge those cells and try again.");
24966
+ const TableHeaderMoveErrorMessage = _t("The header row of a table can't be moved.");
24954
24967
  const SplitToColumnsTerms = {
24955
24968
  Errors: {
24956
24969
  Unexpected: _t("Cannot split the selection for an unknown reason"),
@@ -27196,10 +27209,6 @@ stores.inject(MyMetaStore, storeInstance);
27196
27209
  };
27197
27210
  }
27198
27211
  getDefinitionForExcel() {
27199
- // Excel does not support aggregating labels
27200
- if (this.aggregated) {
27201
- return undefined;
27202
- }
27203
27212
  const dataSets = this.dataSets
27204
27213
  .map((ds) => toExcelDataset(this.getters, ds))
27205
27214
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -28353,9 +28362,6 @@ stores.inject(MyMetaStore, storeInstance);
28353
28362
  };
28354
28363
  }
28355
28364
  getDefinitionForExcel() {
28356
- if (this.aggregated) {
28357
- return undefined;
28358
- }
28359
28365
  const dataSets = this.dataSets
28360
28366
  .map((ds) => toExcelDataset(this.getters, ds))
28361
28367
  .filter((ds) => ds.range !== "" && ds.range !== CellErrorType.InvalidReference);
@@ -28500,10 +28506,6 @@ stores.inject(MyMetaStore, storeInstance);
28500
28506
  return new ScatterChart(definition, this.sheetId, this.getters);
28501
28507
  }
28502
28508
  getDefinitionForExcel() {
28503
- // Excel does not support aggregating labels
28504
- if (this.aggregated) {
28505
- return undefined;
28506
- }
28507
28509
  const dataSets = this.dataSets
28508
28510
  .map((ds) => toExcelDataset(this.getters, ds))
28509
28511
  .filter((ds) => ds.range !== "");
@@ -43757,6 +43759,9 @@ stores.inject(MyMetaStore, storeInstance);
43757
43759
  this.contentHelper.removeSelection();
43758
43760
  }
43759
43761
  onMouseup() {
43762
+ if (this.env.model.getters.isReadonly()) {
43763
+ return;
43764
+ }
43760
43765
  const selection = this.contentHelper.getCurrentSelection();
43761
43766
  if (selection.start !== selection.end) {
43762
43767
  this.props.composerStore.hoverToken(undefined);
@@ -54692,8 +54697,13 @@ stores.inject(MyMetaStore, storeInstance);
54692
54697
  elements,
54693
54698
  position: this.state.position,
54694
54699
  });
54695
- if (!result.isSuccessful && result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
54696
- this.env.raiseError(MergeErrorMessage);
54700
+ if (!result.isSuccessful) {
54701
+ if (result.reasons.includes("WillRemoveExistingMerge" /* CommandResult.WillRemoveExistingMerge */)) {
54702
+ this.env.raiseError(MergeErrorMessage);
54703
+ }
54704
+ else if (result.reasons.includes("CannotMoveTableHeader" /* CommandResult.CannotMoveTableHeader */)) {
54705
+ this.env.raiseError(TableHeaderMoveErrorMessage);
54706
+ }
54697
54707
  }
54698
54708
  }
54699
54709
  _selectElement(index, addDistinctHeader) {
@@ -66667,7 +66677,7 @@ stores.inject(MyMetaStore, storeInstance);
66667
66677
  return PivotPresentationLayer;
66668
66678
  }
66669
66679
 
66670
- const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT"];
66680
+ const UNDO_REDO_PIVOT_COMMANDS = ["ADD_PIVOT", "UPDATE_PIVOT", "REMOVE_PIVOT"];
66671
66681
  function isPivotCommand(cmd) {
66672
66682
  return UNDO_REDO_PIVOT_COMMANDS.includes(cmd.type);
66673
66683
  }
@@ -72099,8 +72109,33 @@ stores.inject(MyMetaStore, storeInstance);
72099
72109
  if (headers.some((h) => h < 0 || h >= maxHeaderValue)) {
72100
72110
  return "InvalidHeaderIndex" /* CommandResult.InvalidHeaderIndex */;
72101
72111
  }
72112
+ if (!isCol && !this.isTableRowMoveAllowed(id, cmd.elements)) {
72113
+ return "CannotMoveTableHeader" /* CommandResult.CannotMoveTableHeader */;
72114
+ }
72102
72115
  return "Success" /* CommandResult.Success */;
72103
72116
  }
72117
+ isTableRowMoveAllowed(sheetId, selectedRows) {
72118
+ const tables = this.getters.getCoreTables(sheetId);
72119
+ if (tables.length === 0) {
72120
+ return true;
72121
+ }
72122
+ const selectedRowSet = new Set(selectedRows);
72123
+ return tables.every(({ range: { zone }, config }) => {
72124
+ const { top, bottom } = zone;
72125
+ if (config.numberOfHeaders === 0) {
72126
+ return true;
72127
+ }
72128
+ const headerRowEnd = top + config.numberOfHeaders - 1;
72129
+ // Moving the table is allowed if table header rows are not part of the selection
72130
+ // Or if the entire table (including header) is selected
72131
+ const isHeaderSelected = selectedRows.some((row) => row >= top && row <= headerRowEnd);
72132
+ if (!isHeaderSelected) {
72133
+ return true;
72134
+ }
72135
+ const isWholeTableSelected = range(top, bottom + 1).every((r) => selectedRowSet.has(r));
72136
+ return isWholeTableSelected;
72137
+ });
72138
+ }
72104
72139
  fallbackToVisibleSheet() {
72105
72140
  if (!this.getters.tryGetSheet(this.getters.getActiveSheetId())) {
72106
72141
  const currentSheetIds = this.getters.getVisibleSheetIds();
@@ -80919,9 +80954,9 @@ stores.inject(MyMetaStore, storeInstance);
80919
80954
  exports.tokenize = tokenize;
80920
80955
 
80921
80956
 
80922
- __info__.version = "18.3.16";
80923
- __info__.date = "2025-08-18T08:15:07.809Z";
80924
- __info__.hash = "68ef497";
80957
+ __info__.version = "18.3.18";
80958
+ __info__.date = "2025-08-26T10:14:21.408Z";
80959
+ __info__.hash = "ec2777d";
80925
80960
 
80926
80961
 
80927
80962
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);