@odoo/o-spreadsheet 16.3.0-alpha.7 → 16.3.0-alpha.8
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 +655 -245
- package/dist/o-spreadsheet.d.ts +185 -110
- package/dist/o-spreadsheet.esm.js +655 -245
- package/dist/o-spreadsheet.iife.js +655 -245
- package/dist/o-spreadsheet.iife.min.js +373 -289
- package/package.json +1 -1
|
@@ -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",
|
|
@@ -4389,6 +4402,7 @@ exports.CommandResult = void 0;
|
|
|
4389
4402
|
CommandResult[CommandResult["NoSplitSeparatorInSelection"] = 91] = "NoSplitSeparatorInSelection";
|
|
4390
4403
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
4391
4404
|
|
|
4405
|
+
const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
|
|
4392
4406
|
var DIRECTION;
|
|
4393
4407
|
(function (DIRECTION) {
|
|
4394
4408
|
DIRECTION["UP"] = "up";
|
|
@@ -5482,12 +5496,6 @@ css /* scss */ `
|
|
|
5482
5496
|
cursor: pointer;
|
|
5483
5497
|
user-select: none;
|
|
5484
5498
|
|
|
5485
|
-
.o-menu-item-name {
|
|
5486
|
-
overflow: hidden;
|
|
5487
|
-
white-space: nowrap;
|
|
5488
|
-
text-overflow: ellipsis;
|
|
5489
|
-
}
|
|
5490
|
-
|
|
5491
5499
|
&.o-menu-root {
|
|
5492
5500
|
display: flex;
|
|
5493
5501
|
justify-content: space-between;
|
|
@@ -5498,10 +5506,6 @@ css /* scss */ `
|
|
|
5498
5506
|
margin: 0px 8px 0px 0px;
|
|
5499
5507
|
width: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
5500
5508
|
line-height: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
5501
|
-
|
|
5502
|
-
.o-icon {
|
|
5503
|
-
color: ${ICONS_COLOR};
|
|
5504
|
-
}
|
|
5505
5509
|
}
|
|
5506
5510
|
.o-menu-item-root {
|
|
5507
5511
|
width: 10px;
|
|
@@ -5515,6 +5519,11 @@ css /* scss */ `
|
|
|
5515
5519
|
.o-menu-item-description {
|
|
5516
5520
|
color: grey;
|
|
5517
5521
|
}
|
|
5522
|
+
.o-menu-item-icon {
|
|
5523
|
+
.o-icon {
|
|
5524
|
+
color: ${ICONS_COLOR};
|
|
5525
|
+
}
|
|
5526
|
+
}
|
|
5518
5527
|
}
|
|
5519
5528
|
&.disabled {
|
|
5520
5529
|
color: ${MENU_ITEM_DISABLED_COLOR};
|
|
@@ -6331,8 +6340,14 @@ function createDataSets(getters, dataSetsString, sheetId, dataSetsHaveTitle) {
|
|
|
6331
6340
|
: undefined));
|
|
6332
6341
|
}
|
|
6333
6342
|
}
|
|
6343
|
+
else if (zone.left === zone.right && zone.top === zone.bottom) {
|
|
6344
|
+
// A single cell. If it's only the title, the dataset is not added.
|
|
6345
|
+
if (!dataSetsHaveTitle) {
|
|
6346
|
+
dataSets.push(createDataSet(getters, dataSetSheetId, zone, undefined));
|
|
6347
|
+
}
|
|
6348
|
+
}
|
|
6334
6349
|
else {
|
|
6335
|
-
/* 1
|
|
6350
|
+
/* 1 row or 1 column */
|
|
6336
6351
|
dataSets.push(createDataSet(getters, dataSetSheetId, zone, dataSetsHaveTitle
|
|
6337
6352
|
? {
|
|
6338
6353
|
top: zone.top,
|
|
@@ -8943,7 +8958,7 @@ const DELETE_CELL_SHIFT_LEFT = (env) => {
|
|
|
8943
8958
|
handlePasteResult(env, result);
|
|
8944
8959
|
};
|
|
8945
8960
|
const MENU_INSERT_ROWS_NAME = (env) => {
|
|
8946
|
-
const number =
|
|
8961
|
+
const number = getRowsNumber(env);
|
|
8947
8962
|
return number === 1 ? _lt("Insert row") : _lt("Insert %s rows", number.toString());
|
|
8948
8963
|
};
|
|
8949
8964
|
const MENU_INSERT_ROWS_BEFORE_NAME = (env) => {
|
|
@@ -15308,7 +15323,11 @@ const LOOKUP = {
|
|
|
15308
15323
|
: getNormalizedValueFromRowRange;
|
|
15309
15324
|
const rangeLength = verticalSearch ? nbRow : nbCol;
|
|
15310
15325
|
const index = dichotomicSearch(searchArray, _searchKey, "nextSmaller", "asc", rangeLength, getElement);
|
|
15311
|
-
|
|
15326
|
+
if (index === -1)
|
|
15327
|
+
assertAvailable(undefined, searchKey);
|
|
15328
|
+
verticalSearch
|
|
15329
|
+
? assertAvailable(searchArray[0][index], searchKey)
|
|
15330
|
+
: assertAvailable(searchArray[index][nbRow - 1], searchKey);
|
|
15312
15331
|
if (resultRange === undefined) {
|
|
15313
15332
|
return (verticalSearch ? searchArray[nbCol - 1][index] : searchArray[index][nbRow - 1]);
|
|
15314
15333
|
}
|
|
@@ -16215,75 +16234,97 @@ for (let category of categories) {
|
|
|
16215
16234
|
|
|
16216
16235
|
const insertRow = {
|
|
16217
16236
|
name: MENU_INSERT_ROWS_NAME,
|
|
16218
|
-
isVisible:
|
|
16237
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
|
|
16238
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16239
|
+
env.model.getters.getActiveCols().size === 0,
|
|
16219
16240
|
icon: "o-spreadsheet-Icon.INSERT_ROW",
|
|
16220
16241
|
};
|
|
16221
16242
|
const rowInsertRowBefore = {
|
|
16222
16243
|
name: ROW_INSERT_ROWS_BEFORE_NAME,
|
|
16223
16244
|
execute: INSERT_ROWS_BEFORE_ACTION,
|
|
16245
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
|
|
16246
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16247
|
+
env.model.getters.getActiveCols().size === 0,
|
|
16248
|
+
icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
|
|
16224
16249
|
};
|
|
16225
16250
|
const topBarInsertRowsBefore = {
|
|
16226
16251
|
...rowInsertRowBefore,
|
|
16227
16252
|
name: MENU_INSERT_ROWS_BEFORE_NAME,
|
|
16228
|
-
isVisible: (env) => env.model.getters.getActiveCols().size === 0,
|
|
16229
16253
|
};
|
|
16230
16254
|
const cellInsertRowsBefore = {
|
|
16231
16255
|
...rowInsertRowBefore,
|
|
16232
16256
|
name: CELL_INSERT_ROWS_BEFORE_NAME,
|
|
16233
16257
|
isVisible: IS_ONLY_ONE_RANGE,
|
|
16234
|
-
icon: "o-spreadsheet-Icon.
|
|
16258
|
+
icon: "o-spreadsheet-Icon.INSERT_ROW_BEFORE",
|
|
16235
16259
|
};
|
|
16236
16260
|
const rowInsertRowsAfter = {
|
|
16237
16261
|
execute: INSERT_ROWS_AFTER_ACTION,
|
|
16238
16262
|
name: ROW_INSERT_ROWS_AFTER_NAME,
|
|
16263
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveRows()) &&
|
|
16264
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16265
|
+
env.model.getters.getActiveCols().size === 0,
|
|
16266
|
+
icon: "o-spreadsheet-Icon.INSERT_ROW_AFTER",
|
|
16239
16267
|
};
|
|
16240
16268
|
const topBarInsertRowsAfter = {
|
|
16241
16269
|
...rowInsertRowsAfter,
|
|
16242
16270
|
name: MENU_INSERT_ROWS_AFTER_NAME,
|
|
16243
|
-
isVisible: (env) => env.model.getters.getActiveCols().size === 0,
|
|
16244
16271
|
};
|
|
16245
16272
|
const insertCol = {
|
|
16246
16273
|
name: MENU_INSERT_COLUMNS_NAME,
|
|
16247
|
-
isVisible:
|
|
16274
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
|
|
16275
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16276
|
+
env.model.getters.getActiveRows().size === 0,
|
|
16248
16277
|
icon: "o-spreadsheet-Icon.INSERT_COL",
|
|
16249
16278
|
};
|
|
16250
16279
|
const colInsertColsBefore = {
|
|
16251
16280
|
name: COLUMN_INSERT_COLUMNS_BEFORE_NAME,
|
|
16252
16281
|
execute: INSERT_COLUMNS_BEFORE_ACTION,
|
|
16282
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
|
|
16283
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16284
|
+
env.model.getters.getActiveRows().size === 0,
|
|
16285
|
+
icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
|
|
16253
16286
|
};
|
|
16254
16287
|
const topBarInsertColsBefore = {
|
|
16255
16288
|
...colInsertColsBefore,
|
|
16256
16289
|
name: MENU_INSERT_COLUMNS_BEFORE_NAME,
|
|
16257
|
-
isVisible: (env) => env.model.getters.getActiveRows().size === 0,
|
|
16258
16290
|
};
|
|
16259
16291
|
const cellInsertColsBefore = {
|
|
16260
16292
|
...colInsertColsBefore,
|
|
16261
16293
|
name: CELL_INSERT_COLUMNS_BEFORE_NAME,
|
|
16262
16294
|
isVisible: IS_ONLY_ONE_RANGE,
|
|
16263
|
-
icon: "o-spreadsheet-Icon.
|
|
16295
|
+
icon: "o-spreadsheet-Icon.INSERT_COL_BEFORE",
|
|
16264
16296
|
};
|
|
16265
16297
|
const colInsertColsAfter = {
|
|
16266
16298
|
name: COLUMN_INSERT_COLUMNS_AFTER_NAME,
|
|
16267
16299
|
execute: INSERT_COLUMNS_AFTER_ACTION,
|
|
16300
|
+
isVisible: (env) => isConsecutive(env.model.getters.getActiveCols()) &&
|
|
16301
|
+
IS_ONLY_ONE_RANGE(env) &&
|
|
16302
|
+
env.model.getters.getActiveRows().size === 0,
|
|
16303
|
+
icon: "o-spreadsheet-Icon.INSERT_COL_AFTER",
|
|
16268
16304
|
};
|
|
16269
16305
|
const topBarInsertColsAfter = {
|
|
16270
16306
|
...colInsertColsAfter,
|
|
16271
16307
|
name: MENU_INSERT_COLUMNS_AFTER_NAME,
|
|
16272
16308
|
execute: INSERT_COLUMNS_AFTER_ACTION,
|
|
16273
|
-
isVisible: (env) => env.model.getters.getActiveRows().size === 0,
|
|
16274
16309
|
};
|
|
16275
16310
|
const insertCell = {
|
|
16276
16311
|
name: _lt("Insert cells"),
|
|
16277
|
-
isVisible: IS_ONLY_ONE_RANGE
|
|
16312
|
+
isVisible: (env) => IS_ONLY_ONE_RANGE(env) &&
|
|
16313
|
+
env.model.getters.getActiveCols().size === 0 &&
|
|
16314
|
+
env.model.getters.getActiveRows().size === 0,
|
|
16278
16315
|
icon: "o-spreadsheet-Icon.INSERT_CELL",
|
|
16279
16316
|
};
|
|
16280
16317
|
const insertCellShiftDown = {
|
|
16281
16318
|
name: _lt("Insert cells and shift down"),
|
|
16282
16319
|
execute: INSERT_CELL_SHIFT_DOWN,
|
|
16320
|
+
isVisible: (env) => env.model.getters.getActiveRows().size === 0 && env.model.getters.getActiveCols().size === 0,
|
|
16321
|
+
icon: "o-spreadsheet-Icon.INSERT_CELL_SHIFT_DOWN",
|
|
16283
16322
|
};
|
|
16284
16323
|
const insertCellShiftRight = {
|
|
16285
16324
|
name: _lt("Insert cells and shift right"),
|
|
16286
16325
|
execute: INSERT_CELL_SHIFT_RIGHT,
|
|
16326
|
+
isVisible: (env) => env.model.getters.getActiveRows().size === 0 && env.model.getters.getActiveCols().size === 0,
|
|
16327
|
+
icon: "o-spreadsheet-Icon.INSERT_CELL_SHIFT_RIGHT",
|
|
16287
16328
|
};
|
|
16288
16329
|
const insertChart = {
|
|
16289
16330
|
name: _lt("Chart"),
|
|
@@ -16481,6 +16522,7 @@ const splitToColumns = {
|
|
|
16481
16522
|
sequence: 1,
|
|
16482
16523
|
execute: (env) => env.openSidePanel("SplitToColumns", {}),
|
|
16483
16524
|
isEnabled: (env) => env.model.getters.isSingleColSelected(),
|
|
16525
|
+
icon: "o-spreadsheet-Icon.SPLIT_TEXT",
|
|
16484
16526
|
};
|
|
16485
16527
|
|
|
16486
16528
|
const formatNumberAutomatic = {
|
|
@@ -16696,60 +16738,6 @@ const clearFormat = {
|
|
|
16696
16738
|
execute: FORMAT_CLEARFORMAT_ACTION,
|
|
16697
16739
|
icon: "o-spreadsheet-Icon.CLEAR_FORMAT",
|
|
16698
16740
|
};
|
|
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
16741
|
function fontSizeMenuBuilder() {
|
|
16754
16742
|
return FONT_SIZES.map((fs) => {
|
|
16755
16743
|
return {
|
|
@@ -16762,24 +16750,17 @@ function fontSizeMenuBuilder() {
|
|
|
16762
16750
|
});
|
|
16763
16751
|
}
|
|
16764
16752
|
function isAutomaticFormatSelected(env) {
|
|
16765
|
-
const activeCell = env.model.getters.
|
|
16753
|
+
const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
|
|
16766
16754
|
return !activeCell || !activeCell.format;
|
|
16767
16755
|
}
|
|
16768
16756
|
function isFormatSelected(env, format) {
|
|
16769
|
-
const activeCell = env.model.getters.
|
|
16770
|
-
return activeCell
|
|
16757
|
+
const activeCell = env.model.getters.getCell(env.model.getters.getActivePosition());
|
|
16758
|
+
return activeCell?.format === format;
|
|
16771
16759
|
}
|
|
16772
16760
|
function isFontSizeSelected(env, fontSize) {
|
|
16773
16761
|
const currentFontSize = env.model.getters.getCurrentStyle().fontSize || DEFAULT_FONT_SIZE;
|
|
16774
16762
|
return currentFontSize === fontSize;
|
|
16775
16763
|
}
|
|
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
16764
|
function getHorizontalAlign(env) {
|
|
16784
16765
|
const style = env.model.getters.getCurrentStyle();
|
|
16785
16766
|
if (style.align) {
|
|
@@ -16826,18 +16807,7 @@ var ACTION_FORMAT = /*#__PURE__*/Object.freeze({
|
|
|
16826
16807
|
fillColor: fillColor,
|
|
16827
16808
|
formatCF: formatCF,
|
|
16828
16809
|
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
|
|
16810
|
+
clearFormat: clearFormat
|
|
16841
16811
|
});
|
|
16842
16812
|
|
|
16843
16813
|
function interactiveFreezeColumnsRows(env, dimension, base) {
|
|
@@ -16853,6 +16823,7 @@ const hideCols = {
|
|
|
16853
16823
|
name: HIDE_COLUMNS_NAME,
|
|
16854
16824
|
execute: HIDE_COLUMNS_ACTION,
|
|
16855
16825
|
isVisible: NOT_ALL_VISIBLE_COLS_SELECTED,
|
|
16826
|
+
icon: "o-spreadsheet-Icon.HIDE_COL",
|
|
16856
16827
|
};
|
|
16857
16828
|
const unhideCols = {
|
|
16858
16829
|
name: _lt("Unhide columns"),
|
|
@@ -16874,6 +16845,7 @@ const hideRows = {
|
|
|
16874
16845
|
name: HIDE_ROWS_NAME,
|
|
16875
16846
|
execute: HIDE_ROWS_ACTION,
|
|
16876
16847
|
isVisible: NOT_ALL_VISIBLE_ROWS_SELECTED,
|
|
16848
|
+
icon: "o-spreadsheet-Icon.HIDE_ROW",
|
|
16877
16849
|
};
|
|
16878
16850
|
const unhideRows = {
|
|
16879
16851
|
name: _lt("Unhide rows"),
|
|
@@ -17077,19 +17049,21 @@ colMenuRegistry
|
|
|
17077
17049
|
.add("delete_column", {
|
|
17078
17050
|
...deleteCols,
|
|
17079
17051
|
sequence: 90,
|
|
17052
|
+
icon: "o-spreadsheet-Icon.DELETE",
|
|
17080
17053
|
})
|
|
17081
17054
|
.add("clear_column", {
|
|
17082
17055
|
...clearCols,
|
|
17083
17056
|
sequence: 100,
|
|
17057
|
+
icon: "o-spreadsheet-Icon.CLEAR",
|
|
17084
17058
|
})
|
|
17085
17059
|
.add("hide_columns", {
|
|
17086
17060
|
...hideCols,
|
|
17087
|
-
sequence:
|
|
17061
|
+
sequence: 105,
|
|
17088
17062
|
separator: true,
|
|
17089
17063
|
})
|
|
17090
17064
|
.add("unhide_columns", {
|
|
17091
17065
|
...unhideCols,
|
|
17092
|
-
sequence:
|
|
17066
|
+
sequence: 106,
|
|
17093
17067
|
separator: true,
|
|
17094
17068
|
})
|
|
17095
17069
|
.add("conditional_formatting", {
|
|
@@ -17187,10 +17161,12 @@ rowMenuRegistry
|
|
|
17187
17161
|
.add("delete_row", {
|
|
17188
17162
|
...deleteRows,
|
|
17189
17163
|
sequence: 70,
|
|
17164
|
+
icon: "o-spreadsheet-Icon.DELETE",
|
|
17190
17165
|
})
|
|
17191
17166
|
.add("clear_row", {
|
|
17192
17167
|
...clearRows,
|
|
17193
17168
|
sequence: 80,
|
|
17169
|
+
icon: "o-spreadsheet-Icon.CLEAR",
|
|
17194
17170
|
})
|
|
17195
17171
|
.add("hide_rows", {
|
|
17196
17172
|
...hideRows,
|
|
@@ -17683,6 +17659,12 @@ css /* scss */ `
|
|
|
17683
17659
|
height: 25px;
|
|
17684
17660
|
}
|
|
17685
17661
|
}
|
|
17662
|
+
/** Make the character a bit bigger
|
|
17663
|
+
compared to its neighbor INPUT box */
|
|
17664
|
+
.o-remove-selection {
|
|
17665
|
+
font-weight: bold;
|
|
17666
|
+
font-size: calc(100% + 4px);
|
|
17667
|
+
}
|
|
17686
17668
|
}
|
|
17687
17669
|
`;
|
|
17688
17670
|
/**
|
|
@@ -17778,6 +17760,9 @@ class SelectionInput extends owl.Component {
|
|
|
17778
17760
|
this.confirm();
|
|
17779
17761
|
}
|
|
17780
17762
|
}
|
|
17763
|
+
extractRanges(value) {
|
|
17764
|
+
return this.props.hasSingleRange ? value.split(",")[0] : value;
|
|
17765
|
+
}
|
|
17781
17766
|
focus(rangeId) {
|
|
17782
17767
|
this.state.isMissing = false;
|
|
17783
17768
|
this.state.mode = "select-range";
|
|
@@ -17796,10 +17781,11 @@ class SelectionInput extends owl.Component {
|
|
|
17796
17781
|
}
|
|
17797
17782
|
onInputChanged(rangeId, ev) {
|
|
17798
17783
|
const target = ev.target;
|
|
17784
|
+
const value = this.extractRanges(target.value);
|
|
17799
17785
|
this.env.model.dispatch("CHANGE_RANGE", {
|
|
17800
17786
|
id: this.id,
|
|
17801
17787
|
rangeId,
|
|
17802
|
-
value
|
|
17788
|
+
value,
|
|
17803
17789
|
});
|
|
17804
17790
|
this.triggerChange();
|
|
17805
17791
|
}
|
|
@@ -20568,14 +20554,31 @@ class ContentEditableHelper {
|
|
|
20568
20554
|
* */
|
|
20569
20555
|
getCurrentSelection() {
|
|
20570
20556
|
let { startElement, endElement, startSelectionOffset, endSelectionOffset } = this.getStartAndEndSelection();
|
|
20571
|
-
let startSizeBefore = this.
|
|
20572
|
-
let endSizeBefore = this.
|
|
20557
|
+
let startSizeBefore = this.findSelectionIndex(startElement, startSelectionOffset);
|
|
20558
|
+
let endSizeBefore = this.findSelectionIndex(endElement, endSelectionOffset);
|
|
20573
20559
|
return {
|
|
20574
|
-
start: startSizeBefore
|
|
20575
|
-
end: endSizeBefore
|
|
20560
|
+
start: startSizeBefore,
|
|
20561
|
+
end: endSizeBefore,
|
|
20576
20562
|
};
|
|
20577
20563
|
}
|
|
20578
|
-
|
|
20564
|
+
/**
|
|
20565
|
+
* Computes the text 'index' inside this.el based on the currently selected node and its offset.
|
|
20566
|
+
* The selected node is either a Text node or an Element node.
|
|
20567
|
+
*
|
|
20568
|
+
* case 1 -Text node:
|
|
20569
|
+
* the offset is the number of characters from the start of the node. We have to add this offset to the
|
|
20570
|
+
* content length of all previous nodes.
|
|
20571
|
+
*
|
|
20572
|
+
* case 2 - Element node:
|
|
20573
|
+
* the offset is the number of child nodes before the selected node. We have to add the content length of
|
|
20574
|
+
* all the bnodes prior to the selected node as well as the content of the child node before the offset.
|
|
20575
|
+
*
|
|
20576
|
+
* See the MDN documentation for more details.
|
|
20577
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/startOffset
|
|
20578
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/Range/endOffset
|
|
20579
|
+
*
|
|
20580
|
+
*/
|
|
20581
|
+
findSelectionIndex(nodeToFind, nodeOffset) {
|
|
20579
20582
|
let usedCharacters = 0;
|
|
20580
20583
|
let it = iterateChildren(this.el);
|
|
20581
20584
|
let current = it.next();
|
|
@@ -20602,6 +20605,28 @@ class ContentEditableHelper {
|
|
|
20602
20605
|
if (current.value !== nodeToFind) {
|
|
20603
20606
|
throw new Error("Cannot find the node in the children of the element");
|
|
20604
20607
|
}
|
|
20608
|
+
else {
|
|
20609
|
+
if (!current.value.hasChildNodes()) {
|
|
20610
|
+
usedCharacters += nodeOffset;
|
|
20611
|
+
}
|
|
20612
|
+
else {
|
|
20613
|
+
const children = [...current.value.childNodes].slice(0, nodeOffset);
|
|
20614
|
+
usedCharacters += children.reduce((acc, child, index) => {
|
|
20615
|
+
if (child.textContent !== null) {
|
|
20616
|
+
// need to account for paragraph nodes that implicitely add a new line
|
|
20617
|
+
// except for the last paragraph
|
|
20618
|
+
let chars = child.textContent.length;
|
|
20619
|
+
if (child.nodeName === "P" && index !== children.length - 1) {
|
|
20620
|
+
chars++;
|
|
20621
|
+
}
|
|
20622
|
+
return acc + chars;
|
|
20623
|
+
}
|
|
20624
|
+
else {
|
|
20625
|
+
return acc;
|
|
20626
|
+
}
|
|
20627
|
+
}, 0);
|
|
20628
|
+
}
|
|
20629
|
+
}
|
|
20605
20630
|
if (nodeToFind.nodeName === "P" && !isFirstParagraph && nodeToFind.textContent == "") {
|
|
20606
20631
|
usedCharacters++;
|
|
20607
20632
|
}
|
|
@@ -21402,13 +21427,13 @@ GridComposer.props = {
|
|
|
21402
21427
|
|
|
21403
21428
|
const CSS$1 = css /* scss */ `
|
|
21404
21429
|
.o-filter-icon {
|
|
21430
|
+
color: ${FILTERS_COLOR};
|
|
21405
21431
|
position: absolute;
|
|
21406
21432
|
display: flex;
|
|
21407
21433
|
align-items: center;
|
|
21408
21434
|
justify-content: center;
|
|
21409
21435
|
width: ${FILTER_ICON_EDGE_LENGTH}px;
|
|
21410
21436
|
height: ${FILTER_ICON_EDGE_LENGTH}px;
|
|
21411
|
-
color: #4a4f59;
|
|
21412
21437
|
}
|
|
21413
21438
|
.o-filter-icon:hover {
|
|
21414
21439
|
background: ${FILTERS_COLOR};
|
|
@@ -24139,17 +24164,17 @@ const CELL_TYPE_CONVERSION_MAP = {
|
|
|
24139
24164
|
const BORDER_STYLE_CONVERSION_MAP = {
|
|
24140
24165
|
dashDot: "thin",
|
|
24141
24166
|
dashDotDot: "thin",
|
|
24142
|
-
dashed: "
|
|
24143
|
-
dotted: "
|
|
24167
|
+
dashed: "dashed",
|
|
24168
|
+
dotted: "dotted",
|
|
24144
24169
|
double: "thin",
|
|
24145
24170
|
hair: "thin",
|
|
24146
|
-
medium: "
|
|
24171
|
+
medium: "medium",
|
|
24147
24172
|
mediumDashDot: "thin",
|
|
24148
24173
|
mediumDashDotDot: "thin",
|
|
24149
24174
|
mediumDashed: "thin",
|
|
24150
24175
|
none: undefined,
|
|
24151
24176
|
slantDashDot: "thin",
|
|
24152
|
-
thick: "
|
|
24177
|
+
thick: "thick",
|
|
24153
24178
|
thin: "thin",
|
|
24154
24179
|
};
|
|
24155
24180
|
/** Conversion map Horizontal Alignment in XLSX <=> Horizontal Alignment in o_spreadsheet*/
|
|
@@ -24648,7 +24673,7 @@ function convertBorderDescr$1(borderDescr, warningManager) {
|
|
|
24648
24673
|
return undefined;
|
|
24649
24674
|
addBorderDescrWarnings(borderDescr, warningManager);
|
|
24650
24675
|
const style = BORDER_STYLE_CONVERSION_MAP[borderDescr.style];
|
|
24651
|
-
return style ?
|
|
24676
|
+
return style ? { style, color: convertColor(borderDescr.color) } : undefined;
|
|
24652
24677
|
}
|
|
24653
24678
|
function convertStyles(data, warningManager) {
|
|
24654
24679
|
const stylesArray = data.styles.map((style) => {
|
|
@@ -26046,8 +26071,8 @@ function convertBorderDescr(descr) {
|
|
|
26046
26071
|
return undefined;
|
|
26047
26072
|
}
|
|
26048
26073
|
return {
|
|
26049
|
-
style: descr
|
|
26050
|
-
color: { rgb: descr
|
|
26074
|
+
style: descr.style,
|
|
26075
|
+
color: { rgb: descr.color },
|
|
26051
26076
|
};
|
|
26052
26077
|
}
|
|
26053
26078
|
function extractStyle(cell, data) {
|
|
@@ -26625,7 +26650,7 @@ const TABLE_HEADER_STYLE = {
|
|
|
26625
26650
|
const TABLE_HIGHLIGHTED_CELL_STYLE = {
|
|
26626
26651
|
bold: true,
|
|
26627
26652
|
};
|
|
26628
|
-
const TABLE_BORDER_STYLE =
|
|
26653
|
+
const TABLE_BORDER_STYLE = { style: "thin", color: "#000000FF" };
|
|
26629
26654
|
/**
|
|
26630
26655
|
* Convert the imported XLSX tables.
|
|
26631
26656
|
*
|
|
@@ -28194,7 +28219,7 @@ function normalizeV9(formula) {
|
|
|
28194
28219
|
* a breaking change is made in the way the state is handled, and an upgrade
|
|
28195
28220
|
* function should be defined
|
|
28196
28221
|
*/
|
|
28197
|
-
const CURRENT_VERSION =
|
|
28222
|
+
const CURRENT_VERSION = 13;
|
|
28198
28223
|
const INITIAL_SHEET_ID = "Sheet1";
|
|
28199
28224
|
/**
|
|
28200
28225
|
* This function tries to load anything that could look like a valid
|
|
@@ -28458,6 +28483,25 @@ const MIGRATIONS = [
|
|
|
28458
28483
|
return data;
|
|
28459
28484
|
},
|
|
28460
28485
|
},
|
|
28486
|
+
{
|
|
28487
|
+
description: "Change Border description structure",
|
|
28488
|
+
from: 12,
|
|
28489
|
+
to: 13,
|
|
28490
|
+
applyMigration(data) {
|
|
28491
|
+
for (const borderId in data.borders) {
|
|
28492
|
+
const border = data.borders[borderId];
|
|
28493
|
+
for (const position in border) {
|
|
28494
|
+
if (Array.isArray(border[position])) {
|
|
28495
|
+
border[position] = {
|
|
28496
|
+
style: border[position][0],
|
|
28497
|
+
color: border[position][1],
|
|
28498
|
+
};
|
|
28499
|
+
}
|
|
28500
|
+
}
|
|
28501
|
+
}
|
|
28502
|
+
return data;
|
|
28503
|
+
},
|
|
28504
|
+
},
|
|
28461
28505
|
];
|
|
28462
28506
|
/**
|
|
28463
28507
|
* This function is used to repair faulty data independently of the migration.
|
|
@@ -28793,7 +28837,7 @@ class CorePlugin extends BasePlugin {
|
|
|
28793
28837
|
* - borders
|
|
28794
28838
|
*/
|
|
28795
28839
|
class BordersPlugin extends CorePlugin {
|
|
28796
|
-
static getters = ["getCellBorder"];
|
|
28840
|
+
static getters = ["getCellBorder", "getBordersColors"];
|
|
28797
28841
|
borders = {};
|
|
28798
28842
|
// ---------------------------------------------------------------------------
|
|
28799
28843
|
// Command Handling
|
|
@@ -28824,10 +28868,15 @@ class BordersPlugin extends CorePlugin {
|
|
|
28824
28868
|
case "SET_BORDER":
|
|
28825
28869
|
this.setBorder(cmd.sheetId, cmd.col, cmd.row, cmd.border);
|
|
28826
28870
|
break;
|
|
28827
|
-
case "
|
|
28871
|
+
case "SET_ZONE_BORDERS":
|
|
28828
28872
|
if (cmd.border) {
|
|
28829
28873
|
const target = cmd.target.map((zone) => this.getters.expandZone(cmd.sheetId, zone));
|
|
28830
|
-
this.setBorders(cmd.sheetId, target, cmd.border
|
|
28874
|
+
this.setBorders(cmd.sheetId, target, cmd.border.position, cmd.border.color === ""
|
|
28875
|
+
? undefined
|
|
28876
|
+
: {
|
|
28877
|
+
style: cmd.border.style || DEFAULT_BORDER_DESC.style,
|
|
28878
|
+
color: cmd.border.color || DEFAULT_BORDER_DESC.color,
|
|
28879
|
+
});
|
|
28831
28880
|
}
|
|
28832
28881
|
break;
|
|
28833
28882
|
case "CLEAR_FORMATTING":
|
|
@@ -28916,6 +28965,23 @@ class BordersPlugin extends CorePlugin {
|
|
|
28916
28965
|
}
|
|
28917
28966
|
return border;
|
|
28918
28967
|
}
|
|
28968
|
+
getBordersColors(sheetId) {
|
|
28969
|
+
const colors = [];
|
|
28970
|
+
const sheetBorders = this.borders[sheetId];
|
|
28971
|
+
if (sheetBorders) {
|
|
28972
|
+
for (const borders of sheetBorders.filter(isDefined$1)) {
|
|
28973
|
+
for (const cellBorder of borders) {
|
|
28974
|
+
if (cellBorder?.horizontal) {
|
|
28975
|
+
colors.push(cellBorder.horizontal.color);
|
|
28976
|
+
}
|
|
28977
|
+
if (cellBorder?.vertical) {
|
|
28978
|
+
colors.push(cellBorder.vertical.color);
|
|
28979
|
+
}
|
|
28980
|
+
}
|
|
28981
|
+
}
|
|
28982
|
+
}
|
|
28983
|
+
return colors;
|
|
28984
|
+
}
|
|
28919
28985
|
// ---------------------------------------------------------------------------
|
|
28920
28986
|
// Private
|
|
28921
28987
|
// ---------------------------------------------------------------------------
|
|
@@ -29127,43 +29193,43 @@ class BordersPlugin extends CorePlugin {
|
|
|
29127
29193
|
* Set the borders of a zone by computing the borders to add from the given
|
|
29128
29194
|
* command
|
|
29129
29195
|
*/
|
|
29130
|
-
setBorders(sheetId, zones,
|
|
29131
|
-
if (
|
|
29196
|
+
setBorders(sheetId, zones, position, border) {
|
|
29197
|
+
if (position === "clear") {
|
|
29132
29198
|
return this.clearBorders(sheetId, zones);
|
|
29133
29199
|
}
|
|
29134
29200
|
for (let zone of zones) {
|
|
29135
|
-
if (
|
|
29201
|
+
if (position === "h" || position === "hv" || position === "all") {
|
|
29136
29202
|
for (let row = zone.top + 1; row <= zone.bottom; row++) {
|
|
29137
29203
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
29138
|
-
this.addBorder(sheetId, col, row, { top:
|
|
29204
|
+
this.addBorder(sheetId, col, row, { top: border });
|
|
29139
29205
|
}
|
|
29140
29206
|
}
|
|
29141
29207
|
}
|
|
29142
|
-
if (
|
|
29208
|
+
if (position === "v" || position === "hv" || position === "all") {
|
|
29143
29209
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
29144
29210
|
for (let col = zone.left + 1; col <= zone.right; col++) {
|
|
29145
|
-
this.addBorder(sheetId, col, row, { left:
|
|
29211
|
+
this.addBorder(sheetId, col, row, { left: border });
|
|
29146
29212
|
}
|
|
29147
29213
|
}
|
|
29148
29214
|
}
|
|
29149
|
-
if (
|
|
29215
|
+
if (position === "left" || position === "all" || position === "external") {
|
|
29150
29216
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
29151
|
-
this.addBorder(sheetId, zone.left, row, { left:
|
|
29217
|
+
this.addBorder(sheetId, zone.left, row, { left: border });
|
|
29152
29218
|
}
|
|
29153
29219
|
}
|
|
29154
|
-
if (
|
|
29220
|
+
if (position === "right" || position === "all" || position === "external") {
|
|
29155
29221
|
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
29156
|
-
this.addBorder(sheetId, zone.right + 1, row, { left:
|
|
29222
|
+
this.addBorder(sheetId, zone.right + 1, row, { left: border });
|
|
29157
29223
|
}
|
|
29158
29224
|
}
|
|
29159
|
-
if (
|
|
29225
|
+
if (position === "top" || position === "all" || position === "external") {
|
|
29160
29226
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
29161
|
-
this.addBorder(sheetId, col, zone.top, { top:
|
|
29227
|
+
this.addBorder(sheetId, col, zone.top, { top: border });
|
|
29162
29228
|
}
|
|
29163
29229
|
}
|
|
29164
|
-
if (
|
|
29230
|
+
if (position === "bottom" || position === "all" || position === "external") {
|
|
29165
29231
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
29166
|
-
this.addBorder(sheetId, col, zone.bottom + 1, { top:
|
|
29232
|
+
this.addBorder(sheetId, col, zone.bottom + 1, { top: border });
|
|
29167
29233
|
}
|
|
29168
29234
|
}
|
|
29169
29235
|
}
|
|
@@ -29177,16 +29243,22 @@ class BordersPlugin extends CorePlugin {
|
|
|
29177
29243
|
const bordersBottomRight = this.getCellBorder({ sheetId, col: right, row: bottom });
|
|
29178
29244
|
this.clearBorders(sheetId, [zone]);
|
|
29179
29245
|
if (bordersTopLeft?.top) {
|
|
29180
|
-
this.setBorders(sheetId, [{ ...zone, bottom: top }], "top");
|
|
29246
|
+
this.setBorders(sheetId, [{ ...zone, bottom: top }], "top", bordersTopLeft.top);
|
|
29181
29247
|
}
|
|
29182
29248
|
if (bordersTopLeft?.left) {
|
|
29183
|
-
this.setBorders(sheetId, [{ ...zone, right: left }], "left");
|
|
29249
|
+
this.setBorders(sheetId, [{ ...zone, right: left }], "left", bordersTopLeft.left);
|
|
29250
|
+
}
|
|
29251
|
+
if (bordersBottomRight?.bottom) {
|
|
29252
|
+
this.setBorders(sheetId, [{ ...zone, top: bottom }], "bottom", bordersBottomRight.bottom);
|
|
29253
|
+
}
|
|
29254
|
+
else if (bordersTopLeft?.bottom) {
|
|
29255
|
+
this.setBorders(sheetId, [{ ...zone, top: bottom }], "bottom", bordersTopLeft.bottom);
|
|
29184
29256
|
}
|
|
29185
|
-
if (bordersBottomRight?.
|
|
29186
|
-
this.setBorders(sheetId, [{ ...zone,
|
|
29257
|
+
if (bordersBottomRight?.right) {
|
|
29258
|
+
this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersBottomRight.right);
|
|
29187
29259
|
}
|
|
29188
|
-
if (
|
|
29189
|
-
this.setBorders(sheetId, [{ ...zone, left: right }], "right");
|
|
29260
|
+
else if (bordersTopLeft?.right) {
|
|
29261
|
+
this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
|
|
29190
29262
|
}
|
|
29191
29263
|
}
|
|
29192
29264
|
// ---------------------------------------------------------------------------
|
|
@@ -33039,6 +33111,9 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
33039
33111
|
case "UPDATE_CHART":
|
|
33040
33112
|
case "CREATE_CHART":
|
|
33041
33113
|
case "ADD_CONDITIONAL_FORMAT":
|
|
33114
|
+
case "SET_BORDER":
|
|
33115
|
+
case "SET_ZONE_BORDERS":
|
|
33116
|
+
case "SET_FORMATTING":
|
|
33042
33117
|
this.shouldUpdateColors = true;
|
|
33043
33118
|
}
|
|
33044
33119
|
}
|
|
@@ -33053,8 +33128,7 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
33053
33128
|
getCustomColors() {
|
|
33054
33129
|
let usedColors = [];
|
|
33055
33130
|
for (const sheetId of this.getters.getSheetIds()) {
|
|
33056
|
-
|
|
33057
|
-
usedColors = usedColors.concat(this.getColorsFromCells(cells), this.getFormattingColors(sheetId), this.getChartColors(sheetId));
|
|
33131
|
+
usedColors = usedColors.concat(this.getColorsFromCells(sheetId), this.getFormattingColors(sheetId), this.getChartColors(sheetId));
|
|
33058
33132
|
}
|
|
33059
33133
|
return sortWithClusters([
|
|
33060
33134
|
...new Set(
|
|
@@ -33064,7 +33138,8 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
33064
33138
|
[...new Set([...usedColors, ...this.customColors])].filter(isColorValid).map(toHex)),
|
|
33065
33139
|
]).filter((color) => !COLOR_PICKER_DEFAULTS.includes(color));
|
|
33066
33140
|
}
|
|
33067
|
-
getColorsFromCells(
|
|
33141
|
+
getColorsFromCells(sheetId) {
|
|
33142
|
+
const cells = Object.values(this.getters.getCells(sheetId));
|
|
33068
33143
|
const colors = new Set();
|
|
33069
33144
|
for (const cell of cells) {
|
|
33070
33145
|
if (cell.style?.textColor) {
|
|
@@ -33074,6 +33149,9 @@ class CustomColorsPlugin extends UIPlugin {
|
|
|
33074
33149
|
colors.add(cell.style.fillColor);
|
|
33075
33150
|
}
|
|
33076
33151
|
}
|
|
33152
|
+
for (const color of this.getters.getBordersColors(sheetId)) {
|
|
33153
|
+
colors.add(color);
|
|
33154
|
+
}
|
|
33077
33155
|
return [...colors];
|
|
33078
33156
|
}
|
|
33079
33157
|
getFormattingColors(sheetId) {
|
|
@@ -33347,7 +33425,7 @@ class EvaluationPlugin extends UIPlugin {
|
|
|
33347
33425
|
// magic "empty" value
|
|
33348
33426
|
// Returning {value: null} instead of undefined will ensure that we don't
|
|
33349
33427
|
// fall back on the default value of the argument provided to the formula's compute function
|
|
33350
|
-
return { value: null };
|
|
33428
|
+
return { value: null, format: cell?.format };
|
|
33351
33429
|
}
|
|
33352
33430
|
return getEvaluatedCell(cell);
|
|
33353
33431
|
}
|
|
@@ -36176,6 +36254,7 @@ function transformPositionWithMerge(cmd, executed) {
|
|
|
36176
36254
|
|
|
36177
36255
|
class Revision {
|
|
36178
36256
|
rootCommand;
|
|
36257
|
+
timestamp;
|
|
36179
36258
|
id;
|
|
36180
36259
|
clientId;
|
|
36181
36260
|
_commands = [];
|
|
@@ -36189,8 +36268,9 @@ class Revision {
|
|
|
36189
36268
|
* - clientId: Client who initiated the action
|
|
36190
36269
|
* - changes: List of changes applied on the state.
|
|
36191
36270
|
*/
|
|
36192
|
-
constructor(id, clientId, commands, rootCommand, changes) {
|
|
36271
|
+
constructor(id, clientId, commands, rootCommand, changes, timestamp) {
|
|
36193
36272
|
this.rootCommand = rootCommand;
|
|
36273
|
+
this.timestamp = timestamp;
|
|
36194
36274
|
this.id = id;
|
|
36195
36275
|
this.clientId = clientId;
|
|
36196
36276
|
this._commands = [...commands];
|
|
@@ -36262,7 +36342,7 @@ class Session extends EventBus {
|
|
|
36262
36342
|
save(rootCommand, commands, changes) {
|
|
36263
36343
|
if (!commands.length || !changes.length || !this.canApplyOptimisticUpdate())
|
|
36264
36344
|
return;
|
|
36265
|
-
const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes);
|
|
36345
|
+
const revision = new Revision(this.uuidGenerator.uuidv4(), this.clientId, commands, rootCommand, changes, Date.now());
|
|
36266
36346
|
this.revisions.append(revision.id, revision);
|
|
36267
36347
|
this.trigger("new-local-state-update", { id: revision.id });
|
|
36268
36348
|
this.sendUpdateMessage({
|
|
@@ -36313,13 +36393,9 @@ class Session extends EventBus {
|
|
|
36313
36393
|
}
|
|
36314
36394
|
loadInitialMessages(messages) {
|
|
36315
36395
|
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
36396
|
for (const message of messages) {
|
|
36320
36397
|
this.onMessageReceived(message);
|
|
36321
36398
|
}
|
|
36322
|
-
this.off("unexpected-revision-id", this);
|
|
36323
36399
|
this.isReplayingInitialRevisions = false;
|
|
36324
36400
|
}
|
|
36325
36401
|
/**
|
|
@@ -36405,6 +36481,10 @@ class Session extends EventBus {
|
|
|
36405
36481
|
onMessageReceived(message) {
|
|
36406
36482
|
if (this.isAlreadyProcessed(message))
|
|
36407
36483
|
return;
|
|
36484
|
+
if (this.isWrongServerRevisionId(message)) {
|
|
36485
|
+
this.trigger("unexpected-revision-id");
|
|
36486
|
+
return;
|
|
36487
|
+
}
|
|
36408
36488
|
switch (message.type) {
|
|
36409
36489
|
case "CLIENT_MOVED":
|
|
36410
36490
|
this.onClientMoved(message);
|
|
@@ -36431,12 +36511,8 @@ class Session extends EventBus {
|
|
|
36431
36511
|
});
|
|
36432
36512
|
break;
|
|
36433
36513
|
case "REMOTE_REVISION":
|
|
36434
|
-
|
|
36435
|
-
|
|
36436
|
-
return;
|
|
36437
|
-
}
|
|
36438
|
-
const { clientId, commands } = message;
|
|
36439
|
-
const revision = new Revision(message.nextRevisionId, clientId, commands, "REMOTE");
|
|
36514
|
+
const { clientId, commands, timestamp } = message;
|
|
36515
|
+
const revision = new Revision(message.nextRevisionId, clientId, commands, "REMOTE", undefined, timestamp);
|
|
36440
36516
|
if (revision.clientId !== this.clientId) {
|
|
36441
36517
|
this.revisions.insert(revision.id, revision, message.serverRevisionId);
|
|
36442
36518
|
const pendingCommands = this.pendingMessages
|
|
@@ -36449,7 +36525,7 @@ class Session extends EventBus {
|
|
|
36449
36525
|
}
|
|
36450
36526
|
break;
|
|
36451
36527
|
case "SNAPSHOT_CREATED": {
|
|
36452
|
-
const revision = new Revision(message.nextRevisionId, "server", [], "SNAPSHOT");
|
|
36528
|
+
const revision = new Revision(message.nextRevisionId, "server", [], "SNAPSHOT", undefined, Date.now());
|
|
36453
36529
|
this.revisions.insert(revision.id, revision, message.serverRevisionId);
|
|
36454
36530
|
this.dropPendingHistoryMessages();
|
|
36455
36531
|
this.trigger("snapshot");
|
|
@@ -36566,6 +36642,17 @@ class Session extends EventBus {
|
|
|
36566
36642
|
return false;
|
|
36567
36643
|
}
|
|
36568
36644
|
}
|
|
36645
|
+
isWrongServerRevisionId(message) {
|
|
36646
|
+
switch (message.type) {
|
|
36647
|
+
case "REMOTE_REVISION":
|
|
36648
|
+
case "REVISION_REDONE":
|
|
36649
|
+
case "REVISION_UNDONE":
|
|
36650
|
+
case "SNAPSHOT_CREATED":
|
|
36651
|
+
return message.serverRevisionId !== this.serverRevisionId;
|
|
36652
|
+
default:
|
|
36653
|
+
return false;
|
|
36654
|
+
}
|
|
36655
|
+
}
|
|
36569
36656
|
dropPendingHistoryMessages() {
|
|
36570
36657
|
this.waitingUndoRedoAck = false;
|
|
36571
36658
|
this.pendingMessages = this.pendingMessages.filter(({ type }) => type !== "REVISION_REDONE" && type !== "REVISION_UNDONE");
|
|
@@ -37281,7 +37368,7 @@ class RendererPlugin extends UIPlugin {
|
|
|
37281
37368
|
}
|
|
37282
37369
|
}
|
|
37283
37370
|
drawBorders(renderingContext) {
|
|
37284
|
-
const { ctx
|
|
37371
|
+
const { ctx } = renderingContext;
|
|
37285
37372
|
for (let box of this.boxes) {
|
|
37286
37373
|
const border = box.border;
|
|
37287
37374
|
if (border) {
|
|
@@ -37300,13 +37387,66 @@ class RendererPlugin extends UIPlugin {
|
|
|
37300
37387
|
}
|
|
37301
37388
|
}
|
|
37302
37389
|
}
|
|
37303
|
-
|
|
37390
|
+
/**
|
|
37391
|
+
* Following https://usefulangle.com/post/17/html5-canvas-drawing-1px-crisp-straight-lines,
|
|
37392
|
+
* we need to make sure that a "single" pixel line is drawn on a "half" pixel coordinate,
|
|
37393
|
+
* while a "double" pixel line is drawn on a "full" pixel coordinate. As, in the rendering
|
|
37394
|
+
* process, we always had 0.5 before rendering line (to make sure it is drawn on a "half"
|
|
37395
|
+
* pixel), we need to correct this behavior for the "medium" and the "dotted" styles, as
|
|
37396
|
+
* they are drawing a two pixels width line.
|
|
37397
|
+
* We also adapt here the coordinates of the line to make sure corner are correctly drawn,
|
|
37398
|
+
* avoiding a "round corners" effect. This is done by subtracting 1 pixel to the origin of
|
|
37399
|
+
* each line and adding 1 pixel to the end of each line (depending on the direction of the
|
|
37400
|
+
* line).
|
|
37401
|
+
*/
|
|
37402
|
+
function drawBorder({ style, color }, x1, y1, x2, y2) {
|
|
37304
37403
|
ctx.strokeStyle = color;
|
|
37305
|
-
|
|
37404
|
+
switch (style) {
|
|
37405
|
+
case "medium":
|
|
37406
|
+
ctx.lineWidth = 2;
|
|
37407
|
+
x1 += y1 === y2 ? -0.5 : 0.5;
|
|
37408
|
+
x2 += y1 === y2 ? 1.5 : 0.5;
|
|
37409
|
+
y1 += x1 === x2 ? -0.5 : 0.5;
|
|
37410
|
+
y2 += x1 === x2 ? 1.5 : 0.5;
|
|
37411
|
+
break;
|
|
37412
|
+
case "thick":
|
|
37413
|
+
ctx.lineWidth = 3;
|
|
37414
|
+
if (y1 === y2) {
|
|
37415
|
+
x1--;
|
|
37416
|
+
x2++;
|
|
37417
|
+
}
|
|
37418
|
+
if (x1 === x2) {
|
|
37419
|
+
y1--;
|
|
37420
|
+
y2++;
|
|
37421
|
+
}
|
|
37422
|
+
break;
|
|
37423
|
+
case "dashed":
|
|
37424
|
+
ctx.lineWidth = 1;
|
|
37425
|
+
ctx.setLineDash([1, 3]);
|
|
37426
|
+
break;
|
|
37427
|
+
case "dotted":
|
|
37428
|
+
ctx.lineWidth = 1;
|
|
37429
|
+
if (y1 === y2) {
|
|
37430
|
+
x1 += 0.5;
|
|
37431
|
+
x2 += 0.5;
|
|
37432
|
+
}
|
|
37433
|
+
if (x1 === x2) {
|
|
37434
|
+
y1 += 0.5;
|
|
37435
|
+
y2 += 0.5;
|
|
37436
|
+
}
|
|
37437
|
+
ctx.setLineDash([1, 1]);
|
|
37438
|
+
break;
|
|
37439
|
+
case "thin":
|
|
37440
|
+
default:
|
|
37441
|
+
ctx.lineWidth = 1;
|
|
37442
|
+
break;
|
|
37443
|
+
}
|
|
37306
37444
|
ctx.beginPath();
|
|
37307
37445
|
ctx.moveTo(x1, y1);
|
|
37308
37446
|
ctx.lineTo(x2, y2);
|
|
37309
37447
|
ctx.stroke();
|
|
37448
|
+
ctx.lineWidth = 1;
|
|
37449
|
+
ctx.setLineDash([]);
|
|
37310
37450
|
}
|
|
37311
37451
|
}
|
|
37312
37452
|
drawTexts(renderingContext) {
|
|
@@ -37784,6 +37924,9 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
37784
37924
|
activeSheet;
|
|
37785
37925
|
willAddNewRange = false;
|
|
37786
37926
|
constructor(config, initialRanges, inputHasSingleRange) {
|
|
37927
|
+
if (inputHasSingleRange && initialRanges.length > 1) {
|
|
37928
|
+
throw new Error("Input with a single range cannot be instantiated with several range references.");
|
|
37929
|
+
}
|
|
37787
37930
|
super(config);
|
|
37788
37931
|
this.inputHasSingleRange = inputHasSingleRange;
|
|
37789
37932
|
this.insertNewRange(0, initialRanges);
|
|
@@ -37803,6 +37946,11 @@ class SelectionInputPlugin extends UIPlugin {
|
|
|
37803
37946
|
return 30 /* CommandResult.MaximumRangesReached */;
|
|
37804
37947
|
}
|
|
37805
37948
|
break;
|
|
37949
|
+
case "CHANGE_RANGE":
|
|
37950
|
+
if (this.inputHasSingleRange && cmd.value.split(",").length > 1) {
|
|
37951
|
+
return 30 /* CommandResult.MaximumRangesReached */;
|
|
37952
|
+
}
|
|
37953
|
+
break;
|
|
37806
37954
|
}
|
|
37807
37955
|
return 0 /* CommandResult.Success */;
|
|
37808
37956
|
}
|
|
@@ -41289,7 +41437,8 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
41289
41437
|
},
|
|
41290
41438
|
zone: selectedZone,
|
|
41291
41439
|
};
|
|
41292
|
-
this.
|
|
41440
|
+
const selections = this.gridSelection.zones.map((zone) => updateSelectionOnDeletion(zone, "left", [...cmd.elements]));
|
|
41441
|
+
this.setSelectionMixin(anchor, selections);
|
|
41293
41442
|
}
|
|
41294
41443
|
onRowsRemoved(cmd) {
|
|
41295
41444
|
const { cell, zone } = this.gridSelection.anchor;
|
|
@@ -41303,13 +41452,18 @@ class GridSelectionPlugin extends UIPlugin {
|
|
|
41303
41452
|
},
|
|
41304
41453
|
zone: selectedZone,
|
|
41305
41454
|
};
|
|
41306
|
-
this.
|
|
41455
|
+
const selections = this.gridSelection.zones.map((zone) => updateSelectionOnDeletion(zone, "top", [...cmd.elements]));
|
|
41456
|
+
this.setSelectionMixin(anchor, selections);
|
|
41307
41457
|
}
|
|
41308
41458
|
onAddElements(cmd) {
|
|
41309
|
-
const
|
|
41310
|
-
const
|
|
41311
|
-
const
|
|
41312
|
-
|
|
41459
|
+
const start = cmd.dimension === "COL" ? "left" : "top";
|
|
41460
|
+
const anchorZone = updateSelectionOnInsertion(this.gridSelection.anchor.zone, start, cmd.base, cmd.position, cmd.quantity);
|
|
41461
|
+
const selection = this.gridSelection.zones.map((zone) => updateSelectionOnInsertion(zone, start, cmd.base, cmd.position, cmd.quantity));
|
|
41462
|
+
const anchor = {
|
|
41463
|
+
cell: { col: anchorZone.left, row: anchorZone.top },
|
|
41464
|
+
zone: anchorZone,
|
|
41465
|
+
};
|
|
41466
|
+
this.setSelectionMixin(anchor, selection);
|
|
41313
41467
|
}
|
|
41314
41468
|
onMoveElements(cmd) {
|
|
41315
41469
|
const thickness = cmd.elements.length;
|
|
@@ -42555,7 +42709,6 @@ css /* scss */ `
|
|
|
42555
42709
|
color: dimgrey;
|
|
42556
42710
|
}
|
|
42557
42711
|
.o-sidePanelClose {
|
|
42558
|
-
font-size: 1.5rem;
|
|
42559
42712
|
padding: 5px 10px;
|
|
42560
42713
|
cursor: pointer;
|
|
42561
42714
|
&:hover {
|
|
@@ -42740,7 +42893,6 @@ css /* scss */ `
|
|
|
42740
42893
|
justify-content: center;
|
|
42741
42894
|
align-items: center;
|
|
42742
42895
|
margin: 2px;
|
|
42743
|
-
padding: 0px 3px;
|
|
42744
42896
|
border-radius: 2px;
|
|
42745
42897
|
min-width: 20px;
|
|
42746
42898
|
}
|
|
@@ -42797,7 +42949,228 @@ ActionButton.props = {
|
|
|
42797
42949
|
onClick: { type: Function, optional: true },
|
|
42798
42950
|
};
|
|
42799
42951
|
|
|
42952
|
+
/**
|
|
42953
|
+
* List the available borders positions and the corresponding icons.
|
|
42954
|
+
* The structure of this array is defined to match the order/lines we want
|
|
42955
|
+
* to display in the topbar's border tool.
|
|
42956
|
+
*/
|
|
42957
|
+
const BORDER_POSITIONS = [
|
|
42958
|
+
[
|
|
42959
|
+
["all", "o-spreadsheet-Icon.BORDERS"],
|
|
42960
|
+
["hv", "o-spreadsheet-Icon.BORDER_HV"],
|
|
42961
|
+
["h", "o-spreadsheet-Icon.BORDER_H"],
|
|
42962
|
+
["v", "o-spreadsheet-Icon.BORDER_V"],
|
|
42963
|
+
["external", "o-spreadsheet-Icon.BORDER_EXTERNAL"],
|
|
42964
|
+
],
|
|
42965
|
+
[
|
|
42966
|
+
["left", "o-spreadsheet-Icon.BORDER_LEFT"],
|
|
42967
|
+
["top", "o-spreadsheet-Icon.BORDER_TOP"],
|
|
42968
|
+
["right", "o-spreadsheet-Icon.BORDER_RIGHT"],
|
|
42969
|
+
["bottom", "o-spreadsheet-Icon.BORDER_BOTTOM"],
|
|
42970
|
+
["clear", "o-spreadsheet-Icon.BORDER_CLEAR"],
|
|
42971
|
+
],
|
|
42972
|
+
];
|
|
42973
|
+
// -----------------------------------------------------------------------------
|
|
42974
|
+
// Border Editor
|
|
42975
|
+
// -----------------------------------------------------------------------------
|
|
42976
|
+
css /* scss */ `
|
|
42977
|
+
.o-border-selector {
|
|
42978
|
+
padding: 4px;
|
|
42979
|
+
}
|
|
42980
|
+
.o-divider {
|
|
42981
|
+
border-right: 1px solid #e0e2e4;
|
|
42982
|
+
margin: 0 6px;
|
|
42983
|
+
}
|
|
42984
|
+
.o-border-selector-section {
|
|
42985
|
+
.o-dropdown-line {
|
|
42986
|
+
height: 30px;
|
|
42987
|
+
margin: 1px;
|
|
42988
|
+
.o-line-item {
|
|
42989
|
+
padding: 4px;
|
|
42990
|
+
width: 18px;
|
|
42991
|
+
height: 18px;
|
|
42992
|
+
}
|
|
42993
|
+
}
|
|
42994
|
+
.o-border-style-tool {
|
|
42995
|
+
padding: 0px 3px;
|
|
42996
|
+
margin: 2px;
|
|
42997
|
+
height: 25px;
|
|
42998
|
+
}
|
|
42999
|
+
}
|
|
43000
|
+
.o-style-preview {
|
|
43001
|
+
margin: 7px 5px 7px 5px;
|
|
43002
|
+
width: 60px;
|
|
43003
|
+
height: 5px;
|
|
43004
|
+
}
|
|
43005
|
+
.o-style-thin {
|
|
43006
|
+
border-bottom: 1px solid #000000;
|
|
43007
|
+
}
|
|
43008
|
+
.o-style-medium {
|
|
43009
|
+
border-bottom: 2px solid #000000;
|
|
43010
|
+
}
|
|
43011
|
+
.o-style-thick {
|
|
43012
|
+
border-bottom: 3px solid #000000;
|
|
43013
|
+
}
|
|
43014
|
+
.o-style-dashed {
|
|
43015
|
+
border-bottom: 1px dashed #000000;
|
|
43016
|
+
}
|
|
43017
|
+
.o-style-dotted {
|
|
43018
|
+
border-bottom: 1px dotted #000000;
|
|
43019
|
+
}
|
|
43020
|
+
.o-dropdown-border-type {
|
|
43021
|
+
&:not(.o-disabled):not(.active):hover {
|
|
43022
|
+
background-color: ${BG_HOVER_COLOR};
|
|
43023
|
+
}
|
|
43024
|
+
}
|
|
43025
|
+
.o-dropdown-border-check {
|
|
43026
|
+
width: 20px;
|
|
43027
|
+
font-size: 12px;
|
|
43028
|
+
}
|
|
43029
|
+
.o-border-style-dropdown {
|
|
43030
|
+
background: #ffffff;
|
|
43031
|
+
padding: 4px;
|
|
43032
|
+
.o-dropdown-line {
|
|
43033
|
+
.o-line-item.active {
|
|
43034
|
+
background-color: rgba(0, 0, 0, 0.2);
|
|
43035
|
+
}
|
|
43036
|
+
}
|
|
43037
|
+
}
|
|
43038
|
+
.o-border-picker-button {
|
|
43039
|
+
padding: 0px !important;
|
|
43040
|
+
margin: 5px 0px 0px 0px !important;
|
|
43041
|
+
height: 25px !important;
|
|
43042
|
+
}
|
|
43043
|
+
`;
|
|
43044
|
+
class BorderEditor extends owl.Component {
|
|
43045
|
+
static template = "o-spreadsheet-BorderEditor";
|
|
43046
|
+
static components = { ColorPickerWidget, Popover };
|
|
43047
|
+
BORDER_POSITIONS = BORDER_POSITIONS;
|
|
43048
|
+
lineStyleButtonRef = owl.useRef("lineStyleButton");
|
|
43049
|
+
borderStyles = borderStyles;
|
|
43050
|
+
state = owl.useState({
|
|
43051
|
+
activeTool: undefined,
|
|
43052
|
+
});
|
|
43053
|
+
toggleDropdownTool(tool) {
|
|
43054
|
+
const isOpen = this.state.activeTool === tool;
|
|
43055
|
+
this.state.activeTool = isOpen ? undefined : tool;
|
|
43056
|
+
}
|
|
43057
|
+
closeDropdown() {
|
|
43058
|
+
this.state.activeTool = undefined;
|
|
43059
|
+
}
|
|
43060
|
+
setBorderPosition(position) {
|
|
43061
|
+
this.props.onBorderPositionPicked(position);
|
|
43062
|
+
this.closeDropdown();
|
|
43063
|
+
}
|
|
43064
|
+
setBorderColor(color) {
|
|
43065
|
+
this.props.onBorderColorPicked(color);
|
|
43066
|
+
this.closeDropdown();
|
|
43067
|
+
}
|
|
43068
|
+
setBorderStyle(style) {
|
|
43069
|
+
this.props.onBorderStylePicked(style);
|
|
43070
|
+
this.closeDropdown();
|
|
43071
|
+
}
|
|
43072
|
+
get lineStylePickerPopoverProps() {
|
|
43073
|
+
return {
|
|
43074
|
+
anchorRect: this.lineStylePickerAnchorRect,
|
|
43075
|
+
positioning: "BottomLeft",
|
|
43076
|
+
verticalOffset: 0,
|
|
43077
|
+
};
|
|
43078
|
+
}
|
|
43079
|
+
get popoverProps() {
|
|
43080
|
+
return {
|
|
43081
|
+
anchorRect: this.props.anchorRect,
|
|
43082
|
+
maxHeight: this.props.maxHeight,
|
|
43083
|
+
positioning: "BottomLeft",
|
|
43084
|
+
verticalOffset: 0,
|
|
43085
|
+
};
|
|
43086
|
+
}
|
|
43087
|
+
get lineStylePickerAnchorRect() {
|
|
43088
|
+
const button = this.lineStyleButtonRef.el;
|
|
43089
|
+
if (button === null) {
|
|
43090
|
+
return { x: 0, y: 0, width: 0, height: 0 };
|
|
43091
|
+
}
|
|
43092
|
+
const buttonRect = button.getBoundingClientRect();
|
|
43093
|
+
return {
|
|
43094
|
+
x: buttonRect.x,
|
|
43095
|
+
y: buttonRect.y,
|
|
43096
|
+
width: buttonRect.width,
|
|
43097
|
+
height: buttonRect.height,
|
|
43098
|
+
};
|
|
43099
|
+
}
|
|
43100
|
+
}
|
|
43101
|
+
BorderEditor.props = {
|
|
43102
|
+
class: { type: String, optional: true },
|
|
43103
|
+
currentBorderColor: { type: String, optional: false },
|
|
43104
|
+
currentBorderStyle: { type: String, optional: false },
|
|
43105
|
+
currentBorderPosition: { type: String, optional: true },
|
|
43106
|
+
onBorderColorPicked: Function,
|
|
43107
|
+
onBorderStylePicked: Function,
|
|
43108
|
+
onBorderPositionPicked: Function,
|
|
43109
|
+
maxHeight: { type: Number, optional: true },
|
|
43110
|
+
anchorRect: Object,
|
|
43111
|
+
};
|
|
43112
|
+
|
|
43113
|
+
class BorderEditorWidget extends owl.Component {
|
|
43114
|
+
static template = "o-spreadsheet-BorderEditorWidget";
|
|
43115
|
+
static components = { BorderEditor };
|
|
43116
|
+
borderEditorButtonRef = owl.useRef("borderEditorButton");
|
|
43117
|
+
state = owl.useState({
|
|
43118
|
+
currentColor: DEFAULT_BORDER_DESC.color,
|
|
43119
|
+
currentStyle: DEFAULT_BORDER_DESC.style,
|
|
43120
|
+
currentPosition: undefined,
|
|
43121
|
+
});
|
|
43122
|
+
get borderEditorAnchorRect() {
|
|
43123
|
+
const button = this.borderEditorButtonRef.el;
|
|
43124
|
+
const buttonRect = button.getBoundingClientRect();
|
|
43125
|
+
return {
|
|
43126
|
+
x: buttonRect.x,
|
|
43127
|
+
y: buttonRect.y,
|
|
43128
|
+
width: buttonRect.width,
|
|
43129
|
+
height: buttonRect.height,
|
|
43130
|
+
};
|
|
43131
|
+
}
|
|
43132
|
+
onBorderPositionPicked(position) {
|
|
43133
|
+
this.state.currentPosition = position;
|
|
43134
|
+
this.updateBorder();
|
|
43135
|
+
}
|
|
43136
|
+
onBorderColorPicked(color) {
|
|
43137
|
+
this.state.currentColor = color;
|
|
43138
|
+
this.updateBorder();
|
|
43139
|
+
}
|
|
43140
|
+
onBorderStylePicked(style) {
|
|
43141
|
+
this.state.currentStyle = style;
|
|
43142
|
+
this.updateBorder();
|
|
43143
|
+
}
|
|
43144
|
+
updateBorder() {
|
|
43145
|
+
if (this.state.currentPosition === undefined) {
|
|
43146
|
+
return;
|
|
43147
|
+
}
|
|
43148
|
+
this.env.model.dispatch("SET_ZONE_BORDERS", {
|
|
43149
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
43150
|
+
target: this.env.model.getters.getSelectedZones(),
|
|
43151
|
+
border: {
|
|
43152
|
+
position: this.state.currentPosition,
|
|
43153
|
+
color: this.state.currentColor,
|
|
43154
|
+
style: this.state.currentStyle,
|
|
43155
|
+
},
|
|
43156
|
+
});
|
|
43157
|
+
}
|
|
43158
|
+
}
|
|
43159
|
+
BorderEditorWidget.props = {
|
|
43160
|
+
toggleBorderEditor: Function,
|
|
43161
|
+
showBorderEditor: Boolean,
|
|
43162
|
+
disabled: { type: Boolean, optional: true },
|
|
43163
|
+
dropdownMaxHeight: { type: Number, optional: true },
|
|
43164
|
+
class: { type: String, optional: true },
|
|
43165
|
+
};
|
|
43166
|
+
|
|
42800
43167
|
const COMPOSER_MAX_HEIGHT = 100;
|
|
43168
|
+
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
43169
|
+
const FX_SVG = /*xml*/ `
|
|
43170
|
+
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 121.8 122.9' width='16' height='16' focusable='false'>
|
|
43171
|
+
<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'/>
|
|
43172
|
+
</svg>
|
|
43173
|
+
`;
|
|
42801
43174
|
css /* scss */ `
|
|
42802
43175
|
.o-topbar-composer {
|
|
42803
43176
|
height: fit-content;
|
|
@@ -42805,9 +43178,10 @@ css /* scss */ `
|
|
|
42805
43178
|
border: 1px solid;
|
|
42806
43179
|
z-index: ${ComponentsImportance.TopBarComposer};
|
|
42807
43180
|
|
|
42808
|
-
.o-composer:empty:not(:focus)::before {
|
|
42809
|
-
|
|
42810
|
-
|
|
43181
|
+
.o-composer:empty:not(:focus):not(.active)::before {
|
|
43182
|
+
content: url("data:image/svg+xml,${encodeURIComponent(FX_SVG)}");
|
|
43183
|
+
position: relative;
|
|
43184
|
+
top: 20%;
|
|
42811
43185
|
}
|
|
42812
43186
|
}
|
|
42813
43187
|
`;
|
|
@@ -42930,11 +43304,6 @@ FontSizeEditor.props = {
|
|
|
42930
43304
|
dropdownStyle: String,
|
|
42931
43305
|
};
|
|
42932
43306
|
|
|
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
43307
|
// -----------------------------------------------------------------------------
|
|
42939
43308
|
// TopBar
|
|
42940
43309
|
// -----------------------------------------------------------------------------
|
|
@@ -42944,27 +43313,6 @@ css /* scss */ `
|
|
|
42944
43313
|
font-size: 13px;
|
|
42945
43314
|
font-weight: 500;
|
|
42946
43315
|
|
|
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
43316
|
.o-topbar-top {
|
|
42969
43317
|
border-bottom: 1px solid ${SEPARATOR_COLOR};
|
|
42970
43318
|
padding: 2px 10px;
|
|
@@ -42974,6 +43322,11 @@ css /* scss */ `
|
|
|
42974
43322
|
.o-topbar-menu {
|
|
42975
43323
|
padding: 4px 6px;
|
|
42976
43324
|
margin: 0 2px;
|
|
43325
|
+
|
|
43326
|
+
&.active {
|
|
43327
|
+
background-color: ${BG_HOVER_COLOR};
|
|
43328
|
+
color: #000;
|
|
43329
|
+
}
|
|
42977
43330
|
}
|
|
42978
43331
|
}
|
|
42979
43332
|
}
|
|
@@ -43051,6 +43404,7 @@ class TopBar extends owl.Component {
|
|
|
43051
43404
|
TopBarComposer,
|
|
43052
43405
|
FontSizeEditor,
|
|
43053
43406
|
ActionButton,
|
|
43407
|
+
BorderEditorWidget,
|
|
43054
43408
|
};
|
|
43055
43409
|
state = owl.useState({
|
|
43056
43410
|
menuState: { isOpen: false, position: null, menuItems: [] },
|
|
@@ -43126,7 +43480,9 @@ class TopBar extends owl.Component {
|
|
|
43126
43480
|
this.state.activeTool = "";
|
|
43127
43481
|
this.state.menuState.isOpen = true;
|
|
43128
43482
|
this.state.menuState.position = { x: left, y: top + height };
|
|
43129
|
-
this.state.menuState.menuItems = menu
|
|
43483
|
+
this.state.menuState.menuItems = menu
|
|
43484
|
+
.children(this.env)
|
|
43485
|
+
.sort((a, b) => a.sequence - b.sequence);
|
|
43130
43486
|
this.state.menuState.parentMenu = menu;
|
|
43131
43487
|
this.isSelectingMenu = true;
|
|
43132
43488
|
this.openedEl = ev.target;
|
|
@@ -43212,6 +43568,11 @@ class WebClipboardWrapper {
|
|
|
43212
43568
|
}
|
|
43213
43569
|
}
|
|
43214
43570
|
|
|
43571
|
+
// If we ever change these colors, make sure the filter tool stays green to match the icon in the grid
|
|
43572
|
+
const ACTIVE_BG_COLOR = BACKGROUND_HEADER_FILTER_COLOR;
|
|
43573
|
+
const ACTIVE_FONT_COLOR = FILTERS_COLOR;
|
|
43574
|
+
const HOVERED_BG_COLOR = BG_HOVER_COLOR;
|
|
43575
|
+
const HOVERED_FONT_COLOR = "#000";
|
|
43215
43576
|
css /* scss */ `
|
|
43216
43577
|
.o-spreadsheet {
|
|
43217
43578
|
position: relative;
|
|
@@ -43244,6 +43605,27 @@ css /* scss */ `
|
|
|
43244
43605
|
margin-top: ${MENU_SEPARATOR_PADDING}px;
|
|
43245
43606
|
margin-bottom: ${MENU_SEPARATOR_PADDING}px;
|
|
43246
43607
|
}
|
|
43608
|
+
.o-hoverable-button {
|
|
43609
|
+
border-radius: 2px;
|
|
43610
|
+
cursor: pointer;
|
|
43611
|
+
.o-icon {
|
|
43612
|
+
color: ${ICONS_COLOR};
|
|
43613
|
+
}
|
|
43614
|
+
&:not(.o-disabled):not(.active):hover {
|
|
43615
|
+
background-color: ${HOVERED_BG_COLOR};
|
|
43616
|
+
color: ${HOVERED_FONT_COLOR};
|
|
43617
|
+
.o-icon {
|
|
43618
|
+
color: ${HOVERED_FONT_COLOR};
|
|
43619
|
+
}
|
|
43620
|
+
}
|
|
43621
|
+
&.active {
|
|
43622
|
+
background-color: ${ACTIVE_BG_COLOR};
|
|
43623
|
+
color: ${ACTIVE_FONT_COLOR};
|
|
43624
|
+
.o-icon {
|
|
43625
|
+
color: ${ACTIVE_FONT_COLOR};
|
|
43626
|
+
}
|
|
43627
|
+
}
|
|
43628
|
+
}
|
|
43247
43629
|
}
|
|
43248
43630
|
|
|
43249
43631
|
.o-two-columns {
|
|
@@ -43393,6 +43775,9 @@ class Spreadsheet extends owl.Component {
|
|
|
43393
43775
|
}
|
|
43394
43776
|
}
|
|
43395
43777
|
openSidePanel(panel, panelProps) {
|
|
43778
|
+
if (this.sidePanel.isOpen && panel !== this.sidePanel.component) {
|
|
43779
|
+
this.sidePanel.panelProps?.onCloseSidePanel?.();
|
|
43780
|
+
}
|
|
43396
43781
|
this.sidePanel.component = panel;
|
|
43397
43782
|
this.sidePanel.panelProps = panelProps;
|
|
43398
43783
|
this.sidePanel.isOpen = true;
|
|
@@ -44102,13 +44487,13 @@ class Tree {
|
|
|
44102
44487
|
}
|
|
44103
44488
|
|
|
44104
44489
|
class SelectiveHistory {
|
|
44490
|
+
HEAD_BRANCH;
|
|
44491
|
+
HEAD_OPERATION;
|
|
44492
|
+
tree;
|
|
44105
44493
|
applyOperation;
|
|
44106
44494
|
revertOperation;
|
|
44107
44495
|
buildEmpty;
|
|
44108
44496
|
buildTransformation;
|
|
44109
|
-
HEAD_BRANCH;
|
|
44110
|
-
HEAD_OPERATION;
|
|
44111
|
-
tree;
|
|
44112
44497
|
/**
|
|
44113
44498
|
* The selective history is a data structure used to register changes/updates of a state.
|
|
44114
44499
|
* Each change/update is called an "operation".
|
|
@@ -44129,14 +44514,15 @@ class SelectiveHistory {
|
|
|
44129
44514
|
* (used for internal implementation)
|
|
44130
44515
|
* @param buildTransformation Factory used to build transformations
|
|
44131
44516
|
*/
|
|
44132
|
-
constructor(
|
|
44133
|
-
this.applyOperation = applyOperation;
|
|
44134
|
-
this.revertOperation = revertOperation;
|
|
44135
|
-
this.buildEmpty = buildEmpty;
|
|
44136
|
-
this.buildTransformation = buildTransformation;
|
|
44517
|
+
constructor(args) {
|
|
44518
|
+
this.applyOperation = args.applyOperation;
|
|
44519
|
+
this.revertOperation = args.revertOperation;
|
|
44520
|
+
this.buildEmpty = args.buildEmpty;
|
|
44521
|
+
this.buildTransformation = args.buildTransformation;
|
|
44137
44522
|
this.HEAD_BRANCH = new Branch(this.buildTransformation);
|
|
44138
|
-
this.tree = new Tree(buildTransformation, this.HEAD_BRANCH);
|
|
44139
|
-
const
|
|
44523
|
+
this.tree = new Tree(this.buildTransformation, this.HEAD_BRANCH);
|
|
44524
|
+
const initialOperationId = args.initialOperationId;
|
|
44525
|
+
const initial = new Operation(initialOperationId, this.buildEmpty(initialOperationId));
|
|
44140
44526
|
this.tree.insertOperationLast(this.HEAD_BRANCH, initial);
|
|
44141
44527
|
this.HEAD_OPERATION = initial;
|
|
44142
44528
|
}
|
|
@@ -44250,21 +44636,27 @@ class SelectiveHistory {
|
|
|
44250
44636
|
}
|
|
44251
44637
|
}
|
|
44252
44638
|
|
|
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);
|
|
44639
|
+
function buildRevisionLog(args) {
|
|
44640
|
+
return new SelectiveHistory({
|
|
44641
|
+
initialOperationId: args.initialRevisionId,
|
|
44642
|
+
applyOperation: (revision) => {
|
|
44643
|
+
const commands = revision.commands.slice();
|
|
44644
|
+
const { changes } = args.recordChanges(() => {
|
|
44645
|
+
for (const command of commands) {
|
|
44646
|
+
args.dispatch(command);
|
|
44647
|
+
}
|
|
44648
|
+
});
|
|
44649
|
+
revision.setChanges(changes);
|
|
44265
44650
|
},
|
|
44266
|
-
|
|
44267
|
-
|
|
44651
|
+
revertOperation: (revision) => revertChanges([revision]),
|
|
44652
|
+
buildEmpty: (id) => new Revision(id, "empty", []),
|
|
44653
|
+
buildTransformation: {
|
|
44654
|
+
with: (revision) => (toTransform) => {
|
|
44655
|
+
return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands), toTransform.rootCommand, undefined, toTransform.timestamp);
|
|
44656
|
+
},
|
|
44657
|
+
without: (revision) => (toTransform) => {
|
|
44658
|
+
return new Revision(toTransform.id, toTransform.clientId, transformAll(toTransform.commands, revision.commands.map(inverseCommand).flat()), toTransform.rootCommand, undefined, toTransform.timestamp);
|
|
44659
|
+
},
|
|
44268
44660
|
},
|
|
44269
44661
|
});
|
|
44270
44662
|
}
|
|
@@ -45937,11 +46329,21 @@ function addBorders(borders) {
|
|
|
45937
46329
|
for (let border of Object.values(borders)) {
|
|
45938
46330
|
borderNodes.push(escapeXml /*xml*/ `
|
|
45939
46331
|
<border>
|
|
45940
|
-
<left ${formatBorderAttribute(border["left"])}
|
|
45941
|
-
|
|
45942
|
-
|
|
45943
|
-
<
|
|
45944
|
-
|
|
46332
|
+
<left ${formatBorderAttribute(border["left"])}>
|
|
46333
|
+
${addBorderColor(border["left"])}
|
|
46334
|
+
</left>
|
|
46335
|
+
<right ${formatBorderAttribute(border["right"])}>
|
|
46336
|
+
${addBorderColor(border["right"])}
|
|
46337
|
+
</right>
|
|
46338
|
+
<top ${formatBorderAttribute(border["top"])}>
|
|
46339
|
+
${addBorderColor(border["top"])}
|
|
46340
|
+
</top>
|
|
46341
|
+
<bottom ${formatBorderAttribute(border["bottom"])}>
|
|
46342
|
+
${addBorderColor(border["bottom"])}
|
|
46343
|
+
</bottom>
|
|
46344
|
+
<diagonal ${formatBorderAttribute(border["diagonal"])}>
|
|
46345
|
+
${addBorderColor(border["diagonal"])}
|
|
46346
|
+
</diagonal>
|
|
45945
46347
|
</border>
|
|
45946
46348
|
`);
|
|
45947
46349
|
}
|
|
@@ -45955,10 +46357,15 @@ function formatBorderAttribute(description) {
|
|
|
45955
46357
|
if (!description) {
|
|
45956
46358
|
return escapeXml ``;
|
|
45957
46359
|
}
|
|
45958
|
-
return formatAttributes([
|
|
45959
|
-
|
|
45960
|
-
|
|
45961
|
-
|
|
46360
|
+
return formatAttributes([["style", description.style]]);
|
|
46361
|
+
}
|
|
46362
|
+
function addBorderColor(description) {
|
|
46363
|
+
if (!description) {
|
|
46364
|
+
return escapeXml ``;
|
|
46365
|
+
}
|
|
46366
|
+
return escapeXml /*xml*/ `
|
|
46367
|
+
<color ${formatAttributes([["rgb", toXlsxHexColor(description.color.rgb)]])}/>
|
|
46368
|
+
`;
|
|
45962
46369
|
}
|
|
45963
46370
|
function addStyles(styles) {
|
|
45964
46371
|
const styleNodes = [];
|
|
@@ -46602,6 +47009,7 @@ class Model extends EventBus {
|
|
|
46602
47009
|
this.setupCorePlugin(Plugin, workbookData);
|
|
46603
47010
|
}
|
|
46604
47011
|
Object.assign(this.getters, this.coreGetters);
|
|
47012
|
+
this.session.loadInitialMessages(stateUpdateMessages);
|
|
46605
47013
|
for (let Plugin of statefulUIPluginRegistry.getAll()) {
|
|
46606
47014
|
const plugin = this.setupUiPlugin(Plugin);
|
|
46607
47015
|
this.statefulUIPlugins.push(plugin);
|
|
@@ -46629,8 +47037,6 @@ class Model extends EventBus {
|
|
|
46629
47037
|
// This should be done after construction of LocalHistory due to order of
|
|
46630
47038
|
// events
|
|
46631
47039
|
this.setupSessionEvents();
|
|
46632
|
-
// Load the initial revisions
|
|
46633
|
-
this.session.loadInitialMessages(stateUpdateMessages);
|
|
46634
47040
|
this.joinSession();
|
|
46635
47041
|
if (config.snapshotRequested) {
|
|
46636
47042
|
this.session.snapshot(this.exportData());
|
|
@@ -46694,14 +47100,18 @@ class Model extends EventBus {
|
|
|
46694
47100
|
this.finalize();
|
|
46695
47101
|
}
|
|
46696
47102
|
setupSession(revisionId) {
|
|
46697
|
-
const session = new Session(buildRevisionLog(
|
|
46698
|
-
|
|
46699
|
-
|
|
46700
|
-
|
|
46701
|
-
|
|
46702
|
-
|
|
46703
|
-
|
|
46704
|
-
|
|
47103
|
+
const session = new Session(buildRevisionLog({
|
|
47104
|
+
initialRevisionId: revisionId,
|
|
47105
|
+
recordChanges: this.state.recordChanges.bind(this.state),
|
|
47106
|
+
dispatch: (command) => {
|
|
47107
|
+
const result = this.checkDispatchAllowed(command);
|
|
47108
|
+
if (!result.isSuccessful) {
|
|
47109
|
+
return;
|
|
47110
|
+
}
|
|
47111
|
+
this.isReplayingCommand = true;
|
|
47112
|
+
this.dispatchToHandlers(this.coreHandlers, command);
|
|
47113
|
+
this.isReplayingCommand = false;
|
|
47114
|
+
},
|
|
46705
47115
|
}), this.config.transportService, revisionId);
|
|
46706
47116
|
return session;
|
|
46707
47117
|
}
|
|
@@ -47100,6 +47510,6 @@ exports.setTranslationMethod = setTranslationMethod;
|
|
|
47100
47510
|
exports.tokenize = tokenize;
|
|
47101
47511
|
|
|
47102
47512
|
|
|
47103
|
-
__info__.version = '16.3.0-alpha.
|
|
47104
|
-
__info__.date = '2023-05-
|
|
47105
|
-
__info__.hash = '
|
|
47513
|
+
__info__.version = '16.3.0-alpha.8';
|
|
47514
|
+
__info__.date = '2023-05-12T10:59:42.550Z';
|
|
47515
|
+
__info__.hash = 'afee7d5';
|