@odoo/o-spreadsheet 16.3.0-alpha.7 → 16.3.0
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.
- package/dist/o-spreadsheet.cjs.js +751 -293
- package/dist/o-spreadsheet.d.ts +212 -118
- package/dist/o-spreadsheet.esm.js +751 -293
- package/dist/o-spreadsheet.iife.js +751 -293
- package/dist/o-spreadsheet.iife.min.js +384 -289
- package/package.json +2 -2
|
@@ -240,8 +240,8 @@ const HEADER_FONT_SIZE = 11;
|
|
|
240
240
|
const DEFAULT_FONT = "'Roboto', arial";
|
|
241
241
|
const DEFAULT_VERTICAL_ALIGN = "bottom";
|
|
242
242
|
// Borders
|
|
243
|
-
const DEFAULT_BORDER_DESC =
|
|
244
|
-
const DEFAULT_FILTER_BORDER_DESC =
|
|
243
|
+
const DEFAULT_BORDER_DESC = { style: "thin", color: "#000000" };
|
|
244
|
+
const DEFAULT_FILTER_BORDER_DESC = { style: "thin", color: FILTERS_COLOR };
|
|
245
245
|
// Ranges
|
|
246
246
|
const INCORRECT_RANGE_STRING = CellErrorType.InvalidReference;
|
|
247
247
|
// Max Number of history steps kept in memory
|
|
@@ -1105,6 +1105,18 @@ function replaceSpecialSpaces(text) {
|
|
|
1105
1105
|
text = text.replace(whiteSpaceRegexp, " ");
|
|
1106
1106
|
text = text.replace(newLineRegex, NEWLINE);
|
|
1107
1107
|
return text;
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Determine if the numbers are consecutive.
|
|
1111
|
+
*/
|
|
1112
|
+
function isConsecutive(iterable) {
|
|
1113
|
+
const array = Array.from(iterable).sort((a, b) => a - b); // sort numerically rather than lexicographically
|
|
1114
|
+
for (let i = 1; i < array.length; i++) {
|
|
1115
|
+
if (array[i] - array[i - 1] !== 1) {
|
|
1116
|
+
return false;
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
return true;
|
|
1108
1120
|
}
|
|
1109
1121
|
|
|
1110
1122
|
const RBA_REGEX = /rgba?\(|\s+|\)/gi;
|
|
@@ -4247,6 +4259,7 @@ const coreTypes = new Set([
|
|
|
4247
4259
|
"SET_FORMATTING",
|
|
4248
4260
|
"CLEAR_FORMATTING",
|
|
4249
4261
|
"SET_BORDER",
|
|
4262
|
+
"SET_ZONE_BORDERS",
|
|
4250
4263
|
/** CHART */
|
|
4251
4264
|
"CREATE_CHART",
|
|
4252
4265
|
"UPDATE_CHART",
|
|
@@ -4387,8 +4400,10 @@ exports.CommandResult = void 0;
|
|
|
4387
4400
|
CommandResult[CommandResult["EmptySplitSeparator"] = 89] = "EmptySplitSeparator";
|
|
4388
4401
|
CommandResult[CommandResult["SplitWillOverwriteContent"] = 90] = "SplitWillOverwriteContent";
|
|
4389
4402
|
CommandResult[CommandResult["NoSplitSeparatorInSelection"] = 91] = "NoSplitSeparatorInSelection";
|
|
4403
|
+
CommandResult[CommandResult["NoActiveSheet"] = 92] = "NoActiveSheet";
|
|
4390
4404
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
4391
4405
|
|
|
4406
|
+
const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
|
|
4392
4407
|
var DIRECTION;
|
|
4393
4408
|
(function (DIRECTION) {
|
|
4394
4409
|
DIRECTION["UP"] = "up";
|
|
@@ -5482,12 +5497,6 @@ css /* scss */ `
|
|
|
5482
5497
|
cursor: pointer;
|
|
5483
5498
|
user-select: none;
|
|
5484
5499
|
|
|
5485
|
-
.o-menu-item-name {
|
|
5486
|
-
overflow: hidden;
|
|
5487
|
-
white-space: nowrap;
|
|
5488
|
-
text-overflow: ellipsis;
|
|
5489
|
-
}
|
|
5490
|
-
|
|
5491
5500
|
&.o-menu-root {
|
|
5492
5501
|
display: flex;
|
|
5493
5502
|
justify-content: space-between;
|
|
@@ -5498,10 +5507,6 @@ css /* scss */ `
|
|
|
5498
5507
|
margin: 0px 8px 0px 0px;
|
|
5499
5508
|
width: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
5500
5509
|
line-height: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
5501
|
-
|
|
5502
|
-
.o-icon {
|
|
5503
|
-
color: ${ICONS_COLOR};
|
|
5504
|
-
}
|
|
5505
5510
|
}
|
|
5506
5511
|
.o-menu-item-root {
|
|
5507
5512
|
width: 10px;
|
|
@@ -5515,6 +5520,11 @@ css /* scss */ `
|
|
|
5515
5520
|
.o-menu-item-description {
|
|
5516
5521
|
color: grey;
|
|
5517
5522
|
}
|
|
5523
|
+
.o-menu-item-icon {
|
|
5524
|
+
.o-icon {
|
|
5525
|
+
color: ${ICONS_COLOR};
|
|
5526
|
+
}
|
|
5527
|
+
}
|
|
5518
5528
|
}
|
|
5519
5529
|
&.disabled {
|
|
5520
5530
|
color: ${MENU_ITEM_DISABLED_COLOR};
|
|
@@ -6331,8 +6341,14 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6331
6341
|
: undefined));
|
|
6332
6342
|
}
|
|
6333
6343
|
}
|
|
6344
|
+
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
6345
|
+
// A single cell. If it's only the title, the dataset is not added.
|
|
6346
|
+
if (!dataSetsHaveTitle) {
|
|
6347
|
+
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
6348
|
+
}
|
|
6349
|
+
}
|
|
6334
6350
|
else {
|
|
6335
|
-
/* 1
|
|
6351
|
+
/* 1 row or 1 column */
|
|
6336
6352
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
6337
6353
|
? {
|
|
6338
6354
|
top: zone.top,
|
|
@@ -8943,7 +8959,7 @@ const DELETE_CELL_SHIFT_LEFT = (env) => {
|
|
|
8943
8959
|
handlePasteResult(env, result);
|
|
8944
8960
|
};
|
|
8945
8961
|
const MENU_INSERT_ROWS_NAME = (env) => {
|
|
8946
|
-
const number =
|
|
8962
|
+
const number = getRowsNumber(env);
|
|
8947
8963
|
return number === 1 ? _lt("Insert row") : _lt("Insert %s rows", number.toString());
|
|
8948
8964
|
};
|
|
8949
8965
|
const MENU_INSERT_ROWS_BEFORE_NAME = (env) => {
|
|
@@ -15308,7 +15324,11 @@ const LOOKUP = {
|
|
|
15308
15324
|
: getNormalizedValueFromRowRange;
|
|
15309
15325
|
const rangeLength = verticalSearch ? nbRow : nbCol;
|
|
15310
15326
|
const index = dichotomicSearch(searchArray, _searchKey, "nextSmaller", "asc", rangeLength, getElement);
|
|
15311
|
-
|
|
15327
|
+
if (index === -1)
|
|
15328
|
+
assertAvailable(undefined, searchKey);
|
|
15329
|
+
verticalSearch
|
|
15330
|
+
? assertAvailable(searchArray[0][index], searchKey)
|
|
15331
|
+
: assertAvailable(searchArray[index][nbRow - 1], searchKey);
|
|
15312
15332
|
if (resultRange === undefined) {
|
|
15313
15333
|
return (verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1]);
|
|
15314
15334
|
}
|
|
@@ -16215,75 +16235,97 @@ for (let category of categories) {
|
|
|
16215
16235
|
|
|
16216
16236
|
const insertRow = {
|
|
16217
16237
|
name: MENU_INSERT_ROWS_NAME,
|
|
16218
|
-
isVisible:
|
|
16238
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
|
|
16239
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16240
|
+
env.model.getters.getActiveCols().size === 0,
|
|
16219
16241
|
icon: "o-spreadsheet-Icon.INSERT_ROW",
|
|
16220
16242
|
};
|
|
16221
16243
|
const rowInsertRowBefore = {
|
|
16222
16244
|
name: ROW_INSERT_ROWS_BEFORE_NAME,
|
|
16223
16245
|
execute: INSERT_ROWS_BEFORE_ACTION,
|
|
16246
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
|
|
16247
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16248
|
+
env.model.getters.getActiveCols().size === 0,
|
|
16249
|
+
icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
|
|
16224
16250
|
};
|
|
16225
16251
|
const topBarInsertRowsBefore = {
|
|
16226
16252
|
...rowInsertRowBefore,
|
|
16227
16253
|
name: MENU_INSERT_ROWS_BEFORE_NAME,
|
|
16228
|
-
isVisible: (env) => env.model.getters.getActiveCols().size === 0,
|
|
16229
16254
|
};
|
|
16230
16255
|
const cellInsertRowsBefore = {
|
|
16231
16256
|
...rowInsertRowBefore,
|
|
16232
16257
|
name: CELL_INSERT_ROWS_BEFORE_NAME,
|
|
16233
16258
|
isVisible: IS_ONLY_ONE_RANGE,
|
|
16234
|
-
icon: "o-spreadsheet-Icon.
|
|
16259
|
+
icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
|
|
16235
16260
|
};
|
|
16236
16261
|
const rowInsertRowsAfter = {
|
|
16237
16262
|
execute: INSERT_ROWS_AFTER_ACTION,
|
|
16238
16263
|
name: ROW_INSERT_ROWS_AFTER_NAME,
|
|
16264
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
|
|
16265
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16266
|
+
env.model.getters.getActiveCols().size === 0,
|
|
16267
|
+
icon: "o-spreadsheet-Icon.INSERT_ROW_AFTER",
|
|
16239
16268
|
};
|
|
16240
16269
|
const topBarInsertRowsAfter = {
|
|
16241
16270
|
...rowInsertRowsAfter,
|
|
16242
16271
|
name: MENU_INSERT_ROWS_AFTER_NAME,
|
|
16243
|
-
isVisible: (env) => env.model.getters.getActiveCols().size === 0,
|
|
16244
16272
|
};
|
|
16245
16273
|
const insertCol = {
|
|
16246
16274
|
name: MENU_INSERT_COLUMNS_NAME,
|
|
16247
|
-
isVisible:
|
|
16275
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
|
|
16276
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16277
|
+
env.model.getters.getActiveRows().size === 0,
|
|
16248
16278
|
icon: "o-spreadsheet-Icon.INSERT_COL",
|
|
16249
16279
|
};
|
|
16250
16280
|
const colInsertColsBefore = {
|
|
16251
16281
|
name: COLUMN_INSERT_COLUMNS_BEFORE_NAME,
|
|
16252
16282
|
execute: INSERT_COLUMNS_BEFORE_ACTION,
|
|
16283
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
|
|
16284
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16285
|
+
env.model.getters.getActiveRows().size === 0,
|
|
16286
|
+
icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
|
|
16253
16287
|
};
|
|
16254
16288
|
const topBarInsertColsBefore = {
|
|
16255
16289
|
...colInsertColsBefore,
|
|
16256
16290
|
name: MENU_INSERT_COLUMNS_BEFORE_NAME,
|
|
16257
|
-
isVisible: (env) => env.model.getters.getActiveRows().size === 0,
|
|
16258
16291
|
};
|
|
16259
16292
|
const cellInsertColsBefore = {
|
|
16260
16293
|
...colInsertColsBefore,
|
|
16261
16294
|
name: CELL_INSERT_COLUMNS_BEFORE_NAME,
|
|
16262
16295
|
isVisible: IS_ONLY_ONE_RANGE,
|
|
16263
|
-
icon: "o-spreadsheet-Icon.
|
|
16296
|
+
icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
|
|
16264
16297
|
};
|
|
16265
16298
|
const colInsertColsAfter = {
|
|
16266
16299
|
name: COLUMN_INSERT_COLUMNS_AFTER_NAME,
|
|
16267
16300
|
execute: INSERT_COLUMNS_AFTER_ACTION,
|
|
16301
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
|
|
16302
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16303
|
+
env.model.getters.getActiveRows().size === 0,
|
|
16304
|
+
icon: "o-spreadsheet-Icon.INSERT_COL_AFTER",
|
|
16268
16305
|
};
|
|
16269
16306
|
const topBarInsertColsAfter = {
|
|
16270
16307
|
...colInsertColsAfter,
|
|
16271
16308
|
name: MENU_INSERT_COLUMNS_AFTER_NAME,
|
|
16272
16309
|
execute: INSERT_COLUMNS_AFTER_ACTION,
|
|
16273
|
-
isVisible: (env) => env.model.getters.getActiveRows().size === 0,
|
|
16274
16310
|
};
|
|
16275
16311
|
const insertCell = {
|
|
16276
16312
|
name: _lt("Insert cells"),
|
|
16277
|
-
isVisible: IS_ONLY_ONE_RANGE
|
|
16313
|
+
isVisible: (env) => IS_ONLY_ONE_RANGE(env) &&
|
|
16314
|
+
env.model.getters.getActiveCols().size === 0 &&
|
|
16315
|
+
env.model.getters.getActiveRows().size === 0,
|
|
16278
16316
|
icon: "o-spreadsheet-Icon.INSERT_CELL",
|
|
16279
16317
|
};
|
|
16280
16318
|
const insertCellShiftDown = {
|
|
16281
16319
|
name: _lt("Insert cells and shift down"),
|
|
16282
16320
|
execute: INSERT_CELL_SHIFT_DOWN,
|
|
16321
|
+
isVisible: (env) => env.model.getters.getActiveRows().size === 0 && env.model.getters.getActiveCols().size === 0,
|
|
16322
|
+
icon: "o-spreadsheet-Icon.INSERT_CELL_SHIFT_DOWN",
|
|
16283
16323
|
};
|
|
16284
16324
|
const insertCellShiftRight = {
|
|
16285
16325
|
name: _lt("Insert cells and shift right"),
|
|
16286
16326
|
execute: INSERT_CELL_SHIFT_RIGHT,
|
|
16327
|
+
isVisible: (env) => env.model.getters.getActiveRows().size === 0 && env.model.getters.getActiveCols().size === 0,
|
|
16328
|
+
icon: "o-spreadsheet-Icon.INSERT_CELL_SHIFT_RIGHT",
|
|
16287
16329
|
};
|
|
16288
16330
|
const insertChart = {
|
|
16289
16331
|
name: _lt("Chart"),
|
|
@@ -16481,6 +16523,7 @@ const splitToColumns = {
|
|
|
16481
16523
|
sequence: 1,
|
|
16482
16524
|
execute: (env) => env.openSidePanel("SplitToColumns", {}),
|
|
16483
16525
|
isEnabled: (env) => env.model.getters.isSingleColSelected(),
|
|
16526
|
+
icon: "o-spreadsheet-Icon.SPLIT_TEXT",
|
|
16484
16527
|
};
|
|
16485
16528
|
|
|
16486
16529
|
const formatNumberAutomatic = {
|
|
@@ -16696,60 +16739,6 @@ const clearFormat = {
|
|
|
16696
16739
|
execute: FORMAT_CLEARFORMAT_ACTION,
|
|
16697
16740
|
icon: "o-spreadsheet-Icon.CLEAR_FORMAT",
|
|
16698
16741
|
};
|
|
16699
|
-
const borders = {
|
|
16700
|
-
name: _lt("Borders"),
|
|
16701
|
-
icon: "o-spreadsheet-Icon.BORDERS",
|
|
16702
|
-
};
|
|
16703
|
-
const bordersAll = {
|
|
16704
|
-
name: _lt("All borders"),
|
|
16705
|
-
execute: (env) => setBorder(env, "all"),
|
|
16706
|
-
icon: "o-spreadsheet-Icon.BORDERS",
|
|
16707
|
-
};
|
|
16708
|
-
const bordersInner = {
|
|
16709
|
-
name: _lt("Inner borders"),
|
|
16710
|
-
execute: (env) => setBorder(env, "hv"),
|
|
16711
|
-
icon: "o-spreadsheet-Icon.BORDER_HV",
|
|
16712
|
-
};
|
|
16713
|
-
const bordersHorizontal = {
|
|
16714
|
-
name: _lt("Horizontal borders"),
|
|
16715
|
-
execute: (env) => setBorder(env, "h"),
|
|
16716
|
-
icon: "o-spreadsheet-Icon.BORDER_H",
|
|
16717
|
-
};
|
|
16718
|
-
const bordersVertical = {
|
|
16719
|
-
name: _lt("Vertical borders"),
|
|
16720
|
-
execute: (env) => setBorder(env, "v"),
|
|
16721
|
-
icon: "o-spreadsheet-Icon.BORDER_V",
|
|
16722
|
-
};
|
|
16723
|
-
const bordersExternal = {
|
|
16724
|
-
name: _lt("External borders"),
|
|
16725
|
-
execute: (env) => setBorder(env, "external"),
|
|
16726
|
-
icon: "o-spreadsheet-Icon.BORDER_EXTERNAL",
|
|
16727
|
-
};
|
|
16728
|
-
const bordersLeft = {
|
|
16729
|
-
name: _lt("Left borders"),
|
|
16730
|
-
execute: (env) => setBorder(env, "left"),
|
|
16731
|
-
icon: "o-spreadsheet-Icon.BORDER_LEFT",
|
|
16732
|
-
};
|
|
16733
|
-
const bordersTop = {
|
|
16734
|
-
name: _lt("Top borders"),
|
|
16735
|
-
execute: (env) => setBorder(env, "top"),
|
|
16736
|
-
icon: "o-spreadsheet-Icon.BORDER_TOP",
|
|
16737
|
-
};
|
|
16738
|
-
const bordersRight = {
|
|
16739
|
-
name: _lt("Right borders"),
|
|
16740
|
-
execute: (env) => setBorder(env, "right"),
|
|
16741
|
-
icon: "o-spreadsheet-Icon.BORDER_RIGHT",
|
|
16742
|
-
};
|
|
16743
|
-
const bordersBottom = {
|
|
16744
|
-
name: _lt("Bottom borders"),
|
|
16745
|
-
execute: (env) => setBorder(env, "bottom"),
|
|
16746
|
-
icon: "o-spreadsheet-Icon.BORDER_BOTTOM",
|
|
16747
|
-
};
|
|
16748
|
-
const bordersClear = {
|
|
16749
|
-
name: _lt("Clear borders"),
|
|
16750
|
-
execute: (env) => setBorder(env, "clear"),
|
|
16751
|
-
icon: "o-spreadsheet-Icon.BORDER_CLEAR",
|
|
16752
|
-
};
|
|
16753
16742
|
function fontSizeMenuBuilder() {
|
|
16754
16743
|
return FONT_SIZES.map((fs) => {
|
|
16755
16744
|
return {
|
|
@@ -16762,24 +16751,17 @@ function fontSizeMenuBuilder() {
|
|
|
16762
16751
|
});
|
|
16763
16752
|
}
|
|
16764
16753
|
function isAutomaticFormatSelected(env) {
|
|
16765
|
-
const activeCell = env.model.getters.
|
|
16754
|
+
const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
|
|
16766
16755
|
return !activeCell || !activeCell.format;
|
|
16767
16756
|
}
|
|
16768
16757
|
function isFormatSelected(env, format) {
|
|
16769
|
-
const activeCell = env.model.getters.
|
|
16770
|
-
return activeCell
|
|
16758
|
+
const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
|
|
16759
|
+
return activeCell?.format === format;
|
|
16771
16760
|
}
|
|
16772
16761
|
function isFontSizeSelected(env, fontSize) {
|
|
16773
16762
|
const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
|
|
16774
16763
|
return currentFontSize === fontSize;
|
|
16775
16764
|
}
|
|
16776
|
-
function setBorder(env, command) {
|
|
16777
|
-
env.model.dispatch("SET_FORMATTING", {
|
|
16778
|
-
sheetId: env.model.getters.getActiveSheetId(),
|
|
16779
|
-
target: env.model.getters.getSelectedZones(),
|
|
16780
|
-
border: command,
|
|
16781
|
-
});
|
|
16782
|
-
}
|
|
16783
16765
|
function getHorizontalAlign(env) {
|
|
16784
16766
|
const style = env.model.getters.getCurrentStyle();
|
|
16785
16767
|
if (style.align) {
|
|
@@ -16826,18 +16808,7 @@ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
|
16826
16808
|
fillColor: fillColor,
|
|
16827
16809
|
formatCF: formatCF,
|
|
16828
16810
|
paintFormat: paintFormat,
|
|
16829
|
-
clearFormat: clearFormat
|
|
16830
|
-
borders: borders,
|
|
16831
|
-
bordersAll: bordersAll,
|
|
16832
|
-
bordersInner: bordersInner,
|
|
16833
|
-
bordersHorizontal: bordersHorizontal,
|
|
16834
|
-
bordersVertical: bordersVertical,
|
|
16835
|
-
bordersExternal: bordersExternal,
|
|
16836
|
-
bordersLeft: bordersLeft,
|
|
16837
|
-
bordersTop: bordersTop,
|
|
16838
|
-
bordersRight: bordersRight,
|
|
16839
|
-
bordersBottom: bordersBottom,
|
|
16840
|
-
bordersClear: bordersClear
|
|
16811
|
+
clearFormat: clearFormat
|
|
16841
16812
|
});
|
|
16842
16813
|
|
|
16843
16814
|
function interactiveFreezeColumnsRows(env, dimension, base) {
|
|
@@ -16853,6 +16824,7 @@ const hideCols = {
|
|
|
16853
16824
|
name: HIDE_COLUMNS_NAME,
|
|
16854
16825
|
execute: HIDE_COLUMNS_ACTION,
|
|
16855
16826
|
isVisible: NOT_ALL_VISIBLE_COLS_SELECTED,
|
|
16827
|
+
icon: "o-spreadsheet-Icon.HIDE_COL",
|
|
16856
16828
|
};
|
|
16857
16829
|
const unhideCols = {
|
|
16858
16830
|
name: _lt("Unhide columns"),
|
|
@@ -16874,6 +16846,7 @@ const hideRows = {
|
|
|
16874
16846
|
name: HIDE_ROWS_NAME,
|
|
16875
16847
|
execute: HIDE_ROWS_ACTION,
|
|
16876
16848
|
isVisible: NOT_ALL_VISIBLE_ROWS_SELECTED,
|
|
16849
|
+
icon: "o-spreadsheet-Icon.HIDE_ROW",
|
|
16877
16850
|
};
|
|
16878
16851
|
const unhideRows = {
|
|
16879
16852
|
name: _lt("Unhide rows"),
|
|
@@ -17077,19 +17050,21 @@ colMenuRegistry
|
|
|
17077
17050
|
.add("delete_column", {
|
|
17078
17051
|
...deleteCols,
|
|
17079
17052
|
sequence: 90,
|
|
17053
|
+
icon: "o-spreadsheet-Icon.DELETE",
|
|
17080
17054
|
})
|
|
17081
17055
|
.add("clear_column", {
|
|
17082
17056
|
...clearCols,
|
|
17083
17057
|
sequence: 100,
|
|
17058
|
+
icon: "o-spreadsheet-Icon.CLEAR",
|
|
17084
17059
|
})
|
|
17085
17060
|
.add("hide_columns", {
|
|
17086
17061
|
...hideCols,
|
|
17087
|
-
sequence:
|
|
17062
|
+
sequence: 105,
|
|
17088
17063
|
separator: true,
|
|
17089
17064
|
})
|
|
17090
17065
|
.add("unhide_columns", {
|
|
17091
17066
|
...unhideCols,
|
|
17092
|
-
sequence:
|
|
17067
|
+
sequence: 106,
|
|
17093
17068
|
separator: true,
|
|
17094
17069
|
})
|
|
17095
17070
|
.add("conditional_formatting", {
|
|
@@ -17187,10 +17162,12 @@ rowMenuRegistry
|
|
|
17187
17162
|
.add("delete_row", {
|
|
17188
17163
|
...deleteRows,
|
|
17189
17164
|
sequence: 70,
|
|
17165
|
+
icon: "o-spreadsheet-Icon.DELETE",
|
|
17190
17166
|
})
|
|
17191
17167
|
.add("clear_row", {
|
|
17192
17168
|
...clearRows,
|
|
17193
17169
|
sequence: 80,
|
|
17170
|
+
icon: "o-spreadsheet-Icon.CLEAR",
|
|
17194
17171
|
})
|
|
17195
17172
|
.add("hide_rows", {
|
|
17196
17173
|
...hideRows,
|
|
@@ -17573,7 +17550,7 @@ topbarMenuRegistry
|
|
|
17573
17550
|
})
|
|
17574
17551
|
.addChild("sort_range", ["data"], {
|
|
17575
17552
|
...sortRange,
|
|
17576
|
-
sequence:
|
|
17553
|
+
sequence: 10,
|
|
17577
17554
|
separator: true,
|
|
17578
17555
|
})
|
|
17579
17556
|
.addChild("sort_ascending", ["data", "sort_range"], {
|
|
@@ -17586,16 +17563,16 @@ topbarMenuRegistry
|
|
|
17586
17563
|
})
|
|
17587
17564
|
.addChild("split_to_columns", ["data"], {
|
|
17588
17565
|
...splitToColumns,
|
|
17589
|
-
sequence:
|
|
17566
|
+
sequence: 20,
|
|
17590
17567
|
separator: true,
|
|
17591
17568
|
})
|
|
17592
17569
|
.addChild("add_data_filter", ["data"], {
|
|
17593
17570
|
...addDataFilter,
|
|
17594
|
-
sequence:
|
|
17571
|
+
sequence: 30,
|
|
17595
17572
|
})
|
|
17596
17573
|
.addChild("remove_data_filter", ["data"], {
|
|
17597
17574
|
...removeDataFilter,
|
|
17598
|
-
sequence:
|
|
17575
|
+
sequence: 30,
|
|
17599
17576
|
});
|
|
17600
17577
|
|
|
17601
17578
|
class OTRegistry extends Registry {
|
|
@@ -17683,6 +17660,12 @@ css /* scss */ `
|
|
|
17683
17660
|
height: 25px;
|
|
17684
17661
|
}
|
|
17685
17662
|
}
|
|
17663
|
+
/** Make the character a bit bigger
|
|
17664
|
+
compared to its neighbor INPUT box */
|
|
17665
|
+
.o-remove-selection {
|
|
17666
|
+
font-weight: bold;
|
|
17667
|
+
font-size: calc(100% + 4px);
|
|
17668
|
+
}
|
|
17686
17669
|
}
|
|
17687
17670
|
`;
|
|
17688
17671
|
/**
|
|
@@ -17778,6 +17761,9 @@ class SelectionInput extends owl.Component {
|
|
|
17778
17761
|
this.confirm();
|
|
17779
17762
|
}
|
|
17780
17763
|
}
|
|
17764
|
+
extractRanges(value) {
|
|
17765
|
+
return this.props.hasSingleRange ? value.split(",")[0] : value;
|
|
17766
|
+
}
|
|
17781
17767
|
focus(rangeId) {
|
|
17782
17768
|
this.state.isMissing = false;
|
|
17783
17769
|
this.state.mode = "select-range";
|
|
@@ -17796,10 +17782,11 @@ class SelectionInput extends owl.Component {
|
|
|
17796
17782
|
}
|
|
17797
17783
|
onInputChanged(rangeId, ev) {
|
|
17798
17784
|
const target = ev.target;
|
|
17785
|
+
const value = this.extractRanges(target.value);
|
|
17799
17786
|
this.env.model.dispatch("CHANGE_RANGE", {
|
|
17800
17787
|
id: this.id,
|
|
17801
17788
|
rangeId,
|
|
17802
|
-
value
|
|
17789
|
+
value,
|
|
17803
17790
|
});
|
|
17804
17791
|
this.triggerChange();
|
|
17805
17792
|
}
|
|
@@ -18692,6 +18679,18 @@ ChartPanel.props = {
|
|
|
18692
18679
|
onCloseSidePanel: Function,
|
|
18693
18680
|
};
|
|
18694
18681
|
|
|
18682
|
+
css /* scss */ `
|
|
18683
|
+
.o-spreadsheet {
|
|
18684
|
+
.o-icon {
|
|
18685
|
+
.small-text {
|
|
18686
|
+
font: bold 9px sans-serif;
|
|
18687
|
+
}
|
|
18688
|
+
.heavy-text {
|
|
18689
|
+
font: bold 16px sans-serif;
|
|
18690
|
+
}
|
|
18691
|
+
}
|
|
18692
|
+
}
|
|
18693
|
+
`;
|
|
18695
18694
|
// -----------------------------------------------------------------------------
|
|
18696
18695
|
// We need here the svg of the icons that we need to convert to images for the renderer
|
|
18697
18696
|
// -----------------------------------------------------------------------------
|
|
@@ -20568,14 +20567,31 @@ class ContentEditableHelper {
|
|
|
20568
20567
|
* */
|
|
20569
20568
|
getCurrentSelection() {
|
|
20570
20569
|
let { startElement, endElement, startSelectionOffset, endSelectionOffset } = this.getStartAndEndSelection();
|
|
20571
|
-
let startSizeBefore = this.
|
|
20572
|
-
let endSizeBefore = this.
|
|
20570
|
+
let startSizeBefore = this.findSelectionIndex(startElement, startSelectionOffset);
|
|
20571
|
+
let endSizeBefore = this.findSelectionIndex(endElement, endSelectionOffset);
|
|
20573
20572
|
return {
|
|
20574
|
-
start: startSizeBefore
|
|
20575
|
-
end: endSizeBefore
|
|
20573
|
+
start: startSizeBefore,
|
|
20574
|
+
end: endSizeBefore,
|
|
20576
20575
|
};
|
|
20577
20576
|
}
|
|
20578
|
-
|
|
20577
|
+
/**
|
|
20578
|
+
* Computes the text 'index' inside this.el based on the currently selected node and its offset.
|
|
20579
|
+
* The selected node is either a Text node or an Element node.
|
|
20580
|
+
*
|
|
20581
|
+
* case 1 -Text node:
|
|
20582
|
+
* the offset is the number of characters from the start of the node. We have to add this offset to the
|
|
20583
|
+
* content length of all previous nodes.
|
|
20584
|
+
*
|
|
20585
|
+
* case 2 - Element node:
|
|
20586
|
+
* the offset is the number of child nodes before the selected node. We have to add the content length of
|
|
20587
|
+
* all the bnodes prior to the selected node as well as the content of the child node before the offset.
|
|
20588
|
+
*
|
|
20589
|
+
* See the MDN documentation for more details.
|
|
20590
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
|
|
20591
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
|
|
20592
|
+
*
|
|
20593
|
+
*/
|
|
20594
|
+
findSelectionIndex(nodeToFind, nodeOffset) {
|
|
20579
20595
|
let usedCharacters = 0;
|
|
20580
20596
|
let it = iterateChildren(this.el);
|
|
20581
20597
|
let current = it.next();
|
|
@@ -20602,6 +20618,28 @@ class ContentEditableHelper {
|
|
|
20602
20618
|
if (current.value !== nodeToFind) {
|
|
20603
20619
|
throw new Error("Cannot find the node in the children of the element");
|
|
20604
20620
|
}
|
|
20621
|
+
else {
|
|
20622
|
+
if (!current.value.hasChildNodes()) {
|
|
20623
|
+
usedCharacters += nodeOffset;
|
|
20624
|
+
}
|
|
20625
|
+
else {
|
|
20626
|
+
const children = [...current.value.childNodes].slice(0, nodeOffset);
|
|
20627
|
+
usedCharacters += children.reduce((acc, child, index) => {
|
|
20628
|
+
if (child.textContent !== null) {
|
|
20629
|
+
// need to account for paragraph nodes that implicitely add a new line
|
|
20630
|
+
// except for the last paragraph
|
|
20631
|
+
let chars = child.textContent.length;
|
|
20632
|
+
if (child.nodeName === "P" && index !== children.length - 1) {
|
|
20633
|
+
chars++;
|
|
20634
|
+
}
|
|
20635
|
+
return acc + chars;
|
|
20636
|
+
}
|
|
20637
|
+
else {
|
|
20638
|
+
return acc;
|
|
20639
|
+
}
|
|
20640
|
+
}, 0);
|
|
20641
|
+
}
|
|
20642
|
+
}
|
|
20605
20643
|
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent == "") {
|
|
20606
20644
|
usedCharacters++;
|
|
20607
20645
|
}
|
|
@@ -21402,13 +21440,13 @@ GridComposer.props = {
|
|
|
21402
21440
|
|
|
21403
21441
|
const CSS$1 = css /* scss */ `
|
|
21404
21442
|
.o-filter-icon {
|
|
21443
|
+
color: ${FILTERS_COLOR};
|
|
21405
21444
|
position: absolute;
|
|
21406
21445
|
display: flex;
|
|
21407
21446
|
align-items: center;
|
|
21408
21447
|
justify-content: center;
|
|
21409
21448
|
width: ${FILTER_ICON_EDGE_LENGTH}px;
|
|
21410
21449
|
height: ${FILTER_ICON_EDGE_LENGTH}px;
|
|
21411
|
-
color: #4a4f59;
|
|
21412
21450
|
}
|
|
21413
21451
|
.o-filter-icon:hover {
|
|
21414
21452
|
background: ${FILTERS_COLOR};
|
|
@@ -24139,17 +24177,17 @@ const CELL_TYPE_CONVERSION_MAP = {
|
|
|
24139
24177
|
const BORDER_STYLE_CONVERSION_MAP = {
|
|
24140
24178
|
dashDot: "thin",
|
|
24141
24179
|
dashDotDot: "thin",
|
|
24142
|
-
dashed: "
|
|
24143
|
-
dotted: "
|
|
24180
|
+
dashed: "dashed",
|
|
24181
|
+
dotted: "dotted",
|
|
24144
24182
|
double: "thin",
|
|
24145
24183
|
hair: "thin",
|
|
24146
|
-
medium: "
|
|
24184
|
+
medium: "medium",
|
|
24147
24185
|
mediumDashDot: "thin",
|
|
24148
24186
|
mediumDashDotDot: "thin",
|
|
24149
24187
|
mediumDashed: "thin",
|
|
24150
24188
|
none: undefined,
|
|
24151
24189
|
slantDashDot: "thin",
|
|
24152
|
-
thick: "
|
|
24190
|
+
thick: "thick",
|
|
24153
24191
|
thin: "thin",
|
|
24154
24192
|
};
|
|
24155
24193
|
/** Conversion map Horizontal Alignment in XLSX <=> Horizontal Alignment in o_spreadsheet*/
|
|
@@ -24648,7 +24686,7 @@ function convertBorderDescr$1(borderDescr, warningManager) {
|
|
|
24648
24686
|
return undefined;
|
|
24649
24687
|
addBorderDescrWarnings(borderDescr, warningManager);
|
|
24650
24688
|
const style = BORDER_STYLE_CONVERSION_MAP[borderDescr.style];
|
|
24651
|
-
return style ?
|
|
24689
|
+
return style ? { style, color: convertColor(borderDescr.color) } : undefined;
|
|
24652
24690
|
}
|
|
24653
24691
|
function convertStyles(data, warningManager) {
|
|
24654
24692
|
const stylesArray = data.styles.map((style) => {
|
|
@@ -26046,8 +26084,8 @@ function convertBorderDescr(descr) {
|
|
|
26046
26084
|
return undefined;
|
|
26047
26085
|
}
|
|
26048
26086
|
return {
|
|
26049
|
-
style: descr
|
|
26050
|
-
color: { rgb: descr
|
|
26087
|
+
style: descr.style,
|
|
26088
|
+
color: { rgb: descr.color },
|
|
26051
26089
|
};
|
|
26052
26090
|
}
|
|
26053
26091
|
function extractStyle(cell, data) {
|
|
@@ -26625,7 +26663,7 @@ const TABLE_HEADER_STYLE = {
|
|
|
26625
26663
|
const TABLE_HIGHLIGHTED_CELL_STYLE = {
|
|
26626
26664
|
bold: true,
|
|
26627
26665
|
};
|
|
26628
|
-
const TABLE_BORDER_STYLE =
|
|
26666
|
+
const TABLE_BORDER_STYLE = { style: "thin", color: "#000000FF" };
|
|
26629
26667
|
/**
|
|
26630
26668
|
* Convert the imported XLSX tables.
|
|
26631
26669
|
*
|
|
@@ -28194,7 +28232,7 @@ function normalizeV9(formula) {
|
|
|
28194
28232
|
* a breaking change is made in the way the state is handled, and an upgrade
|
|
28195
28233
|
* function should be defined
|
|
28196
28234
|
*/
|
|
28197
|
-
const CURRENT_VERSION =
|
|
28235
|
+
const CURRENT_VERSION = 13;
|
|
28198
28236
|
const INITIAL_SHEET_ID = "Sheet1";
|
|
28199
28237
|
/**
|
|
28200
28238
|
* This function tries to load anything that could look like a valid
|
|
@@ -28458,6 +28496,25 @@ const MIGRATIONS = [
|
|
|
28458
28496
|
return data;
|
|
28459
28497
|
},
|
|
28460
28498
|
},
|
|
28499
|
+
{
|
|
28500
|
+
description: "Change Border description structure",
|
|
28501
|
+
from: 12,
|
|
28502
|
+
to: 13,
|
|
28503
|
+
applyMigration(data) {
|
|
28504
|
+
for (const borderId in data.borders) {
|
|
28505
|
+
const border = data.borders[borderId];
|
|
28506
|
+
for (const position in border) {
|
|
28507
|
+
if (Array.isArray(border[position])) {
|
|
28508
|
+
border[position] = {
|
|
28509
|
+
style: border[position][0],
|
|
28510
|
+
color: border[position][1],
|
|
28511
|
+
};
|
|
28512
|
+
}
|
|
28513
|
+
}
|
|
28514
|
+
}
|
|
28515
|
+
return data;
|
|
28516
|
+
},
|
|
28517
|
+
},
|
|
28461
28518
|
];
|
|
28462
28519
|
/**
|
|
28463
28520
|
* This function is used to repair faulty data independently of the migration.
|
|
@@ -28793,7 +28850,7 @@ class CorePlugin extends BasePlugin {
|
|
|
28793
28850
|
* - borders
|
|
28794
28851
|
*/
|
|
28795
28852
|
class BordersPlugin extends CorePlugin {
|
|
28796
|
-
static getters = ["getCellBorder"];
|
|
28853
|
+
static getters = ["getCellBorder", "getBordersColors"];
|
|
28797
28854
|
borders = {};
|
|
28798
28855
|
// ---------------------------------------------------------------------------
|
|
28799
28856
|
// Command Handling
|
|
@@ -28824,10 +28881,15 @@ class BordersPlugin extends CorePlugin {
|
|
|
28824
28881
|
case "SET_BORDER":
|
|
28825
28882
|
this.setBorder(cmd.sheetId, cmd.col, cmd.row, cmd.border);
|
|
28826
28883
|
break;
|
|
28827
|
-
case "
|
|
28884
|
+
case "SET_ZONE_BORDERS":
|
|
28828
28885
|
if (cmd.border) {
|
|
28829
28886
|
const target = cmd.target.map((zone) => this.getters.expandZone(cmd.sheetId, zone));
|
|
28830
|
-
this.setBorders(cmd.sheetId, target, cmd.border
|
|
28887
|
+
this.setBorders(cmd.sheetId, target, cmd.border.position, cmd.border.color === ""
|
|
28888
|
+
? undefined
|
|
28889
|
+
: {
|
|
28890
|
+
style: cmd.border.style || DEFAULT_BORDER_DESC.style,
|
|
28891
|
+
color: cmd.border.color || DEFAULT_BORDER_DESC.color,
|
|
28892
|
+
});
|
|
28831
28893
|
}
|
|
28832
28894
|
break;
|
|
28833
28895
|
case "CLEAR_FORMATTING":
|
|
@@ -28916,6 +28978,23 @@ class BordersPlugin extends CorePlugin {
|
|
|
28916
28978
|
}
|
|
28917
28979
|
return border;
|
|
28918
28980
|
}
|
|
28981
|
+
getBordersColors(sheetId) {
|
|
28982
|
+
const colors = [];
|
|
28983
|
+
const sheetBorders = this.borders[sheetId];
|
|
28984
|
+
if (sheetBorders) {
|
|
28985
|
+
for (const borders of sheetBorders.filter(isDefined$1)) {
|
|
28986
|
+
for (const cellBorder of borders) {
|
|
28987
|
+
if (cellBorder?.horizontal) {
|
|
28988
|
+
colors.push(cellBorder.horizontal.color);
|
|
28989
|
+
}
|
|
28990
|
+
if (cellBorder?.vertical) {
|
|
28991
|
+
colors.push(cellBorder.vertical.color);
|
|
28992
|
+
}
|
|
28993
|
+
}
|
|
28994
|
+
}
|
|
28995
|
+
}
|
|
28996
|
+
return colors;
|
|
28997
|
+
}
|
|
28919
28998
|
// ---------------------------------------------------------------------------
|
|
28920
28999
|
// Private
|
|
28921
29000
|
// ---------------------------------------------------------------------------
|
|
@@ -29127,43 +29206,43 @@ class BordersPlugin extends CorePlugin {
|
|
|
29127
29206
|
* Set the borders of a zone by computing the borders to add from the given
|
|
29128
29207
|
* command
|
|
29129
29208
|
*/
|
|
29130
|
-
setBorders(sheetId, zones,
|
|
29131
|
-
if (
|
|
29209
|
+
setBorders(sheetId, zones, position, border) {
|
|
29210
|
+
if (position === "clear") {
|
|
29132
29211
|
return this.clearBorders(sheetId, zones);
|
|
29133
29212
|
}
|
|
29134
29213
|
for (let zone of zones) {
|
|
29135
|
-
if (
|
|
29214
|
+
if (position === "h" || position === "hv" || position === "all") {
|
|
29136
29215
|
for (let row = zone.top + 1; row <= zone.bottom; row++) {
|
|
29137
29216
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
29138
|
-
this.addBorder(sheetId, col, row, { top:
|
|
29217
|
+
this.addBorder(sheetId, col, row, { top: border });
|
|
29139
29218
|
}
|
|
29140
29219
|
}
|
|
29141
29220
|
}
|
|
29142
|
-
if (
|
|
29221
|
+
if (position === "v" || position === "hv" || position === "all") {
|
|
29143
29222
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
29144
29223
|
for (let col = zone.left + 1; col <= zone.right; col++) {
|
|
29145
|
-
this.addBorder(sheetId, col, row, { left:
|
|
29224
|
+
this.addBorder(sheetId, col, row, { left: border });
|
|
29146
29225
|
}
|
|
29147
29226
|
}
|
|
29148
29227
|
}
|
|
29149
|
-
if (
|
|
29228
|
+
if (position === "left" || position === "all" || position === "external") {
|
|
29150
29229
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
29151
|
-
this.addBorder(sheetId, zone.left, row, { left:
|
|
29230
|
+
this.addBorder(sheetId, zone.left, row, { left: border });
|
|
29152
29231
|
}
|
|
29153
29232
|
}
|
|
29154
|
-
if (
|
|
29233
|
+
if (position === "right" || position === "all" || position === "external") {
|
|
29155
29234
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
29156
|
-
this.addBorder(sheetId, zone.right + 1, row, { left:
|
|
29235
|
+
this.addBorder(sheetId, zone.right + 1, row, { left: border });
|
|
29157
29236
|
}
|
|
29158
29237
|
}
|
|
29159
|
-
if (
|
|
29238
|
+
if (position === "top" || position === "all" || position === "external") {
|
|
29160
29239
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
29161
|
-
this.addBorder(sheetId, col, zone.top, { top:
|
|
29240
|
+
this.addBorder(sheetId, col, zone.top, { top: border });
|
|
29162
29241
|
}
|
|
29163
29242
|
}
|
|
29164
|
-
if (
|
|
29243
|
+
if (position === "bottom" || position === "all" || position === "external") {
|
|
29165
29244
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
29166
|
-
this.addBorder(sheetId, col, zone.bottom + 1, { top:
|
|
29245
|
+
this.addBorder(sheetId, col, zone.bottom + 1, { top: border });
|
|
29167
29246
|
}
|
|
29168
29247
|
}
|
|
29169
29248
|
}
|
|
@@ -29177,16 +29256,22 @@ class BordersPlugin extends CorePlugin {
|
|
|
29177
29256
|
const bordersBottomRight = this.getCellBorder({ sheetId, col: right, row: bottom });
|
|
29178
29257
|
this.clearBorders(sheetId, [zone]);
|
|
29179
29258
|
if (bordersTopLeft?.top) {
|
|
29180
|
-
this.setBorders(sheetId, [{ ...zone, bottom: top }], "top");
|
|
29259
|
+
this.setBorders(sheetId, [{ ...zone, bottom: top }], "top", bordersTopLeft.top);
|
|
29181
29260
|
}
|
|
29182
29261
|
if (bordersTopLeft?.left) {
|
|
29183
|
-
this.setBorders(sheetId, [{ ...zone, right: left }], "left");
|
|
29262
|
+
this.setBorders(sheetId, [{ ...zone, right: left }], "left", bordersTopLeft.left);
|
|
29263
|
+
}
|
|
29264
|
+
if (bordersBottomRight?.bottom) {
|
|
29265
|
+
this.setBorders(sheetId, [{ ...zone, top: bottom }], "bottom", bordersBottomRight.bottom);
|
|
29184
29266
|
}
|
|
29185
|
-
if (
|
|
29186
|
-
this.setBorders(sheetId, [{ ...zone, top: bottom }], "bottom");
|
|
29267
|
+
else if (bordersTopLeft?.bottom) {
|
|
29268
|
+
this.setBorders(sheetId, [{ ...zone, top: bottom }], "bottom", bordersTopLeft.bottom);
|
|
29187
29269
|
}
|
|
29188
|
-
if (bordersBottomRight?.right
|
|
29189
|
-
this.setBorders(sheetId, [{ ...zone, left: right }], "right");
|
|
29270
|
+
if (bordersBottomRight?.right) {
|
|
29271
|
+
this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersBottomRight.right);
|
|
29272
|
+
}
|
|
29273
|
+
else if (bordersTopLeft?.right) {
|
|
29274
|
+
this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
|
|
29190
29275
|
}
|
|
29191
29276
|
}
|
|
29192
29277
|
// ---------------------------------------------------------------------------
|
|
@@ -32122,6 +32207,8 @@ class SheetPlugin extends CorePlugin {
|
|
|
32122
32207
|
"getSheetSize",
|
|
32123
32208
|
"getSheetZone",
|
|
32124
32209
|
"getPaneDivisions",
|
|
32210
|
+
"checkZonesExistInSheet",
|
|
32211
|
+
"getCommandZones",
|
|
32125
32212
|
];
|
|
32126
32213
|
sheetIdsMapName = {};
|
|
32127
32214
|
orderedSheetIds = [];
|
|
@@ -32131,7 +32218,7 @@ class SheetPlugin extends CorePlugin {
|
|
|
32131
32218
|
// Command Handling
|
|
32132
32219
|
// ---------------------------------------------------------------------------
|
|
32133
32220
|
allowDispatch(cmd) {
|
|
32134
|
-
const genericChecks = this.chainValidations(this.checkSheetExists, this.
|
|
32221
|
+
const genericChecks = this.chainValidations(this.checkSheetExists, this.checkZonesAreInSheet)(cmd);
|
|
32135
32222
|
if (genericChecks !== 0 /* CommandResult.Success */) {
|
|
32136
32223
|
return genericChecks;
|
|
32137
32224
|
}
|
|
@@ -32471,6 +32558,37 @@ class SheetPlugin extends CorePlugin {
|
|
|
32471
32558
|
.map(({ col, row }) => this.getCell({ sheetId, col, row }))
|
|
32472
32559
|
.every((cell) => !cell || cell.content === "");
|
|
32473
32560
|
}
|
|
32561
|
+
getCommandZones(cmd) {
|
|
32562
|
+
const zones = [];
|
|
32563
|
+
if ("zone" in cmd) {
|
|
32564
|
+
zones.push(cmd.zone);
|
|
32565
|
+
}
|
|
32566
|
+
if ("target" in cmd) {
|
|
32567
|
+
zones.push(...cmd.target);
|
|
32568
|
+
}
|
|
32569
|
+
if ("ranges" in cmd) {
|
|
32570
|
+
zones.push(...cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData).zone));
|
|
32571
|
+
}
|
|
32572
|
+
if ("col" in cmd && "row" in cmd) {
|
|
32573
|
+
zones.push({ top: cmd.row, left: cmd.col, bottom: cmd.row, right: cmd.col });
|
|
32574
|
+
}
|
|
32575
|
+
return zones;
|
|
32576
|
+
}
|
|
32577
|
+
/**
|
|
32578
|
+
* Check if zones in the command are well formed and
|
|
32579
|
+
* not outside the sheet.
|
|
32580
|
+
*/
|
|
32581
|
+
checkZonesExistInSheet(sheetId, zones) {
|
|
32582
|
+
if (!zones.every(isZoneValid))
|
|
32583
|
+
return 25 /* CommandResult.InvalidRange */;
|
|
32584
|
+
if (zones.length) {
|
|
32585
|
+
const sheetZone = this.getSheetZone(sheetId);
|
|
32586
|
+
return zones.every((zone) => isZoneInside(zone, sheetZone))
|
|
32587
|
+
? 0 /* CommandResult.Success */
|
|
32588
|
+
: 18 /* CommandResult.TargetOutOfSheet */;
|
|
32589
|
+
}
|
|
32590
|
+
return 0 /* CommandResult.Success */;
|
|
32591
|
+
}
|
|
32474
32592
|
updateCellPosition(cmd) {
|
|
32475
32593
|
const { sheetId, cellId, col, row } = cmd;
|
|
32476
32594
|
if (cellId) {
|
|
@@ -32919,9 +33037,6 @@ class SheetPlugin extends CorePlugin {
|
|
|
32919
33037
|
}
|
|
32920
33038
|
return { rowNumber, colNumber };
|
|
32921
33039
|
}
|
|
32922
|
-
// ----------------------------------------------------
|
|
32923
|
-
// HIDE / SHOW
|
|
32924
|
-
// ----------------------------------------------------
|
|
32925
33040
|
/**
|
|
32926
33041
|
* Check that any "sheetId" in the command matches an existing
|
|
32927
33042
|
* sheet.
|
|
@@ -32939,27 +33054,10 @@ class SheetPlugin extends CorePlugin {
|
|
|
32939
33054
|
* Check if zones in the command are well formed and
|
|
32940
33055
|
* not outside the sheet.
|
|
32941
33056
|
*/
|
|
32942
|
-
|
|
32943
|
-
|
|
32944
|
-
|
|
32945
|
-
|
|
32946
|
-
}
|
|
32947
|
-
if ("target" in cmd && Array.isArray(cmd.target)) {
|
|
32948
|
-
zones.push(...cmd.target);
|
|
32949
|
-
}
|
|
32950
|
-
if ("ranges" in cmd && Array.isArray(cmd.ranges)) {
|
|
32951
|
-
zones.push(...cmd.ranges.map((rangeData) => this.getters.getRangeFromRangeData(rangeData).zone));
|
|
32952
|
-
}
|
|
32953
|
-
if (!zones.every(isZoneValid)) {
|
|
32954
|
-
return 25 /* CommandResult.InvalidRange */;
|
|
32955
|
-
}
|
|
32956
|
-
else if (zones.length && "sheetId" in cmd) {
|
|
32957
|
-
const sheetZone = this.getSheetZone(cmd.sheetId);
|
|
32958
|
-
return zones.every((zone) => isZoneInside(zone, sheetZone))
|
|
32959
|
-
? 0 /* CommandResult.Success */
|
|
32960
|
-
: 18 /* CommandResult.TargetOutOfSheet */;
|
|
32961
|
-
}
|
|
32962
|
-
return 0 /* CommandResult.Success */;
|
|
33057
|
+
checkZonesAreInSheet(cmd) {
|
|
33058
|
+
if (!("sheetId" in cmd))
|
|
33059
|
+
return 0 /* CommandResult.Success */;
|
|
33060
|
+
return this.checkZonesExistInSheet(cmd.sheetId, this.getCommandZones(cmd));
|
|
32963
33061
|
}
|
|
32964
33062
|
}
|
|
32965
33063
|
|
|
@@ -33039,6 +33137,9 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
33039
33137
|
case "UPDATE_CHART":
|
|
33040
33138
|
case "CREATE_CHART":
|
|
33041
33139
|
case "ADD_CONDITIONAL_FORMAT":
|
|
33140
|
+
case "SET_BORDER":
|
|
33141
|
+
case "SET_ZONE_BORDERS":
|
|
33142
|
+
case "SET_FORMATTING":
|
|
33042
33143
|
this.shouldUpdateColors = true;
|
|
33043
33144
|
}
|
|
33044
33145
|
}
|
|
@@ -33053,8 +33154,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
33053
33154
|
getCustomColors() {
|
|
33054
33155
|
let usedColors = [];
|
|
33055
33156
|
for (const sheetId of this.getters.getSheetIds()) {
|
|
33056
|
-
|
|
33057
|
-
usedColors = usedColors.concat(this.getColorsFromCells(cells), this.getFormattingColors(sheetId), this.getChartColors(sheetId));
|
|
33157
|
+
usedColors = usedColors.concat(this.getColorsFromCells(sheetId), this.getFormattingColors(sheetId), this.getChartColors(sheetId));
|
|
33058
33158
|
}
|
|
33059
33159
|
return sortWithClusters([
|
|
33060
33160
|
...new Set(
|
|
@@ -33064,7 +33164,8 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
33064
33164
|
[...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
|
|
33065
33165
|
]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
|
|
33066
33166
|
}
|
|
33067
|
-
getColorsFromCells(
|
|
33167
|
+
getColorsFromCells(sheetId) {
|
|
33168
|
+
const cells = Object.values(this.getters.getCells(sheetId));
|
|
33068
33169
|
const colors = new Set();
|
|
33069
33170
|
for (const cell of cells) {
|
|
33070
33171
|
if (cell.style?.textColor) {
|
|
@@ -33074,6 +33175,9 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
33074
33175
|
colors.add(cell.style.fillColor);
|
|
33075
33176
|
}
|
|
33076
33177
|
}
|
|
33178
|
+
for (const color of this.getters.getBordersColors(sheetId)) {
|
|
33179
|
+
colors.add(color);
|
|
33180
|
+
}
|
|
33077
33181
|
return [...colors];
|
|
33078
33182
|
}
|
|
33079
33183
|
getFormattingColors(sheetId) {
|
|
@@ -33347,7 +33451,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
33347
33451
|
// magic "empty" value
|
|
33348
33452
|
// Returning {value: null} instead of undefined will ensure that we don't
|
|
33349
33453
|
// fall back on the default value of the argument provided to the formula's compute function
|
|
33350
|
-
return { value: null };
|
|
33454
|
+
return { value: null, format: cell?.format };
|
|
33351
33455
|
}
|
|
33352
33456
|
return getEvaluatedCell(cell);
|
|
33353
33457
|
}
|
|
@@ -33544,7 +33648,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
|
|
|
33544
33648
|
}
|
|
33545
33649
|
break;
|
|
33546
33650
|
case "PASTE_CONDITIONAL_FORMAT":
|
|
33547
|
-
this.pasteCf(cmd.
|
|
33651
|
+
this.pasteCf(cmd.originPosition, cmd.targetPosition, cmd.operation);
|
|
33548
33652
|
break;
|
|
33549
33653
|
}
|
|
33550
33654
|
}
|
|
@@ -36176,6 +36280,7 @@ function transformPositionWithMerge(cmd, executed) {
|
|
|
36176
36280
|
|
|
36177
36281
|
class Revision {
|
|
36178
36282
|
rootCommand;
|
|
36283
|
+
timestamp;
|
|
36179
36284
|
id;
|
|
36180
36285
|
clientId;
|
|
36181
36286
|
_commands = [];
|
|
@@ -36189,8 +36294,9 @@ class Revision {
|
|
|
36189
36294
|
* - clientId: Client who initiated the action
|
|
36190
36295
|
* - changes: List of changes applied on the state.
|
|
36191
36296
|
*/
|
|
36192
|
-
constructor(id, clientId, commands, rootCommand, changes) {
|
|
36297
|
+
constructor(id, clientId, commands, rootCommand, changes, timestamp) {
|
|
36193
36298
|
this.rootCommand = rootCommand;
|
|
36299
|
+
this.timestamp = timestamp;
|
|
36194
36300
|
this.id = id;
|
|
36195
36301
|
this.clientId = clientId;
|
|
36196
36302
|
this._commands = [...commands];
|
|
@@ -36262,7 +36368,7 @@ class Session extends EventBus {
|
|
|
36262
36368
|
save(rootCommand, commands, changes) {
|
|
36263
36369
|
if (!commands.length || !changes.length || !this.canApplyOptimisticUpdate())
|
|
36264
36370
|
return;
|
|
36265
|
-
const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes);
|
|
36371
|
+
const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes, Date.now());
|
|
36266
36372
|
this.revisions.append(revision.id, revision);
|
|
36267
36373
|
this.trigger("new-local-state-update", { id: revision.id });
|
|
36268
36374
|
this.sendUpdateMessage({
|
|
@@ -36313,13 +36419,9 @@ class Session extends EventBus {
|
|
|
36313
36419
|
}
|
|
36314
36420
|
loadInitialMessages(messages) {
|
|
36315
36421
|
this.isReplayingInitialRevisions = true;
|
|
36316
|
-
this.on("unexpected-revision-id", this, ({ revisionId }) => {
|
|
36317
|
-
throw new Error(`The spreadsheet could not be loaded. Revision ${revisionId} is corrupted.`);
|
|
36318
|
-
});
|
|
36319
36422
|
for (const message of messages) {
|
|
36320
36423
|
this.onMessageReceived(message);
|
|
36321
36424
|
}
|
|
36322
|
-
this.off("unexpected-revision-id", this);
|
|
36323
36425
|
this.isReplayingInitialRevisions = false;
|
|
36324
36426
|
}
|
|
36325
36427
|
/**
|
|
@@ -36405,6 +36507,10 @@ class Session extends EventBus {
|
|
|
36405
36507
|
onMessageReceived(message) {
|
|
36406
36508
|
if (this.isAlreadyProcessed(message))
|
|
36407
36509
|
return;
|
|
36510
|
+
if (this.isWrongServerRevisionId(message)) {
|
|
36511
|
+
this.trigger("unexpected-revision-id");
|
|
36512
|
+
return;
|
|
36513
|
+
}
|
|
36408
36514
|
switch (message.type) {
|
|
36409
36515
|
case "CLIENT_MOVED":
|
|
36410
36516
|
this.onClientMoved(message);
|
|
@@ -36431,12 +36537,8 @@ class Session extends EventBus {
|
|
|
36431
36537
|
});
|
|
36432
36538
|
break;
|
|
36433
36539
|
case "REMOTE_REVISION":
|
|
36434
|
-
|
|
36435
|
-
|
|
36436
|
-
return;
|
|
36437
|
-
}
|
|
36438
|
-
const { clientId, commands } = message;
|
|
36439
|
-
const revision = new Revision(message.nextRevisionId, clientId, commands, "REMOTE");
|
|
36540
|
+
const { clientId, commands, timestamp } = message;
|
|
36541
|
+
const revision = new Revision(message.nextRevisionId, clientId, commands, "REMOTE", undefined, timestamp);
|
|
36440
36542
|
if (revision.clientId !== this.clientId) {
|
|
36441
36543
|
this.revisions.insert(revision.id, revision, message.serverRevisionId);
|
|
36442
36544
|
const pendingCommands = this.pendingMessages
|
|
@@ -36449,7 +36551,7 @@ class Session extends EventBus {
|
|
|
36449
36551
|
}
|
|
36450
36552
|
break;
|
|
36451
36553
|
case "SNAPSHOT_CREATED": {
|
|
36452
|
-
const revision = new Revision(message.nextRevisionId, "server", [], "SNAPSHOT");
|
|
36554
|
+
const revision = new Revision(message.nextRevisionId, "server", [], "SNAPSHOT", undefined, Date.now());
|
|
36453
36555
|
this.revisions.insert(revision.id, revision, message.serverRevisionId);
|
|
36454
36556
|
this.dropPendingHistoryMessages();
|
|
36455
36557
|
this.trigger("snapshot");
|
|
@@ -36566,6 +36668,17 @@ class Session extends EventBus {
|
|
|
36566
36668
|
return false;
|
|
36567
36669
|
}
|
|
36568
36670
|
}
|
|
36671
|
+
isWrongServerRevisionId(message) {
|
|
36672
|
+
switch (message.type) {
|
|
36673
|
+
case "REMOTE_REVISION":
|
|
36674
|
+
case "REVISION_REDONE":
|
|
36675
|
+
case "REVISION_UNDONE":
|
|
36676
|
+
case "SNAPSHOT_CREATED":
|
|
36677
|
+
return message.serverRevisionId !== this.serverRevisionId;
|
|
36678
|
+
default:
|
|
36679
|
+
return false;
|
|
36680
|
+
}
|
|
36681
|
+
}
|
|
36569
36682
|
dropPendingHistoryMessages() {
|
|
36570
36683
|
this.waitingUndoRedoAck = false;
|
|
36571
36684
|
this.pendingMessages = this.pendingMessages.filter(({ type }) => type !== "REVISION_REDONE" && type !== "REVISION_UNDONE");
|
|
@@ -37281,7 +37394,7 @@ class RendererPlugin extends UIPlugin {
|
|
|
37281
37394
|
}
|
|
37282
37395
|
}
|
|
37283
37396
|
drawBorders(renderingContext) {
|
|
37284
|
-
const { ctx
|
|
37397
|
+
const { ctx } = renderingContext;
|
|
37285
37398
|
for (let box of this.boxes) {
|
|
37286
37399
|
const border = box.border;
|
|
37287
37400
|
if (border) {
|
|
@@ -37300,13 +37413,66 @@ class RendererPlugin extends UIPlugin {
|
|
|
37300
37413
|
}
|
|
37301
37414
|
}
|
|
37302
37415
|
}
|
|
37303
|
-
|
|
37416
|
+
/**
|
|
37417
|
+
* Following https://usefulangle.com/post/17/html5-canvas-drawing-1px-crisp-straight-lines,
|
|
37418
|
+
* we need to make sure that a "single" pixel line is drawn on a "half" pixel coordinate,
|
|
37419
|
+
* while a "double" pixel line is drawn on a "full" pixel coordinate. As, in the rendering
|
|
37420
|
+
* process, we always had 0.5 before rendering line (to make sure it is drawn on a "half"
|
|
37421
|
+
* pixel), we need to correct this behavior for the "medium" and the "dotted" styles, as
|
|
37422
|
+
* they are drawing a two pixels width line.
|
|
37423
|
+
* We also adapt here the coordinates of the line to make sure corner are correctly drawn,
|
|
37424
|
+
* avoiding a "round corners" effect. This is done by subtracting 1 pixel to the origin of
|
|
37425
|
+
* each line and adding 1 pixel to the end of each line (depending on the direction of the
|
|
37426
|
+
* line).
|
|
37427
|
+
*/
|
|
37428
|
+
function drawBorder({ style, color }, x1, y1, x2, y2) {
|
|
37304
37429
|
ctx.strokeStyle = color;
|
|
37305
|
-
|
|
37430
|
+
switch (style) {
|
|
37431
|
+
case "medium":
|
|
37432
|
+
ctx.lineWidth = 2;
|
|
37433
|
+
x1 += y1 === y2 ? -0.5 : 0.5;
|
|
37434
|
+
x2 += y1 === y2 ? 1.5 : 0.5;
|
|
37435
|
+
y1 += x1 === x2 ? -0.5 : 0.5;
|
|
37436
|
+
y2 += x1 === x2 ? 1.5 : 0.5;
|
|
37437
|
+
break;
|
|
37438
|
+
case "thick":
|
|
37439
|
+
ctx.lineWidth = 3;
|
|
37440
|
+
if (y1 === y2) {
|
|
37441
|
+
x1--;
|
|
37442
|
+
x2++;
|
|
37443
|
+
}
|
|
37444
|
+
if (x1 === x2) {
|
|
37445
|
+
y1--;
|
|
37446
|
+
y2++;
|
|
37447
|
+
}
|
|
37448
|
+
break;
|
|
37449
|
+
case "dashed":
|
|
37450
|
+
ctx.lineWidth = 1;
|
|
37451
|
+
ctx.setLineDash([1, 3]);
|
|
37452
|
+
break;
|
|
37453
|
+
case "dotted":
|
|
37454
|
+
ctx.lineWidth = 1;
|
|
37455
|
+
if (y1 === y2) {
|
|
37456
|
+
x1 += 0.5;
|
|
37457
|
+
x2 += 0.5;
|
|
37458
|
+
}
|
|
37459
|
+
if (x1 === x2) {
|
|
37460
|
+
y1 += 0.5;
|
|
37461
|
+
y2 += 0.5;
|
|
37462
|
+
}
|
|
37463
|
+
ctx.setLineDash([1, 1]);
|
|
37464
|
+
break;
|
|
37465
|
+
case "thin":
|
|
37466
|
+
default:
|
|
37467
|
+
ctx.lineWidth = 1;
|
|
37468
|
+
break;
|
|
37469
|
+
}
|
|
37306
37470
|
ctx.beginPath();
|
|
37307
37471
|
ctx.moveTo(x1, y1);
|
|
37308
37472
|
ctx.lineTo(x2, y2);
|
|
37309
37473
|
ctx.stroke();
|
|
37474
|
+
ctx.lineWidth = 1;
|
|
37475
|
+
ctx.setLineDash([]);
|
|
37310
37476
|
}
|
|
37311
37477
|
}
|
|
37312
37478
|
drawTexts(renderingContext) {
|
|
@@ -37784,6 +37950,9 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
37784
37950
|
activeSheet;
|
|
37785
37951
|
willAddNewRange = false;
|
|
37786
37952
|
constructor(config, initialRanges, inputHasSingleRange) {
|
|
37953
|
+
if (inputHasSingleRange && initialRanges.length > 1) {
|
|
37954
|
+
throw new Error("Input with a single range cannot be instantiated with several range references.");
|
|
37955
|
+
}
|
|
37787
37956
|
super(config);
|
|
37788
37957
|
this.inputHasSingleRange = inputHasSingleRange;
|
|
37789
37958
|
this.insertNewRange(0, initialRanges);
|
|
@@ -37803,6 +37972,11 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
37803
37972
|
return 30 /* CommandResult.MaximumRangesReached */;
|
|
37804
37973
|
}
|
|
37805
37974
|
break;
|
|
37975
|
+
case "CHANGE_RANGE":
|
|
37976
|
+
if (this.inputHasSingleRange && cmd.value.split(",").length > 1) {
|
|
37977
|
+
return 30 /* CommandResult.MaximumRangesReached */;
|
|
37978
|
+
}
|
|
37979
|
+
break;
|
|
37806
37980
|
}
|
|
37807
37981
|
return 0 /* CommandResult.Success */;
|
|
37808
37982
|
}
|
|
@@ -38459,18 +38633,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
38459
38633
|
// Command Handling
|
|
38460
38634
|
// ---------------------------------------------------------------------------
|
|
38461
38635
|
allowDispatch(cmd) {
|
|
38462
|
-
|
|
38463
|
-
case "AUTORESIZE_ROWS":
|
|
38464
|
-
case "AUTORESIZE_COLUMNS":
|
|
38465
|
-
try {
|
|
38466
|
-
this.getters.getSheet(cmd.sheetId);
|
|
38467
|
-
break;
|
|
38468
|
-
}
|
|
38469
|
-
catch (error) {
|
|
38470
|
-
return 27 /* CommandResult.InvalidSheetId */;
|
|
38471
|
-
}
|
|
38472
|
-
}
|
|
38473
|
-
return 0 /* CommandResult.Success */;
|
|
38636
|
+
return this.chainValidations(this.checkSheetExists, this.checkZonesAreInSheet)(cmd);
|
|
38474
38637
|
}
|
|
38475
38638
|
handle(cmd) {
|
|
38476
38639
|
switch (cmd.type) {
|
|
@@ -38670,6 +38833,31 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
38670
38833
|
splitWord.push(wordPart);
|
|
38671
38834
|
return splitWord;
|
|
38672
38835
|
}
|
|
38836
|
+
/**
|
|
38837
|
+
* Check that any "sheetId" in the command matches an existing
|
|
38838
|
+
* sheet.
|
|
38839
|
+
*/
|
|
38840
|
+
checkSheetExists(cmd) {
|
|
38841
|
+
if ("sheetId" in cmd && this.getters.tryGetSheet(cmd.sheetId) === undefined) {
|
|
38842
|
+
return 27 /* CommandResult.InvalidSheetId */;
|
|
38843
|
+
}
|
|
38844
|
+
return 0 /* CommandResult.Success */;
|
|
38845
|
+
}
|
|
38846
|
+
/**
|
|
38847
|
+
* Check if zones in the command are well formed and
|
|
38848
|
+
* not outside the sheet.
|
|
38849
|
+
*/
|
|
38850
|
+
checkZonesAreInSheet(cmd) {
|
|
38851
|
+
const sheetId = "sheetId" in cmd ? cmd.sheetId : this.getters.tryGetActiveSheetId();
|
|
38852
|
+
const zones = this.getters.getCommandZones(cmd);
|
|
38853
|
+
if (!sheetId && zones.length > 0) {
|
|
38854
|
+
return 92 /* CommandResult.NoActiveSheet */;
|
|
38855
|
+
}
|
|
38856
|
+
if (sheetId && zones.length > 0) {
|
|
38857
|
+
return this.getters.checkZonesExistInSheet(sheetId, zones);
|
|
38858
|
+
}
|
|
38859
|
+
return 0 /* CommandResult.Success */;
|
|
38860
|
+
}
|
|
38673
38861
|
}
|
|
38674
38862
|
|
|
38675
38863
|
const genericRepeatsTransforms = [
|
|
@@ -39494,8 +39682,8 @@ class ClipboardCellsState extends ClipboardCellsAbstractState {
|
|
|
39494
39682
|
this.pasteCell(origin, position, this.operation, clipboardOptions);
|
|
39495
39683
|
if (shouldPasteCF) {
|
|
39496
39684
|
this.dispatch("PASTE_CONDITIONAL_FORMAT", {
|
|
39497
|
-
|
|
39498
|
-
|
|
39685
|
+
originPosition: origin.position,
|
|
39686
|
+
targetPosition: position,
|
|
39499
39687
|
operation: this.operation,
|
|
39500
39688
|
});
|
|
39501
39689
|
}
|
|
@@ -39886,7 +40074,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
39886
40074
|
allowDispatch(cmd) {
|
|
39887
40075
|
switch (cmd.type) {
|
|
39888
40076
|
case "CUT":
|
|
39889
|
-
const zones = cmd.
|
|
40077
|
+
const zones = cmd.cutTarget || this.getters.getSelectedZones();
|
|
39890
40078
|
const state = this.getClipboardState(zones, cmd.type);
|
|
39891
40079
|
return state.isCutAllowed(zones);
|
|
39892
40080
|
case "PASTE":
|
|
@@ -39916,7 +40104,7 @@ class ClipboardPlugin extends UIPlugin {
|
|
|
39916
40104
|
switch (cmd.type) {
|
|
39917
40105
|
case "COPY":
|
|
39918
40106
|
case "CUT":
|
|
39919
|
-
const zones = ("
|
|
40107
|
+
const zones = ("cutTarget" in cmd && cmd.cutTarget) || this.getters.getSelectedZones();
|
|
39920
40108
|
this.state = this.getClipboardState(zones, cmd.type);
|
|
39921
40109
|
this.status = "visible";
|
|
39922
40110
|
break;
|
|
@@ -40872,6 +41060,7 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
40872
41060
|
"isSelected",
|
|
40873
41061
|
"isSingleColSelected",
|
|
40874
41062
|
"getElementsFromSelection",
|
|
41063
|
+
"tryGetActiveSheetId",
|
|
40875
41064
|
];
|
|
40876
41065
|
gridSelection = {
|
|
40877
41066
|
anchor: {
|
|
@@ -41087,6 +41276,9 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
41087
41276
|
getActiveSheetId() {
|
|
41088
41277
|
return this.activeSheet.id;
|
|
41089
41278
|
}
|
|
41279
|
+
tryGetActiveSheetId() {
|
|
41280
|
+
return this.activeSheet?.id;
|
|
41281
|
+
}
|
|
41090
41282
|
getActiveCell() {
|
|
41091
41283
|
return this.getters.getEvaluatedCell(this.getActivePosition());
|
|
41092
41284
|
}
|
|
@@ -41289,7 +41481,8 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
41289
41481
|
},
|
|
41290
41482
|
zone: selectedZone,
|
|
41291
41483
|
};
|
|
41292
|
-
this.
|
|
41484
|
+
const selections = this.gridSelection.zones.map((zone) => updateSelectionOnDeletion(zone, "left", [...cmd.elements]));
|
|
41485
|
+
this.setSelectionMixin(anchor, selections);
|
|
41293
41486
|
}
|
|
41294
41487
|
onRowsRemoved(cmd) {
|
|
41295
41488
|
const { cell, zone } = this.gridSelection.anchor;
|
|
@@ -41303,13 +41496,18 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
41303
41496
|
},
|
|
41304
41497
|
zone: selectedZone,
|
|
41305
41498
|
};
|
|
41306
|
-
this.
|
|
41499
|
+
const selections = this.gridSelection.zones.map((zone) => updateSelectionOnDeletion(zone, "top", [...cmd.elements]));
|
|
41500
|
+
this.setSelectionMixin(anchor, selections);
|
|
41307
41501
|
}
|
|
41308
41502
|
onAddElements(cmd) {
|
|
41309
|
-
const
|
|
41310
|
-
const
|
|
41311
|
-
const
|
|
41312
|
-
|
|
41503
|
+
const start = cmd.dimension === "COL" ? "left" : "top";
|
|
41504
|
+
const anchorZone = updateSelectionOnInsertion(this.gridSelection.anchor.zone, start, cmd.base, cmd.position, cmd.quantity);
|
|
41505
|
+
const selection = this.gridSelection.zones.map((zone) => updateSelectionOnInsertion(zone, start, cmd.base, cmd.position, cmd.quantity));
|
|
41506
|
+
const anchor = {
|
|
41507
|
+
cell: { col: anchorZone.left, row: anchorZone.top },
|
|
41508
|
+
zone: anchorZone,
|
|
41509
|
+
};
|
|
41510
|
+
this.setSelectionMixin(anchor, selection);
|
|
41313
41511
|
}
|
|
41314
41512
|
onMoveElements(cmd) {
|
|
41315
41513
|
const thickness = cmd.elements.length;
|
|
@@ -41327,7 +41525,7 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
41327
41525
|
const deltaCol = isBasedBefore && isCol ? thickness : 0;
|
|
41328
41526
|
const deltaRow = isBasedBefore && !isCol ? thickness : 0;
|
|
41329
41527
|
this.dispatch("CUT", {
|
|
41330
|
-
|
|
41528
|
+
cutTarget: [
|
|
41331
41529
|
{
|
|
41332
41530
|
left: isCol ? start + deltaCol : 0,
|
|
41333
41531
|
right: isCol ? end + deltaCol : this.getters.getNumberCols(cmd.sheetId) - 1,
|
|
@@ -42555,7 +42753,6 @@ css /* scss */ `
|
|
|
42555
42753
|
color: dimgrey;
|
|
42556
42754
|
}
|
|
42557
42755
|
.o-sidePanelClose {
|
|
42558
|
-
font-size: 1.5rem;
|
|
42559
42756
|
padding: 5px 10px;
|
|
42560
42757
|
cursor: pointer;
|
|
42561
42758
|
&:hover {
|
|
@@ -42740,7 +42937,6 @@ css /* scss */ `
|
|
|
42740
42937
|
justify-content: center;
|
|
42741
42938
|
align-items: center;
|
|
42742
42939
|
margin: 2px;
|
|
42743
|
-
padding: 0px 3px;
|
|
42744
42940
|
border-radius: 2px;
|
|
42745
42941
|
min-width: 20px;
|
|
42746
42942
|
}
|
|
@@ -42797,7 +42993,228 @@ ActionButton.props = {
|
|
|
42797
42993
|
onClick: { type: Function, optional: true },
|
|
42798
42994
|
};
|
|
42799
42995
|
|
|
42996
|
+
/**
|
|
42997
|
+
* List the available borders positions and the corresponding icons.
|
|
42998
|
+
* The structure of this array is defined to match the order/lines we want
|
|
42999
|
+
* to display in the topbar's border tool.
|
|
43000
|
+
*/
|
|
43001
|
+
const BORDER_POSITIONS = [
|
|
43002
|
+
[
|
|
43003
|
+
["all", "o-spreadsheet-Icon.BORDERS"],
|
|
43004
|
+
["hv", "o-spreadsheet-Icon.BORDER_HV"],
|
|
43005
|
+
["h", "o-spreadsheet-Icon.BORDER_H"],
|
|
43006
|
+
["v", "o-spreadsheet-Icon.BORDER_V"],
|
|
43007
|
+
["external", "o-spreadsheet-Icon.BORDER_EXTERNAL"],
|
|
43008
|
+
],
|
|
43009
|
+
[
|
|
43010
|
+
["left", "o-spreadsheet-Icon.BORDER_LEFT"],
|
|
43011
|
+
["top", "o-spreadsheet-Icon.BORDER_TOP"],
|
|
43012
|
+
["right", "o-spreadsheet-Icon.BORDER_RIGHT"],
|
|
43013
|
+
["bottom", "o-spreadsheet-Icon.BORDER_BOTTOM"],
|
|
43014
|
+
["clear", "o-spreadsheet-Icon.BORDER_CLEAR"],
|
|
43015
|
+
],
|
|
43016
|
+
];
|
|
43017
|
+
// -----------------------------------------------------------------------------
|
|
43018
|
+
// Border Editor
|
|
43019
|
+
// -----------------------------------------------------------------------------
|
|
43020
|
+
css /* scss */ `
|
|
43021
|
+
.o-border-selector {
|
|
43022
|
+
padding: 4px;
|
|
43023
|
+
}
|
|
43024
|
+
.o-divider {
|
|
43025
|
+
border-right: 1px solid #e0e2e4;
|
|
43026
|
+
margin: 0 6px;
|
|
43027
|
+
}
|
|
43028
|
+
.o-border-selector-section {
|
|
43029
|
+
.o-dropdown-line {
|
|
43030
|
+
height: 30px;
|
|
43031
|
+
margin: 1px;
|
|
43032
|
+
.o-line-item {
|
|
43033
|
+
padding: 4px;
|
|
43034
|
+
width: 18px;
|
|
43035
|
+
height: 18px;
|
|
43036
|
+
}
|
|
43037
|
+
}
|
|
43038
|
+
.o-border-style-tool {
|
|
43039
|
+
padding: 0px 3px;
|
|
43040
|
+
margin: 2px;
|
|
43041
|
+
height: 25px;
|
|
43042
|
+
}
|
|
43043
|
+
}
|
|
43044
|
+
.o-style-preview {
|
|
43045
|
+
margin: 7px 5px 7px 5px;
|
|
43046
|
+
width: 60px;
|
|
43047
|
+
height: 5px;
|
|
43048
|
+
}
|
|
43049
|
+
.o-style-thin {
|
|
43050
|
+
border-bottom: 1px solid #000000;
|
|
43051
|
+
}
|
|
43052
|
+
.o-style-medium {
|
|
43053
|
+
border-bottom: 2px solid #000000;
|
|
43054
|
+
}
|
|
43055
|
+
.o-style-thick {
|
|
43056
|
+
border-bottom: 3px solid #000000;
|
|
43057
|
+
}
|
|
43058
|
+
.o-style-dashed {
|
|
43059
|
+
border-bottom: 1px dashed #000000;
|
|
43060
|
+
}
|
|
43061
|
+
.o-style-dotted {
|
|
43062
|
+
border-bottom: 1px dotted #000000;
|
|
43063
|
+
}
|
|
43064
|
+
.o-dropdown-border-type {
|
|
43065
|
+
&:not(.o-disabled):not(.active):hover {
|
|
43066
|
+
background-color: ${BG_HOVER_COLOR};
|
|
43067
|
+
}
|
|
43068
|
+
}
|
|
43069
|
+
.o-dropdown-border-check {
|
|
43070
|
+
width: 20px;
|
|
43071
|
+
font-size: 12px;
|
|
43072
|
+
}
|
|
43073
|
+
.o-border-style-dropdown {
|
|
43074
|
+
background: #ffffff;
|
|
43075
|
+
padding: 4px;
|
|
43076
|
+
.o-dropdown-line {
|
|
43077
|
+
.o-line-item.active {
|
|
43078
|
+
background-color: rgba(0, 0, 0, 0.2);
|
|
43079
|
+
}
|
|
43080
|
+
}
|
|
43081
|
+
}
|
|
43082
|
+
.o-border-picker-button {
|
|
43083
|
+
padding: 0px !important;
|
|
43084
|
+
margin: 5px 0px 0px 0px !important;
|
|
43085
|
+
height: 25px !important;
|
|
43086
|
+
}
|
|
43087
|
+
`;
|
|
43088
|
+
class BorderEditor extends owl.Component {
|
|
43089
|
+
static template = "o-spreadsheet-BorderEditor";
|
|
43090
|
+
static components = { ColorPickerWidget, Popover };
|
|
43091
|
+
BORDER_POSITIONS = BORDER_POSITIONS;
|
|
43092
|
+
lineStyleButtonRef = owl.useRef("lineStyleButton");
|
|
43093
|
+
borderStyles = borderStyles;
|
|
43094
|
+
state = owl.useState({
|
|
43095
|
+
activeTool: undefined,
|
|
43096
|
+
});
|
|
43097
|
+
toggleDropdownTool(tool) {
|
|
43098
|
+
const isOpen = this.state.activeTool === tool;
|
|
43099
|
+
this.state.activeTool = isOpen ? undefined : tool;
|
|
43100
|
+
}
|
|
43101
|
+
closeDropdown() {
|
|
43102
|
+
this.state.activeTool = undefined;
|
|
43103
|
+
}
|
|
43104
|
+
setBorderPosition(position) {
|
|
43105
|
+
this.props.onBorderPositionPicked(position);
|
|
43106
|
+
this.closeDropdown();
|
|
43107
|
+
}
|
|
43108
|
+
setBorderColor(color) {
|
|
43109
|
+
this.props.onBorderColorPicked(color);
|
|
43110
|
+
this.closeDropdown();
|
|
43111
|
+
}
|
|
43112
|
+
setBorderStyle(style) {
|
|
43113
|
+
this.props.onBorderStylePicked(style);
|
|
43114
|
+
this.closeDropdown();
|
|
43115
|
+
}
|
|
43116
|
+
get lineStylePickerPopoverProps() {
|
|
43117
|
+
return {
|
|
43118
|
+
anchorRect: this.lineStylePickerAnchorRect,
|
|
43119
|
+
positioning: "BottomLeft",
|
|
43120
|
+
verticalOffset: 0,
|
|
43121
|
+
};
|
|
43122
|
+
}
|
|
43123
|
+
get popoverProps() {
|
|
43124
|
+
return {
|
|
43125
|
+
anchorRect: this.props.anchorRect,
|
|
43126
|
+
maxHeight: this.props.maxHeight,
|
|
43127
|
+
positioning: "BottomLeft",
|
|
43128
|
+
verticalOffset: 0,
|
|
43129
|
+
};
|
|
43130
|
+
}
|
|
43131
|
+
get lineStylePickerAnchorRect() {
|
|
43132
|
+
const button = this.lineStyleButtonRef.el;
|
|
43133
|
+
if (button === null) {
|
|
43134
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
43135
|
+
}
|
|
43136
|
+
const buttonRect = button.getBoundingClientRect();
|
|
43137
|
+
return {
|
|
43138
|
+
x: buttonRect.x,
|
|
43139
|
+
y: buttonRect.y,
|
|
43140
|
+
width: buttonRect.width,
|
|
43141
|
+
height: buttonRect.height,
|
|
43142
|
+
};
|
|
43143
|
+
}
|
|
43144
|
+
}
|
|
43145
|
+
BorderEditor.props = {
|
|
43146
|
+
class: { type: String, optional: true },
|
|
43147
|
+
currentBorderColor: { type: String, optional: false },
|
|
43148
|
+
currentBorderStyle: { type: String, optional: false },
|
|
43149
|
+
currentBorderPosition: { type: String, optional: true },
|
|
43150
|
+
onBorderColorPicked: Function,
|
|
43151
|
+
onBorderStylePicked: Function,
|
|
43152
|
+
onBorderPositionPicked: Function,
|
|
43153
|
+
maxHeight: { type: Number, optional: true },
|
|
43154
|
+
anchorRect: Object,
|
|
43155
|
+
};
|
|
43156
|
+
|
|
43157
|
+
class BorderEditorWidget extends owl.Component {
|
|
43158
|
+
static template = "o-spreadsheet-BorderEditorWidget";
|
|
43159
|
+
static components = { BorderEditor };
|
|
43160
|
+
borderEditorButtonRef = owl.useRef("borderEditorButton");
|
|
43161
|
+
state = owl.useState({
|
|
43162
|
+
currentColor: DEFAULT_BORDER_DESC.color,
|
|
43163
|
+
currentStyle: DEFAULT_BORDER_DESC.style,
|
|
43164
|
+
currentPosition: undefined,
|
|
43165
|
+
});
|
|
43166
|
+
get borderEditorAnchorRect() {
|
|
43167
|
+
const button = this.borderEditorButtonRef.el;
|
|
43168
|
+
const buttonRect = button.getBoundingClientRect();
|
|
43169
|
+
return {
|
|
43170
|
+
x: buttonRect.x,
|
|
43171
|
+
y: buttonRect.y,
|
|
43172
|
+
width: buttonRect.width,
|
|
43173
|
+
height: buttonRect.height,
|
|
43174
|
+
};
|
|
43175
|
+
}
|
|
43176
|
+
onBorderPositionPicked(position) {
|
|
43177
|
+
this.state.currentPosition = position;
|
|
43178
|
+
this.updateBorder();
|
|
43179
|
+
}
|
|
43180
|
+
onBorderColorPicked(color) {
|
|
43181
|
+
this.state.currentColor = color;
|
|
43182
|
+
this.updateBorder();
|
|
43183
|
+
}
|
|
43184
|
+
onBorderStylePicked(style) {
|
|
43185
|
+
this.state.currentStyle = style;
|
|
43186
|
+
this.updateBorder();
|
|
43187
|
+
}
|
|
43188
|
+
updateBorder() {
|
|
43189
|
+
if (this.state.currentPosition === undefined) {
|
|
43190
|
+
return;
|
|
43191
|
+
}
|
|
43192
|
+
this.env.model.dispatch("SET_ZONE_BORDERS", {
|
|
43193
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
43194
|
+
target: this.env.model.getters.getSelectedZones(),
|
|
43195
|
+
border: {
|
|
43196
|
+
position: this.state.currentPosition,
|
|
43197
|
+
color: this.state.currentColor,
|
|
43198
|
+
style: this.state.currentStyle,
|
|
43199
|
+
},
|
|
43200
|
+
});
|
|
43201
|
+
}
|
|
43202
|
+
}
|
|
43203
|
+
BorderEditorWidget.props = {
|
|
43204
|
+
toggleBorderEditor: Function,
|
|
43205
|
+
showBorderEditor: Boolean,
|
|
43206
|
+
disabled: { type: Boolean, optional: true },
|
|
43207
|
+
dropdownMaxHeight: { type: Number, optional: true },
|
|
43208
|
+
class: { type: String, optional: true },
|
|
43209
|
+
};
|
|
43210
|
+
|
|
42800
43211
|
const COMPOSER_MAX_HEIGHT = 100;
|
|
43212
|
+
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
43213
|
+
const FX_SVG = /*xml*/ `
|
|
43214
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 121.8 122.9' width='16' height='16' focusable='false'>
|
|
43215
|
+
<path d='m28 34-4 5v2h10l-6 40c-4 22-6 28-7 30-2 2-3 3-5 3-3 0-7-2-9-4H4c-2 2-4 4-4 7s4 6 8 6 9-2 15-8c8-7 13-17 18-39l7-35 13-1 3-6H49c4-23 7-27 11-27 2 0 5 2 8 6h4c1-1 4-4 4-7 0-2-3-6-9-6-5 0-13 4-20 10-6 7-9 14-11 24h-8zm41 16c4-5 7-7 8-7s2 1 5 9l3 12c-7 11-12 17-16 17l-3-1-2-1c-3 0-6 3-6 7s3 7 7 7c6 0 12-6 22-23l3 10c3 9 6 13 10 13 5 0 11-4 18-15l-3-4c-4 6-7 8-8 8-2 0-4-3-6-10l-5-15 8-10 6-4 3 1 3 2c2 0 6-3 6-7s-2-7-6-7c-6 0-11 5-21 20l-2-6c-3-9-5-14-9-14-5 0-12 6-18 15l3 3z' fill='#BDBDBD'/>
|
|
43216
|
+
</svg>
|
|
43217
|
+
`;
|
|
42801
43218
|
css /* scss */ `
|
|
42802
43219
|
.o-topbar-composer {
|
|
42803
43220
|
height: fit-content;
|
|
@@ -42805,9 +43222,10 @@ css /* scss */ `
|
|
|
42805
43222
|
border: 1px solid;
|
|
42806
43223
|
z-index: ${ComponentsImportance.TopBarComposer};
|
|
42807
43224
|
|
|
42808
|
-
.o-composer:empty:not(:focus)::before {
|
|
42809
|
-
|
|
42810
|
-
|
|
43225
|
+
.o-composer:empty:not(:focus):not(.active)::before {
|
|
43226
|
+
content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
|
|
43227
|
+
position: relative;
|
|
43228
|
+
top: 20%;
|
|
42811
43229
|
}
|
|
42812
43230
|
}
|
|
42813
43231
|
`;
|
|
@@ -42930,11 +43348,6 @@ FontSizeEditor.props = {
|
|
|
42930
43348
|
dropdownStyle: String,
|
|
42931
43349
|
};
|
|
42932
43350
|
|
|
42933
|
-
// If we ever change these colors, make sure the filter tool stays green to match the icon in the grid
|
|
42934
|
-
const ACTIVE_BG_COLOR = BACKGROUND_HEADER_FILTER_COLOR;
|
|
42935
|
-
const ACTIVE_FONT_COLOR = FILTERS_COLOR;
|
|
42936
|
-
const HOVERED_BG_COLOR = BG_HOVER_COLOR;
|
|
42937
|
-
const HOVERED_FONT_COLOR = "#000";
|
|
42938
43351
|
// -----------------------------------------------------------------------------
|
|
42939
43352
|
// TopBar
|
|
42940
43353
|
// -----------------------------------------------------------------------------
|
|
@@ -42944,27 +43357,6 @@ css /* scss */ `
|
|
|
42944
43357
|
font-size: 13px;
|
|
42945
43358
|
font-weight: 500;
|
|
42946
43359
|
|
|
42947
|
-
.o-topbar-hoverable {
|
|
42948
|
-
cursor: pointer;
|
|
42949
|
-
.o-icon {
|
|
42950
|
-
color: ${ICONS_COLOR};
|
|
42951
|
-
}
|
|
42952
|
-
&:not(.o-disabled):not(.active):hover {
|
|
42953
|
-
background-color: ${HOVERED_BG_COLOR};
|
|
42954
|
-
color: ${HOVERED_FONT_COLOR};
|
|
42955
|
-
.o-icon {
|
|
42956
|
-
color: ${HOVERED_FONT_COLOR};
|
|
42957
|
-
}
|
|
42958
|
-
}
|
|
42959
|
-
&.active {
|
|
42960
|
-
background-color: ${ACTIVE_BG_COLOR};
|
|
42961
|
-
color: ${ACTIVE_FONT_COLOR};
|
|
42962
|
-
.o-icon {
|
|
42963
|
-
color: ${ACTIVE_FONT_COLOR};
|
|
42964
|
-
}
|
|
42965
|
-
}
|
|
42966
|
-
}
|
|
42967
|
-
|
|
42968
43360
|
.o-topbar-top {
|
|
42969
43361
|
border-bottom: 1px solid ${SEPARATOR_COLOR};
|
|
42970
43362
|
padding: 2px 10px;
|
|
@@ -42974,6 +43366,11 @@ css /* scss */ `
|
|
|
42974
43366
|
.o-topbar-menu {
|
|
42975
43367
|
padding: 4px 6px;
|
|
42976
43368
|
margin: 0 2px;
|
|
43369
|
+
|
|
43370
|
+
&.active {
|
|
43371
|
+
background-color: ${BG_HOVER_COLOR};
|
|
43372
|
+
color: #000;
|
|
43373
|
+
}
|
|
42977
43374
|
}
|
|
42978
43375
|
}
|
|
42979
43376
|
}
|
|
@@ -43051,6 +43448,7 @@ class TopBar extends owl.Component {
|
|
|
43051
43448
|
TopBarComposer,
|
|
43052
43449
|
FontSizeEditor,
|
|
43053
43450
|
ActionButton,
|
|
43451
|
+
BorderEditorWidget,
|
|
43054
43452
|
};
|
|
43055
43453
|
state = owl.useState({
|
|
43056
43454
|
menuState: { isOpen: false, position: null, menuItems: [] },
|
|
@@ -43126,7 +43524,9 @@ class TopBar extends owl.Component {
|
|
|
43126
43524
|
this.state.activeTool = "";
|
|
43127
43525
|
this.state.menuState.isOpen = true;
|
|
43128
43526
|
this.state.menuState.position = { x: left, y: top + height };
|
|
43129
|
-
this.state.menuState.menuItems = menu
|
|
43527
|
+
this.state.menuState.menuItems = menu
|
|
43528
|
+
.children(this.env)
|
|
43529
|
+
.sort((a, b) => a.sequence - b.sequence);
|
|
43130
43530
|
this.state.menuState.parentMenu = menu;
|
|
43131
43531
|
this.isSelectingMenu = true;
|
|
43132
43532
|
this.openedEl = ev.target;
|
|
@@ -43212,6 +43612,11 @@ class WebClipboardWrapper {
|
|
|
43212
43612
|
}
|
|
43213
43613
|
}
|
|
43214
43614
|
|
|
43615
|
+
// If we ever change these colors, make sure the filter tool stays green to match the icon in the grid
|
|
43616
|
+
const ACTIVE_BG_COLOR = BACKGROUND_HEADER_FILTER_COLOR;
|
|
43617
|
+
const ACTIVE_FONT_COLOR = FILTERS_COLOR;
|
|
43618
|
+
const HOVERED_BG_COLOR = BG_HOVER_COLOR;
|
|
43619
|
+
const HOVERED_FONT_COLOR = "#000";
|
|
43215
43620
|
css /* scss */ `
|
|
43216
43621
|
.o-spreadsheet {
|
|
43217
43622
|
position: relative;
|
|
@@ -43244,6 +43649,27 @@ css /* scss */ `
|
|
|
43244
43649
|
margin-top: ${MENU_SEPARATOR_PADDING}px;
|
|
43245
43650
|
margin-bottom: ${MENU_SEPARATOR_PADDING}px;
|
|
43246
43651
|
}
|
|
43652
|
+
.o-hoverable-button {
|
|
43653
|
+
border-radius: 2px;
|
|
43654
|
+
cursor: pointer;
|
|
43655
|
+
.o-icon {
|
|
43656
|
+
color: ${ICONS_COLOR};
|
|
43657
|
+
}
|
|
43658
|
+
&:not(.o-disabled):not(.active):hover {
|
|
43659
|
+
background-color: ${HOVERED_BG_COLOR};
|
|
43660
|
+
color: ${HOVERED_FONT_COLOR};
|
|
43661
|
+
.o-icon {
|
|
43662
|
+
color: ${HOVERED_FONT_COLOR};
|
|
43663
|
+
}
|
|
43664
|
+
}
|
|
43665
|
+
&.active {
|
|
43666
|
+
background-color: ${ACTIVE_BG_COLOR};
|
|
43667
|
+
color: ${ACTIVE_FONT_COLOR};
|
|
43668
|
+
.o-icon {
|
|
43669
|
+
color: ${ACTIVE_FONT_COLOR};
|
|
43670
|
+
}
|
|
43671
|
+
}
|
|
43672
|
+
}
|
|
43247
43673
|
}
|
|
43248
43674
|
|
|
43249
43675
|
.o-two-columns {
|
|
@@ -43393,6 +43819,9 @@ class Spreadsheet extends owl.Component {
|
|
|
43393
43819
|
}
|
|
43394
43820
|
}
|
|
43395
43821
|
openSidePanel(panel, panelProps) {
|
|
43822
|
+
if (this.sidePanel.isOpen && panel !== this.sidePanel.component) {
|
|
43823
|
+
this.sidePanel.panelProps?.onCloseSidePanel?.();
|
|
43824
|
+
}
|
|
43396
43825
|
this.sidePanel.component = panel;
|
|
43397
43826
|
this.sidePanel.panelProps = panelProps;
|
|
43398
43827
|
this.sidePanel.isOpen = true;
|
|
@@ -44102,13 +44531,13 @@ class Tree {
|
|
|
44102
44531
|
}
|
|
44103
44532
|
|
|
44104
44533
|
class SelectiveHistory {
|
|
44534
|
+
HEAD_BRANCH;
|
|
44535
|
+
HEAD_OPERATION;
|
|
44536
|
+
tree;
|
|
44105
44537
|
applyOperation;
|
|
44106
44538
|
revertOperation;
|
|
44107
44539
|
buildEmpty;
|
|
44108
44540
|
buildTransformation;
|
|
44109
|
-
HEAD_BRANCH;
|
|
44110
|
-
HEAD_OPERATION;
|
|
44111
|
-
tree;
|
|
44112
44541
|
/**
|
|
44113
44542
|
* The selective history is a data structure used to register changes/updates of a state.
|
|
44114
44543
|
* Each change/update is called an "operation".
|
|
@@ -44129,14 +44558,15 @@ class SelectiveHistory {
|
|
|
44129
44558
|
* (used for internal implementation)
|
|
44130
44559
|
* @param buildTransformation Factory used to build transformations
|
|
44131
44560
|
*/
|
|
44132
|
-
constructor(
|
|
44133
|
-
this.applyOperation = applyOperation;
|
|
44134
|
-
this.revertOperation = revertOperation;
|
|
44135
|
-
this.buildEmpty = buildEmpty;
|
|
44136
|
-
this.buildTransformation = buildTransformation;
|
|
44561
|
+
constructor(args) {
|
|
44562
|
+
this.applyOperation = args.applyOperation;
|
|
44563
|
+
this.revertOperation = args.revertOperation;
|
|
44564
|
+
this.buildEmpty = args.buildEmpty;
|
|
44565
|
+
this.buildTransformation = args.buildTransformation;
|
|
44137
44566
|
this.HEAD_BRANCH = new Branch(this.buildTransformation);
|
|
44138
|
-
this.tree = new Tree(buildTransformation, this.HEAD_BRANCH);
|
|
44139
|
-
const
|
|
44567
|
+
this.tree = new Tree(this.buildTransformation, this.HEAD_BRANCH);
|
|
44568
|
+
const initialOperationId = args.initialOperationId;
|
|
44569
|
+
const initial = new Operation(initialOperationId, this.buildEmpty(initialOperationId));
|
|
44140
44570
|
this.tree.insertOperationLast(this.HEAD_BRANCH, initial);
|
|
44141
44571
|
this.HEAD_OPERATION = initial;
|
|
44142
44572
|
}
|
|
@@ -44250,21 +44680,27 @@ class SelectiveHistory {
|
|
|
44250
44680
|
}
|
|
44251
44681
|
}
|
|
44252
44682
|
|
|
44253
|
-
function buildRevisionLog(
|
|
44254
|
-
return new SelectiveHistory(
|
|
44255
|
-
|
|
44256
|
-
|
|
44257
|
-
|
|
44258
|
-
|
|
44259
|
-
|
|
44260
|
-
|
|
44261
|
-
|
|
44262
|
-
|
|
44263
|
-
|
|
44264
|
-
return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands), toTransform.rootCommand);
|
|
44683
|
+
function buildRevisionLog(args) {
|
|
44684
|
+
return new SelectiveHistory({
|
|
44685
|
+
initialOperationId: args.initialRevisionId,
|
|
44686
|
+
applyOperation: (revision) => {
|
|
44687
|
+
const commands = revision.commands.slice();
|
|
44688
|
+
const { changes } = args.recordChanges(() => {
|
|
44689
|
+
for (const command of commands) {
|
|
44690
|
+
args.dispatch(command);
|
|
44691
|
+
}
|
|
44692
|
+
});
|
|
44693
|
+
revision.setChanges(changes);
|
|
44265
44694
|
},
|
|
44266
|
-
|
|
44267
|
-
|
|
44695
|
+
revertOperation: (revision) => revertChanges([revision]),
|
|
44696
|
+
buildEmpty: (id) => new Revision(id, "empty", []),
|
|
44697
|
+
buildTransformation: {
|
|
44698
|
+
with: (revision) => (toTransform) => {
|
|
44699
|
+
return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands), toTransform.rootCommand, undefined, toTransform.timestamp);
|
|
44700
|
+
},
|
|
44701
|
+
without: (revision) => (toTransform) => {
|
|
44702
|
+
return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands.map(inverseCommand).flat()), toTransform.rootCommand, undefined, toTransform.timestamp);
|
|
44703
|
+
},
|
|
44268
44704
|
},
|
|
44269
44705
|
});
|
|
44270
44706
|
}
|
|
@@ -45937,11 +46373,21 @@ function addBorders(borders) {
|
|
|
45937
46373
|
for (let border of Object.values(borders)) {
|
|
45938
46374
|
borderNodes.push(escapeXml /*xml*/ `
|
|
45939
46375
|
<border>
|
|
45940
|
-
<left ${formatBorderAttribute(border["left"])}
|
|
45941
|
-
|
|
45942
|
-
|
|
45943
|
-
<
|
|
45944
|
-
|
|
46376
|
+
<left ${formatBorderAttribute(border["left"])}>
|
|
46377
|
+
${addBorderColor(border["left"])}
|
|
46378
|
+
</left>
|
|
46379
|
+
<right ${formatBorderAttribute(border["right"])}>
|
|
46380
|
+
${addBorderColor(border["right"])}
|
|
46381
|
+
</right>
|
|
46382
|
+
<top ${formatBorderAttribute(border["top"])}>
|
|
46383
|
+
${addBorderColor(border["top"])}
|
|
46384
|
+
</top>
|
|
46385
|
+
<bottom ${formatBorderAttribute(border["bottom"])}>
|
|
46386
|
+
${addBorderColor(border["bottom"])}
|
|
46387
|
+
</bottom>
|
|
46388
|
+
<diagonal ${formatBorderAttribute(border["diagonal"])}>
|
|
46389
|
+
${addBorderColor(border["diagonal"])}
|
|
46390
|
+
</diagonal>
|
|
45945
46391
|
</border>
|
|
45946
46392
|
`);
|
|
45947
46393
|
}
|
|
@@ -45955,10 +46401,15 @@ function formatBorderAttribute(description) {
|
|
|
45955
46401
|
if (!description) {
|
|
45956
46402
|
return escapeXml ``;
|
|
45957
46403
|
}
|
|
45958
|
-
return formatAttributes([
|
|
45959
|
-
|
|
45960
|
-
|
|
45961
|
-
|
|
46404
|
+
return formatAttributes([["style", description.style]]);
|
|
46405
|
+
}
|
|
46406
|
+
function addBorderColor(description) {
|
|
46407
|
+
if (!description) {
|
|
46408
|
+
return escapeXml ``;
|
|
46409
|
+
}
|
|
46410
|
+
return escapeXml /*xml*/ `
|
|
46411
|
+
<color ${formatAttributes([["rgb", toXlsxHexColor(description.color.rgb)]])}/>
|
|
46412
|
+
`;
|
|
45962
46413
|
}
|
|
45963
46414
|
function addStyles(styles) {
|
|
45964
46415
|
const styleNodes = [];
|
|
@@ -46568,6 +47019,7 @@ class Model extends EventBus {
|
|
|
46568
47019
|
coreGetters;
|
|
46569
47020
|
uuidGenerator;
|
|
46570
47021
|
handlers = [];
|
|
47022
|
+
uiHandlers = [];
|
|
46571
47023
|
coreHandlers = [];
|
|
46572
47024
|
constructor(data = {}, config = {}, stateUpdateMessages = [], uuidGenerator = new UuidGenerator(), verboseImport = true) {
|
|
46573
47025
|
super();
|
|
@@ -46602,21 +47054,25 @@ class Model extends EventBus {
|
|
|
46602
47054
|
this.setupCorePlugin(Plugin, workbookData);
|
|
46603
47055
|
}
|
|
46604
47056
|
Object.assign(this.getters, this.coreGetters);
|
|
47057
|
+
this.session.loadInitialMessages(stateUpdateMessages);
|
|
46605
47058
|
for (let Plugin of statefulUIPluginRegistry.getAll()) {
|
|
46606
47059
|
const plugin = this.setupUiPlugin(Plugin);
|
|
46607
47060
|
this.statefulUIPlugins.push(plugin);
|
|
46608
47061
|
this.handlers.push(plugin);
|
|
47062
|
+
this.uiHandlers.push(plugin);
|
|
46609
47063
|
}
|
|
46610
47064
|
for (let Plugin of coreViewsPluginRegistry.getAll()) {
|
|
46611
47065
|
const plugin = this.setupUiPlugin(Plugin);
|
|
46612
47066
|
this.coreViewsPlugins.push(plugin);
|
|
46613
47067
|
this.handlers.push(plugin);
|
|
47068
|
+
this.uiHandlers.push(plugin);
|
|
46614
47069
|
this.coreHandlers.push(plugin);
|
|
46615
47070
|
}
|
|
46616
47071
|
for (let Plugin of featurePluginRegistry.getAll()) {
|
|
46617
47072
|
const plugin = this.setupUiPlugin(Plugin);
|
|
46618
47073
|
this.featurePlugins.push(plugin);
|
|
46619
47074
|
this.handlers.push(plugin);
|
|
47075
|
+
this.uiHandlers.push(plugin);
|
|
46620
47076
|
}
|
|
46621
47077
|
this.uuidGenerator.setIsFastStrategy(false);
|
|
46622
47078
|
// starting plugins
|
|
@@ -46629,8 +47085,6 @@ class Model extends EventBus {
|
|
|
46629
47085
|
// This should be done after construction of LocalHistory due to order of
|
|
46630
47086
|
// events
|
|
46631
47087
|
this.setupSessionEvents();
|
|
46632
|
-
// Load the initial revisions
|
|
46633
|
-
this.session.loadInitialMessages(stateUpdateMessages);
|
|
46634
47088
|
this.joinSession();
|
|
46635
47089
|
if (config.snapshotRequested) {
|
|
46636
47090
|
this.session.snapshot(this.exportData());
|
|
@@ -46694,14 +47148,18 @@ class Model extends EventBus {
|
|
|
46694
47148
|
this.finalize();
|
|
46695
47149
|
}
|
|
46696
47150
|
setupSession(revisionId) {
|
|
46697
|
-
const session = new Session(buildRevisionLog(
|
|
46698
|
-
|
|
46699
|
-
|
|
46700
|
-
|
|
46701
|
-
|
|
46702
|
-
|
|
46703
|
-
|
|
46704
|
-
|
|
47151
|
+
const session = new Session(buildRevisionLog({
|
|
47152
|
+
initialRevisionId: revisionId,
|
|
47153
|
+
recordChanges: this.state.recordChanges.bind(this.state),
|
|
47154
|
+
dispatch: (command) => {
|
|
47155
|
+
const result = this.checkDispatchAllowed(command);
|
|
47156
|
+
if (!result.isSuccessful) {
|
|
47157
|
+
return;
|
|
47158
|
+
}
|
|
47159
|
+
this.isReplayingCommand = true;
|
|
47160
|
+
this.dispatchToHandlers(this.coreHandlers, command);
|
|
47161
|
+
this.isReplayingCommand = false;
|
|
47162
|
+
},
|
|
46705
47163
|
}), this.config.transportService, revisionId);
|
|
46706
47164
|
return session;
|
|
46707
47165
|
}
|
|
@@ -46783,7 +47241,7 @@ class Model extends EventBus {
|
|
|
46783
47241
|
return new DispatchResult(results.flat());
|
|
46784
47242
|
}
|
|
46785
47243
|
checkDispatchAllowedLocalCommand(command) {
|
|
46786
|
-
const results = this.
|
|
47244
|
+
const results = this.uiHandlers.map((handler) => handler.allowDispatch(command));
|
|
46787
47245
|
return new DispatchResult(results.flat());
|
|
46788
47246
|
}
|
|
46789
47247
|
finalize() {
|
|
@@ -47100,6 +47558,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
47100
47558
|
exports.tokenize = tokenize;
|
|
47101
47559
|
|
|
47102
47560
|
|
|
47103
|
-
__info__.version = '16.3.0
|
|
47104
|
-
__info__.date = '2023-05-
|
|
47105
|
-
__info__.hash = '
|
|
47561
|
+
__info__.version = '16.3.0';
|
|
47562
|
+
__info__.date = '2023-05-17T14:44:57.860Z';
|
|
47563
|
+
__info__.hash = '33b37e4';
|