@odoo/o-spreadsheet 17.0.18 → 17.0.20

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.0.18
6
- * @date 2024-04-10T13:28:23.664Z
7
- * @hash 6294758
5
+ * @version 17.0.20
6
+ * @date 2024-04-26T07:37:04.503Z
7
+ * @hash 065ac98
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -8119,6 +8119,7 @@
8119
8119
  this.save();
8120
8120
  }
8121
8121
  ev.stopPropagation();
8122
+ ev.preventDefault();
8122
8123
  break;
8123
8124
  case "Escape":
8124
8125
  this.cancel();
@@ -19901,6 +19902,332 @@
19901
19902
  }
19902
19903
  }
19903
19904
 
19905
+ function interactiveFreezeColumnsRows(env, dimension, base) {
19906
+ const sheetId = env.model.getters.getActiveSheetId();
19907
+ const cmd = dimension === "COL" ? "FREEZE_COLUMNS" : "FREEZE_ROWS";
19908
+ const result = env.model.dispatch(cmd, { sheetId, quantity: base });
19909
+ if (result.isCancelledBecause("MergeOverlap" /* CommandResult.MergeOverlap */)) {
19910
+ env.raiseError(MergeErrorMessage);
19911
+ }
19912
+ }
19913
+
19914
+ const hideCols = {
19915
+ name: HIDE_COLUMNS_NAME,
19916
+ execute: (env) => {
19917
+ const columns = env.model.getters.getElementsFromSelection("COL");
19918
+ env.model.dispatch("HIDE_COLUMNS_ROWS", {
19919
+ sheetId: env.model.getters.getActiveSheetId(),
19920
+ dimension: "COL",
19921
+ elements: columns,
19922
+ });
19923
+ },
19924
+ isVisible: NOT_ALL_VISIBLE_COLS_SELECTED,
19925
+ icon: "o-spreadsheet-Icon.HIDE_COL",
19926
+ };
19927
+ const unhideCols = {
19928
+ name: _t("Unhide columns"),
19929
+ execute: (env) => {
19930
+ const columns = env.model.getters.getElementsFromSelection("COL");
19931
+ env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
19932
+ sheetId: env.model.getters.getActiveSheetId(),
19933
+ dimension: "COL",
19934
+ elements: columns,
19935
+ });
19936
+ },
19937
+ isVisible: (env) => {
19938
+ const hiddenCols = env.model.getters
19939
+ .getHiddenColsGroups(env.model.getters.getActiveSheetId())
19940
+ .flat();
19941
+ const currentCols = env.model.getters.getElementsFromSelection("COL");
19942
+ return currentCols.some((col) => hiddenCols.includes(col));
19943
+ },
19944
+ };
19945
+ const unhideAllCols = {
19946
+ name: _t("Unhide all columns"),
19947
+ execute: (env) => {
19948
+ const sheetId = env.model.getters.getActiveSheetId();
19949
+ env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
19950
+ sheetId,
19951
+ dimension: "COL",
19952
+ elements: Array.from(Array(env.model.getters.getNumberCols(sheetId)).keys()),
19953
+ });
19954
+ },
19955
+ isVisible: (env) => env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId()).length > 0,
19956
+ };
19957
+ const hideRows = {
19958
+ name: HIDE_ROWS_NAME,
19959
+ execute: (env) => {
19960
+ const rows = env.model.getters.getElementsFromSelection("ROW");
19961
+ env.model.dispatch("HIDE_COLUMNS_ROWS", {
19962
+ sheetId: env.model.getters.getActiveSheetId(),
19963
+ dimension: "ROW",
19964
+ elements: rows,
19965
+ });
19966
+ },
19967
+ isVisible: NOT_ALL_VISIBLE_ROWS_SELECTED,
19968
+ icon: "o-spreadsheet-Icon.HIDE_ROW",
19969
+ };
19970
+ const unhideRows = {
19971
+ name: _t("Unhide rows"),
19972
+ execute: (env) => {
19973
+ const columns = env.model.getters.getElementsFromSelection("ROW");
19974
+ env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
19975
+ sheetId: env.model.getters.getActiveSheetId(),
19976
+ dimension: "ROW",
19977
+ elements: columns,
19978
+ });
19979
+ },
19980
+ isVisible: (env) => {
19981
+ const hiddenRows = env.model.getters
19982
+ .getHiddenRowsGroups(env.model.getters.getActiveSheetId())
19983
+ .flat();
19984
+ const currentRows = env.model.getters.getElementsFromSelection("ROW");
19985
+ return currentRows.some((col) => hiddenRows.includes(col));
19986
+ },
19987
+ };
19988
+ const unhideAllRows = {
19989
+ name: _t("Unhide all rows"),
19990
+ execute: (env) => {
19991
+ const sheetId = env.model.getters.getActiveSheetId();
19992
+ env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
19993
+ sheetId,
19994
+ dimension: "ROW",
19995
+ elements: Array.from(Array(env.model.getters.getNumberRows(sheetId)).keys()),
19996
+ });
19997
+ },
19998
+ isVisible: (env) => env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId()).length > 0,
19999
+ };
20000
+ const unFreezePane = {
20001
+ name: _t("Unfreeze"),
20002
+ isVisible: (env) => {
20003
+ const { xSplit, ySplit } = env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId());
20004
+ return xSplit + ySplit > 0;
20005
+ },
20006
+ execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS_ROWS", {
20007
+ sheetId: env.model.getters.getActiveSheetId(),
20008
+ }),
20009
+ icon: "o-spreadsheet-Icon.UNFREEZE",
20010
+ };
20011
+ const freezePane = {
20012
+ name: _t("Freeze"),
20013
+ icon: "o-spreadsheet-Icon.FREEZE",
20014
+ };
20015
+ const unFreezeRows = {
20016
+ name: _t("No rows"),
20017
+ execute: (env) => env.model.dispatch("UNFREEZE_ROWS", {
20018
+ sheetId: env.model.getters.getActiveSheetId(),
20019
+ }),
20020
+ isReadonlyAllowed: true,
20021
+ isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).ySplit,
20022
+ };
20023
+ const freezeFirstRow = {
20024
+ name: _t("1 row"),
20025
+ execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 1),
20026
+ isReadonlyAllowed: true,
20027
+ };
20028
+ const freezeSecondRow = {
20029
+ name: _t("2 rows"),
20030
+ execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 2),
20031
+ isReadonlyAllowed: true,
20032
+ };
20033
+ const freezeCurrentRow = {
20034
+ name: _t("Up to current row"),
20035
+ execute: (env) => {
20036
+ const { bottom } = env.model.getters.getSelectedZone();
20037
+ interactiveFreezeColumnsRows(env, "ROW", bottom + 1);
20038
+ },
20039
+ isReadonlyAllowed: true,
20040
+ };
20041
+ const unFreezeCols = {
20042
+ name: _t("No columns"),
20043
+ execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS", {
20044
+ sheetId: env.model.getters.getActiveSheetId(),
20045
+ }),
20046
+ isReadonlyAllowed: true,
20047
+ isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).xSplit,
20048
+ };
20049
+ const freezeFirstCol = {
20050
+ name: _t("1 column"),
20051
+ execute: (env) => interactiveFreezeColumnsRows(env, "COL", 1),
20052
+ isReadonlyAllowed: true,
20053
+ };
20054
+ const freezeSecondCol = {
20055
+ name: _t("2 columns"),
20056
+ execute: (env) => interactiveFreezeColumnsRows(env, "COL", 2),
20057
+ isReadonlyAllowed: true,
20058
+ };
20059
+ const freezeCurrentCol = {
20060
+ name: _t("Up to current column"),
20061
+ execute: (env) => {
20062
+ const { right } = env.model.getters.getSelectedZone();
20063
+ interactiveFreezeColumnsRows(env, "COL", right + 1);
20064
+ },
20065
+ isReadonlyAllowed: true,
20066
+ };
20067
+ const viewGridlines = {
20068
+ name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
20069
+ ? _t("Hide gridlines")
20070
+ : _t("Show gridlines"),
20071
+ execute: (env) => {
20072
+ const sheetId = env.model.getters.getActiveSheetId();
20073
+ env.model.dispatch("SET_GRID_LINES_VISIBILITY", {
20074
+ sheetId,
20075
+ areGridLinesVisible: !env.model.getters.getGridLinesVisibility(sheetId),
20076
+ });
20077
+ },
20078
+ icon: "o-spreadsheet-Icon.SHOW_HIDE_GRID",
20079
+ };
20080
+ const viewFormulas = {
20081
+ name: (env) => env.model.getters.shouldShowFormulas() ? "Hide formulas" : _t("Show formulas"),
20082
+ execute: (env) => env.model.dispatch("SET_FORMULA_VISIBILITY", { show: !env.model.getters.shouldShowFormulas() }),
20083
+ isReadonlyAllowed: true,
20084
+ icon: "o-spreadsheet-Icon.SHOW_HIDE_FORMULA",
20085
+ };
20086
+ const createRemoveFilter = {
20087
+ name: (env) => selectionContainsFilter(env) ? _t("Remove selected filters") : _t("Create filter"),
20088
+ isActive: (env) => selectionContainsFilter(env),
20089
+ isEnabled: (env) => !cannotCreateFilter(env),
20090
+ execute: (env) => createRemoveFilterAction(env),
20091
+ icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
20092
+ };
20093
+ const groupColumns = {
20094
+ name: (env) => {
20095
+ const selection = env.model.getters.getSelectedZone();
20096
+ if (selection.left === selection.right) {
20097
+ return _t("Group column %s", numberToLetters(selection.left));
20098
+ }
20099
+ return _t("Group columns %s - %s", numberToLetters(selection.left), numberToLetters(selection.right));
20100
+ },
20101
+ execute: (env) => groupHeadersAction(env, "COL"),
20102
+ isVisible: (env) => {
20103
+ const sheetId = env.model.getters.getActiveSheetId();
20104
+ const selection = env.model.getters.getSelectedZone();
20105
+ const groups = env.model.getters.getHeaderGroupsInZone(sheetId, "COL", selection);
20106
+ return (IS_ONLY_ONE_RANGE(env) &&
20107
+ !groups.some((group) => group.start === selection.left && group.end === selection.right));
20108
+ },
20109
+ icon: "o-spreadsheet-Icon.GROUP_COLUMNS",
20110
+ };
20111
+ const groupRows = {
20112
+ name: (env) => {
20113
+ const selection = env.model.getters.getSelectedZone();
20114
+ if (selection.top === selection.bottom) {
20115
+ return _t("Group row %s", String(selection.top + 1));
20116
+ }
20117
+ return _t("Group rows %s - %s", String(selection.top + 1), String(selection.bottom + 1));
20118
+ },
20119
+ execute: (env) => groupHeadersAction(env, "ROW"),
20120
+ isVisible: (env) => {
20121
+ const sheetId = env.model.getters.getActiveSheetId();
20122
+ const selection = env.model.getters.getSelectedZone();
20123
+ const groups = env.model.getters.getHeaderGroupsInZone(sheetId, "ROW", selection);
20124
+ return (IS_ONLY_ONE_RANGE(env) &&
20125
+ !groups.some((group) => group.start === selection.top && group.end === selection.bottom));
20126
+ },
20127
+ icon: "o-spreadsheet-Icon.GROUP_ROWS",
20128
+ };
20129
+ const ungroupColumns = {
20130
+ name: (env) => {
20131
+ const selection = env.model.getters.getSelectedZone();
20132
+ if (selection.left === selection.right) {
20133
+ return _t("Ungroup column %s", numberToLetters(selection.left));
20134
+ }
20135
+ return _t("Ungroup columns %s - %s", numberToLetters(selection.left), numberToLetters(selection.right));
20136
+ },
20137
+ execute: (env) => ungroupHeaders(env, "COL"),
20138
+ icon: "o-spreadsheet-Icon.UNGROUP_COLUMNS",
20139
+ };
20140
+ const ungroupRows = {
20141
+ name: (env) => {
20142
+ const selection = env.model.getters.getSelectedZone();
20143
+ if (selection.top === selection.bottom) {
20144
+ return _t("Ungroup row %s", String(selection.top + 1));
20145
+ }
20146
+ return _t("Ungroup rows %s - %s", String(selection.top + 1), String(selection.bottom + 1));
20147
+ },
20148
+ execute: (env) => ungroupHeaders(env, "ROW"),
20149
+ icon: "o-spreadsheet-Icon.UNGROUP_ROWS",
20150
+ };
20151
+ function selectionContainsFilter(env) {
20152
+ const sheetId = env.model.getters.getActiveSheetId();
20153
+ const selectedZones = env.model.getters.getSelectedZones();
20154
+ return env.model.getters.doesZonesContainFilter(sheetId, selectedZones);
20155
+ }
20156
+ function cannotCreateFilter(env) {
20157
+ return !areZonesContinuous(...env.model.getters.getSelectedZones());
20158
+ }
20159
+ function createRemoveFilterAction(env) {
20160
+ if (selectionContainsFilter(env)) {
20161
+ env.model.dispatch("REMOVE_FILTER_TABLE", {
20162
+ sheetId: env.model.getters.getActiveSheetId(),
20163
+ target: env.model.getters.getSelectedZones(),
20164
+ });
20165
+ return;
20166
+ }
20167
+ if (cannotCreateFilter(env)) {
20168
+ return;
20169
+ }
20170
+ env.model.selection.selectTableAroundSelection();
20171
+ const sheetId = env.model.getters.getActiveSheetId();
20172
+ const selection = env.model.getters.getSelectedZones();
20173
+ interactiveAddFilter(env, sheetId, selection);
20174
+ }
20175
+ function groupHeadersAction(env, dim) {
20176
+ const selection = env.model.getters.getSelectedZone();
20177
+ const sheetId = env.model.getters.getActiveSheetId();
20178
+ env.model.dispatch("GROUP_HEADERS", {
20179
+ sheetId,
20180
+ dimension: dim,
20181
+ start: dim === "COL" ? selection.left : selection.top,
20182
+ end: dim === "COL" ? selection.right : selection.bottom,
20183
+ });
20184
+ }
20185
+ function ungroupHeaders(env, dim) {
20186
+ const selection = env.model.getters.getSelectedZone();
20187
+ const sheetId = env.model.getters.getActiveSheetId();
20188
+ env.model.dispatch("UNGROUP_HEADERS", {
20189
+ sheetId,
20190
+ dimension: dim,
20191
+ start: dim === "COL" ? selection.left : selection.top,
20192
+ end: dim === "COL" ? selection.right : selection.bottom,
20193
+ });
20194
+ }
20195
+ function canUngroupHeaders(env, dimension) {
20196
+ const sheetId = env.model.getters.getActiveSheetId();
20197
+ const selection = env.model.getters.getSelectedZones();
20198
+ return (selection.length === 1 &&
20199
+ env.model.getters.getHeaderGroupsInZone(sheetId, dimension, selection[0]).length > 0);
20200
+ }
20201
+
20202
+ var ACTION_VIEW = /*#__PURE__*/Object.freeze({
20203
+ __proto__: null,
20204
+ canUngroupHeaders: canUngroupHeaders,
20205
+ createRemoveFilter: createRemoveFilter,
20206
+ createRemoveFilterAction: createRemoveFilterAction,
20207
+ freezeCurrentCol: freezeCurrentCol,
20208
+ freezeCurrentRow: freezeCurrentRow,
20209
+ freezeFirstCol: freezeFirstCol,
20210
+ freezeFirstRow: freezeFirstRow,
20211
+ freezePane: freezePane,
20212
+ freezeSecondCol: freezeSecondCol,
20213
+ freezeSecondRow: freezeSecondRow,
20214
+ groupColumns: groupColumns,
20215
+ groupRows: groupRows,
20216
+ hideCols: hideCols,
20217
+ hideRows: hideRows,
20218
+ unFreezeCols: unFreezeCols,
20219
+ unFreezePane: unFreezePane,
20220
+ unFreezeRows: unFreezeRows,
20221
+ ungroupColumns: ungroupColumns,
20222
+ ungroupRows: ungroupRows,
20223
+ unhideAllCols: unhideAllCols,
20224
+ unhideAllRows: unhideAllRows,
20225
+ unhideCols: unhideCols,
20226
+ unhideRows: unhideRows,
20227
+ viewFormulas: viewFormulas,
20228
+ viewGridlines: viewGridlines
20229
+ });
20230
+
19904
20231
  const sortRange = {
19905
20232
  name: _t("Sort range"),
19906
20233
  isVisible: IS_ONLY_ONE_RANGE,
@@ -19943,32 +20270,15 @@
19943
20270
  },
19944
20271
  icon: "o-spreadsheet-Icon.SORT_DESCENDING",
19945
20272
  };
19946
- const addDataFilter = {
19947
- name: _t("Create filter"),
19948
- execute: (env) => {
19949
- const sheetId = env.model.getters.getActiveSheetId();
19950
- const selection = env.model.getters.getSelection().zones;
19951
- interactiveAddFilter(env, sheetId, selection);
19952
- },
19953
- isVisible: (env) => !SELECTION_CONTAINS_FILTER(env),
20273
+ const addRemoveDataFilter = {
20274
+ name: (env) => SELECTION_CONTAINS_FILTER(env) ? _t("Remove filter") : _t("Create filter"),
20275
+ execute: (env) => createRemoveFilterAction(env),
19954
20276
  isEnabled: (env) => {
19955
20277
  const selectedZones = env.model.getters.getSelectedZones();
19956
20278
  return areZonesContinuous(...selectedZones);
19957
20279
  },
19958
20280
  icon: "o-spreadsheet-Icon.MENU_FILTER_ICON",
19959
20281
  };
19960
- const removeDataFilter = {
19961
- name: _t("Remove filter"),
19962
- execute: (env) => {
19963
- const sheetId = env.model.getters.getActiveSheetId();
19964
- env.model.dispatch("REMOVE_FILTER_TABLE", {
19965
- sheetId,
19966
- target: env.model.getters.getSelectedZones(),
19967
- });
19968
- },
19969
- isVisible: SELECTION_CONTAINS_FILTER,
19970
- icon: "o-spreadsheet-Icon.MENU_FILTER_ICON",
19971
- };
19972
20282
  const splitToColumns = {
19973
20283
  name: _t("Split text to columns"),
19974
20284
  sequence: 1,
@@ -20374,331 +20684,6 @@
20374
20684
  textColor: textColor
20375
20685
  });
20376
20686
 
20377
- function interactiveFreezeColumnsRows(env, dimension, base) {
20378
- const sheetId = env.model.getters.getActiveSheetId();
20379
- const cmd = dimension === "COL" ? "FREEZE_COLUMNS" : "FREEZE_ROWS";
20380
- const result = env.model.dispatch(cmd, { sheetId, quantity: base });
20381
- if (result.isCancelledBecause("MergeOverlap" /* CommandResult.MergeOverlap */)) {
20382
- env.raiseError(MergeErrorMessage);
20383
- }
20384
- }
20385
-
20386
- const hideCols = {
20387
- name: HIDE_COLUMNS_NAME,
20388
- execute: (env) => {
20389
- const columns = env.model.getters.getElementsFromSelection("COL");
20390
- env.model.dispatch("HIDE_COLUMNS_ROWS", {
20391
- sheetId: env.model.getters.getActiveSheetId(),
20392
- dimension: "COL",
20393
- elements: columns,
20394
- });
20395
- },
20396
- isVisible: NOT_ALL_VISIBLE_COLS_SELECTED,
20397
- icon: "o-spreadsheet-Icon.HIDE_COL",
20398
- };
20399
- const unhideCols = {
20400
- name: _t("Unhide columns"),
20401
- execute: (env) => {
20402
- const columns = env.model.getters.getElementsFromSelection("COL");
20403
- env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
20404
- sheetId: env.model.getters.getActiveSheetId(),
20405
- dimension: "COL",
20406
- elements: columns,
20407
- });
20408
- },
20409
- isVisible: (env) => {
20410
- const hiddenCols = env.model.getters
20411
- .getHiddenColsGroups(env.model.getters.getActiveSheetId())
20412
- .flat();
20413
- const currentCols = env.model.getters.getElementsFromSelection("COL");
20414
- return currentCols.some((col) => hiddenCols.includes(col));
20415
- },
20416
- };
20417
- const unhideAllCols = {
20418
- name: _t("Unhide all columns"),
20419
- execute: (env) => {
20420
- const sheetId = env.model.getters.getActiveSheetId();
20421
- env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
20422
- sheetId,
20423
- dimension: "COL",
20424
- elements: Array.from(Array(env.model.getters.getNumberCols(sheetId)).keys()),
20425
- });
20426
- },
20427
- isVisible: (env) => env.model.getters.getHiddenColsGroups(env.model.getters.getActiveSheetId()).length > 0,
20428
- };
20429
- const hideRows = {
20430
- name: HIDE_ROWS_NAME,
20431
- execute: (env) => {
20432
- const rows = env.model.getters.getElementsFromSelection("ROW");
20433
- env.model.dispatch("HIDE_COLUMNS_ROWS", {
20434
- sheetId: env.model.getters.getActiveSheetId(),
20435
- dimension: "ROW",
20436
- elements: rows,
20437
- });
20438
- },
20439
- isVisible: NOT_ALL_VISIBLE_ROWS_SELECTED,
20440
- icon: "o-spreadsheet-Icon.HIDE_ROW",
20441
- };
20442
- const unhideRows = {
20443
- name: _t("Unhide rows"),
20444
- execute: (env) => {
20445
- const columns = env.model.getters.getElementsFromSelection("ROW");
20446
- env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
20447
- sheetId: env.model.getters.getActiveSheetId(),
20448
- dimension: "ROW",
20449
- elements: columns,
20450
- });
20451
- },
20452
- isVisible: (env) => {
20453
- const hiddenRows = env.model.getters
20454
- .getHiddenRowsGroups(env.model.getters.getActiveSheetId())
20455
- .flat();
20456
- const currentRows = env.model.getters.getElementsFromSelection("ROW");
20457
- return currentRows.some((col) => hiddenRows.includes(col));
20458
- },
20459
- };
20460
- const unhideAllRows = {
20461
- name: _t("Unhide all rows"),
20462
- execute: (env) => {
20463
- const sheetId = env.model.getters.getActiveSheetId();
20464
- env.model.dispatch("UNHIDE_COLUMNS_ROWS", {
20465
- sheetId,
20466
- dimension: "ROW",
20467
- elements: Array.from(Array(env.model.getters.getNumberRows(sheetId)).keys()),
20468
- });
20469
- },
20470
- isVisible: (env) => env.model.getters.getHiddenRowsGroups(env.model.getters.getActiveSheetId()).length > 0,
20471
- };
20472
- const unFreezePane = {
20473
- name: _t("Unfreeze"),
20474
- isVisible: (env) => {
20475
- const { xSplit, ySplit } = env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId());
20476
- return xSplit + ySplit > 0;
20477
- },
20478
- execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS_ROWS", {
20479
- sheetId: env.model.getters.getActiveSheetId(),
20480
- }),
20481
- icon: "o-spreadsheet-Icon.UNFREEZE",
20482
- };
20483
- const freezePane = {
20484
- name: _t("Freeze"),
20485
- icon: "o-spreadsheet-Icon.FREEZE",
20486
- };
20487
- const unFreezeRows = {
20488
- name: _t("No rows"),
20489
- execute: (env) => env.model.dispatch("UNFREEZE_ROWS", {
20490
- sheetId: env.model.getters.getActiveSheetId(),
20491
- }),
20492
- isReadonlyAllowed: true,
20493
- isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).ySplit,
20494
- };
20495
- const freezeFirstRow = {
20496
- name: _t("1 row"),
20497
- execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 1),
20498
- isReadonlyAllowed: true,
20499
- };
20500
- const freezeSecondRow = {
20501
- name: _t("2 rows"),
20502
- execute: (env) => interactiveFreezeColumnsRows(env, "ROW", 2),
20503
- isReadonlyAllowed: true,
20504
- };
20505
- const freezeCurrentRow = {
20506
- name: _t("Up to current row"),
20507
- execute: (env) => {
20508
- const { bottom } = env.model.getters.getSelectedZone();
20509
- interactiveFreezeColumnsRows(env, "ROW", bottom + 1);
20510
- },
20511
- isReadonlyAllowed: true,
20512
- };
20513
- const unFreezeCols = {
20514
- name: _t("No columns"),
20515
- execute: (env) => env.model.dispatch("UNFREEZE_COLUMNS", {
20516
- sheetId: env.model.getters.getActiveSheetId(),
20517
- }),
20518
- isReadonlyAllowed: true,
20519
- isVisible: (env) => !!env.model.getters.getPaneDivisions(env.model.getters.getActiveSheetId()).xSplit,
20520
- };
20521
- const freezeFirstCol = {
20522
- name: _t("1 column"),
20523
- execute: (env) => interactiveFreezeColumnsRows(env, "COL", 1),
20524
- isReadonlyAllowed: true,
20525
- };
20526
- const freezeSecondCol = {
20527
- name: _t("2 columns"),
20528
- execute: (env) => interactiveFreezeColumnsRows(env, "COL", 2),
20529
- isReadonlyAllowed: true,
20530
- };
20531
- const freezeCurrentCol = {
20532
- name: _t("Up to current column"),
20533
- execute: (env) => {
20534
- const { right } = env.model.getters.getSelectedZone();
20535
- interactiveFreezeColumnsRows(env, "COL", right + 1);
20536
- },
20537
- isReadonlyAllowed: true,
20538
- };
20539
- const viewGridlines = {
20540
- name: (env) => env.model.getters.getGridLinesVisibility(env.model.getters.getActiveSheetId())
20541
- ? _t("Hide gridlines")
20542
- : _t("Show gridlines"),
20543
- execute: (env) => {
20544
- const sheetId = env.model.getters.getActiveSheetId();
20545
- env.model.dispatch("SET_GRID_LINES_VISIBILITY", {
20546
- sheetId,
20547
- areGridLinesVisible: !env.model.getters.getGridLinesVisibility(sheetId),
20548
- });
20549
- },
20550
- icon: "o-spreadsheet-Icon.SHOW_HIDE_GRID",
20551
- };
20552
- const viewFormulas = {
20553
- name: (env) => env.model.getters.shouldShowFormulas() ? "Hide formulas" : _t("Show formulas"),
20554
- execute: (env) => env.model.dispatch("SET_FORMULA_VISIBILITY", { show: !env.model.getters.shouldShowFormulas() }),
20555
- isReadonlyAllowed: true,
20556
- icon: "o-spreadsheet-Icon.SHOW_HIDE_FORMULA",
20557
- };
20558
- const createRemoveFilter = {
20559
- name: (env) => selectionContainsFilter(env) ? _t("Remove selected filters") : _t("Create filter"),
20560
- isActive: (env) => selectionContainsFilter(env),
20561
- isEnabled: (env) => !cannotCreateFilter(env),
20562
- execute: (env) => createRemoveFilterAction(env),
20563
- icon: "o-spreadsheet-Icon.FILTER_ICON_INACTIVE",
20564
- };
20565
- const groupColumns = {
20566
- name: (env) => {
20567
- const selection = env.model.getters.getSelectedZone();
20568
- if (selection.left === selection.right) {
20569
- return _t("Group column %s", numberToLetters(selection.left));
20570
- }
20571
- return _t("Group columns %s - %s", numberToLetters(selection.left), numberToLetters(selection.right));
20572
- },
20573
- execute: (env) => groupHeadersAction(env, "COL"),
20574
- isVisible: (env) => {
20575
- const sheetId = env.model.getters.getActiveSheetId();
20576
- const selection = env.model.getters.getSelectedZone();
20577
- const groups = env.model.getters.getHeaderGroupsInZone(sheetId, "COL", selection);
20578
- return (IS_ONLY_ONE_RANGE(env) &&
20579
- !groups.some((group) => group.start === selection.left && group.end === selection.right));
20580
- },
20581
- icon: "o-spreadsheet-Icon.GROUP_COLUMNS",
20582
- };
20583
- const groupRows = {
20584
- name: (env) => {
20585
- const selection = env.model.getters.getSelectedZone();
20586
- if (selection.top === selection.bottom) {
20587
- return _t("Group row %s", String(selection.top + 1));
20588
- }
20589
- return _t("Group rows %s - %s", String(selection.top + 1), String(selection.bottom + 1));
20590
- },
20591
- execute: (env) => groupHeadersAction(env, "ROW"),
20592
- isVisible: (env) => {
20593
- const sheetId = env.model.getters.getActiveSheetId();
20594
- const selection = env.model.getters.getSelectedZone();
20595
- const groups = env.model.getters.getHeaderGroupsInZone(sheetId, "ROW", selection);
20596
- return (IS_ONLY_ONE_RANGE(env) &&
20597
- !groups.some((group) => group.start === selection.top && group.end === selection.bottom));
20598
- },
20599
- icon: "o-spreadsheet-Icon.GROUP_ROWS",
20600
- };
20601
- const ungroupColumns = {
20602
- name: (env) => {
20603
- const selection = env.model.getters.getSelectedZone();
20604
- if (selection.left === selection.right) {
20605
- return _t("Ungroup column %s", numberToLetters(selection.left));
20606
- }
20607
- return _t("Ungroup columns %s - %s", numberToLetters(selection.left), numberToLetters(selection.right));
20608
- },
20609
- execute: (env) => ungroupHeaders(env, "COL"),
20610
- icon: "o-spreadsheet-Icon.UNGROUP_COLUMNS",
20611
- };
20612
- const ungroupRows = {
20613
- name: (env) => {
20614
- const selection = env.model.getters.getSelectedZone();
20615
- if (selection.top === selection.bottom) {
20616
- return _t("Ungroup row %s", String(selection.top + 1));
20617
- }
20618
- return _t("Ungroup rows %s - %s", String(selection.top + 1), String(selection.bottom + 1));
20619
- },
20620
- execute: (env) => ungroupHeaders(env, "ROW"),
20621
- icon: "o-spreadsheet-Icon.UNGROUP_ROWS",
20622
- };
20623
- function selectionContainsFilter(env) {
20624
- const sheetId = env.model.getters.getActiveSheetId();
20625
- const selectedZones = env.model.getters.getSelectedZones();
20626
- return env.model.getters.doesZonesContainFilter(sheetId, selectedZones);
20627
- }
20628
- function cannotCreateFilter(env) {
20629
- return !areZonesContinuous(...env.model.getters.getSelectedZones());
20630
- }
20631
- function createRemoveFilterAction(env) {
20632
- if (selectionContainsFilter(env)) {
20633
- env.model.dispatch("REMOVE_FILTER_TABLE", {
20634
- sheetId: env.model.getters.getActiveSheetId(),
20635
- target: env.model.getters.getSelectedZones(),
20636
- });
20637
- return;
20638
- }
20639
- if (cannotCreateFilter(env)) {
20640
- return;
20641
- }
20642
- env.model.selection.selectTableAroundSelection();
20643
- const sheetId = env.model.getters.getActiveSheetId();
20644
- const selection = env.model.getters.getSelectedZones();
20645
- interactiveAddFilter(env, sheetId, selection);
20646
- }
20647
- function groupHeadersAction(env, dim) {
20648
- const selection = env.model.getters.getSelectedZone();
20649
- const sheetId = env.model.getters.getActiveSheetId();
20650
- env.model.dispatch("GROUP_HEADERS", {
20651
- sheetId,
20652
- dimension: dim,
20653
- start: dim === "COL" ? selection.left : selection.top,
20654
- end: dim === "COL" ? selection.right : selection.bottom,
20655
- });
20656
- }
20657
- function ungroupHeaders(env, dim) {
20658
- const selection = env.model.getters.getSelectedZone();
20659
- const sheetId = env.model.getters.getActiveSheetId();
20660
- env.model.dispatch("UNGROUP_HEADERS", {
20661
- sheetId,
20662
- dimension: dim,
20663
- start: dim === "COL" ? selection.left : selection.top,
20664
- end: dim === "COL" ? selection.right : selection.bottom,
20665
- });
20666
- }
20667
- function canUngroupHeaders(env, dimension) {
20668
- const sheetId = env.model.getters.getActiveSheetId();
20669
- const selection = env.model.getters.getSelectedZones();
20670
- return (selection.length === 1 &&
20671
- env.model.getters.getHeaderGroupsInZone(sheetId, dimension, selection[0]).length > 0);
20672
- }
20673
-
20674
- var ACTION_VIEW = /*#__PURE__*/Object.freeze({
20675
- __proto__: null,
20676
- canUngroupHeaders: canUngroupHeaders,
20677
- createRemoveFilter: createRemoveFilter,
20678
- freezeCurrentCol: freezeCurrentCol,
20679
- freezeCurrentRow: freezeCurrentRow,
20680
- freezeFirstCol: freezeFirstCol,
20681
- freezeFirstRow: freezeFirstRow,
20682
- freezePane: freezePane,
20683
- freezeSecondCol: freezeSecondCol,
20684
- freezeSecondRow: freezeSecondRow,
20685
- groupColumns: groupColumns,
20686
- groupRows: groupRows,
20687
- hideCols: hideCols,
20688
- hideRows: hideRows,
20689
- unFreezeCols: unFreezeCols,
20690
- unFreezePane: unFreezePane,
20691
- unFreezeRows: unFreezeRows,
20692
- ungroupColumns: ungroupColumns,
20693
- ungroupRows: ungroupRows,
20694
- unhideAllCols: unhideAllCols,
20695
- unhideAllRows: unhideAllRows,
20696
- unhideCols: unhideCols,
20697
- unhideRows: unhideRows,
20698
- viewFormulas: viewFormulas,
20699
- viewGridlines: viewGridlines
20700
- });
20701
-
20702
20687
  const colMenuRegistry = new MenuItemRegistry();
20703
20688
  colMenuRegistry
20704
20689
  .add("cut", {
@@ -21341,13 +21326,8 @@
21341
21326
  sequence: 30,
21342
21327
  separator: true,
21343
21328
  })
21344
- .addChild("add_data_filter", ["data"], {
21345
- ...addDataFilter,
21346
- sequence: 40,
21347
- separator: true,
21348
- })
21349
- .addChild("remove_data_filter", ["data"], {
21350
- ...removeDataFilter,
21329
+ .addChild("add_remove_data_filter", ["data"], {
21330
+ ...addRemoveDataFilter,
21351
21331
  sequence: 40,
21352
21332
  separator: true,
21353
21333
  });
@@ -26687,17 +26667,13 @@
26687
26667
  this.env.focusableElement.setFocusableElement(el);
26688
26668
  }
26689
26669
  this.contentHelper.updateEl(el);
26690
- this.processTokenAtCursor();
26691
26670
  });
26692
26671
  owl.useEffect(() => {
26693
26672
  this.processContent();
26694
26673
  });
26695
- owl.onPatched(() => {
26696
- // Required because typing '=SUM' and double-clicking another cell leaves ShowProvider/ShowDescription true
26697
- if (this.env.model.getters.getEditionMode() === "inactive") {
26698
- this.processTokenAtCursor();
26699
- }
26700
- });
26674
+ owl.useEffect(() => {
26675
+ this.processTokenAtCursor();
26676
+ }, () => [this.env.model.getters.getEditionMode() !== "inactive"]);
26701
26677
  }
26702
26678
  // ---------------------------------------------------------------------------
26703
26679
  // Handlers
@@ -27128,6 +27104,7 @@
27128
27104
  const dataValidationAutocompleteValues = this.env.model.getters.getAutoCompleteDataValidationValues();
27129
27105
  if (!content.startsWith("=") && dataValidationAutocompleteValues.length) {
27130
27106
  this.showDataValidationAutocomplete(dataValidationAutocompleteValues);
27107
+ return;
27131
27108
  }
27132
27109
  if (content.startsWith("=")) {
27133
27110
  const token = this.env.model.getters.getTokenAtCursor();
@@ -27850,6 +27827,10 @@
27850
27827
  height: 0px;
27851
27828
  }
27852
27829
  }
27830
+ .o-figure-container {
27831
+ -webkit-user-select: none; // safari
27832
+ user-select: none;
27833
+ }
27853
27834
  `;
27854
27835
  /**
27855
27836
  * Each figure ⭐ is positioned inside a container `div` placed and sized
@@ -34383,7 +34364,7 @@
34383
34364
  this.clearBorders(cmd.sheetId, cmd.target);
34384
34365
  break;
34385
34366
  case "REMOVE_COLUMNS_ROWS":
34386
- for (let el of cmd.elements) {
34367
+ for (let el of [...cmd.elements].sort((a, b) => b - a)) {
34387
34368
  if (cmd.dimension === "COL") {
34388
34369
  this.shiftBordersHorizontally(cmd.sheetId, el + 1, -1);
34389
34370
  }
@@ -40163,6 +40144,353 @@
40163
40144
  }
40164
40145
  }
40165
40146
 
40147
+ /**
40148
+ * ####################################################
40149
+ * # INTRODUCTION
40150
+ * ####################################################
40151
+ *
40152
+ * This file contain the function recomputeZones.
40153
+ * This function try to recompute in a performant way
40154
+ * an ensemble of zones possibly overlapping to avoid
40155
+ * overlapping and to reduce the number of zones.
40156
+ *
40157
+ * It also allows to remove some zones from the ensemble.
40158
+ *
40159
+ * In the following example, 2 zones are overlapping.
40160
+ * Applying recomputeZones will return zones without
40161
+ * overlapping:
40162
+ *
40163
+ * ["B3:D4", "D2:E3"] ["B3:C4", "D2:D4", "E2:E3"]
40164
+ *
40165
+ * A B C D E A B C D E
40166
+ * 1 ___ 1 ___
40167
+ * 2 ___|_ | 2 ___| | |
40168
+ * 3 | |_|_| ---> 3 | | |_|
40169
+ * 4 |_____| 4 |___|_|
40170
+ * 6 6
40171
+ * 7 7
40172
+ *
40173
+ *
40174
+ * In the following example, 2 zones are contiguous.
40175
+ * Applying recomputeZones will return only one zone:
40176
+ *
40177
+ * ["B2:B3", "C2:D3"] ["B2:D3"]
40178
+ *
40179
+ * A B C D E A B C D E
40180
+ * 1 _ ___ 1 _____
40181
+ * 2 | | | ---> 2 | |
40182
+ * 3 |_|___| 3 |_____|
40183
+ * 4 4
40184
+ *
40185
+ *
40186
+ * In the following example, we want to remove a zone
40187
+ * from the ensemble. Applying recomputeZones will
40188
+ * return the ensemble without the zone to remove:
40189
+ *
40190
+ * remove ["C3:D3"] ["B2:B4", "C2:D2",
40191
+ * "C4:D4", "E2:E4"]
40192
+ *
40193
+ * A B C D E F A B C D E F
40194
+ * 1 _______ 1 _______
40195
+ * 2 | | ---> 2 | |___| |
40196
+ * 3 | xxx | 3 | |___| |
40197
+ * 4 |_______| 4 |_|___|_|
40198
+ * 5 5
40199
+ *
40200
+ *
40201
+ * The exercise seems simple when we have only 2 zones.
40202
+ * But with n zones and in a performant way, we want to
40203
+ * avoid comparing each zone with all the others.
40204
+ *
40205
+ *
40206
+ * ####################################################
40207
+ * # Methodological approach
40208
+ * ####################################################
40209
+ *
40210
+ * The methodological approach to avoid comparing each
40211
+ * zone with all the others is to use a data structure
40212
+ * that allow to quickly find which zones are
40213
+ * overlapping with any other given zone.
40214
+ *
40215
+ * Here the idea is to profile the zones at the columns level.
40216
+ *
40217
+ * To do that, we propose to use a data structure
40218
+ * composed of 2 parts:
40219
+ * - profilesStartingPosition: a sorted number array
40220
+ * indicating on which columns a new profile begins.
40221
+ * - profiles: a map where the key is a column
40222
+ * position (from profilesStartingPosition) and the
40223
+ * value is a sorted number array representing a
40224
+ * profile.
40225
+ *
40226
+ *
40227
+ * See the following example: here profileStartingPosition
40228
+ * corresponds to [A,C,E,G,K]
40229
+ * A B C D E F G H I J K so with number [0,2,4,6,10]
40230
+ * 1 ' ' ' '
40231
+ * 2 ' ' '_______' here profile correspond
40232
+ * 3 '___' |_______| for A to []
40233
+ * 4 | | for C to [3, 5]
40234
+ * 5 |___| for E to []
40235
+ * 6 for G to [2, 3]
40236
+ * 7 for K to []
40237
+ *
40238
+ *
40239
+ * Now we can easily find which zones are overlapping
40240
+ * with a given zone. Suppose we want to add a new zone
40241
+ * D5:H6 to the ensemble:
40242
+ *
40243
+ * With a binary search of left and right
40244
+ * A B C D E F G H I J K on profilesStartingPosition, we can
40245
+ * 1 ' ' ' ' find the indexes of the profiles on which
40246
+ * 2 ' ' '_______' to apply a modification.
40247
+ * 3 '___' |_______|
40248
+ * 4 | _|_______ Here we will:
40249
+ * 5 |_|_| | - add a new profile in D --> become [3, 6]
40250
+ * 6 |_________| - modify the profile in E --> become [4, 6]
40251
+ * 7 - modify the profile in G --> become [2, 3, 4, 6]
40252
+ * - add a new profile in I --> become [8, 10]
40253
+ *
40254
+ * See below the result:
40255
+ *
40256
+ * Note the particularity of the profile
40257
+ * A B C D E F G H I J K for G: it will correspond to [2, 3, 4, 6]
40258
+ * 1 ' ' ' ' ' '
40259
+ * 2 ' ' ' '___'___' To know how to modify the profile (add a
40260
+ * 3 '_'_' |___|___| zone or remove it) we do a binary
40261
+ * 4 | | |___ ___ search of the top and bottom value on the
40262
+ * 5 |_| | | | profile array. Depending on the result index
40263
+ * 6 |_|___|___| parity (odd or even), because zone boundaries
40264
+ * 7 go by pairs, we know if we are in a zone or
40265
+ * not and how operate.
40266
+ */
40267
+ /**
40268
+ * Recompute the zone without the cells in toRemoveZones and avoid overlapping.
40269
+ * This compute is particularly useful because after this function:
40270
+ * - you will find coordinate of a cell only once among all the zones
40271
+ * - the number of zones will be reduced to the minimum
40272
+ */
40273
+ function futureRecomputeZones(zones, zonesToRemove = []) {
40274
+ const profilesStartingPosition = [0];
40275
+ const profiles = new Map([[0, []]]);
40276
+ modifyProfiles(profilesStartingPosition, profiles, zones, false);
40277
+ modifyProfiles(profilesStartingPosition, profiles, zonesToRemove, true);
40278
+ return constructZonesFromProfiles(profilesStartingPosition, profiles);
40279
+ }
40280
+ function modifyProfiles(// export for testing only
40281
+ profilesStartingPosition, profiles, zones, toRemove = false) {
40282
+ for (const zone of zones) {
40283
+ const leftValue = zone.left;
40284
+ const rightValue = zone.right === undefined ? undefined : zone.right + 1;
40285
+ const leftIndex = findIndexAndCreateProfile(profilesStartingPosition, profiles, leftValue, true, 0);
40286
+ const rightIndex = findIndexAndCreateProfile(profilesStartingPosition, profiles, rightValue, false, leftIndex);
40287
+ for (let i = leftIndex; i <= rightIndex; i++) {
40288
+ const profile = profiles.get(profilesStartingPosition[i]);
40289
+ modifyProfile(profile, zone, toRemove);
40290
+ }
40291
+ // maybe this part cost in performance, and maybe it's not necessary (depending on the use case). To be checked
40292
+ removeContiguousProfiles(profilesStartingPosition, profiles, leftIndex, rightIndex);
40293
+ }
40294
+ }
40295
+ function findIndexAndCreateProfile(profilesStartingPosition, profiles, value, searchLeft, startIndex) {
40296
+ if (value === undefined) {
40297
+ // this is only the case when the value correspond to a bottom value that could be undefined
40298
+ return profilesStartingPosition.length - 1;
40299
+ }
40300
+ const predecessorIndex = binaryPredecessorSearch(profilesStartingPosition, value, startIndex);
40301
+ if (value != profilesStartingPosition[predecessorIndex]) {
40302
+ // mean that the value is not ending/starting at the same position as the previous/next profile
40303
+ // --> it's a new profile
40304
+ // --> we need to add it
40305
+ profilesStartingPosition.splice(predecessorIndex + 1, 0, value);
40306
+ // suppose the we want to add the for the left value
40307
+ // following profile following zone: 'C', the predecessor index
40308
+ // for B: [1, 3] "C3:D4" correspond to 'B'.
40309
+ // The next line code will
40310
+ // A B C D A B C D copy the profile of 'B'
40311
+ // 1 '___' 1 '___' to 'C'. In the rest of the
40312
+ // 2 | | ---> 2 | _|_ process the 'modifyProfile'
40313
+ // 3 |___| 3 |_|_| | function will adapt the waiting
40314
+ // 4 4 |___| 'C' profile [1, 3] to the
40315
+ // correct 'C' profile [1, 4]
40316
+ profiles.set(value, [...profiles.get(profilesStartingPosition[predecessorIndex])]);
40317
+ return searchLeft ? predecessorIndex + 1 : predecessorIndex;
40318
+ }
40319
+ return searchLeft ? predecessorIndex : predecessorIndex - 1;
40320
+ }
40321
+ /**
40322
+ * Suppose the following Suppose we want to add We want to have the
40323
+ * profile: the following zone: following profile:
40324
+ *
40325
+ * A B C D E F A B C D E F A B C D E F
40326
+ * 1 '___' 1 ' ' 1 '___'
40327
+ * 2 |___| 2 '___' 2 | |
40328
+ * 3 ' ' 3 | | 3 | |
40329
+ * 4 '___' --> 4 | | --> 4 | |
40330
+ * 6 | | 6 |___| 6 | |
40331
+ * 7 |___| 7 7 |___|
40332
+ * 8 8 8
40333
+ *
40334
+ * the profile for 'C' the top zone correspond Here [2, 3, 5, 8] with [3, 7]
40335
+ * corresponds to: to 3 and the bottom zone would be merged into [2, 8]
40336
+ * ____ ____ correspond to 6
40337
+ * [2, 3, 5, 8] would be the profile: The difficulty of modify profile
40338
+ * ____ is to know what must be deleted
40339
+ * Note that the 'filled [3, 7] and what must be added to the
40340
+ * zone' are always between existing profile.
40341
+ * an even index and its
40342
+ * next index
40343
+ *
40344
+ */
40345
+ function modifyProfile(profile, zone, toRemove = false) {
40346
+ const topValue = zone.top;
40347
+ const bottomValue = zone.bottom === undefined ? undefined : zone.bottom + 1;
40348
+ const newPoints = [];
40349
+ // Case we want to add a zone to the profile:
40350
+ // - If the top predecessor index `topPredIndex` is even, it means the top of the zone is already positioned on a filled zone
40351
+ // so we don't need to add it to the profile. we can keep in reference the index of the predecessor.
40352
+ // - If it is odd, it means the top of the zone must be the beginning of a filled zone.
40353
+ // so we can keep the index of the top position
40354
+ // Case we want to remove a zone from the profile: it's the opposite of the previous case
40355
+ const topPredIndex = binaryPredecessorSearch(profile, topValue, 0, false);
40356
+ if ((topPredIndex % 2 !== 0 && !toRemove) || (topPredIndex % 2 === 0 && toRemove)) {
40357
+ newPoints.push(topValue);
40358
+ }
40359
+ if (bottomValue === undefined) {
40360
+ // The following two code lines will not impact the final result,
40361
+ // but they will impact the intermediate profile.
40362
+ // We keep them for performance reason
40363
+ profile.splice(topPredIndex + 1);
40364
+ profile.push(...newPoints);
40365
+ return;
40366
+ }
40367
+ // Case we want to add a zone to the profile:
40368
+ // - If the bottom successor index `bottomSuccIndex` is even, it means the bottom of the zone must be the ending of a filled zone
40369
+ // so we can keep the index of the bottom position.
40370
+ // - If it is odd, it means the bottom of the zone is already positioned on a filled zone
40371
+ // so we don't need to add it to the profile. we can keep in reference the index of the successor
40372
+ // Case we want to remove a zone from the profile: it's the opposite of the previous case
40373
+ const bottomSuccIndex = binarySuccessorSearch(profile, bottomValue, 0, false);
40374
+ if ((bottomSuccIndex % 2 === 0 && !toRemove) || (bottomSuccIndex % 2 !== 0 && toRemove)) {
40375
+ newPoints.push(bottomValue);
40376
+ }
40377
+ // add the top and bottom value to the profile and
40378
+ // remove all information between the top and bottom index
40379
+ profile.splice(topPredIndex + 1, bottomSuccIndex - topPredIndex - 1, ...newPoints);
40380
+ }
40381
+ function removeContiguousProfiles(profilesStartingPosition, profiles, leftIndex, rightIndex) {
40382
+ const start = leftIndex - 1 === -1 ? 0 : leftIndex - 1;
40383
+ const end = rightIndex === profilesStartingPosition.length - 1 ? rightIndex : rightIndex + 1;
40384
+ for (let i = end; i > start; i--) {
40385
+ if (deepEqualsArray(profiles.get(profilesStartingPosition[i]), profiles.get(profilesStartingPosition[i - 1]))) {
40386
+ profiles.delete(profilesStartingPosition[i]);
40387
+ profilesStartingPosition.splice(i, 1);
40388
+ }
40389
+ }
40390
+ }
40391
+ function constructZonesFromProfiles(profilesStartingPosition, profiles) {
40392
+ const mergedZone = [];
40393
+ let pendingZones = [];
40394
+ for (let colIndex = 0; colIndex < profilesStartingPosition.length; colIndex++) {
40395
+ const left = profilesStartingPosition[colIndex];
40396
+ const profile = profiles.get(left);
40397
+ if (!profile || profile.length === 0) {
40398
+ mergedZone.push(...pendingZones);
40399
+ pendingZones = [];
40400
+ continue;
40401
+ }
40402
+ let right = profilesStartingPosition[colIndex + 1];
40403
+ if (right !== undefined) {
40404
+ right--;
40405
+ }
40406
+ const nextPendingZones = [];
40407
+ for (let i = 0; i < profile.length; i += 2) {
40408
+ const top = profile[i];
40409
+ let bottom = profile[i + 1];
40410
+ if (bottom !== undefined) {
40411
+ bottom--;
40412
+ }
40413
+ const profileZone = {
40414
+ top,
40415
+ left,
40416
+ bottom,
40417
+ right,
40418
+ hasHeader: (bottom === undefined && top !== 0) || (right === undefined && left !== 0),
40419
+ };
40420
+ let findCorrespondingZone = false;
40421
+ for (let j = pendingZones.length - 1; j >= 0; j--) {
40422
+ const pendingZone = pendingZones[j];
40423
+ if (pendingZone.top === profileZone.top && pendingZone.bottom === profileZone.bottom) {
40424
+ pendingZone.right = profileZone.right;
40425
+ pendingZones.splice(j, 1);
40426
+ nextPendingZones.push(pendingZone);
40427
+ findCorrespondingZone = true;
40428
+ break;
40429
+ }
40430
+ }
40431
+ if (!findCorrespondingZone) {
40432
+ nextPendingZones.push(profileZone);
40433
+ }
40434
+ }
40435
+ mergedZone.push(...pendingZones);
40436
+ pendingZones = nextPendingZones;
40437
+ }
40438
+ mergedZone.push(...pendingZones);
40439
+ return mergedZone;
40440
+ }
40441
+ function binaryPredecessorSearch(arr, val, start = 0, matchEqual = true) {
40442
+ let end = arr.length - 1;
40443
+ let result = -1;
40444
+ while (start <= end) {
40445
+ const mid = Math.floor((start + end) / 2);
40446
+ if (arr[mid] === val && matchEqual) {
40447
+ return mid;
40448
+ }
40449
+ else if (arr[mid] < val) {
40450
+ result = mid;
40451
+ start = mid + 1;
40452
+ }
40453
+ else {
40454
+ end = mid - 1;
40455
+ }
40456
+ }
40457
+ return result;
40458
+ }
40459
+ function binarySuccessorSearch(arr, val, start = 0, matchEqual = true) {
40460
+ let end = arr.length - 1;
40461
+ let result = arr.length;
40462
+ while (start <= end) {
40463
+ const mid = Math.floor((start + end) / 2);
40464
+ if (arr[mid] === val && matchEqual) {
40465
+ return mid;
40466
+ }
40467
+ else if (arr[mid] > val) {
40468
+ result = mid;
40469
+ end = mid - 1;
40470
+ }
40471
+ else {
40472
+ start = mid + 1;
40473
+ }
40474
+ }
40475
+ return result;
40476
+ }
40477
+ /**
40478
+ * Compares two arrays.
40479
+ * For performance reasons, this function is to be preferred
40480
+ * to 'deepEquals' in the case we know that the inputs are arrays.
40481
+ */
40482
+ function deepEqualsArray(arr1, arr2) {
40483
+ if (arr1.length !== arr2.length) {
40484
+ return false;
40485
+ }
40486
+ for (let i = 0; i < arr1.length; i++) {
40487
+ if (!deepEquals(arr1[i], arr2[i])) {
40488
+ return false;
40489
+ }
40490
+ }
40491
+ return true;
40492
+ }
40493
+
40166
40494
  function quickselect(arr, k, left, right, compare) {
40167
40495
  quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare);
40168
40496
  }
@@ -40926,7 +41254,7 @@
40926
41254
  }
40927
41255
  }
40928
41256
  /**
40929
- * Return the cell and all cells that depend on it,
41257
+ * Return all the cells that depend on the provided ranges,
40930
41258
  * in the correct order they should be evaluated.
40931
41259
  * This is called a topological ordering (excluding cycles)
40932
41260
  */
@@ -40937,11 +41265,20 @@
40937
41265
  const range = queue.pop();
40938
41266
  visited.addMany(this.encoder.encodeBoundingBox(range));
40939
41267
  const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
41268
+ const nextInQueue = {};
40940
41269
  for (const positionId of impactedPositionIds) {
40941
41270
  if (!visited.has(positionId)) {
40942
- queue.push(this.encoder.decodeToBoundingBox(positionId));
41271
+ const { sheetId, zone } = this.encoder.decodeToBoundingBox(positionId);
41272
+ if (!nextInQueue[sheetId]) {
41273
+ nextInQueue[sheetId] = [];
41274
+ }
41275
+ nextInQueue[sheetId].push(zone);
40943
41276
  }
40944
41277
  }
41278
+ for (const sheetId in nextInQueue) {
41279
+ const zones = futureRecomputeZones(nextInQueue[sheetId]);
41280
+ queue.push(...zones.map((zone) => ({ sheetId, zone })));
41281
+ }
40945
41282
  }
40946
41283
  visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
40947
41284
  return visited;
@@ -41097,7 +41434,7 @@
41097
41434
  }
41098
41435
  if (!content) {
41099
41436
  // The previous content could have blocked some array formulas
41100
- impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
41437
+ impactedPositionIds.addMany(this.getArrayFormulasBlockedBy(positionId));
41101
41438
  }
41102
41439
  }
41103
41440
  return impactedPositionIds;
@@ -41142,13 +41479,22 @@
41142
41479
  }
41143
41480
  return positionIds;
41144
41481
  }
41145
- getArrayFormulasBlockedByOrSpreadingOn(positionId) {
41482
+ /**
41483
+ * Return the position of formulas blocked by the given position
41484
+ * as well as all their dependencies.
41485
+ */
41486
+ getArrayFormulasBlockedBy(positionId) {
41146
41487
  if (!this.spreadingRelations.hasArrayFormulaResult(positionId)) {
41147
41488
  return [];
41148
41489
  }
41149
41490
  const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
41150
41491
  const cells = new JetSet(arrayFormulas);
41151
- cells.addMany(this.getCellsDependingOn(arrayFormulas));
41492
+ const arrayFormulaPositionId = this.getArrayFormulaSpreadingOnId(positionId);
41493
+ if (arrayFormulaPositionId) {
41494
+ // ignore the formula spreading on the position. Keep only the blocked ones
41495
+ cells.delete(arrayFormulaPositionId);
41496
+ }
41497
+ cells.addMany(this.getCellsDependingOn(cells));
41152
41498
  return cells;
41153
41499
  }
41154
41500
  nextPositionsToUpdate = new JetSet();
@@ -41313,7 +41659,7 @@
41313
41659
  }
41314
41660
  this.evaluatedCells.delete(child);
41315
41661
  this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
41316
- this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
41662
+ this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedBy(child));
41317
41663
  }
41318
41664
  this.spreadingRelations.removeNode(positionId);
41319
41665
  }
@@ -48926,7 +49272,7 @@
48926
49272
  "isFilterActive",
48927
49273
  ];
48928
49274
  filterValues = {};
48929
- hiddenRows = new Set();
49275
+ hiddenRows = {};
48930
49276
  isEvaluationDirty = false;
48931
49277
  allowDispatch(cmd) {
48932
49278
  switch (cmd.type) {
@@ -48969,11 +49315,11 @@
48969
49315
  case "UNFOLD_HEADER_GROUP":
48970
49316
  case "FOLD_ALL_HEADER_GROUPS":
48971
49317
  case "UNFOLD_ALL_HEADER_GROUPS":
48972
- this.updateHiddenRows();
49318
+ this.updateHiddenRows(cmd.sheetId);
48973
49319
  break;
48974
49320
  case "UPDATE_FILTER":
48975
49321
  this.updateFilter(cmd);
48976
- this.updateHiddenRows();
49322
+ this.updateHiddenRows(cmd.sheetId);
48977
49323
  break;
48978
49324
  case "DUPLICATE_SHEET":
48979
49325
  const filterValues = {};
@@ -48993,15 +49339,14 @@
48993
49339
  }
48994
49340
  finalize() {
48995
49341
  if (this.isEvaluationDirty) {
48996
- this.updateHiddenRows();
49342
+ for (const sheetId of this.getters.getSheetIds()) {
49343
+ this.updateHiddenRows(sheetId);
49344
+ }
48997
49345
  this.isEvaluationDirty = false;
48998
49346
  }
48999
49347
  }
49000
49348
  isRowFiltered(sheetId, row) {
49001
- if (sheetId !== this.getters.getActiveSheetId()) {
49002
- return false;
49003
- }
49004
- return this.hiddenRows.has(row);
49349
+ return !!this.hiddenRows[sheetId]?.has(row);
49005
49350
  }
49006
49351
  getCellBorderWithFilterBorder(position) {
49007
49352
  const { sheetId, col, row } = position;
@@ -49052,8 +49397,7 @@
49052
49397
  this.filterValues[sheetId] = {};
49053
49398
  this.filterValues[sheetId][id] = hiddenValues;
49054
49399
  }
49055
- updateHiddenRows() {
49056
- const sheetId = this.getters.getActiveSheetId();
49400
+ updateHiddenRows(sheetId) {
49057
49401
  const filters = this.getters
49058
49402
  .getFilters(sheetId)
49059
49403
  .sort((filter1, filter2) => filter1.zoneWithHeaders.top - filter2.zoneWithHeaders.top);
@@ -49074,7 +49418,7 @@
49074
49418
  }
49075
49419
  }
49076
49420
  }
49077
- this.hiddenRows = hiddenRows;
49421
+ this.hiddenRows[sheetId] = hiddenRows;
49078
49422
  }
49079
49423
  getCellValueAsString(sheetId, col, row) {
49080
49424
  const value = this.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue;
@@ -50215,13 +50559,14 @@
50215
50559
  }
50216
50560
  }
50217
50561
  handleEvent(event) {
50562
+ const sheetId = this.getters.getActiveSheetId();
50218
50563
  if (event.options.scrollIntoView) {
50219
50564
  let { col, row } = findCellInNewZone(event.previousAnchor.zone, event.anchor.zone);
50220
50565
  if (event.mode === "updateAnchor") {
50221
50566
  const oldZone = event.previousAnchor.zone;
50222
50567
  const newZone = event.anchor.zone;
50223
50568
  // altering a zone should not move the viewport in a dimension that wasn't changed
50224
- const { top, bottom, left, right } = this.getters.getActiveMainViewport();
50569
+ const { top, bottom, left, right } = this.getMainInternalViewport(sheetId);
50225
50570
  if (oldZone.left === newZone.left && oldZone.right === newZone.right) {
50226
50571
  col = left > col || col > right ? left : col;
50227
50572
  }
@@ -50229,7 +50574,6 @@
50229
50574
  row = top > row || row > bottom ? top : row;
50230
50575
  }
50231
50576
  }
50232
- const sheetId = this.getters.getActiveSheetId();
50233
50577
  col = Math.min(col, this.getters.getNumberCols(sheetId) - 1);
50234
50578
  row = Math.min(row, this.getters.getNumberRows(sheetId) - 1);
50235
50579
  if (!this.sheetsWithDirtyViewports.has(sheetId)) {
@@ -50266,16 +50610,16 @@
50266
50610
  this.setSheetViewOffset(cmd.offsetX, cmd.offsetY);
50267
50611
  break;
50268
50612
  case "SHIFT_VIEWPORT_DOWN":
50269
- const { top } = this.getActiveMainViewport();
50270
50613
  const sheetId = this.getters.getActiveSheetId();
50271
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).start + this.sheetViewHeight);
50272
- this.shiftVertically(shiftedOffsetY);
50614
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
50615
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
50616
+ this.shiftVertically(topRowDims.start + viewportHeight - offsetCorrectionY);
50273
50617
  break;
50274
50618
  case "SHIFT_VIEWPORT_UP": {
50275
- const { top } = this.getActiveMainViewport();
50276
50619
  const sheetId = this.getters.getActiveSheetId();
50277
- const shiftedOffsetY = this.clipOffsetY(this.getters.getRowDimensions(sheetId, top).end - this.sheetViewHeight);
50278
- this.shiftVertically(shiftedOffsetY);
50620
+ const { top, viewportHeight, offsetCorrectionY } = this.getMainInternalViewport(sheetId);
50621
+ const topRowDims = this.getters.getRowDimensions(sheetId, top);
50622
+ this.shiftVertically(topRowDims.end - offsetCorrectionY - viewportHeight);
50279
50623
  break;
50280
50624
  }
50281
50625
  case "REMOVE_FILTER_TABLE":
@@ -50668,17 +51012,6 @@
50668
51012
  const { maxOffsetX, maxOffsetY } = this.getMaximumSheetOffset();
50669
51013
  Object.values(this.getSubViewports(sheetId)).forEach((viewport) => viewport.setViewportOffset(clip(offsetX, 0, maxOffsetX), clip(offsetY, 0, maxOffsetY)));
50670
51014
  }
50671
- /**
50672
- * Clip the vertical offset within the allowed range.
50673
- * Not above the sheet, nor below the sheet.
50674
- */
50675
- clipOffsetY(offsetY) {
50676
- const { height } = this.getMainViewportRect();
50677
- const maxOffset = height - this.sheetViewHeight;
50678
- offsetY = Math.min(offsetY, maxOffset);
50679
- offsetY = Math.max(offsetY, 0);
50680
- return offsetY;
50681
- }
50682
51015
  getViewportOffset(sheetId) {
50683
51016
  return {
50684
51017
  x: this.viewports[sheetId]?.bottomRight.offsetScrollbarX || 0,
@@ -50734,12 +51067,15 @@
50734
51067
  * viewport top.
50735
51068
  */
50736
51069
  shiftVertically(offset) {
50737
- const { top } = this.getActiveMainViewport();
51070
+ const sheetId = this.getters.getActiveSheetId();
51071
+ const { top } = this.getMainInternalViewport(sheetId);
50738
51072
  const { scrollX } = this.getActiveSheetScrollInfo();
50739
51073
  this.setSheetViewOffset(scrollX, offset);
50740
51074
  const { anchor } = this.getters.getSelection();
50741
- const deltaRow = this.getActiveMainViewport().top - top;
50742
- this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
51075
+ if (anchor.cell.row >= this.getters.getPaneDivisions(sheetId).ySplit) {
51076
+ const deltaRow = this.getMainInternalViewport(sheetId).top - top;
51077
+ this.selection.selectCell(anchor.cell.col, anchor.cell.row + deltaRow);
51078
+ }
50743
51079
  }
50744
51080
  getVisibleFigures() {
50745
51081
  const sheetId = this.getters.getActiveSheetId();
@@ -51670,7 +52006,6 @@
51670
52006
  cursor: pointer;
51671
52007
  }
51672
52008
  `;
51673
- let tKey = 1;
51674
52009
  class SpreadsheetDashboard extends owl.Component {
51675
52010
  static template = "o-spreadsheet-SpreadsheetDashboard";
51676
52011
  static components = {
@@ -51748,13 +52083,9 @@
51748
52083
  coordinates: rect,
51749
52084
  position: { col, row },
51750
52085
  action,
51751
- // we can't rely on position only because a row or a column could
51752
- // be inserted at any time.
51753
- tKey: `${tKey}-${col}-${row}`,
51754
52086
  });
51755
52087
  }
51756
52088
  }
51757
- tKey++;
51758
52089
  return cells;
51759
52090
  }
51760
52091
  getClickableAction(position) {
@@ -57060,9 +57391,9 @@
57060
57391
  exports.tokenize = tokenize;
57061
57392
 
57062
57393
 
57063
- __info__.version = "17.0.18";
57064
- __info__.date = "2024-04-10T13:28:23.664Z";
57065
- __info__.hash = "6294758";
57394
+ __info__.version = "17.0.20";
57395
+ __info__.date = "2024-04-26T07:37:04.503Z";
57396
+ __info__.hash = "065ac98";
57066
57397
 
57067
57398
 
57068
57399
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);