@odoo/o-spreadsheet 18.4.0-alpha.5 → 18.4.0-alpha.7
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 +1167 -606
- package/dist/o-spreadsheet.d.ts +323 -161
- package/dist/o-spreadsheet.esm.js +1167 -606
- package/dist/o-spreadsheet.iife.js +1167 -606
- package/dist/o-spreadsheet.iife.min.js +475 -495
- package/dist/o_spreadsheet.xml +202 -154
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.4.0-alpha.
|
|
6
|
-
* @date 2025-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.4.0-alpha.7
|
|
6
|
+
* @date 2025-06-06T09:32:44.285Z
|
|
7
|
+
* @hash 2bfbe64
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
(function (exports, owl) {
|
|
@@ -280,8 +280,10 @@
|
|
|
280
280
|
const MIN_COL_WIDTH = 5;
|
|
281
281
|
const HEADER_HEIGHT = 26;
|
|
282
282
|
const HEADER_WIDTH = 48;
|
|
283
|
-
const
|
|
284
|
-
const
|
|
283
|
+
const DESKTOP_TOPBAR_TOOLBAR_HEIGHT = 34;
|
|
284
|
+
const MOBILE_TOPBAR_TOOLBAR_HEIGHT = 44;
|
|
285
|
+
const DESKTOP_BOTTOMBAR_HEIGHT = 36;
|
|
286
|
+
const MOBILE_BOTTOMBAR_HEIGHT = 44;
|
|
285
287
|
const DEFAULT_CELL_WIDTH = 96;
|
|
286
288
|
const DEFAULT_CELL_HEIGHT = 23;
|
|
287
289
|
const SCROLLBAR_WIDTH = 15;
|
|
@@ -302,7 +304,8 @@
|
|
|
302
304
|
// Menus
|
|
303
305
|
const MENU_WIDTH = 250;
|
|
304
306
|
const MENU_VERTICAL_PADDING = 6;
|
|
305
|
-
const
|
|
307
|
+
const DESKTOP_MENU_ITEM_HEIGHT = 26;
|
|
308
|
+
const MOBILE_MENU_ITEM_HEIGHT = 35;
|
|
306
309
|
const MENU_ITEM_PADDING_HORIZONTAL = 11;
|
|
307
310
|
const MENU_ITEM_PADDING_VERTICAL = 4;
|
|
308
311
|
const MENU_SEPARATOR_BORDER_WIDTH = 1;
|
|
@@ -400,6 +403,7 @@
|
|
|
400
403
|
automaticAutofill: false,
|
|
401
404
|
};
|
|
402
405
|
const PIVOT_INDENT = 15;
|
|
406
|
+
const PIVOT_COLLAPSE_ICON_SIZE = 12;
|
|
403
407
|
const DEFAULT_CURRENCY = {
|
|
404
408
|
symbol: "$",
|
|
405
409
|
position: "before",
|
|
@@ -8533,9 +8537,10 @@
|
|
|
8533
8537
|
avg: _t("Average"),
|
|
8534
8538
|
sum: _t("Sum"),
|
|
8535
8539
|
};
|
|
8540
|
+
const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "count"];
|
|
8536
8541
|
const AGGREGATORS_BY_FIELD_TYPE = {
|
|
8537
|
-
integer:
|
|
8538
|
-
char:
|
|
8542
|
+
integer: NUMBER_CHAR_AGGREGATORS,
|
|
8543
|
+
char: NUMBER_CHAR_AGGREGATORS,
|
|
8539
8544
|
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
|
|
8540
8545
|
datetime: ["max", "min", "count_distinct", "count"],
|
|
8541
8546
|
};
|
|
@@ -20556,7 +20561,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
20556
20561
|
description: _t("Converts a number to text according to a specified format."),
|
|
20557
20562
|
args: [
|
|
20558
20563
|
arg("number (number)", _t("The number, date or time to format.")),
|
|
20559
|
-
arg("format (string)", _t(
|
|
20564
|
+
arg("format (string)", _t('The case-sensitive format of the result, enclosed in quotation marks. Examples: "0.00" rounded to 2 decimal places, "hh:mm:ss" for hour:minutes:seconds.')),
|
|
20560
20565
|
],
|
|
20561
20566
|
compute: function (number, format) {
|
|
20562
20567
|
const _number = toNumber(number, this.locale);
|
|
@@ -21663,8 +21668,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21663
21668
|
if (isNaN(value)) {
|
|
21664
21669
|
continue;
|
|
21665
21670
|
}
|
|
21666
|
-
const axisId = chart.config.type === "radar" ? dataset.rAxisID : dataset.yAxisID;
|
|
21667
|
-
const displayValue = options.callback(Number(value), axisId);
|
|
21668
21671
|
const point = dataset.data[i];
|
|
21669
21672
|
const xPosition = point.x;
|
|
21670
21673
|
let yPosition = 0;
|
|
@@ -21688,7 +21691,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21688
21691
|
textsPositions[xPosition].push(yPosition);
|
|
21689
21692
|
ctx.fillStyle = point.options.backgroundColor;
|
|
21690
21693
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
21691
|
-
|
|
21694
|
+
const valueToDisplay = options.callback(Number(value), dataset, i);
|
|
21695
|
+
drawTextWithBackground(valueToDisplay, xPosition, yPosition, ctx);
|
|
21692
21696
|
}
|
|
21693
21697
|
}
|
|
21694
21698
|
}
|
|
@@ -21705,7 +21709,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21705
21709
|
if (isNaN(value)) {
|
|
21706
21710
|
continue;
|
|
21707
21711
|
}
|
|
21708
|
-
const displayValue = options.callback(value, dataset
|
|
21712
|
+
const displayValue = options.callback(value, dataset, i);
|
|
21709
21713
|
const point = dataset.data[i];
|
|
21710
21714
|
const yPosition = point.y;
|
|
21711
21715
|
let xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
@@ -21743,7 +21747,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
21743
21747
|
const y = bar.y + midRadius * Math.sin(midAngle) + 7;
|
|
21744
21748
|
ctx.fillStyle = chartFontColor(options.background);
|
|
21745
21749
|
ctx.strokeStyle = options.background || "#ffffff";
|
|
21746
|
-
const displayValue = options.callback(value,
|
|
21750
|
+
const displayValue = options.callback(value, dataset, i);
|
|
21747
21751
|
drawTextWithBackground(displayValue, x, y, ctx);
|
|
21748
21752
|
}
|
|
21749
21753
|
}
|
|
@@ -23490,7 +23494,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23490
23494
|
* On Mac, this is the "meta" or "command" key.
|
|
23491
23495
|
*/
|
|
23492
23496
|
function isCtrlKey(ev) {
|
|
23493
|
-
return isMacOS() ? ev.metaKey : ev.ctrlKey;
|
|
23497
|
+
return isMacOS() || isIOS() ? ev.metaKey : ev.ctrlKey;
|
|
23494
23498
|
}
|
|
23495
23499
|
/**
|
|
23496
23500
|
* @param {MouseEvent} ev - The mouse event.
|
|
@@ -23529,6 +23533,23 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
23529
23533
|
function isBrowserFirefox() {
|
|
23530
23534
|
return /Firefox/i.test(navigator.userAgent);
|
|
23531
23535
|
}
|
|
23536
|
+
// Mobile detection
|
|
23537
|
+
function maxTouchPoints() {
|
|
23538
|
+
return navigator.maxTouchPoints || 1;
|
|
23539
|
+
}
|
|
23540
|
+
function isAndroid() {
|
|
23541
|
+
return /Android/i.test(navigator.userAgent);
|
|
23542
|
+
}
|
|
23543
|
+
function isIOS() {
|
|
23544
|
+
return (/(iPad|iPhone|iPod)/i.test(navigator.userAgent) ||
|
|
23545
|
+
(navigator.platform === "MacIntel" && maxTouchPoints() > 1));
|
|
23546
|
+
}
|
|
23547
|
+
function isOtherMobileOS() {
|
|
23548
|
+
return /(webOS|BlackBerry|Windows Phone)/i.test(navigator.userAgent);
|
|
23549
|
+
}
|
|
23550
|
+
function isMobileOS() {
|
|
23551
|
+
return isAndroid() || isIOS() || isOtherMobileOS();
|
|
23552
|
+
}
|
|
23532
23553
|
|
|
23533
23554
|
/**
|
|
23534
23555
|
* Convert a JS color hexadecimal to an excel compatible color.
|
|
@@ -25049,14 +25070,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25049
25070
|
...getLegendDisplayOptions(definition),
|
|
25050
25071
|
labels: {
|
|
25051
25072
|
usePointStyle: true,
|
|
25052
|
-
generateLabels: (c) => c.data.labels?.map((label, index) => ({
|
|
25073
|
+
generateLabels: (c) => (c.data.labels?.map((label, index) => ({
|
|
25053
25074
|
text: truncateLabel(String(label)),
|
|
25054
25075
|
strokeStyle: colors[index],
|
|
25055
25076
|
fillStyle: colors[index],
|
|
25056
25077
|
pointStyle: "rect",
|
|
25057
25078
|
lineWidth: 2,
|
|
25058
25079
|
fontColor,
|
|
25059
|
-
})) || [],
|
|
25080
|
+
})) || []).filter((label) => label.text),
|
|
25060
25081
|
filter: (legendItem, data) => {
|
|
25061
25082
|
return "datasetIndex" in legendItem
|
|
25062
25083
|
? !data.datasets[legendItem.datasetIndex].hidden
|
|
@@ -25216,7 +25237,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25216
25237
|
labels: {
|
|
25217
25238
|
color: fontColor,
|
|
25218
25239
|
usePointStyle: true,
|
|
25219
|
-
generateLabels: (chart) => chart.data.datasets
|
|
25240
|
+
generateLabels: (chart) => chart.data.datasets
|
|
25241
|
+
.map((dataset, index) => {
|
|
25220
25242
|
if (isTrendLineAxis(dataset["xAxisID"])) {
|
|
25221
25243
|
return {
|
|
25222
25244
|
text: truncateLabel(dataset.label),
|
|
@@ -25238,7 +25260,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25238
25260
|
datasetIndex: index,
|
|
25239
25261
|
...legendLabelConfig,
|
|
25240
25262
|
};
|
|
25241
|
-
})
|
|
25263
|
+
})
|
|
25264
|
+
.filter((label) => label.text),
|
|
25242
25265
|
filter: (legendItem, data) => {
|
|
25243
25266
|
return "datasetIndex" in legendItem
|
|
25244
25267
|
? !data.datasets[legendItem.datasetIndex].hidden
|
|
@@ -25592,7 +25615,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25592
25615
|
horizontal: "horizontal" in definition && definition.horizontal,
|
|
25593
25616
|
showValues: "showValues" in definition ? !!definition.showValues : false,
|
|
25594
25617
|
background: definition.background,
|
|
25595
|
-
callback:
|
|
25618
|
+
callback: (value, dataset) => {
|
|
25619
|
+
const axisId = getDatasetAxisId(definition, dataset);
|
|
25620
|
+
return formatChartDatasetValue(axisFormats, locale)(value, axisId);
|
|
25621
|
+
},
|
|
25596
25622
|
};
|
|
25597
25623
|
}
|
|
25598
25624
|
function getSunburstShowValues(definition, args) {
|
|
@@ -25610,6 +25636,45 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
25610
25636
|
},
|
|
25611
25637
|
};
|
|
25612
25638
|
}
|
|
25639
|
+
function getPyramidChartShowValues(definition, args) {
|
|
25640
|
+
const { axisFormats, locale } = args;
|
|
25641
|
+
return {
|
|
25642
|
+
horizontal: true,
|
|
25643
|
+
showValues: "showValues" in definition ? !!definition.showValues : false,
|
|
25644
|
+
background: definition.background,
|
|
25645
|
+
callback: (value, dataset) => {
|
|
25646
|
+
value = Math.abs(Number(value));
|
|
25647
|
+
return formatChartDatasetValue(axisFormats, locale)(value, dataset.xAxisID || "x");
|
|
25648
|
+
},
|
|
25649
|
+
};
|
|
25650
|
+
}
|
|
25651
|
+
function getWaterfallChartShowValues(definition, args) {
|
|
25652
|
+
const { axisFormats, locale, dataSetsValues } = args;
|
|
25653
|
+
const subtotalIndexes = dataSetsValues.reduce((subtotalIndexes, ds) => {
|
|
25654
|
+
subtotalIndexes.push((subtotalIndexes.at(-1) || -1) + ds.data.length + 1);
|
|
25655
|
+
return subtotalIndexes;
|
|
25656
|
+
}, []);
|
|
25657
|
+
return {
|
|
25658
|
+
showValues: "showValues" in definition ? !!definition.showValues : false,
|
|
25659
|
+
background: definition.background,
|
|
25660
|
+
callback: (value, dataset, index) => {
|
|
25661
|
+
const raw = dataset._dataset.data[index];
|
|
25662
|
+
const delta = raw[1] - raw[0];
|
|
25663
|
+
let sign = delta >= 0 ? "+" : "";
|
|
25664
|
+
if (definition.showSubTotals && subtotalIndexes.includes(index) && sign === "+") {
|
|
25665
|
+
sign = "";
|
|
25666
|
+
}
|
|
25667
|
+
return `${sign}${formatChartDatasetValue(axisFormats, locale)(delta, dataset.yAxisID)}`;
|
|
25668
|
+
},
|
|
25669
|
+
};
|
|
25670
|
+
}
|
|
25671
|
+
function getDatasetAxisId(definition, dataset) {
|
|
25672
|
+
if (dataset.rAxisID) {
|
|
25673
|
+
return dataset.rAxisID;
|
|
25674
|
+
}
|
|
25675
|
+
const axisId = "horizontal" in definition && definition.horizontal ? dataset.xAxisID : dataset.yAxisID;
|
|
25676
|
+
return axisId || "y";
|
|
25677
|
+
}
|
|
25613
25678
|
|
|
25614
25679
|
function getChartTitle(definition) {
|
|
25615
25680
|
const chartTitle = definition.title;
|
|
@@ -26012,6 +26077,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26012
26077
|
getPieChartTooltip: getPieChartTooltip,
|
|
26013
26078
|
getPyramidChartData: getPyramidChartData,
|
|
26014
26079
|
getPyramidChartScales: getPyramidChartScales,
|
|
26080
|
+
getPyramidChartShowValues: getPyramidChartShowValues,
|
|
26015
26081
|
getPyramidChartTooltip: getPyramidChartTooltip,
|
|
26016
26082
|
getRadarChartData: getRadarChartData,
|
|
26017
26083
|
getRadarChartDatasets: getRadarChartDatasets,
|
|
@@ -26032,6 +26098,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
26032
26098
|
getTrendDatasetForLineChart: getTrendDatasetForLineChart,
|
|
26033
26099
|
getWaterfallChartLegend: getWaterfallChartLegend,
|
|
26034
26100
|
getWaterfallChartScales: getWaterfallChartScales,
|
|
26101
|
+
getWaterfallChartShowValues: getWaterfallChartShowValues,
|
|
26035
26102
|
getWaterfallChartTooltip: getWaterfallChartTooltip,
|
|
26036
26103
|
getWaterfallDatasetAndLabels: getWaterfallDatasetAndLabels,
|
|
26037
26104
|
makeDatasetsCumulative: makeDatasetsCumulative
|
|
@@ -27344,7 +27411,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
27344
27411
|
title: getChartTitle(definition),
|
|
27345
27412
|
legend: getBarChartLegend(definition),
|
|
27346
27413
|
tooltip: getPyramidChartTooltip(definition, chartData),
|
|
27347
|
-
chartShowValuesPlugin:
|
|
27414
|
+
chartShowValuesPlugin: getPyramidChartShowValues(definition, chartData),
|
|
27348
27415
|
},
|
|
27349
27416
|
},
|
|
27350
27417
|
};
|
|
@@ -28092,7 +28159,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28092
28159
|
title: getChartTitle(definition),
|
|
28093
28160
|
legend: getWaterfallChartLegend(definition),
|
|
28094
28161
|
tooltip: getWaterfallChartTooltip(definition, chartData),
|
|
28095
|
-
chartShowValuesPlugin:
|
|
28162
|
+
chartShowValuesPlugin: getWaterfallChartShowValues(definition, chartData),
|
|
28096
28163
|
waterfallLinesPlugin: { showConnectorLines: definition.showConnectorLines },
|
|
28097
28164
|
},
|
|
28098
28165
|
},
|
|
@@ -28884,6 +28951,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
28884
28951
|
env.openSidePanel("ChartPanel");
|
|
28885
28952
|
},
|
|
28886
28953
|
icon: "o-spreadsheet-Icon.EDIT",
|
|
28954
|
+
isEnabled: (env) => !env.isSmall,
|
|
28887
28955
|
},
|
|
28888
28956
|
getCopyMenuItem(figureId, env),
|
|
28889
28957
|
getCutMenuItem(figureId, env),
|
|
@@ -29098,6 +29166,147 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29098
29166
|
};
|
|
29099
29167
|
}
|
|
29100
29168
|
|
|
29169
|
+
//------------------------------------------------------------------------------
|
|
29170
|
+
// Context Menu Component
|
|
29171
|
+
//------------------------------------------------------------------------------
|
|
29172
|
+
css /* scss */ `
|
|
29173
|
+
.o-menu {
|
|
29174
|
+
background-color: white;
|
|
29175
|
+
user-select: none;
|
|
29176
|
+
|
|
29177
|
+
.o-menu-item {
|
|
29178
|
+
height: ${DESKTOP_MENU_ITEM_HEIGHT}px;
|
|
29179
|
+
padding: ${MENU_ITEM_PADDING_VERTICAL}px ${MENU_ITEM_PADDING_HORIZONTAL}px;
|
|
29180
|
+
cursor: pointer;
|
|
29181
|
+
user-select: none;
|
|
29182
|
+
|
|
29183
|
+
.o-menu-item-name {
|
|
29184
|
+
min-width: 40%;
|
|
29185
|
+
}
|
|
29186
|
+
|
|
29187
|
+
.o-menu-item-icon {
|
|
29188
|
+
display: inline-block;
|
|
29189
|
+
margin: 0px 8px 0px 0px;
|
|
29190
|
+
width: ${DESKTOP_MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
29191
|
+
line-height: ${DESKTOP_MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
29192
|
+
}
|
|
29193
|
+
|
|
29194
|
+
&:not(.disabled) {
|
|
29195
|
+
&:hover,
|
|
29196
|
+
&.o-menu-item-active {
|
|
29197
|
+
background-color: ${BUTTON_ACTIVE_BG};
|
|
29198
|
+
color: ${BUTTON_ACTIVE_TEXT_COLOR};
|
|
29199
|
+
}
|
|
29200
|
+
.o-menu-item-description {
|
|
29201
|
+
color: grey;
|
|
29202
|
+
}
|
|
29203
|
+
.o-menu-item-icon {
|
|
29204
|
+
.o-icon {
|
|
29205
|
+
color: ${ICONS_COLOR};
|
|
29206
|
+
}
|
|
29207
|
+
}
|
|
29208
|
+
}
|
|
29209
|
+
&.disabled {
|
|
29210
|
+
color: ${DISABLED_TEXT_COLOR};
|
|
29211
|
+
cursor: not-allowed;
|
|
29212
|
+
}
|
|
29213
|
+
}
|
|
29214
|
+
}
|
|
29215
|
+
|
|
29216
|
+
.o-spreadsheet-mobile {
|
|
29217
|
+
.o-menu-item {
|
|
29218
|
+
height: ${MOBILE_MENU_ITEM_HEIGHT}px;
|
|
29219
|
+
}
|
|
29220
|
+
}
|
|
29221
|
+
`;
|
|
29222
|
+
class Menu extends owl.Component {
|
|
29223
|
+
static template = "o-spreadsheet-Menu";
|
|
29224
|
+
static props = {
|
|
29225
|
+
menuItems: Array,
|
|
29226
|
+
onClose: Function,
|
|
29227
|
+
onClickMenu: { type: Function, optional: true },
|
|
29228
|
+
onMouseEnter: { type: Function, optional: true },
|
|
29229
|
+
onMouseOver: { type: Function, optional: true },
|
|
29230
|
+
onMouseLeave: { type: Function, optional: true },
|
|
29231
|
+
width: { type: Number, optional: true },
|
|
29232
|
+
isActive: { type: Function, optional: true },
|
|
29233
|
+
onScroll: { type: Function, optional: true },
|
|
29234
|
+
};
|
|
29235
|
+
static components = {};
|
|
29236
|
+
static defaultProps = {};
|
|
29237
|
+
hoveredMenu = undefined;
|
|
29238
|
+
setup() {
|
|
29239
|
+
owl.onWillUnmount(() => {
|
|
29240
|
+
this.hoveredMenu?.onStopHover?.(this.env);
|
|
29241
|
+
});
|
|
29242
|
+
}
|
|
29243
|
+
get menuItemsAndSeparators() {
|
|
29244
|
+
const menuItemsAndSeparators = [];
|
|
29245
|
+
for (let i = 0; i < this.props.menuItems.length; i++) {
|
|
29246
|
+
const menuItem = this.props.menuItems[i];
|
|
29247
|
+
if (menuItem.isVisible(this.env)) {
|
|
29248
|
+
menuItemsAndSeparators.push(menuItem);
|
|
29249
|
+
}
|
|
29250
|
+
if (menuItem.separator &&
|
|
29251
|
+
i !== this.props.menuItems.length - 1 && // no separator at the end
|
|
29252
|
+
menuItemsAndSeparators[menuItemsAndSeparators.length - 1] !== "separator" // no double separator
|
|
29253
|
+
) {
|
|
29254
|
+
menuItemsAndSeparators.push("separator");
|
|
29255
|
+
}
|
|
29256
|
+
}
|
|
29257
|
+
if (menuItemsAndSeparators[menuItemsAndSeparators.length - 1] === "separator") {
|
|
29258
|
+
menuItemsAndSeparators.pop();
|
|
29259
|
+
}
|
|
29260
|
+
if (menuItemsAndSeparators.length === 1 && menuItemsAndSeparators[0] === "separator") {
|
|
29261
|
+
return [];
|
|
29262
|
+
}
|
|
29263
|
+
return menuItemsAndSeparators;
|
|
29264
|
+
}
|
|
29265
|
+
get childrenHaveIcon() {
|
|
29266
|
+
return this.props.menuItems.some((menuItem) => !!this.getIconName(menuItem));
|
|
29267
|
+
}
|
|
29268
|
+
getIconName(menu) {
|
|
29269
|
+
if (menu.icon(this.env)) {
|
|
29270
|
+
return menu.icon(this.env);
|
|
29271
|
+
}
|
|
29272
|
+
if (menu.isActive?.(this.env)) {
|
|
29273
|
+
return "o-spreadsheet-Icon.CHECK";
|
|
29274
|
+
}
|
|
29275
|
+
return "";
|
|
29276
|
+
}
|
|
29277
|
+
getColor(menu) {
|
|
29278
|
+
return cssPropertiesToCss({ color: menu.textColor });
|
|
29279
|
+
}
|
|
29280
|
+
getIconColor(menu) {
|
|
29281
|
+
return cssPropertiesToCss({ color: menu.iconColor });
|
|
29282
|
+
}
|
|
29283
|
+
getName(menu) {
|
|
29284
|
+
return menu.name(this.env);
|
|
29285
|
+
}
|
|
29286
|
+
isRoot(menu) {
|
|
29287
|
+
return !menu.execute;
|
|
29288
|
+
}
|
|
29289
|
+
isEnabled(menu) {
|
|
29290
|
+
if (menu.isEnabled(this.env)) {
|
|
29291
|
+
return this.env.model.getters.isReadonly() ? menu.isReadonlyAllowed : true;
|
|
29292
|
+
}
|
|
29293
|
+
return false;
|
|
29294
|
+
}
|
|
29295
|
+
get menuStyle() {
|
|
29296
|
+
return this.props.width ? cssPropertiesToCss({ width: this.props.width + "px" }) : "";
|
|
29297
|
+
}
|
|
29298
|
+
onMouseEnter(menu, ev) {
|
|
29299
|
+
this.hoveredMenu = menu;
|
|
29300
|
+
menu.onStartHover?.(this.env);
|
|
29301
|
+
this.props.onMouseEnter?.(menu, ev);
|
|
29302
|
+
}
|
|
29303
|
+
onMouseLeave(menu, ev) {
|
|
29304
|
+
this.hoveredMenu = undefined;
|
|
29305
|
+
menu.onStopHover?.(this.env);
|
|
29306
|
+
this.props.onMouseLeave?.(menu, ev);
|
|
29307
|
+
}
|
|
29308
|
+
}
|
|
29309
|
+
|
|
29101
29310
|
/**
|
|
29102
29311
|
* Compute the intersection of two rectangles. Returns nothing if the two rectangles don't overlap
|
|
29103
29312
|
*/
|
|
@@ -29126,6 +29335,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29126
29335
|
height: zone.bottom - zone.top,
|
|
29127
29336
|
};
|
|
29128
29337
|
}
|
|
29338
|
+
function isPointInsideRect(x, y, rect) {
|
|
29339
|
+
return x >= rect.x && x <= rect.x + rect.width && y >= rect.y && y <= rect.y + rect.height;
|
|
29340
|
+
}
|
|
29129
29341
|
|
|
29130
29342
|
/**
|
|
29131
29343
|
* Return the o-spreadsheet element position relative
|
|
@@ -29423,57 +29635,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29423
29635
|
}
|
|
29424
29636
|
|
|
29425
29637
|
//------------------------------------------------------------------------------
|
|
29426
|
-
// Context
|
|
29638
|
+
// Context MenuPopover Component
|
|
29427
29639
|
//------------------------------------------------------------------------------
|
|
29428
29640
|
css /* scss */ `
|
|
29429
|
-
.o-menu {
|
|
29430
|
-
background-color: white;
|
|
29641
|
+
.o-menu-wrapper {
|
|
29431
29642
|
padding: ${MENU_VERTICAL_PADDING}px 0px;
|
|
29432
|
-
|
|
29433
|
-
user-select: none;
|
|
29434
|
-
|
|
29435
|
-
.o-menu-item {
|
|
29436
|
-
height: ${MENU_ITEM_HEIGHT}px;
|
|
29437
|
-
padding: ${MENU_ITEM_PADDING_VERTICAL}px ${MENU_ITEM_PADDING_HORIZONTAL}px;
|
|
29438
|
-
cursor: pointer;
|
|
29439
|
-
user-select: none;
|
|
29440
|
-
|
|
29441
|
-
.o-menu-item-name {
|
|
29442
|
-
min-width: 40%;
|
|
29443
|
-
}
|
|
29444
|
-
|
|
29445
|
-
.o-menu-item-icon {
|
|
29446
|
-
display: inline-block;
|
|
29447
|
-
margin: 0px 8px 0px 0px;
|
|
29448
|
-
width: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
29449
|
-
line-height: ${MENU_ITEM_HEIGHT - 2 * MENU_ITEM_PADDING_VERTICAL}px;
|
|
29450
|
-
}
|
|
29451
|
-
|
|
29452
|
-
&:not(.disabled) {
|
|
29453
|
-
&:hover,
|
|
29454
|
-
&.o-menu-item-active {
|
|
29455
|
-
background-color: ${BUTTON_ACTIVE_BG};
|
|
29456
|
-
color: ${BUTTON_ACTIVE_TEXT_COLOR};
|
|
29457
|
-
}
|
|
29458
|
-
.o-menu-item-description {
|
|
29459
|
-
color: grey;
|
|
29460
|
-
}
|
|
29461
|
-
.o-menu-item-icon {
|
|
29462
|
-
.o-icon {
|
|
29463
|
-
color: ${ICONS_COLOR};
|
|
29464
|
-
}
|
|
29465
|
-
}
|
|
29466
|
-
}
|
|
29467
|
-
&.disabled {
|
|
29468
|
-
color: ${DISABLED_TEXT_COLOR};
|
|
29469
|
-
cursor: not-allowed;
|
|
29470
|
-
}
|
|
29471
|
-
}
|
|
29643
|
+
background-color: white;
|
|
29472
29644
|
}
|
|
29473
29645
|
`;
|
|
29474
29646
|
const TIMEOUT_DELAY = 250;
|
|
29475
|
-
class
|
|
29476
|
-
static template = "o-spreadsheet-Menu";
|
|
29647
|
+
class MenuPopover extends owl.Component {
|
|
29648
|
+
static template = "o-spreadsheet-Menu-Popover";
|
|
29477
29649
|
static props = {
|
|
29478
29650
|
anchorRect: Object,
|
|
29479
29651
|
popoverPositioning: { type: String, optional: true },
|
|
@@ -29486,7 +29658,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29486
29658
|
onMouseOver: { type: Function, optional: true },
|
|
29487
29659
|
width: { type: Number, optional: true },
|
|
29488
29660
|
};
|
|
29489
|
-
static components = { Menu, Popover };
|
|
29661
|
+
static components = { MenuPopover, Menu, Popover };
|
|
29490
29662
|
static defaultProps = {
|
|
29491
29663
|
depth: 1,
|
|
29492
29664
|
popoverPositioning: "top-right",
|
|
@@ -29513,27 +29685,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29513
29685
|
this.hoveredMenu?.onStopHover?.(this.env);
|
|
29514
29686
|
});
|
|
29515
29687
|
}
|
|
29516
|
-
get
|
|
29517
|
-
|
|
29518
|
-
|
|
29519
|
-
|
|
29520
|
-
|
|
29521
|
-
|
|
29522
|
-
|
|
29523
|
-
|
|
29524
|
-
|
|
29525
|
-
|
|
29526
|
-
)
|
|
29527
|
-
|
|
29528
|
-
}
|
|
29529
|
-
}
|
|
29530
|
-
if (menuItemsAndSeparators[menuItemsAndSeparators.length - 1] === "separator") {
|
|
29531
|
-
menuItemsAndSeparators.pop();
|
|
29532
|
-
}
|
|
29533
|
-
if (menuItemsAndSeparators.length === 1 && menuItemsAndSeparators[0] === "separator") {
|
|
29534
|
-
return [];
|
|
29535
|
-
}
|
|
29536
|
-
return menuItemsAndSeparators;
|
|
29688
|
+
get menuProps() {
|
|
29689
|
+
return {
|
|
29690
|
+
menuItems: this.props.menuItems,
|
|
29691
|
+
onClose: this.close.bind(this),
|
|
29692
|
+
// @ts-ignore
|
|
29693
|
+
onClickMenu: this.onClickMenu.bind(this),
|
|
29694
|
+
onMouseOver: this.onMouseOver.bind(this),
|
|
29695
|
+
onMouseLeave: this.onMouseLeave.bind(this),
|
|
29696
|
+
width: this.props.width || MENU_WIDTH,
|
|
29697
|
+
isActive: this.isActive.bind(this),
|
|
29698
|
+
onScroll: this.onScroll.bind(this),
|
|
29699
|
+
};
|
|
29537
29700
|
}
|
|
29538
29701
|
get subMenuAnchorRect() {
|
|
29539
29702
|
const anchorRect = Object.assign({}, this.subMenu.anchorRect);
|
|
@@ -29547,12 +29710,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29547
29710
|
x: this.props.anchorRect.x,
|
|
29548
29711
|
y: this.props.anchorRect.y,
|
|
29549
29712
|
width: isRoot ? this.props.anchorRect.width : this.props.width || MENU_WIDTH,
|
|
29550
|
-
height: isRoot ? this.props.anchorRect.height :
|
|
29713
|
+
height: isRoot ? this.props.anchorRect.height : DESKTOP_MENU_ITEM_HEIGHT,
|
|
29551
29714
|
},
|
|
29552
29715
|
positioning: this.props.popoverPositioning,
|
|
29553
29716
|
verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
|
|
29554
29717
|
onPopoverHidden: () => this.closeSubMenu(),
|
|
29555
29718
|
onPopoverMoved: () => this.closeSubMenu(),
|
|
29719
|
+
maxHeight: this.props.maxHeight,
|
|
29556
29720
|
};
|
|
29557
29721
|
}
|
|
29558
29722
|
get childrenHaveIcon() {
|
|
@@ -29622,7 +29786,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29622
29786
|
x: getRefBoundingRect(this.menuRef).x,
|
|
29623
29787
|
y: y - (this.subMenu.scrollOffset || 0),
|
|
29624
29788
|
width: this.props.width || MENU_WIDTH,
|
|
29625
|
-
height:
|
|
29789
|
+
height: DESKTOP_MENU_ITEM_HEIGHT,
|
|
29626
29790
|
};
|
|
29627
29791
|
this.subMenu.menuItems = menu.children(this.env);
|
|
29628
29792
|
this.subMenu.isOpen = true;
|
|
@@ -29671,14 +29835,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29671
29835
|
this.subMenu.isHoveringChild = true;
|
|
29672
29836
|
this.openingTimeOut.clear();
|
|
29673
29837
|
}
|
|
29674
|
-
onMouseEnter(menu, ev) {
|
|
29675
|
-
this.hoveredMenu = menu;
|
|
29676
|
-
menu.onStartHover?.(this.env);
|
|
29677
|
-
}
|
|
29678
29838
|
onMouseLeave(menu) {
|
|
29679
29839
|
this.openingTimeOut.schedule(this.closeSubMenu.bind(this), TIMEOUT_DELAY);
|
|
29680
|
-
this.hoveredMenu = undefined;
|
|
29681
|
-
menu.onStopHover?.(this.env);
|
|
29682
29840
|
}
|
|
29683
29841
|
get menuStyle() {
|
|
29684
29842
|
return this.props.width ? cssPropertiesToCss({ width: this.props.width + "px" }) : "";
|
|
@@ -29687,7 +29845,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29687
29845
|
|
|
29688
29846
|
class ChartDashboardMenu extends owl.Component {
|
|
29689
29847
|
static template = "spreadsheet.ChartDashboardMenu";
|
|
29690
|
-
static components = {
|
|
29848
|
+
static components = { MenuPopover };
|
|
29691
29849
|
static props = { figureUI: Object };
|
|
29692
29850
|
originalChartDefinition;
|
|
29693
29851
|
fullScreenFigureStore;
|
|
@@ -29951,7 +30109,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
29951
30109
|
onMouseDown: { type: Function, optional: true },
|
|
29952
30110
|
onClickAnchor: { type: Function, optional: true },
|
|
29953
30111
|
};
|
|
29954
|
-
static components = {
|
|
30112
|
+
static components = { MenuPopover };
|
|
29955
30113
|
static defaultProps = {
|
|
29956
30114
|
onFigureDeleted: () => { },
|
|
29957
30115
|
onMouseDown: () => { },
|
|
@@ -30038,7 +30196,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
30038
30196
|
this.props.onClickAnchor(dirX, dirY, ev);
|
|
30039
30197
|
}
|
|
30040
30198
|
onMouseDown(ev) {
|
|
30041
|
-
this.
|
|
30199
|
+
if (!this.env.isMobile()) {
|
|
30200
|
+
this.props.onMouseDown(ev);
|
|
30201
|
+
}
|
|
30202
|
+
}
|
|
30203
|
+
onClick(ev) {
|
|
30204
|
+
if (this.env.isMobile()) {
|
|
30205
|
+
this.props.onMouseDown(ev);
|
|
30206
|
+
}
|
|
30042
30207
|
}
|
|
30043
30208
|
onKeyDown(ev) {
|
|
30044
30209
|
const keyDownShortcut = keyboardEventToShortcutString(ev);
|
|
@@ -31505,15 +31670,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31505
31670
|
const activeSheetId = this.getters.getActiveSheetId();
|
|
31506
31671
|
return this.providers
|
|
31507
31672
|
.flatMap((h) => h.highlights)
|
|
31508
|
-
.filter((h) => h.sheetId === activeSheetId)
|
|
31673
|
+
.filter((h) => h.range.sheetId === activeSheetId)
|
|
31509
31674
|
.map((highlight) => {
|
|
31510
|
-
const { numberOfRows, numberOfCols } = zoneToDimension(highlight.zone);
|
|
31675
|
+
const { numberOfRows, numberOfCols } = zoneToDimension(highlight.range.zone);
|
|
31511
31676
|
const zone = numberOfRows * numberOfCols === 1
|
|
31512
|
-
? this.getters.expandZone(highlight.sheetId, highlight.zone)
|
|
31513
|
-
: highlight.
|
|
31677
|
+
? this.getters.expandZone(highlight.range.sheetId, highlight.range.zone)
|
|
31678
|
+
: highlight.range.unboundedZone;
|
|
31514
31679
|
return {
|
|
31515
31680
|
...highlight,
|
|
31516
|
-
zone,
|
|
31681
|
+
range: this.model.getters.getRangeFromZone(highlight.range.sheetId, zone),
|
|
31517
31682
|
};
|
|
31518
31683
|
});
|
|
31519
31684
|
}
|
|
@@ -31526,7 +31691,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
31526
31691
|
drawLayer(ctx, layer) {
|
|
31527
31692
|
if (layer === "Highlights") {
|
|
31528
31693
|
for (const highlight of this.highlights) {
|
|
31529
|
-
const rect = this.getters.getVisibleRect(highlight.zone);
|
|
31694
|
+
const rect = this.getters.getVisibleRect(highlight.range.zone);
|
|
31530
31695
|
drawHighlight(ctx, highlight, rect);
|
|
31531
31696
|
}
|
|
31532
31697
|
}
|
|
@@ -32154,12 +32319,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32154
32319
|
rangeColor(xc, sheetName) {
|
|
32155
32320
|
const refSheet = sheetName ? this.model.getters.getSheetIdByName(sheetName) : this.sheetId;
|
|
32156
32321
|
const highlight = this.highlights.find((highlight) => {
|
|
32157
|
-
if (highlight.sheetId !== refSheet)
|
|
32322
|
+
if (highlight.range.sheetId !== refSheet)
|
|
32158
32323
|
return false;
|
|
32159
32324
|
const range = this.model.getters.getRangeFromSheetXC(refSheet, xc);
|
|
32160
32325
|
let zone = range.zone;
|
|
32161
32326
|
zone = getZoneArea(zone) === 1 ? this.model.getters.expandZone(refSheet, zone) : zone;
|
|
32162
|
-
return isEqual(zone, highlight.zone);
|
|
32327
|
+
return isEqual(zone, highlight.range.zone);
|
|
32163
32328
|
});
|
|
32164
32329
|
return highlight && highlight.color ? highlight.color : undefined;
|
|
32165
32330
|
}
|
|
@@ -32269,11 +32434,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32269
32434
|
const { numberOfRows, numberOfCols } = zoneToDimension(range.zone);
|
|
32270
32435
|
const zone = numberOfRows * numberOfCols === 1
|
|
32271
32436
|
? this.getters.expandZone(range.sheetId, range.zone)
|
|
32272
|
-
: range.
|
|
32437
|
+
: range.unboundedZone;
|
|
32273
32438
|
return {
|
|
32274
|
-
zone,
|
|
32439
|
+
range: this.model.getters.getRangeFromZone(range.sheetId, zone),
|
|
32275
32440
|
color: rangeColor(rangeString),
|
|
32276
|
-
sheetId: range.sheetId,
|
|
32277
32441
|
interactive: true,
|
|
32278
32442
|
};
|
|
32279
32443
|
});
|
|
@@ -32526,11 +32690,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32526
32690
|
onInputContextMenu: { type: Function, optional: true },
|
|
32527
32691
|
composerStore: Object,
|
|
32528
32692
|
placeholder: { type: String, optional: true },
|
|
32693
|
+
inputMode: { type: String, optional: true },
|
|
32694
|
+
showAssistant: { type: Boolean, optional: true },
|
|
32529
32695
|
};
|
|
32530
32696
|
static components = { TextValueProvider, FunctionDescriptionProvider, SpeechBubble };
|
|
32531
32697
|
static defaultProps = {
|
|
32532
32698
|
inputStyle: "",
|
|
32533
32699
|
isDefaultFocus: false,
|
|
32700
|
+
inputMode: "text",
|
|
32701
|
+
showAssistant: true,
|
|
32534
32702
|
};
|
|
32535
32703
|
DOMFocusableElementStore;
|
|
32536
32704
|
composerRef = owl.useRef("o_composer");
|
|
@@ -32581,8 +32749,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32581
32749
|
assistantStyle["max-height"] = `${availableSpaceAbove - CLOSE_ICON_RADIUS}px`;
|
|
32582
32750
|
// render top
|
|
32583
32751
|
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
32584
|
-
assistantStyle.
|
|
32585
|
-
assistantStyle.transform = `translate(0, -100%)`;
|
|
32752
|
+
assistantStyle.transform = `translate(0, calc(-100% - ${cellHeight + 3}px))`;
|
|
32586
32753
|
}
|
|
32587
32754
|
if (cellX + ASSISTANT_WIDTH > this.props.delimitation.width) {
|
|
32588
32755
|
// render left
|
|
@@ -32861,6 +33028,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
32861
33028
|
// not main button, probably a context menu
|
|
32862
33029
|
return;
|
|
32863
33030
|
}
|
|
33031
|
+
if (this.env.isMobile() && !isIOS()) {
|
|
33032
|
+
return;
|
|
33033
|
+
}
|
|
32864
33034
|
this.contentHelper.removeSelection();
|
|
32865
33035
|
}
|
|
32866
33036
|
onMouseup() {
|
|
@@ -33484,7 +33654,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
33484
33654
|
*/
|
|
33485
33655
|
function startDnd(onPointerMove, onPointerUp) {
|
|
33486
33656
|
const removeListeners = () => {
|
|
33487
|
-
window.removeEventListener("pointerup", _onPointerUp);
|
|
33657
|
+
window.removeEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33488
33658
|
window.removeEventListener("dragstart", _onDragStart);
|
|
33489
33659
|
window.removeEventListener("pointermove", onPointerMove);
|
|
33490
33660
|
window.removeEventListener("wheel", onPointerMove);
|
|
@@ -33496,7 +33666,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
33496
33666
|
function _onDragStart(ev) {
|
|
33497
33667
|
ev.preventDefault();
|
|
33498
33668
|
}
|
|
33499
|
-
window.addEventListener("pointerup", _onPointerUp);
|
|
33669
|
+
window.addEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33500
33670
|
window.addEventListener("dragstart", _onDragStart);
|
|
33501
33671
|
window.addEventListener("pointermove", onPointerMove);
|
|
33502
33672
|
// mouse wheel on window is by default a passive event.
|
|
@@ -34118,9 +34288,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34118
34288
|
.filter((reference) => this.shouldBeHighlighted(this.inputSheetId, reference));
|
|
34119
34289
|
return XCs.map((xc) => {
|
|
34120
34290
|
const { sheetName } = splitReference(xc);
|
|
34291
|
+
const sheetId = (sheetName && this.getters.getSheetIdByName(sheetName)) || this.inputSheetId;
|
|
34121
34292
|
return {
|
|
34122
|
-
|
|
34123
|
-
sheetId: (sheetName && this.getters.getSheetIdByName(sheetName)) || this.inputSheetId,
|
|
34293
|
+
range: this.getters.getRangeFromSheetXC(sheetId, xc),
|
|
34124
34294
|
color,
|
|
34125
34295
|
interactive: true,
|
|
34126
34296
|
};
|
|
@@ -34589,7 +34759,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34589
34759
|
return createActions(actionSpecs);
|
|
34590
34760
|
}
|
|
34591
34761
|
|
|
34592
|
-
/** This component looks like a select input, but on click it opens a
|
|
34762
|
+
/** This component looks like a select input, but on click it opens a MenuPopover with the items given as props instead of a dropdown */
|
|
34593
34763
|
class SelectMenu extends owl.Component {
|
|
34594
34764
|
static template = "o-spreadsheet-SelectMenu";
|
|
34595
34765
|
static props = {
|
|
@@ -34597,7 +34767,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
34597
34767
|
selectedValue: String,
|
|
34598
34768
|
class: { type: String, optional: true },
|
|
34599
34769
|
};
|
|
34600
|
-
static components = {
|
|
34770
|
+
static components = { MenuPopover };
|
|
34601
34771
|
menuId = new UuidGenerator().uuidv4();
|
|
34602
34772
|
selectRef = owl.useRef("select");
|
|
34603
34773
|
state = owl.useState({
|
|
@@ -35345,7 +35515,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35345
35515
|
}
|
|
35346
35516
|
|
|
35347
35517
|
//------------------------------------------------------------------------------
|
|
35348
|
-
// Link
|
|
35518
|
+
// Link MenuPopover Registry
|
|
35349
35519
|
//------------------------------------------------------------------------------
|
|
35350
35520
|
const linkMenuRegistry = new MenuItemRegistry();
|
|
35351
35521
|
linkMenuRegistry.add("sheet", {
|
|
@@ -35407,7 +35577,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35407
35577
|
cellPosition: Object,
|
|
35408
35578
|
onClosed: { type: Function, optional: true },
|
|
35409
35579
|
};
|
|
35410
|
-
static components = {
|
|
35580
|
+
static components = { MenuPopover };
|
|
35411
35581
|
menuItems = linkMenuRegistry.getMenuItems();
|
|
35412
35582
|
link = owl.useState(this.defaultState);
|
|
35413
35583
|
menu = owl.useState({
|
|
@@ -35864,58 +36034,149 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35864
36034
|
const ARROW_DOWN = {
|
|
35865
36035
|
width: 448,
|
|
35866
36036
|
height: 512,
|
|
35867
|
-
|
|
35868
|
-
|
|
36037
|
+
paths: [
|
|
36038
|
+
{
|
|
36039
|
+
fillColor: "#E06666",
|
|
36040
|
+
path: "M413.1 222.5l22.2 22.2c9.4 9.4 9.4 24.6 0 33.9L241 473c-9.4 9.4-24.6 9.4-33.9 0L12.7 278.6c-9.4-9.4-9.4-24.6 0-33.9l22.2-22.2c9.5-9.5 25-9.3 34.3.4L184 343.4V56c0-13.3 10.7-24 24-24h32c13.3 0 24 10.7 24 24v287.4l114.8-120.5c9.3-9.8 24.8-10 34.3-.4z",
|
|
36041
|
+
},
|
|
36042
|
+
],
|
|
35869
36043
|
};
|
|
35870
36044
|
const ARROW_UP = {
|
|
35871
36045
|
width: 448,
|
|
35872
36046
|
height: 512,
|
|
35873
|
-
|
|
35874
|
-
|
|
36047
|
+
paths: [
|
|
36048
|
+
{
|
|
36049
|
+
fillColor: "#6AA84F",
|
|
36050
|
+
path: "M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z",
|
|
36051
|
+
},
|
|
36052
|
+
],
|
|
35875
36053
|
};
|
|
35876
36054
|
const ARROW_RIGHT = {
|
|
35877
36055
|
width: 448,
|
|
35878
36056
|
height: 512,
|
|
35879
|
-
|
|
35880
|
-
|
|
36057
|
+
paths: [
|
|
36058
|
+
{
|
|
36059
|
+
fillColor: "#F0AD4E",
|
|
36060
|
+
path: "M190.5 66.9l22.2-22.2c9.4-9.4 24.6-9.4 33.9 0L441 239c9.4 9.4 9.4 24.6 0 33.9L246.6 467.3c-9.4 9.4-24.6 9.4-33.9 0l-22.2-22.2c-9.5-9.5-9.3-25 .4-34.3L311.4 296H24c-13.3 0-24-10.7-24-24v-32c0-13.3 10.7-24 24-24h287.4L190.9 101.2c-9.8-9.3-10-24.8-.4-34.3z",
|
|
36061
|
+
},
|
|
36062
|
+
],
|
|
35881
36063
|
};
|
|
35882
36064
|
const SMILE = {
|
|
35883
36065
|
width: 496,
|
|
35884
36066
|
height: 512,
|
|
35885
|
-
|
|
35886
|
-
|
|
36067
|
+
paths: [
|
|
36068
|
+
{
|
|
36069
|
+
fillColor: "#6AA84F",
|
|
36070
|
+
path: "M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160 0c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm4 72.6c-20.8 25-51.5 39.4-84 39.4s-63.2-14.3-84-39.4c-8.5-10.2-23.7-11.5-33.8-3.1-10.2 8.5-11.5 23.6-3.1 33.8 30 36 74.1 56.6 120.9 56.6s90.9-20.6 120.9-56.6c8.5-10.2 7.1-25.3-3.1-33.8-10.1-8.4-25.3-7.1-33.8 3.1z",
|
|
36071
|
+
},
|
|
36072
|
+
],
|
|
35887
36073
|
};
|
|
35888
36074
|
const MEH = {
|
|
35889
36075
|
width: 496,
|
|
35890
36076
|
height: 512,
|
|
35891
|
-
|
|
35892
|
-
|
|
36077
|
+
paths: [
|
|
36078
|
+
{
|
|
36079
|
+
fillColor: "#F0AD4E",
|
|
36080
|
+
path: "M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160-64c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm8 144H160c-13.2 0-24 10.8-24 24s10.8 24 24 24h176c13.2 0 24-10.8 24-24s-10.8-24-24-24z",
|
|
36081
|
+
},
|
|
36082
|
+
],
|
|
35893
36083
|
};
|
|
35894
36084
|
const FROWN = {
|
|
35895
36085
|
width: 496,
|
|
35896
36086
|
height: 512,
|
|
35897
|
-
|
|
35898
|
-
|
|
36087
|
+
paths: [
|
|
36088
|
+
{
|
|
36089
|
+
fillColor: "#E06666",
|
|
36090
|
+
path: "M248 8C111 8 0 119 0 256s111 248 248 248 248-111 248-248S385 8 248 8zm0 448c-110.3 0-200-89.7-200-200S137.7 56 248 56s200 89.7 200 200-89.7 200-200 200zm-80-216c17.7 0 32-14.3 32-32s-14.3-32-32-32-32 14.3-32 32 14.3 32 32 32zm160-64c-17.7 0-32 14.3-32 32s14.3 32 32 32 32-14.3 32-32-14.3-32-32-32zm-80 128c-40.2 0-78 17.7-103.8 48.6-8.5 10.2-7.1 25.3 3.1 33.8 10.2 8.4 25.3 7.1 33.8-3.1 16.6-19.9 41-31.4 66.9-31.4s50.3 11.4 66.9 31.4c8.1 9.7 23.1 11.9 33.8 3.1 10.2-8.5 11.5-23.6 3.1-33.8C326 321.7 288.2 304 248 304z",
|
|
36091
|
+
},
|
|
36092
|
+
],
|
|
35899
36093
|
};
|
|
35900
36094
|
const DOT_PATH = "M256 9 a247 247 0 1 0.1 0 0";
|
|
35901
36095
|
const GREEN_DOT = {
|
|
35902
36096
|
width: 512,
|
|
35903
36097
|
height: 512,
|
|
35904
|
-
fillColor: "#6AA84F",
|
|
35905
|
-
path: DOT_PATH,
|
|
36098
|
+
paths: [{ fillColor: "#6AA84F", path: DOT_PATH }],
|
|
35906
36099
|
};
|
|
35907
36100
|
const YELLOW_DOT = {
|
|
35908
36101
|
width: 512,
|
|
35909
36102
|
height: 512,
|
|
35910
|
-
fillColor: "#F0AD4E",
|
|
35911
|
-
path: DOT_PATH,
|
|
36103
|
+
paths: [{ fillColor: "#F0AD4E", path: DOT_PATH }],
|
|
35912
36104
|
};
|
|
35913
36105
|
const RED_DOT = {
|
|
35914
36106
|
width: 512,
|
|
35915
36107
|
height: 512,
|
|
35916
|
-
fillColor: "#E06666",
|
|
35917
|
-
|
|
36108
|
+
paths: [{ fillColor: "#E06666", path: DOT_PATH }],
|
|
36109
|
+
};
|
|
36110
|
+
const CARET_DOWN = {
|
|
36111
|
+
width: 512,
|
|
36112
|
+
height: 512,
|
|
36113
|
+
paths: [{ fillColor: TEXT_BODY_MUTED, path: "M120 195 h270 l-135 130" }],
|
|
36114
|
+
};
|
|
36115
|
+
const HOVERED_CARET_DOWN = {
|
|
36116
|
+
width: 512,
|
|
36117
|
+
height: 512,
|
|
36118
|
+
paths: [
|
|
36119
|
+
{ fillColor: TEXT_BODY_MUTED, path: "M15 15 h482 v482 h-482" },
|
|
36120
|
+
{ fillColor: "#fff", path: "M120 195 h270 l-135 130" },
|
|
36121
|
+
],
|
|
35918
36122
|
};
|
|
36123
|
+
const CHECKBOX_UNCHECKED = {
|
|
36124
|
+
width: 512,
|
|
36125
|
+
height: 512,
|
|
36126
|
+
paths: [{ fillColor: GRAY_300, path: "M45,45 h422 v422 h-422 v-422 m30,30 v362 h362 v-362" }],
|
|
36127
|
+
};
|
|
36128
|
+
const CHECKBOX_UNCHECKED_HOVERED = {
|
|
36129
|
+
width: 512,
|
|
36130
|
+
height: 512,
|
|
36131
|
+
paths: [{ fillColor: ACTION_COLOR, path: "M45,45 h422 v422 h-422 v-422 m30,30 v362 h362 v-362" }],
|
|
36132
|
+
};
|
|
36133
|
+
const CHECKBOX_CHECKED = {
|
|
36134
|
+
width: 512,
|
|
36135
|
+
height: 512,
|
|
36136
|
+
paths: [
|
|
36137
|
+
{ fillColor: ACTION_COLOR, path: "M45,45 h422 v422 h-422 v-422" },
|
|
36138
|
+
{ fillColor: "#FFF", path: "M165,240 l45,45 l135,-135 h60 l-195,195 l-105,-105" },
|
|
36139
|
+
],
|
|
36140
|
+
};
|
|
36141
|
+
function getPivotIconSvg(isCollapsed, isHovered) {
|
|
36142
|
+
const symbolPath = isCollapsed
|
|
36143
|
+
? "M149,235 h213 v43 h-213 M235,149 h43 v213 h-43" // +
|
|
36144
|
+
: "M149,235 h213 v43 h-213"; // -
|
|
36145
|
+
return {
|
|
36146
|
+
width: 512,
|
|
36147
|
+
height: 512,
|
|
36148
|
+
paths: [
|
|
36149
|
+
{ path: "M21,21 h469 v469 h-469", fillColor: isHovered ? GRAY_900 : "#777" }, // borders
|
|
36150
|
+
{ path: "M64,64 v384 h384 v-384", fillColor: isHovered ? GRAY_200 : "#eee" }, // background
|
|
36151
|
+
{ path: symbolPath, fillColor: isHovered ? GRAY_900 : "#777" },
|
|
36152
|
+
],
|
|
36153
|
+
};
|
|
36154
|
+
}
|
|
36155
|
+
function getDataFilterIcon(isActive, isHighContrast, isHovered) {
|
|
36156
|
+
const symbolPath = isActive
|
|
36157
|
+
? "M18.6 3.5H4.29c-.7 0-1.06.85-.56 1.35l6.1 6.1v6.8c0 .26.13.5.34.65l2.64 1.85a.79.79 0 0 0 1.25-.65v-8.64l6.1-6.1a.79.79 0 0 0-.56-1.35"
|
|
36158
|
+
: "M 339.667 681 L 510.333 681 L 510.333 595.667 L 339.667 595.667 L 339.667 681 Z M 41 169 L 41 254.333 L 809 254.333 L 809 169 L 41 169 Z M 169 467.667 L 681 467.667 L 681 382.333 L 169 382.333 L 169 467.667 Z";
|
|
36159
|
+
const hoverBackgroundPath = isActive ? "M0,0 h24 v24 h-24" : "M0,0 h850 v850 h-850";
|
|
36160
|
+
const colors = { iconColor: FILTERS_COLOR, hoverBackgroundColor: FILTERS_COLOR };
|
|
36161
|
+
if (isHovered && !isHighContrast) {
|
|
36162
|
+
colors.iconColor = "#fff";
|
|
36163
|
+
}
|
|
36164
|
+
else if (!isHovered && isHighContrast) {
|
|
36165
|
+
colors.iconColor = "#defade";
|
|
36166
|
+
}
|
|
36167
|
+
else if (isHovered && isHighContrast) {
|
|
36168
|
+
colors.iconColor = FILTERS_COLOR;
|
|
36169
|
+
colors.hoverBackgroundColor = "#fff";
|
|
36170
|
+
}
|
|
36171
|
+
return {
|
|
36172
|
+
width: isActive ? 24 : 850,
|
|
36173
|
+
height: isActive ? 24 : 850,
|
|
36174
|
+
paths: [
|
|
36175
|
+
isHovered ? { path: hoverBackgroundPath, fillColor: colors.hoverBackgroundColor } : undefined,
|
|
36176
|
+
{ path: symbolPath, fillColor: colors.iconColor },
|
|
36177
|
+
].filter(isDefined),
|
|
36178
|
+
};
|
|
36179
|
+
}
|
|
35919
36180
|
const ICONS = {
|
|
35920
36181
|
arrowGood: {
|
|
35921
36182
|
template: "ARROW_UP",
|
|
@@ -35971,6 +36232,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
35971
36232
|
bad: "dotBad",
|
|
35972
36233
|
},
|
|
35973
36234
|
};
|
|
36235
|
+
const path2DCache = {};
|
|
36236
|
+
function getPath2D(svgPath) {
|
|
36237
|
+
if (path2DCache[svgPath]) {
|
|
36238
|
+
return path2DCache[svgPath];
|
|
36239
|
+
}
|
|
36240
|
+
const path2D = new Path2D(svgPath);
|
|
36241
|
+
path2DCache[svgPath] = path2D;
|
|
36242
|
+
return path2D;
|
|
36243
|
+
}
|
|
35974
36244
|
|
|
35975
36245
|
/**
|
|
35976
36246
|
* Map of the different types of conversions warnings and their name in error messages
|
|
@@ -41942,6 +42212,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
41942
42212
|
execute: (env) => {
|
|
41943
42213
|
env.openSidePanel("FindAndReplace", {});
|
|
41944
42214
|
},
|
|
42215
|
+
isEnabled: (env) => !env.isSmall,
|
|
41945
42216
|
icon: "o-spreadsheet-Icon.SEARCH",
|
|
41946
42217
|
};
|
|
41947
42218
|
const deleteValues = {
|
|
@@ -42198,11 +42469,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42198
42469
|
const insertChart = {
|
|
42199
42470
|
name: _t("Chart"),
|
|
42200
42471
|
execute: CREATE_CHART,
|
|
42472
|
+
isEnabled: (env) => !env.isSmall,
|
|
42201
42473
|
icon: "o-spreadsheet-Icon.INSERT_CHART",
|
|
42202
42474
|
};
|
|
42203
42475
|
const insertPivot = {
|
|
42204
42476
|
name: _t("Pivot table"),
|
|
42205
42477
|
execute: CREATE_PIVOT,
|
|
42478
|
+
isEnabled: (env) => !env.isSmall,
|
|
42206
42479
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
42207
42480
|
};
|
|
42208
42481
|
const insertImage = {
|
|
@@ -42210,12 +42483,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42210
42483
|
description: "Ctrl+O",
|
|
42211
42484
|
execute: CREATE_IMAGE,
|
|
42212
42485
|
isVisible: (env) => env.imageProvider !== undefined,
|
|
42486
|
+
isEnabled: (env) => !env.isSmall,
|
|
42213
42487
|
icon: "o-spreadsheet-Icon.INSERT_IMAGE",
|
|
42214
42488
|
};
|
|
42215
42489
|
const insertTable = {
|
|
42216
42490
|
name: () => _t("Table"),
|
|
42217
42491
|
execute: INSERT_TABLE,
|
|
42218
42492
|
isVisible: (env) => IS_SELECTION_CONTINUOUS(env) && !env.model.getters.getFirstTableInSelection(),
|
|
42493
|
+
isEnabled: (env) => !env.isSmall,
|
|
42219
42494
|
icon: "o-spreadsheet-Icon.PAINT_TABLE",
|
|
42220
42495
|
};
|
|
42221
42496
|
const insertFunction = {
|
|
@@ -42321,6 +42596,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42321
42596
|
},
|
|
42322
42597
|
});
|
|
42323
42598
|
},
|
|
42599
|
+
isEnabled: (env) => !env.isSmall,
|
|
42324
42600
|
icon: "o-spreadsheet-Icon.INSERT_DROPDOWN",
|
|
42325
42601
|
};
|
|
42326
42602
|
const insertSheet = {
|
|
@@ -42590,7 +42866,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42590
42866
|
isVisible: (env) => {
|
|
42591
42867
|
const position = env.model.getters.getActivePosition();
|
|
42592
42868
|
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
42593
|
-
return (pivotId && env.model.getters.isExistingPivot(pivotId)) || false;
|
|
42869
|
+
return (!env.isSmall && pivotId && env.model.getters.isExistingPivot(pivotId)) || false;
|
|
42594
42870
|
},
|
|
42595
42871
|
isReadonlyAllowed: true,
|
|
42596
42872
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
@@ -42708,7 +42984,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42708
42984
|
}
|
|
42709
42985
|
|
|
42710
42986
|
//------------------------------------------------------------------------------
|
|
42711
|
-
// Context
|
|
42987
|
+
// Context MenuPopover Registry
|
|
42712
42988
|
//------------------------------------------------------------------------------
|
|
42713
42989
|
const cellMenuRegistry = new MenuItemRegistry();
|
|
42714
42990
|
cellMenuRegistry
|
|
@@ -42791,6 +43067,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42791
43067
|
.add("edit_table", {
|
|
42792
43068
|
...editTable,
|
|
42793
43069
|
isVisible: SELECTION_CONTAINS_SINGLE_TABLE,
|
|
43070
|
+
isEnabled: (env) => !env.isSmall,
|
|
42794
43071
|
sequence: 140,
|
|
42795
43072
|
})
|
|
42796
43073
|
.add("delete_table", {
|
|
@@ -42859,6 +43136,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42859
43136
|
}
|
|
42860
43137
|
env.openSidePanel("RemoveDuplicates", {});
|
|
42861
43138
|
},
|
|
43139
|
+
isEnabled: (env) => !env.isSmall,
|
|
42862
43140
|
};
|
|
42863
43141
|
const trimWhitespace = {
|
|
42864
43142
|
name: _t("Trim whitespace"),
|
|
@@ -42886,7 +43164,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42886
43164
|
name: _t("Split text to columns"),
|
|
42887
43165
|
sequence: 1,
|
|
42888
43166
|
execute: (env) => env.openSidePanel("SplitToColumns", {}),
|
|
42889
|
-
isEnabled: (env) => env.model.getters.isSingleColSelected(),
|
|
43167
|
+
isEnabled: (env) => !env.isSmall && env.model.getters.isSingleColSelected(),
|
|
42890
43168
|
icon: "o-spreadsheet-Icon.SPLIT_TEXT",
|
|
42891
43169
|
};
|
|
42892
43170
|
const reinsertDynamicPivotMenu = {
|
|
@@ -42973,7 +43251,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
42973
43251
|
const EXAMPLE_DATE = parseLiteral("2023/09/26 10:43:00 PM", DEFAULT_LOCALE);
|
|
42974
43252
|
const formatCustomCurrency = {
|
|
42975
43253
|
name: _t("Custom currency"),
|
|
42976
|
-
isVisible: (env) => env.loadCurrencies !== undefined,
|
|
43254
|
+
isVisible: (env) => env.loadCurrencies !== undefined && !env.isSmall,
|
|
42977
43255
|
execute: (env) => env.openSidePanel("CustomCurrency", {}),
|
|
42978
43256
|
};
|
|
42979
43257
|
const formatNumberDate = createFormatActionSpec({
|
|
@@ -43196,6 +43474,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43196
43474
|
const formatCF = {
|
|
43197
43475
|
name: _t("Conditional formatting"),
|
|
43198
43476
|
execute: OPEN_CF_SIDEPANEL_ACTION,
|
|
43477
|
+
isEnabled: (env) => !env.isSmall,
|
|
43199
43478
|
icon: "o-spreadsheet-Icon.CONDITIONAL_FORMAT",
|
|
43200
43479
|
};
|
|
43201
43480
|
const clearFormat = {
|
|
@@ -43579,8 +43858,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43579
43858
|
}
|
|
43580
43859
|
return [
|
|
43581
43860
|
{
|
|
43582
|
-
|
|
43583
|
-
zone,
|
|
43861
|
+
range: this.model.getters.getRangeFromZone(position.sheetId, zone),
|
|
43584
43862
|
dashed: cell.value === CellErrorType.SpilledBlocked,
|
|
43585
43863
|
color: "#17A2B8",
|
|
43586
43864
|
noFill: true,
|
|
@@ -43665,6 +43943,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43665
43943
|
let previousEvClientPosition;
|
|
43666
43944
|
let startingX;
|
|
43667
43945
|
let startingY;
|
|
43946
|
+
let scrollDirection = "all";
|
|
43668
43947
|
const getters = env.model.getters;
|
|
43669
43948
|
let cleanUpFns = [];
|
|
43670
43949
|
const cleanUp = () => {
|
|
@@ -43690,55 +43969,59 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43690
43969
|
let timeoutDelay = MAX_DELAY;
|
|
43691
43970
|
const x = currentEv.clientX - position.left;
|
|
43692
43971
|
let colIndex = getters.getColIndex(x);
|
|
43693
|
-
|
|
43694
|
-
|
|
43695
|
-
|
|
43696
|
-
canEdgeScroll
|
|
43697
|
-
|
|
43698
|
-
|
|
43699
|
-
|
|
43700
|
-
|
|
43701
|
-
|
|
43702
|
-
|
|
43703
|
-
|
|
43704
|
-
|
|
43705
|
-
|
|
43706
|
-
|
|
43707
|
-
|
|
43708
|
-
|
|
43709
|
-
|
|
43710
|
-
colIndex
|
|
43711
|
-
|
|
43712
|
-
|
|
43713
|
-
|
|
43972
|
+
if (scrollDirection !== "vertical") {
|
|
43973
|
+
const previousX = previousEvClientPosition.clientX - position.left;
|
|
43974
|
+
const edgeScrollInfoX = getters.getEdgeScrollCol(x, previousX, startingX);
|
|
43975
|
+
if (edgeScrollInfoX.canEdgeScroll) {
|
|
43976
|
+
canEdgeScroll = true;
|
|
43977
|
+
timeoutDelay = Math.min(timeoutDelay, edgeScrollInfoX.delay);
|
|
43978
|
+
let newTarget = colIndex;
|
|
43979
|
+
switch (edgeScrollInfoX.direction) {
|
|
43980
|
+
case "reset":
|
|
43981
|
+
colIndex = newTarget = xSplit;
|
|
43982
|
+
break;
|
|
43983
|
+
case 1:
|
|
43984
|
+
colIndex = right;
|
|
43985
|
+
newTarget = left + 1;
|
|
43986
|
+
break;
|
|
43987
|
+
case -1:
|
|
43988
|
+
colIndex = left - 1;
|
|
43989
|
+
while (env.model.getters.isColHidden(sheetId, colIndex)) {
|
|
43990
|
+
colIndex--;
|
|
43991
|
+
}
|
|
43992
|
+
newTarget = colIndex;
|
|
43993
|
+
break;
|
|
43994
|
+
}
|
|
43995
|
+
scrollX = getters.getColDimensions(sheetId, newTarget).start - offsetCorrectionX;
|
|
43714
43996
|
}
|
|
43715
|
-
scrollX = getters.getColDimensions(sheetId, newTarget).start - offsetCorrectionX;
|
|
43716
43997
|
}
|
|
43717
43998
|
const y = currentEv.clientY - position.top;
|
|
43718
43999
|
let rowIndex = getters.getRowIndex(y);
|
|
43719
|
-
|
|
43720
|
-
|
|
43721
|
-
|
|
43722
|
-
canEdgeScroll
|
|
43723
|
-
|
|
43724
|
-
|
|
43725
|
-
|
|
43726
|
-
|
|
43727
|
-
|
|
43728
|
-
|
|
43729
|
-
|
|
43730
|
-
|
|
43731
|
-
|
|
43732
|
-
|
|
43733
|
-
|
|
43734
|
-
|
|
43735
|
-
|
|
43736
|
-
rowIndex
|
|
43737
|
-
|
|
43738
|
-
|
|
43739
|
-
|
|
44000
|
+
if (scrollDirection !== "horizontal") {
|
|
44001
|
+
const previousY = previousEvClientPosition.clientY - position.top;
|
|
44002
|
+
const edgeScrollInfoY = getters.getEdgeScrollRow(y, previousY, startingY);
|
|
44003
|
+
if (edgeScrollInfoY.canEdgeScroll) {
|
|
44004
|
+
canEdgeScroll = true;
|
|
44005
|
+
timeoutDelay = Math.min(timeoutDelay, edgeScrollInfoY.delay);
|
|
44006
|
+
let newTarget = rowIndex;
|
|
44007
|
+
switch (edgeScrollInfoY.direction) {
|
|
44008
|
+
case "reset":
|
|
44009
|
+
rowIndex = newTarget = ySplit;
|
|
44010
|
+
break;
|
|
44011
|
+
case 1:
|
|
44012
|
+
rowIndex = bottom;
|
|
44013
|
+
newTarget = top + 1;
|
|
44014
|
+
break;
|
|
44015
|
+
case -1:
|
|
44016
|
+
rowIndex = top - 1;
|
|
44017
|
+
while (env.model.getters.isRowHidden(sheetId, rowIndex)) {
|
|
44018
|
+
rowIndex--;
|
|
44019
|
+
}
|
|
44020
|
+
newTarget = rowIndex;
|
|
44021
|
+
break;
|
|
44022
|
+
}
|
|
44023
|
+
scrollY = env.model.getters.getRowDimensions(sheetId, newTarget).start - offsetCorrectionY;
|
|
43740
44024
|
}
|
|
43741
|
-
scrollY = env.model.getters.getRowDimensions(sheetId, newTarget).start - offsetCorrectionY;
|
|
43742
44025
|
}
|
|
43743
44026
|
if (!canEdgeScroll) {
|
|
43744
44027
|
colIndex = adjustIndexWithinBounds(colIndex, x, getters.getNumberCols(sheetId) - 1);
|
|
@@ -43758,9 +44041,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
43758
44041
|
pointerUpCallback?.();
|
|
43759
44042
|
cleanUp();
|
|
43760
44043
|
};
|
|
43761
|
-
const startFn = (initialPointerCoordinates, onPointerMove, onPointerUp) => {
|
|
44044
|
+
const startFn = (initialPointerCoordinates, onPointerMove, onPointerUp, startScrollDirection = "all") => {
|
|
43762
44045
|
cleanUp();
|
|
43763
44046
|
const position = gridOverlayPosition();
|
|
44047
|
+
scrollDirection = startScrollDirection;
|
|
43764
44048
|
startingX = initialPointerCoordinates.clientX - position.left;
|
|
43765
44049
|
startingY = initialPointerCoordinates.clientY - position.top;
|
|
43766
44050
|
previousEvClientPosition = {
|
|
@@ -44238,7 +44522,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44238
44522
|
});
|
|
44239
44523
|
}
|
|
44240
44524
|
get shouldDisplayCellReference() {
|
|
44241
|
-
return this.isCellReferenceVisible;
|
|
44525
|
+
return !this.env.isMobile() && this.isCellReferenceVisible;
|
|
44242
44526
|
}
|
|
44243
44527
|
get cellReference() {
|
|
44244
44528
|
const { col, row, sheetId } = this.composerStore.currentEditedCell;
|
|
@@ -44279,11 +44563,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44279
44563
|
onInputContextMenu: this.props.onInputContextMenu,
|
|
44280
44564
|
composerStore: this.composerStore,
|
|
44281
44565
|
inputStyle: `max-height: ${maxHeight}px;`,
|
|
44566
|
+
inputMode: this.composerStore.editionMode === "inactive" ? "none" : undefined,
|
|
44282
44567
|
};
|
|
44283
44568
|
}
|
|
44284
44569
|
get containerStyle() {
|
|
44285
|
-
if (this.composerStore.editionMode === "inactive") {
|
|
44286
|
-
return `z-index: -1000;`;
|
|
44570
|
+
if (this.composerStore.editionMode === "inactive" || this.env.isMobile()) {
|
|
44571
|
+
return `z-index: -1000; opacity: 0;`; // opacity 0 for safari on ios
|
|
44287
44572
|
}
|
|
44288
44573
|
const _isFormula = isFormula(this.composerStore.currentContent);
|
|
44289
44574
|
const cell = this.env.model.getters.getActiveCell();
|
|
@@ -44312,11 +44597,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44312
44597
|
*
|
|
44313
44598
|
* The +-1 are there to include cell borders in the composer sizing/positioning
|
|
44314
44599
|
*/
|
|
44600
|
+
const minHeight = Math.min(height + 1, maxHeight);
|
|
44601
|
+
const minWidth = Math.min(width + 1, maxWidth);
|
|
44315
44602
|
return cssPropertiesToCss({
|
|
44316
44603
|
left: `${left - 1}px`,
|
|
44317
44604
|
top: `${top}px`,
|
|
44318
|
-
"min-width": `${
|
|
44319
|
-
"min-height": `${
|
|
44605
|
+
"min-width": `${minWidth}px`,
|
|
44606
|
+
"min-height": `${minHeight}px`,
|
|
44320
44607
|
"max-width": `${maxWidth}px`,
|
|
44321
44608
|
"max-height": `${maxHeight}px`,
|
|
44322
44609
|
background,
|
|
@@ -44813,6 +45100,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
44813
45100
|
if (!selectResult.isSuccessful) {
|
|
44814
45101
|
return;
|
|
44815
45102
|
}
|
|
45103
|
+
if (this.env.isMobile()) {
|
|
45104
|
+
return;
|
|
45105
|
+
}
|
|
44816
45106
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
44817
45107
|
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
44818
45108
|
const initialScrollPosition = this.env.model.getters.getActiveSheetScrollInfo();
|
|
@@ -45105,78 +45395,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45105
45395
|
}
|
|
45106
45396
|
}
|
|
45107
45397
|
|
|
45108
|
-
class GridCellIcon extends owl.Component {
|
|
45109
|
-
static template = "o-spreadsheet-GridCellIcon";
|
|
45110
|
-
static props = {
|
|
45111
|
-
icon: Object,
|
|
45112
|
-
verticalAlign: { type: String, optional: true },
|
|
45113
|
-
slots: Object,
|
|
45114
|
-
};
|
|
45115
|
-
get iconStyle() {
|
|
45116
|
-
const cellPosition = this.props.icon.position;
|
|
45117
|
-
const merge = this.env.model.getters.getMerge(cellPosition);
|
|
45118
|
-
const zone = merge || positionToZone(cellPosition);
|
|
45119
|
-
const rect = this.env.model.getters.getVisibleRectWithoutHeaders(zone);
|
|
45120
|
-
const x = this.getIconHorizontalPosition(rect, cellPosition);
|
|
45121
|
-
const y = this.getIconVerticalPosition(rect, cellPosition);
|
|
45122
|
-
return cssPropertiesToCss({
|
|
45123
|
-
top: `${y}px`,
|
|
45124
|
-
left: `${x}px`,
|
|
45125
|
-
width: `${this.props.icon.size}px`,
|
|
45126
|
-
height: `${this.props.icon.size}px`,
|
|
45127
|
-
});
|
|
45128
|
-
}
|
|
45129
|
-
getIconVerticalPosition(rect, cellPosition) {
|
|
45130
|
-
const start = rect.y;
|
|
45131
|
-
const end = rect.y + rect.height;
|
|
45132
|
-
const cell = this.env.model.getters.getCell(cellPosition);
|
|
45133
|
-
const align = this.props.verticalAlign || cell?.style?.verticalAlign || DEFAULT_VERTICAL_ALIGN;
|
|
45134
|
-
switch (align) {
|
|
45135
|
-
case "bottom":
|
|
45136
|
-
return end - GRID_ICON_MARGIN - GRID_ICON_EDGE_LENGTH;
|
|
45137
|
-
case "top":
|
|
45138
|
-
return start + GRID_ICON_MARGIN;
|
|
45139
|
-
default:
|
|
45140
|
-
const centeringOffset = Math.floor((end - start - GRID_ICON_EDGE_LENGTH) / 2);
|
|
45141
|
-
return end - GRID_ICON_EDGE_LENGTH - centeringOffset;
|
|
45142
|
-
}
|
|
45143
|
-
}
|
|
45144
|
-
getIconHorizontalPosition(rect, cellPosition) {
|
|
45145
|
-
const start = rect.x;
|
|
45146
|
-
const end = rect.x + rect.width;
|
|
45147
|
-
const cell = this.env.model.getters.getCell(cellPosition);
|
|
45148
|
-
const evaluatedCell = this.env.model.getters.getEvaluatedCell(cellPosition);
|
|
45149
|
-
const align = this.props.icon.horizontalAlign || cell?.style?.align || evaluatedCell.defaultAlign;
|
|
45150
|
-
switch (align) {
|
|
45151
|
-
case "right":
|
|
45152
|
-
return end - this.props.icon.size - this.props.icon.margin;
|
|
45153
|
-
case "left":
|
|
45154
|
-
return start + this.props.icon.margin;
|
|
45155
|
-
default:
|
|
45156
|
-
const centeringOffset = Math.floor((end - start - this.props.icon.size) / 2);
|
|
45157
|
-
return end - this.props.icon.size - centeringOffset;
|
|
45158
|
-
}
|
|
45159
|
-
}
|
|
45160
|
-
isPositionVisible(position) {
|
|
45161
|
-
const rect = this.env.model.getters.getVisibleRect(positionToZone(position));
|
|
45162
|
-
return !(rect.width === 0 || rect.height === 0);
|
|
45163
|
-
}
|
|
45164
|
-
}
|
|
45165
|
-
|
|
45166
|
-
class GridCellIconOverlay extends owl.Component {
|
|
45167
|
-
static template = "o-spreadsheet-GridCellIconOverlay";
|
|
45168
|
-
static props = {};
|
|
45169
|
-
static components = { GridCellIcon };
|
|
45170
|
-
get icons() {
|
|
45171
|
-
const icons = [];
|
|
45172
|
-
for (const position of this.env.model.getters.getVisibleCellPositions()) {
|
|
45173
|
-
const cellIcons = this.env.model.getters.getCellIcons(position);
|
|
45174
|
-
icons.push(...cellIcons.filter((icon) => icon.component));
|
|
45175
|
-
}
|
|
45176
|
-
return icons;
|
|
45177
|
-
}
|
|
45178
|
-
}
|
|
45179
|
-
|
|
45180
45398
|
/**
|
|
45181
45399
|
* Manages an event listener on a ref. Useful for hooks that want to manage
|
|
45182
45400
|
* event listeners, especially more than one. Prefer using t-on directly in
|
|
@@ -45265,7 +45483,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45265
45483
|
return [];
|
|
45266
45484
|
}
|
|
45267
45485
|
return data.zones.map((zone) => ({
|
|
45268
|
-
zone,
|
|
45486
|
+
range: this.model.getters.getRangeFromZone(data.sheetId, zone),
|
|
45269
45487
|
color: SELECTION_BORDER_COLOR,
|
|
45270
45488
|
dashed: true,
|
|
45271
45489
|
sheetId: data.sheetId,
|
|
@@ -45288,7 +45506,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45288
45506
|
}
|
|
45289
45507
|
}
|
|
45290
45508
|
hover(position) {
|
|
45291
|
-
if (position.col === this.col && position.row === this.row) {
|
|
45509
|
+
if (!this.getters.isDashboard() || (position.col === this.col && position.row === this.row)) {
|
|
45292
45510
|
return "noStateChange";
|
|
45293
45511
|
}
|
|
45294
45512
|
this.col = position.col;
|
|
@@ -45322,6 +45540,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45322
45540
|
}
|
|
45323
45541
|
}
|
|
45324
45542
|
|
|
45543
|
+
class HoveredIconStore extends SpreadsheetStore {
|
|
45544
|
+
mutators = ["setHoveredIcon"];
|
|
45545
|
+
hoveredIcon = undefined;
|
|
45546
|
+
setHoveredIcon(icon) {
|
|
45547
|
+
this.hoveredIcon = icon;
|
|
45548
|
+
}
|
|
45549
|
+
}
|
|
45550
|
+
|
|
45325
45551
|
const CURSOR_SVG = /*xml*/ `
|
|
45326
45552
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="14" height="16"><path d="M6.5.4c1.3-.8 2.9-.1 3.8 1.4l2.9 5.1c.2.4.9 1.6-.4 2.3l-1.6.9 1.8 3.1c.2.4.1 1-.2 1.2l-1.6 1c-.3.1-.9 0-1.1-.4l-1.8-3.1-1.6 1c-.6.4-1.7 0-2.2-.8L0 4.3"/><path fill="#fff" d="M9.1 2a1.4 1.1 60 0 0-1.7-.6L5.5 2.5l.9 1.6-1 .6-.9-1.6-.6.4 1.8 3.1-1.3.7-1.8-3.1-1 .6 3.8 6.6 6.8-3.98M3.9 8.8 10.82 5l.795 1.4-6.81 3.96"/></svg>
|
|
45327
45553
|
`;
|
|
@@ -45393,10 +45619,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45393
45619
|
return pause();
|
|
45394
45620
|
}
|
|
45395
45621
|
}
|
|
45396
|
-
useRefListener(gridRef, "pointermove", updateMousePosition);
|
|
45622
|
+
useRefListener(gridRef, "pointermove", (ev) => !env.isMobile() && updateMousePosition(ev));
|
|
45397
45623
|
useRefListener(gridRef, "mouseleave", onMouseLeave);
|
|
45398
45624
|
useRefListener(gridRef, "mouseenter", resume);
|
|
45399
45625
|
useRefListener(gridRef, "pointerdown", recompute);
|
|
45626
|
+
useRefListener(gridRef, "pointerdown", (ev) => env.isMobile() && updateMousePosition(ev));
|
|
45400
45627
|
owl.useExternalListener(window, "click", handleGlobalClick);
|
|
45401
45628
|
function handleGlobalClick(e) {
|
|
45402
45629
|
const target = e.target;
|
|
@@ -45425,11 +45652,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45425
45652
|
onGridMoved: Function,
|
|
45426
45653
|
gridOverlayDimensions: String,
|
|
45427
45654
|
slots: { type: Object, optional: true },
|
|
45655
|
+
getGridSize: Function,
|
|
45428
45656
|
};
|
|
45429
45657
|
static components = {
|
|
45430
45658
|
FiguresContainer,
|
|
45431
45659
|
GridAddRowsFooter,
|
|
45432
|
-
GridCellIconOverlay,
|
|
45433
45660
|
};
|
|
45434
45661
|
static defaultProps = {
|
|
45435
45662
|
onCellDoubleClicked: () => { },
|
|
@@ -45441,15 +45668,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45441
45668
|
gridOverlay = owl.useRef("gridOverlay");
|
|
45442
45669
|
cellPopovers;
|
|
45443
45670
|
paintFormatStore;
|
|
45671
|
+
hoveredIconStore;
|
|
45444
45672
|
setup() {
|
|
45445
45673
|
useCellHovered(this.env, this.gridOverlay);
|
|
45446
45674
|
const resizeObserver = new ResizeObserver(() => {
|
|
45447
45675
|
const boundingRect = this.gridOverlayEl.getBoundingClientRect();
|
|
45676
|
+
const { width, height } = this.props.getGridSize();
|
|
45448
45677
|
this.props.onGridResized({
|
|
45449
45678
|
x: boundingRect.left,
|
|
45450
45679
|
y: boundingRect.top,
|
|
45451
|
-
height:
|
|
45452
|
-
width:
|
|
45680
|
+
height: height,
|
|
45681
|
+
width: width,
|
|
45453
45682
|
});
|
|
45454
45683
|
});
|
|
45455
45684
|
owl.onMounted(() => {
|
|
@@ -45460,6 +45689,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45460
45689
|
});
|
|
45461
45690
|
this.cellPopovers = useStore(CellPopoverStore);
|
|
45462
45691
|
this.paintFormatStore = useStore(PaintFormatStore);
|
|
45692
|
+
this.hoveredIconStore = useStore(HoveredIconStore);
|
|
45463
45693
|
}
|
|
45464
45694
|
get gridOverlayEl() {
|
|
45465
45695
|
if (!this.gridOverlay.el) {
|
|
@@ -45468,26 +45698,59 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45468
45698
|
return this.gridOverlay.el;
|
|
45469
45699
|
}
|
|
45470
45700
|
get style() {
|
|
45471
|
-
return this.props.gridOverlayDimensions
|
|
45701
|
+
return (this.props.gridOverlayDimensions +
|
|
45702
|
+
cssPropertiesToCss({ cursor: this.hoveredIconStore.hoveredIcon ? "pointer" : "default" }));
|
|
45472
45703
|
}
|
|
45473
45704
|
get isPaintingFormat() {
|
|
45474
45705
|
return this.paintFormatStore.isActive;
|
|
45475
45706
|
}
|
|
45476
|
-
|
|
45477
|
-
if (
|
|
45707
|
+
onPointerMove(ev) {
|
|
45708
|
+
if (this.env.isMobile()) {
|
|
45709
|
+
return;
|
|
45710
|
+
}
|
|
45711
|
+
const icon = this.getInteractiveIconAtEvent(ev);
|
|
45712
|
+
const hoveredIcon = icon?.type ? { id: icon.type, position: icon.position } : undefined;
|
|
45713
|
+
if (!deepEquals(hoveredIcon, this.hoveredIconStore.hoveredIcon)) {
|
|
45714
|
+
this.hoveredIconStore.setHoveredIcon(hoveredIcon);
|
|
45715
|
+
}
|
|
45716
|
+
}
|
|
45717
|
+
onPointerDown(ev) {
|
|
45718
|
+
if (ev.button > 0 || this.env.isMobile()) {
|
|
45478
45719
|
// not main button, probably a context menu
|
|
45479
45720
|
return;
|
|
45480
45721
|
}
|
|
45481
|
-
|
|
45482
|
-
|
|
45722
|
+
this.onCellClicked(ev);
|
|
45723
|
+
}
|
|
45724
|
+
onClick(ev) {
|
|
45725
|
+
if (ev.button > 0 || !this.env.isMobile()) {
|
|
45726
|
+
// not main button, probably a context menu
|
|
45727
|
+
return;
|
|
45483
45728
|
}
|
|
45729
|
+
this.onCellClicked(ev);
|
|
45730
|
+
}
|
|
45731
|
+
onCellClicked(ev) {
|
|
45732
|
+
const openedPopover = this.cellPopovers.persistentCellPopover;
|
|
45484
45733
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
45485
45734
|
this.props.onCellClicked(col, row, {
|
|
45486
45735
|
expandZone: ev.shiftKey,
|
|
45487
45736
|
addZone: isCtrlKey(ev),
|
|
45488
45737
|
}, ev);
|
|
45738
|
+
const clickedIcon = this.getInteractiveIconAtEvent(ev);
|
|
45739
|
+
if (clickedIcon?.onClick) {
|
|
45740
|
+
clickedIcon.onClick(clickedIcon.position, this.env);
|
|
45741
|
+
}
|
|
45742
|
+
if (ev.target === this.gridOverlay.el &&
|
|
45743
|
+
this.cellPopovers.isOpen &&
|
|
45744
|
+
deepEquals(openedPopover, this.cellPopovers.persistentCellPopover)) {
|
|
45745
|
+
// Only close the popover if props.click/icon.click didn't open a new one
|
|
45746
|
+
this.cellPopovers.close();
|
|
45747
|
+
return;
|
|
45748
|
+
}
|
|
45489
45749
|
}
|
|
45490
45750
|
onDoubleClick(ev) {
|
|
45751
|
+
if (this.getInteractiveIconAtEvent(ev)) {
|
|
45752
|
+
return;
|
|
45753
|
+
}
|
|
45491
45754
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
45492
45755
|
this.props.onCellDoubleClicked(col, row);
|
|
45493
45756
|
}
|
|
@@ -45503,6 +45766,24 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45503
45766
|
const rowIndex = this.env.model.getters.getRowIndex(y);
|
|
45504
45767
|
return [colIndex, rowIndex];
|
|
45505
45768
|
}
|
|
45769
|
+
getInteractiveIconAtEvent(ev) {
|
|
45770
|
+
const gridOverLayRect = getRefBoundingRect(this.gridOverlay);
|
|
45771
|
+
const gridOffset = this.env.model.getters.getGridOffset();
|
|
45772
|
+
const x = ev.clientX - gridOverLayRect.x + gridOffset.x;
|
|
45773
|
+
const y = ev.clientY - gridOverLayRect.y + gridOffset.y;
|
|
45774
|
+
const [col, row] = this.getCartesianCoordinates(ev);
|
|
45775
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
45776
|
+
let position = { col, row, sheetId };
|
|
45777
|
+
const merge = this.env.model.getters.getMerge(position);
|
|
45778
|
+
if (merge) {
|
|
45779
|
+
position = { col: merge.left, row: merge.top, sheetId };
|
|
45780
|
+
}
|
|
45781
|
+
const icons = this.env.model.getters.getCellIcons(position);
|
|
45782
|
+
const icon = icons.find((icon) => {
|
|
45783
|
+
return isPointInsideRect(x, y, this.env.model.getters.getCellIconRect(icon));
|
|
45784
|
+
});
|
|
45785
|
+
return icon?.onClick ? icon : undefined;
|
|
45786
|
+
}
|
|
45506
45787
|
}
|
|
45507
45788
|
|
|
45508
45789
|
class GridPopover extends owl.Component {
|
|
@@ -45663,6 +45944,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45663
45944
|
this.state.waitingForMove = false;
|
|
45664
45945
|
}
|
|
45665
45946
|
onMouseMove(ev) {
|
|
45947
|
+
if (this.env.isMobile()) {
|
|
45948
|
+
return;
|
|
45949
|
+
}
|
|
45666
45950
|
if (this.state.isResizing || this.state.isMoving || this.state.isSelecting) {
|
|
45667
45951
|
return;
|
|
45668
45952
|
}
|
|
@@ -45707,7 +45991,21 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45707
45991
|
};
|
|
45708
45992
|
startDnd(onMouseMove, onMouseUp);
|
|
45709
45993
|
}
|
|
45994
|
+
onClick(ev) {
|
|
45995
|
+
if (!this.env.isMobile()) {
|
|
45996
|
+
return;
|
|
45997
|
+
}
|
|
45998
|
+
if (ev.button > 0) {
|
|
45999
|
+
// not main button, probably a context menu
|
|
46000
|
+
return;
|
|
46001
|
+
}
|
|
46002
|
+
const index = this._getElementIndex(this._getEvOffset(ev));
|
|
46003
|
+
this._selectElement(index, false);
|
|
46004
|
+
}
|
|
45710
46005
|
select(ev) {
|
|
46006
|
+
if (this.env.isMobile()) {
|
|
46007
|
+
return;
|
|
46008
|
+
}
|
|
45711
46009
|
if (ev.button > 0) {
|
|
45712
46010
|
// not main button, probably a context menu
|
|
45713
46011
|
return;
|
|
@@ -45776,6 +46074,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
45776
46074
|
this.dragNDropGrid.start(ev, mouseMoveMovement, mouseUpMovement);
|
|
45777
46075
|
}
|
|
45778
46076
|
startSelection(ev, index) {
|
|
46077
|
+
if (this.env.isMobile()) {
|
|
46078
|
+
return;
|
|
46079
|
+
}
|
|
45779
46080
|
this.state.isSelecting = true;
|
|
45780
46081
|
if (ev.shiftKey) {
|
|
45781
46082
|
this._increaseSelection(index);
|
|
@@ -46221,11 +46522,13 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46221
46522
|
renderer;
|
|
46222
46523
|
fingerprints;
|
|
46223
46524
|
hoveredTables;
|
|
46525
|
+
hoveredIcon;
|
|
46224
46526
|
constructor(get) {
|
|
46225
46527
|
this.getters = get(ModelStore).getters;
|
|
46226
46528
|
this.renderer = get(RendererStore);
|
|
46227
46529
|
this.fingerprints = get(FormulaFingerprintStore);
|
|
46228
46530
|
this.hoveredTables = get(HoveredTableStore);
|
|
46531
|
+
this.hoveredIcon = get(HoveredIconStore);
|
|
46229
46532
|
this.renderer.register(this);
|
|
46230
46533
|
}
|
|
46231
46534
|
get renderingLayers() {
|
|
@@ -46462,7 +46765,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46462
46765
|
// compute vertical align start point parameter:
|
|
46463
46766
|
const textLineHeight = computeTextFontSizeInPixels(style);
|
|
46464
46767
|
const numberOfLines = box.content.textLines.length;
|
|
46465
|
-
let y = this.computeTextYCoordinate(box, textLineHeight, numberOfLines);
|
|
46768
|
+
let y = this.getters.computeTextYCoordinate(box, textLineHeight, style.verticalAlign, numberOfLines);
|
|
46466
46769
|
// use the horizontal and the vertical start points to:
|
|
46467
46770
|
// fill text / fill strikethrough / fill underline
|
|
46468
46771
|
for (const brokenLine of box.content.textLines) {
|
|
@@ -46479,7 +46782,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46479
46782
|
const { ctx } = renderingContext;
|
|
46480
46783
|
for (const box of boxes) {
|
|
46481
46784
|
for (const icon of Object.values(box.icons)) {
|
|
46482
|
-
if (!icon
|
|
46785
|
+
if (!icon) {
|
|
46786
|
+
continue;
|
|
46787
|
+
}
|
|
46788
|
+
const isHovered = deepEquals({ id: icon.type, position: icon.position }, this.hoveredIcon.hoveredIcon);
|
|
46789
|
+
const svg = isHovered ? icon.hoverSvg || icon.svg : icon.svg;
|
|
46790
|
+
if (!svg) {
|
|
46483
46791
|
continue;
|
|
46484
46792
|
}
|
|
46485
46793
|
ctx.save();
|
|
@@ -46487,46 +46795,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46487
46795
|
ctx.rect(box.x, box.y, box.width, box.height);
|
|
46488
46796
|
ctx.clip();
|
|
46489
46797
|
const iconSize = icon.size;
|
|
46490
|
-
const
|
|
46491
|
-
|
|
46492
|
-
let x;
|
|
46493
|
-
if (icon.horizontalAlign === "left") {
|
|
46494
|
-
x = box.x + icon.margin;
|
|
46495
|
-
}
|
|
46496
|
-
else if (icon.horizontalAlign === "right") {
|
|
46497
|
-
x = box.x + box.width - iconSize - icon.margin;
|
|
46498
|
-
}
|
|
46499
|
-
else {
|
|
46500
|
-
x = box.x + (box.width - iconSize) / 2;
|
|
46501
|
-
}
|
|
46502
|
-
ctx.translate(x, iconY);
|
|
46798
|
+
const { x, y } = this.getters.getCellIconRect(icon);
|
|
46799
|
+
ctx.translate(x, y);
|
|
46503
46800
|
ctx.scale(iconSize / svg.width, iconSize / svg.height);
|
|
46504
|
-
|
|
46505
|
-
|
|
46801
|
+
for (const path of svg.paths) {
|
|
46802
|
+
ctx.fillStyle = path.fillColor;
|
|
46803
|
+
ctx.fill(getPath2D(path.path));
|
|
46804
|
+
}
|
|
46506
46805
|
ctx.restore();
|
|
46507
46806
|
}
|
|
46508
46807
|
}
|
|
46509
46808
|
}
|
|
46510
|
-
/** Computes the vertical start point from which a text line should be draw.
|
|
46511
|
-
*
|
|
46512
|
-
* Note that in case the cell does not have enough spaces to display its text lines,
|
|
46513
|
-
* (wrapping cell case) then the vertical align should be at the top.
|
|
46514
|
-
* */
|
|
46515
|
-
computeTextYCoordinate(box, textLineHeight, numberOfLines = 1) {
|
|
46516
|
-
const y = box.y + 1;
|
|
46517
|
-
const textHeight = computeTextLinesHeight(textLineHeight, numberOfLines);
|
|
46518
|
-
const hasEnoughSpaces = box.height > textHeight + MIN_CELL_TEXT_MARGIN * 2;
|
|
46519
|
-
const verticalAlign = box.verticalAlign || DEFAULT_VERTICAL_ALIGN;
|
|
46520
|
-
if (hasEnoughSpaces) {
|
|
46521
|
-
if (verticalAlign === "middle") {
|
|
46522
|
-
return y + (box.height - textHeight) / 2;
|
|
46523
|
-
}
|
|
46524
|
-
if (verticalAlign === "bottom") {
|
|
46525
|
-
return y + box.height - textHeight - MIN_CELL_TEXT_MARGIN;
|
|
46526
|
-
}
|
|
46527
|
-
}
|
|
46528
|
-
return y + MIN_CELL_TEXT_MARGIN;
|
|
46529
|
-
}
|
|
46530
46809
|
drawHeaders(renderingContext) {
|
|
46531
46810
|
const { ctx, thinLineWidth } = renderingContext;
|
|
46532
46811
|
const visibleCols = this.getters.getSheetViewVisibleCols();
|
|
@@ -46963,6 +47242,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46963
47242
|
const deltaX = lastX - clientX;
|
|
46964
47243
|
const deltaY = lastY - clientY;
|
|
46965
47244
|
const elapsedTime = currentTime - lastTime;
|
|
47245
|
+
if (!elapsedTime) {
|
|
47246
|
+
return;
|
|
47247
|
+
}
|
|
46966
47248
|
velocityX = deltaX / elapsedTime;
|
|
46967
47249
|
velocityY = deltaY / elapsedTime;
|
|
46968
47250
|
lastX = clientX;
|
|
@@ -46983,6 +47265,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
46983
47265
|
function onTouchEnd(ev) {
|
|
46984
47266
|
isMouseDown = false;
|
|
46985
47267
|
lastX = lastY = 0;
|
|
47268
|
+
if (resetTimeout) {
|
|
47269
|
+
clearTimeout(resetTimeout);
|
|
47270
|
+
}
|
|
47271
|
+
velocityX *= 1.2;
|
|
47272
|
+
velocityY *= 1.2;
|
|
46986
47273
|
requestAnimationFrame(scroll);
|
|
46987
47274
|
}
|
|
46988
47275
|
function scroll() {
|
|
@@ -47067,12 +47354,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47067
47354
|
}
|
|
47068
47355
|
}
|
|
47069
47356
|
|
|
47357
|
+
const MOBILE_HANDLER_WIDTH = 40;
|
|
47070
47358
|
css /* scss */ `
|
|
47071
47359
|
.o-corner {
|
|
47072
47360
|
position: absolute;
|
|
47073
|
-
|
|
47074
|
-
|
|
47361
|
+
}
|
|
47362
|
+
|
|
47363
|
+
.o-corner-button {
|
|
47075
47364
|
border: 1px solid white;
|
|
47365
|
+
height: ${AUTOFILL_EDGE_LENGTH}px;
|
|
47366
|
+
width: ${AUTOFILL_EDGE_LENGTH}px;
|
|
47076
47367
|
}
|
|
47077
47368
|
.o-corner-nw,
|
|
47078
47369
|
.o-corner-se {
|
|
@@ -47099,34 +47390,61 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47099
47390
|
isResizing: Boolean,
|
|
47100
47391
|
onResizeHighlight: Function,
|
|
47101
47392
|
};
|
|
47102
|
-
|
|
47103
|
-
|
|
47104
|
-
|
|
47393
|
+
dirX;
|
|
47394
|
+
dirY;
|
|
47395
|
+
setup() {
|
|
47396
|
+
const { dirX, dirY } = orientationToDir(this.props.orientation);
|
|
47397
|
+
this.dirX = dirX;
|
|
47398
|
+
this.dirY = dirY;
|
|
47399
|
+
}
|
|
47400
|
+
get handlerStyle() {
|
|
47105
47401
|
const z = this.props.zone;
|
|
47106
|
-
const col = this.isLeft ? z.left : z.right;
|
|
47107
|
-
const row = this.isTop ? z.top : z.bottom;
|
|
47108
47402
|
const rect = this.env.model.getters.getVisibleRect({
|
|
47109
|
-
left:
|
|
47110
|
-
right:
|
|
47111
|
-
top:
|
|
47112
|
-
bottom:
|
|
47403
|
+
left: this.dirX === 1 ? z.right : z.left,
|
|
47404
|
+
right: this.dirX === -1 ? z.left : z.right,
|
|
47405
|
+
top: this.dirY === 1 ? z.bottom : z.top,
|
|
47406
|
+
bottom: this.dirY === -1 ? z.top : z.bottom,
|
|
47113
47407
|
});
|
|
47114
47408
|
// Don't show if not visible in the viewport
|
|
47115
47409
|
if (rect.width * rect.height === 0) {
|
|
47116
|
-
return `display:none
|
|
47410
|
+
return `display: none !important;`;
|
|
47411
|
+
}
|
|
47412
|
+
const leftValue = rect.x + rect.width / 2 + (this.dirX * rect.width) / 2;
|
|
47413
|
+
const topValue = rect.y + rect.height / 2 + (this.dirY * rect.height) / 2;
|
|
47414
|
+
const edgeLength = this.getHandlerEdgeLength();
|
|
47415
|
+
const css = {
|
|
47416
|
+
left: `${leftValue - edgeLength / 2}px`,
|
|
47417
|
+
top: `${topValue - edgeLength / 2}px`,
|
|
47418
|
+
height: `${edgeLength}px`,
|
|
47419
|
+
width: `${edgeLength}px`,
|
|
47420
|
+
};
|
|
47421
|
+
if (this.env.isMobile()) {
|
|
47422
|
+
css["border-radius"] = `${edgeLength / 2}px`;
|
|
47117
47423
|
}
|
|
47118
|
-
|
|
47119
|
-
|
|
47120
|
-
|
|
47121
|
-
|
|
47122
|
-
|
|
47424
|
+
return cssPropertiesToCss(css);
|
|
47425
|
+
}
|
|
47426
|
+
getHandlerEdgeLength() {
|
|
47427
|
+
return this.env.isMobile() ? MOBILE_HANDLER_WIDTH : AUTOFILL_EDGE_LENGTH;
|
|
47428
|
+
}
|
|
47429
|
+
get buttonLook() {
|
|
47430
|
+
const css = {
|
|
47123
47431
|
"background-color": this.props.color,
|
|
47124
|
-
|
|
47432
|
+
cursor: `${this.props.orientation}-resize`,
|
|
47433
|
+
};
|
|
47434
|
+
if (this.env.isMobile()) {
|
|
47435
|
+
css["border-radius"] = `${AUTOFILL_EDGE_LENGTH / 2}px`;
|
|
47436
|
+
}
|
|
47437
|
+
return cssPropertiesToCss(css);
|
|
47125
47438
|
}
|
|
47126
47439
|
onMouseDown(ev) {
|
|
47127
|
-
this.props.onResizeHighlight(ev, this.
|
|
47440
|
+
this.props.onResizeHighlight(ev, this.dirX, this.dirY);
|
|
47128
47441
|
}
|
|
47129
47442
|
}
|
|
47443
|
+
function orientationToDir(or) {
|
|
47444
|
+
const dirX = or.includes("w") ? -1 : or.includes("e") ? 1 : 0;
|
|
47445
|
+
const dirY = or.includes("n") ? -1 : or.includes("s") ? 1 : 0;
|
|
47446
|
+
return { dirX, dirY };
|
|
47447
|
+
}
|
|
47130
47448
|
|
|
47131
47449
|
css /*SCSS*/ `
|
|
47132
47450
|
.o-highlight {
|
|
@@ -47136,7 +47454,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47136
47454
|
class Highlight extends owl.Component {
|
|
47137
47455
|
static template = "o-spreadsheet-Highlight";
|
|
47138
47456
|
static props = {
|
|
47139
|
-
|
|
47457
|
+
range: Object,
|
|
47140
47458
|
color: String,
|
|
47141
47459
|
};
|
|
47142
47460
|
static components = {
|
|
@@ -47147,26 +47465,49 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47147
47465
|
shiftingMode: "none",
|
|
47148
47466
|
});
|
|
47149
47467
|
dragNDropGrid = useDragAndDropBeyondTheViewport(this.env);
|
|
47150
|
-
|
|
47468
|
+
get cornerOrientations() {
|
|
47469
|
+
if (!this.env.isMobile()) {
|
|
47470
|
+
return ["nw", "ne", "sw", "se"];
|
|
47471
|
+
}
|
|
47472
|
+
const z = this.props.range.unboundedZone;
|
|
47473
|
+
if (z.bottom === undefined) {
|
|
47474
|
+
return ["w", "e"];
|
|
47475
|
+
}
|
|
47476
|
+
else if (z.right === undefined) {
|
|
47477
|
+
return ["n", "s"];
|
|
47478
|
+
}
|
|
47479
|
+
else {
|
|
47480
|
+
return ["nw", "se"];
|
|
47481
|
+
}
|
|
47482
|
+
}
|
|
47483
|
+
onResizeHighlight(ev, dirX, dirY) {
|
|
47151
47484
|
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
47152
47485
|
this.highlightState.shiftingMode = "isResizing";
|
|
47153
|
-
const z = this.props.zone;
|
|
47154
|
-
const pivotCol =
|
|
47155
|
-
const pivotRow =
|
|
47156
|
-
let lastCol =
|
|
47157
|
-
let lastRow =
|
|
47486
|
+
const z = this.props.range.zone;
|
|
47487
|
+
const pivotCol = dirX === 1 ? z.left : z.right;
|
|
47488
|
+
const pivotRow = dirY === 1 ? z.top : z.bottom;
|
|
47489
|
+
let lastCol = dirX === 1 ? z.right : z.left;
|
|
47490
|
+
let lastRow = dirY === 1 ? z.bottom : z.top;
|
|
47158
47491
|
let currentZone = z;
|
|
47492
|
+
let scrollDirection = "all";
|
|
47493
|
+
if (this.env.isMobile()) {
|
|
47494
|
+
scrollDirection = dirX === 0 ? "vertical" : dirY === 0 ? "horizontal" : "all";
|
|
47495
|
+
}
|
|
47159
47496
|
this.env.model.dispatch("START_CHANGE_HIGHLIGHT", { zone: currentZone });
|
|
47160
47497
|
const mouseMove = (col, row) => {
|
|
47161
47498
|
if (lastCol !== col || lastRow !== row) {
|
|
47162
|
-
|
|
47163
|
-
|
|
47164
|
-
|
|
47165
|
-
|
|
47166
|
-
|
|
47167
|
-
|
|
47168
|
-
|
|
47169
|
-
|
|
47499
|
+
let { left, right, top, bottom } = currentZone;
|
|
47500
|
+
if (scrollDirection !== "horizontal") {
|
|
47501
|
+
lastRow = lastRow = clip(row === -1 ? lastRow : row, 0, this.env.model.getters.getNumberRows(activeSheetId) - 1);
|
|
47502
|
+
top = Math.min(pivotRow, lastRow);
|
|
47503
|
+
bottom = Math.max(pivotRow, lastRow);
|
|
47504
|
+
}
|
|
47505
|
+
if (scrollDirection !== "vertical") {
|
|
47506
|
+
lastCol = clip(col === -1 ? lastCol : col, 0, this.env.model.getters.getNumberCols(activeSheetId) - 1);
|
|
47507
|
+
left = Math.min(pivotCol, lastCol);
|
|
47508
|
+
right = Math.max(pivotCol, lastCol);
|
|
47509
|
+
}
|
|
47510
|
+
const newZone = { left, right, top, bottom };
|
|
47170
47511
|
if (!isEqual(newZone, currentZone)) {
|
|
47171
47512
|
this.env.model.selection.selectZone({
|
|
47172
47513
|
cell: { col: newZone.left, row: newZone.top },
|
|
@@ -47179,11 +47520,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47179
47520
|
const mouseUp = () => {
|
|
47180
47521
|
this.highlightState.shiftingMode = "none";
|
|
47181
47522
|
};
|
|
47182
|
-
this.dragNDropGrid.start(ev, mouseMove, mouseUp);
|
|
47523
|
+
this.dragNDropGrid.start(ev, mouseMove, mouseUp, scrollDirection);
|
|
47183
47524
|
}
|
|
47184
47525
|
onMoveHighlight(ev) {
|
|
47185
47526
|
this.highlightState.shiftingMode = "isMoving";
|
|
47186
|
-
const z = this.props.zone;
|
|
47527
|
+
const z = this.props.range.zone;
|
|
47187
47528
|
const position = gridOverlayPosition();
|
|
47188
47529
|
const activeSheetId = this.env.model.getters.getActiveSheetId();
|
|
47189
47530
|
const initCol = this.env.model.getters.getColIndex(ev.clientX - position.left);
|
|
@@ -47405,6 +47746,18 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
47405
47746
|
}
|
|
47406
47747
|
}
|
|
47407
47748
|
|
|
47749
|
+
class Selection extends owl.Component {
|
|
47750
|
+
static template = "o-spreadsheet-Selection";
|
|
47751
|
+
static props = {};
|
|
47752
|
+
static components = { Highlight };
|
|
47753
|
+
get highlightProps() {
|
|
47754
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
47755
|
+
const zone = this.env.model.getters.getUnboundedZone(sheetId, this.env.model.getters.getSelectedZone());
|
|
47756
|
+
const range = this.env.model.getters.getRangeFromZone(sheetId, zone);
|
|
47757
|
+
return { range, color: SELECTION_BORDER_COLOR };
|
|
47758
|
+
}
|
|
47759
|
+
}
|
|
47760
|
+
|
|
47408
47761
|
class Section extends owl.Component {
|
|
47409
47762
|
static template = "o_spreadsheet.Section";
|
|
47410
47763
|
static props = {
|
|
@@ -48350,6 +48703,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
48350
48703
|
|
|
48351
48704
|
css /* scss */ `
|
|
48352
48705
|
.o-font-size-editor {
|
|
48706
|
+
width: max-content !important;
|
|
48353
48707
|
height: calc(100% - 4px);
|
|
48354
48708
|
input.o-font-size {
|
|
48355
48709
|
outline: none;
|
|
@@ -50498,8 +50852,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
50498
50852
|
get highlights() {
|
|
50499
50853
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
50500
50854
|
return this.props.conditionalFormat.ranges.map((range) => ({
|
|
50501
|
-
sheetId,
|
|
50502
|
-
zone: this.env.model.getters.getRangeFromSheetXC(sheetId, range).zone,
|
|
50855
|
+
range: this.env.model.getters.getRangeFromSheetXC(sheetId, range),
|
|
50503
50856
|
color: HIGHLIGHT_COLOR,
|
|
50504
50857
|
fillAlpha: 0.06,
|
|
50505
50858
|
}));
|
|
@@ -51457,8 +51810,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51457
51810
|
}
|
|
51458
51811
|
get highlights() {
|
|
51459
51812
|
return this.props.rule.ranges.map((range) => ({
|
|
51460
|
-
|
|
51461
|
-
zone: range.zone,
|
|
51813
|
+
range,
|
|
51462
51814
|
color: HIGHLIGHT_COLOR,
|
|
51463
51815
|
fillAlpha: 0.06,
|
|
51464
51816
|
}));
|
|
@@ -51787,13 +52139,15 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51787
52139
|
if (this.selectedMatchIndex === null) {
|
|
51788
52140
|
return;
|
|
51789
52141
|
}
|
|
52142
|
+
this.preserveSelectedMatchIndex = true;
|
|
52143
|
+
this.shouldFinalizeUpdateSelection = true;
|
|
51790
52144
|
this.model.dispatch("REPLACE_SEARCH", {
|
|
51791
52145
|
searchString: this.toSearch,
|
|
51792
52146
|
replaceWith: this.toReplace,
|
|
51793
52147
|
matches: [this.searchMatches[this.selectedMatchIndex]],
|
|
51794
52148
|
searchOptions: this.searchOptions,
|
|
51795
52149
|
});
|
|
51796
|
-
this.
|
|
52150
|
+
this.preserveSelectedMatchIndex = false;
|
|
51797
52151
|
}
|
|
51798
52152
|
/**
|
|
51799
52153
|
* Apply the replace function to all the matches one time.
|
|
@@ -51865,8 +52219,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51865
52219
|
const { width, height } = this.getters.getVisibleRect(zoneWithMerge);
|
|
51866
52220
|
if (width > 0 && height > 0) {
|
|
51867
52221
|
highlights.push({
|
|
51868
|
-
sheetId,
|
|
51869
|
-
zone: zoneWithMerge,
|
|
52222
|
+
range: this.model.getters.getRangeFromZone(sheetId, zoneWithMerge),
|
|
51870
52223
|
color: FIND_AND_REPLACE_HIGHLIGHT_COLOR,
|
|
51871
52224
|
noBorder: index !== this.selectedMatchIndex,
|
|
51872
52225
|
thinLine: true,
|
|
@@ -51878,8 +52231,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
51878
52231
|
const range = this.searchOptions.specificRange;
|
|
51879
52232
|
if (range && range.sheetId === sheetId) {
|
|
51880
52233
|
highlights.push({
|
|
51881
|
-
|
|
51882
|
-
zone: range.zone,
|
|
52234
|
+
range,
|
|
51883
52235
|
color: FIND_AND_REPLACE_HIGHLIGHT_COLOR,
|
|
51884
52236
|
noFill: true,
|
|
51885
52237
|
thinLine: true,
|
|
@@ -52253,7 +52605,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52253
52605
|
const sheetId = getters.getActiveSheetId();
|
|
52254
52606
|
const pivotCellPositions = getVisiblePivotCellPositions(getters, pivotId);
|
|
52255
52607
|
const mergedZones = mergeContiguousZones(pivotCellPositions.map(positionToZone));
|
|
52256
|
-
return mergedZones.map((zone) => ({
|
|
52608
|
+
return mergedZones.map((zone) => ({
|
|
52609
|
+
range: getters.getRangeFromZone(sheetId, zone),
|
|
52610
|
+
noFill: true,
|
|
52611
|
+
color: HIGHLIGHT_COLOR,
|
|
52612
|
+
}));
|
|
52257
52613
|
}
|
|
52258
52614
|
function getVisiblePivotCellPositions(getters, pivotId) {
|
|
52259
52615
|
const positions = [];
|
|
@@ -52522,7 +52878,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
52522
52878
|
|
|
52523
52879
|
class CogWheelMenu extends owl.Component {
|
|
52524
52880
|
static template = "o-spreadsheet-CogWheelMenu";
|
|
52525
|
-
static components = {
|
|
52881
|
+
static components = { MenuPopover };
|
|
52526
52882
|
static props = {
|
|
52527
52883
|
items: Array,
|
|
52528
52884
|
};
|
|
@@ -54388,12 +54744,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
54388
54744
|
entry[field.name] = { value: null, type: CellValueType.empty, formattedValue: "" };
|
|
54389
54745
|
}
|
|
54390
54746
|
else {
|
|
54391
|
-
|
|
54392
|
-
entry[field.name] = { ...cell, value: cell.formattedValue || null };
|
|
54393
|
-
}
|
|
54394
|
-
else {
|
|
54395
|
-
entry[field.name] = cell;
|
|
54396
|
-
}
|
|
54747
|
+
entry[field.name] = cell;
|
|
54397
54748
|
}
|
|
54398
54749
|
}
|
|
54399
54750
|
entry["__count"] = { value: 1, type: CellValueType.number, formattedValue: "1" };
|
|
@@ -55097,6 +55448,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55097
55448
|
id: "editTableStyle",
|
|
55098
55449
|
name: _t("Edit table style"),
|
|
55099
55450
|
execute: (env) => env.openSidePanel("TableStyleEditorPanel", { styleId }),
|
|
55451
|
+
isEnabled: (env) => !env.isSmall,
|
|
55100
55452
|
icon: "o-spreadsheet-Icon.EDIT",
|
|
55101
55453
|
},
|
|
55102
55454
|
{
|
|
@@ -55218,7 +55570,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55218
55570
|
`;
|
|
55219
55571
|
class TableStylePreview extends owl.Component {
|
|
55220
55572
|
static template = "o-spreadsheet-TableStylePreview";
|
|
55221
|
-
static components = {
|
|
55573
|
+
static components = { MenuPopover };
|
|
55222
55574
|
static props = {
|
|
55223
55575
|
tableConfig: Object,
|
|
55224
55576
|
tableStyle: Object,
|
|
@@ -55789,6 +56141,17 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55789
56141
|
},
|
|
55790
56142
|
});
|
|
55791
56143
|
|
|
56144
|
+
class ScreenWidthStore {
|
|
56145
|
+
mutators = ["setSmallThreshhold"];
|
|
56146
|
+
_isSmallCallback = () => false;
|
|
56147
|
+
get isSmall() {
|
|
56148
|
+
return this._isSmallCallback();
|
|
56149
|
+
}
|
|
56150
|
+
setSmallThreshhold(isSmall) {
|
|
56151
|
+
this._isSmallCallback = isSmall;
|
|
56152
|
+
}
|
|
56153
|
+
}
|
|
56154
|
+
|
|
55792
56155
|
const DEFAULT_SIDE_PANEL_SIZE = 350;
|
|
55793
56156
|
const MIN_SHEET_VIEW_WIDTH = 150;
|
|
55794
56157
|
class SidePanelStore extends SpreadsheetStore {
|
|
@@ -55796,6 +56159,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55796
56159
|
initialPanelProps = {};
|
|
55797
56160
|
componentTag = "";
|
|
55798
56161
|
panelSize = DEFAULT_SIDE_PANEL_SIZE;
|
|
56162
|
+
screenWidthStore = this.get(ScreenWidthStore);
|
|
55799
56163
|
get isOpen() {
|
|
55800
56164
|
if (!this.componentTag) {
|
|
55801
56165
|
return false;
|
|
@@ -55817,6 +56181,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55817
56181
|
return undefined;
|
|
55818
56182
|
}
|
|
55819
56183
|
open(componentTag, panelProps = {}) {
|
|
56184
|
+
if (this.screenWidthStore.isSmall) {
|
|
56185
|
+
return;
|
|
56186
|
+
}
|
|
55820
56187
|
const state = this.computeState(componentTag, panelProps);
|
|
55821
56188
|
if (!state.isOpen) {
|
|
55822
56189
|
return;
|
|
@@ -55931,8 +56298,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55931
56298
|
return [];
|
|
55932
56299
|
return [
|
|
55933
56300
|
{
|
|
55934
|
-
|
|
55935
|
-
sheetId: this.props.table.range.sheetId,
|
|
56301
|
+
range: this.env.model.getters.getRangeFromZone(this.props.table.range.sheetId, this.state.highlightZone),
|
|
55936
56302
|
color: COLOR,
|
|
55937
56303
|
noFill: true,
|
|
55938
56304
|
},
|
|
@@ -55954,13 +56320,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55954
56320
|
static template = "o-spreadsheet-Grid";
|
|
55955
56321
|
static props = {
|
|
55956
56322
|
exposeFocus: Function,
|
|
56323
|
+
getGridSize: Function,
|
|
55957
56324
|
};
|
|
55958
56325
|
static components = {
|
|
55959
56326
|
GridComposer,
|
|
55960
56327
|
GridOverlay,
|
|
55961
56328
|
GridPopover,
|
|
55962
56329
|
HeadersOverlay,
|
|
55963
|
-
|
|
56330
|
+
MenuPopover,
|
|
55964
56331
|
Autofill,
|
|
55965
56332
|
ClientTag,
|
|
55966
56333
|
Highlight,
|
|
@@ -55968,6 +56335,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
55968
56335
|
VerticalScrollBar,
|
|
55969
56336
|
HorizontalScrollBar,
|
|
55970
56337
|
TableResizer,
|
|
56338
|
+
Selection,
|
|
55971
56339
|
};
|
|
55972
56340
|
HEADER_HEIGHT = HEADER_HEIGHT;
|
|
55973
56341
|
HEADER_WIDTH = HEADER_WIDTH;
|
|
@@ -56250,8 +56618,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56250
56618
|
}
|
|
56251
56619
|
onGridResized({ height, width }) {
|
|
56252
56620
|
this.env.model.dispatch("RESIZE_SHEETVIEW", {
|
|
56253
|
-
width: width,
|
|
56254
|
-
height: height,
|
|
56621
|
+
width: width - HEADER_WIDTH,
|
|
56622
|
+
height: height - HEADER_HEIGHT,
|
|
56255
56623
|
gridOffsetX: HEADER_WIDTH,
|
|
56256
56624
|
gridOffsetY: HEADER_HEIGHT,
|
|
56257
56625
|
});
|
|
@@ -56305,6 +56673,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56305
56673
|
else {
|
|
56306
56674
|
this.env.model.selection.selectCell(col, row);
|
|
56307
56675
|
}
|
|
56676
|
+
if (this.env.isMobile()) {
|
|
56677
|
+
return;
|
|
56678
|
+
}
|
|
56308
56679
|
let prevCol = col;
|
|
56309
56680
|
let prevRow = row;
|
|
56310
56681
|
const onMouseMove = (col, row, ev) => {
|
|
@@ -56590,6 +56961,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
56590
56961
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
56591
56962
|
return this.env.model.getters.getCoreTables(sheetId).filter(isStaticTable);
|
|
56592
56963
|
}
|
|
56964
|
+
get displaySelectionHandler() {
|
|
56965
|
+
return this.env.isMobile() && this.composerFocusStore.activeComposer.editionMode === "inactive";
|
|
56966
|
+
}
|
|
56593
56967
|
}
|
|
56594
56968
|
|
|
56595
56969
|
/**
|
|
@@ -62516,7 +62890,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62516
62890
|
break;
|
|
62517
62891
|
}
|
|
62518
62892
|
case "UPDATE_PIVOT": {
|
|
62519
|
-
this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
|
|
62893
|
+
this.history.update("pivots", cmd.pivotId, "definition", this.repairSortedColumn(deepCopy(cmd.pivot)));
|
|
62520
62894
|
this.compileCalculatedMeasures(cmd.pivot.measures);
|
|
62521
62895
|
break;
|
|
62522
62896
|
}
|
|
@@ -62587,7 +62961,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62587
62961
|
// Private
|
|
62588
62962
|
// -------------------------------------------------------------------------
|
|
62589
62963
|
addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
|
|
62590
|
-
this.history.update("pivots", pivotId, {
|
|
62964
|
+
this.history.update("pivots", pivotId, {
|
|
62965
|
+
definition: this.repairSortedColumn(deepCopy(pivot)),
|
|
62966
|
+
formulaId,
|
|
62967
|
+
});
|
|
62591
62968
|
this.compileCalculatedMeasures(pivot.measures);
|
|
62592
62969
|
this.history.update("formulaIds", formulaId, pivotId);
|
|
62593
62970
|
this.history.update("nextFormulaId", this.nextFormulaId + 1);
|
|
@@ -62676,6 +63053,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62676
63053
|
}
|
|
62677
63054
|
}
|
|
62678
63055
|
checkSortedColumnInMeasures(definition) {
|
|
63056
|
+
definition = this.repairSortedColumn(definition);
|
|
62679
63057
|
const measures = definition.measures.map((measure) => measure.id);
|
|
62680
63058
|
if (definition.sortedColumn && !measures.includes(definition.sortedColumn.measure)) {
|
|
62681
63059
|
return "InvalidDefinition" /* CommandResult.InvalidDefinition */;
|
|
@@ -62689,6 +63067,26 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
62689
63067
|
}
|
|
62690
63068
|
return "Success" /* CommandResult.Success */;
|
|
62691
63069
|
}
|
|
63070
|
+
repairSortedColumn(definition) {
|
|
63071
|
+
if (definition.sortedColumn) {
|
|
63072
|
+
// Fix for an upgrade issue: the sortedColumn measure was not updated
|
|
63073
|
+
// from using fieldName to using id. If the sortedColumn measure matches
|
|
63074
|
+
// a measure fieldName in the definition, update it to use the measure's id instead
|
|
63075
|
+
// of its fieldName.
|
|
63076
|
+
// TODO: add an upgrade step to fix this in master and remove this code
|
|
63077
|
+
const sortedMeasure = definition.measures.find((measure) => measure.fieldName === definition.sortedColumn?.measure);
|
|
63078
|
+
if (sortedMeasure) {
|
|
63079
|
+
return {
|
|
63080
|
+
...definition,
|
|
63081
|
+
sortedColumn: {
|
|
63082
|
+
...definition.sortedColumn,
|
|
63083
|
+
measure: sortedMeasure.id,
|
|
63084
|
+
},
|
|
63085
|
+
};
|
|
63086
|
+
}
|
|
63087
|
+
}
|
|
63088
|
+
return definition;
|
|
63089
|
+
}
|
|
62692
63090
|
// ---------------------------------------------------------------------
|
|
62693
63091
|
// Import/Export
|
|
62694
63092
|
// ---------------------------------------------------------------------
|
|
@@ -65556,186 +65954,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65556
65954
|
}
|
|
65557
65955
|
}
|
|
65558
65956
|
|
|
65559
|
-
const MARGIN = (GRID_ICON_EDGE_LENGTH - CHECKBOX_WIDTH) / 2;
|
|
65560
|
-
css /* scss */ `
|
|
65561
|
-
.o-dv-checkbox {
|
|
65562
|
-
margin: ${MARGIN}px;
|
|
65563
|
-
/* required to prevent the checkbox position to be sensible to the font-size (affects Firefox) */
|
|
65564
|
-
position: absolute;
|
|
65565
|
-
}
|
|
65566
|
-
`;
|
|
65567
|
-
class DataValidationCheckbox extends owl.Component {
|
|
65568
|
-
static template = "o-spreadsheet-DataValidationCheckbox";
|
|
65569
|
-
static components = {
|
|
65570
|
-
Checkbox,
|
|
65571
|
-
};
|
|
65572
|
-
static props = {
|
|
65573
|
-
cellPosition: Object,
|
|
65574
|
-
};
|
|
65575
|
-
onCheckboxChange(value) {
|
|
65576
|
-
const { sheetId, col, row } = this.props.cellPosition;
|
|
65577
|
-
const cellContent = value ? "TRUE" : "FALSE";
|
|
65578
|
-
this.env.model.dispatch("UPDATE_CELL", { sheetId, col, row, content: cellContent });
|
|
65579
|
-
}
|
|
65580
|
-
get checkBoxValue() {
|
|
65581
|
-
return !!this.env.model.getters.getEvaluatedCell(this.props.cellPosition).value;
|
|
65582
|
-
}
|
|
65583
|
-
get isDisabled() {
|
|
65584
|
-
const cell = this.env.model.getters.getCell(this.props.cellPosition);
|
|
65585
|
-
return this.env.model.getters.isReadonly() || !!cell?.isFormula;
|
|
65586
|
-
}
|
|
65587
|
-
}
|
|
65588
|
-
|
|
65589
|
-
const ICON_WIDTH = 13;
|
|
65590
|
-
css /* scss */ `
|
|
65591
|
-
.o-dv-list-icon {
|
|
65592
|
-
color: ${TEXT_BODY_MUTED};
|
|
65593
|
-
border-radius: 1px;
|
|
65594
|
-
height: ${GRID_ICON_EDGE_LENGTH}px;
|
|
65595
|
-
width: ${GRID_ICON_EDGE_LENGTH}px;
|
|
65596
|
-
|
|
65597
|
-
&:hover {
|
|
65598
|
-
color: #ffffff;
|
|
65599
|
-
background-color: ${TEXT_BODY_MUTED};
|
|
65600
|
-
}
|
|
65601
|
-
|
|
65602
|
-
svg {
|
|
65603
|
-
width: ${ICON_WIDTH}px;
|
|
65604
|
-
height: ${ICON_WIDTH}px;
|
|
65605
|
-
}
|
|
65606
|
-
}
|
|
65607
|
-
`;
|
|
65608
|
-
class DataValidationListIcon extends owl.Component {
|
|
65609
|
-
static template = "o-spreadsheet-DataValidationListIcon";
|
|
65610
|
-
static props = {
|
|
65611
|
-
cellPosition: Object,
|
|
65612
|
-
};
|
|
65613
|
-
onClick() {
|
|
65614
|
-
const { col, row } = this.props.cellPosition;
|
|
65615
|
-
this.env.model.selection.selectCell(col, row);
|
|
65616
|
-
this.env.startCellEdition();
|
|
65617
|
-
}
|
|
65618
|
-
}
|
|
65619
|
-
|
|
65620
|
-
css /* scss */ `
|
|
65621
|
-
.o-filter-icon {
|
|
65622
|
-
color: ${FILTERS_COLOR};
|
|
65623
|
-
display: flex;
|
|
65624
|
-
align-items: center;
|
|
65625
|
-
justify-content: center;
|
|
65626
|
-
width: ${GRID_ICON_EDGE_LENGTH}px;
|
|
65627
|
-
height: ${GRID_ICON_EDGE_LENGTH}px;
|
|
65628
|
-
|
|
65629
|
-
&:hover {
|
|
65630
|
-
background: ${FILTERS_COLOR};
|
|
65631
|
-
color: #fff;
|
|
65632
|
-
}
|
|
65633
|
-
|
|
65634
|
-
&.o-high-contrast {
|
|
65635
|
-
color: #defade;
|
|
65636
|
-
}
|
|
65637
|
-
&.o-high-contrast:hover {
|
|
65638
|
-
color: ${FILTERS_COLOR};
|
|
65639
|
-
background: #fff;
|
|
65640
|
-
}
|
|
65641
|
-
}
|
|
65642
|
-
.o-filter-icon:hover {
|
|
65643
|
-
background: ${FILTERS_COLOR};
|
|
65644
|
-
color: #fff;
|
|
65645
|
-
}
|
|
65646
|
-
`;
|
|
65647
|
-
class FilterIcon extends owl.Component {
|
|
65648
|
-
static template = "o-spreadsheet-FilterIcon";
|
|
65649
|
-
static props = {
|
|
65650
|
-
cellPosition: Object,
|
|
65651
|
-
};
|
|
65652
|
-
cellPopovers;
|
|
65653
|
-
setup() {
|
|
65654
|
-
this.cellPopovers = useStore(CellPopoverStore);
|
|
65655
|
-
}
|
|
65656
|
-
onClick() {
|
|
65657
|
-
const position = this.props.cellPosition;
|
|
65658
|
-
const activePopover = this.cellPopovers.persistentCellPopover;
|
|
65659
|
-
const { col, row } = position;
|
|
65660
|
-
if (activePopover.isOpen &&
|
|
65661
|
-
activePopover.col === col &&
|
|
65662
|
-
activePopover.row === row &&
|
|
65663
|
-
activePopover.type === "FilterMenu") {
|
|
65664
|
-
this.cellPopovers.close();
|
|
65665
|
-
return;
|
|
65666
|
-
}
|
|
65667
|
-
this.cellPopovers.open({ col, row }, "FilterMenu");
|
|
65668
|
-
}
|
|
65669
|
-
get isFilterActive() {
|
|
65670
|
-
return this.env.model.getters.isFilterActive(this.props.cellPosition);
|
|
65671
|
-
}
|
|
65672
|
-
get iconClass() {
|
|
65673
|
-
const cellStyle = this.env.model.getters.getCellComputedStyle(this.props.cellPosition);
|
|
65674
|
-
const luminance = relativeLuminance(cellStyle.fillColor || "#fff");
|
|
65675
|
-
return luminance < 0.45 ? "o-high-contrast" : "";
|
|
65676
|
-
}
|
|
65677
|
-
}
|
|
65678
|
-
|
|
65679
|
-
css /* scss */ `
|
|
65680
|
-
.o-spreadsheet {
|
|
65681
|
-
.o-pivot-collapse-icon {
|
|
65682
|
-
cursor: pointer;
|
|
65683
|
-
width: 11px;
|
|
65684
|
-
height: 11px;
|
|
65685
|
-
border: 1px solid #777;
|
|
65686
|
-
background-color: #eee;
|
|
65687
|
-
margin: 3px 0 3px 6px;
|
|
65688
|
-
|
|
65689
|
-
.o-icon {
|
|
65690
|
-
width: 5px;
|
|
65691
|
-
height: 5px;
|
|
65692
|
-
}
|
|
65693
|
-
}
|
|
65694
|
-
}
|
|
65695
|
-
`;
|
|
65696
|
-
class PivotCollapseIcon extends owl.Component {
|
|
65697
|
-
static template = "o-spreadsheet-PivotCollapseIcon";
|
|
65698
|
-
static props = {
|
|
65699
|
-
cellPosition: Object,
|
|
65700
|
-
};
|
|
65701
|
-
onClick() {
|
|
65702
|
-
const pivotCell = this.env.model.getters.getPivotCellFromPosition(this.props.cellPosition);
|
|
65703
|
-
const pivotId = this.env.model.getters.getPivotIdFromPosition(this.props.cellPosition);
|
|
65704
|
-
if (!pivotId || pivotCell.type !== "HEADER") {
|
|
65705
|
-
return;
|
|
65706
|
-
}
|
|
65707
|
-
const definition = this.env.model.getters.getPivotCoreDefinition(pivotId);
|
|
65708
|
-
const collapsedDomains = definition.collapsedDomains?.[pivotCell.dimension]
|
|
65709
|
-
? [...definition.collapsedDomains[pivotCell.dimension]]
|
|
65710
|
-
: [];
|
|
65711
|
-
const index = collapsedDomains.findIndex((domain) => deepEquals(domain, pivotCell.domain));
|
|
65712
|
-
if (index !== -1) {
|
|
65713
|
-
collapsedDomains.splice(index, 1);
|
|
65714
|
-
}
|
|
65715
|
-
else {
|
|
65716
|
-
collapsedDomains.push(pivotCell.domain);
|
|
65717
|
-
}
|
|
65718
|
-
const newDomains = definition.collapsedDomains
|
|
65719
|
-
? { ...definition.collapsedDomains }
|
|
65720
|
-
: { COL: [], ROW: [] };
|
|
65721
|
-
newDomains[pivotCell.dimension] = collapsedDomains;
|
|
65722
|
-
this.env.model.dispatch("UPDATE_PIVOT", {
|
|
65723
|
-
pivotId,
|
|
65724
|
-
pivot: { ...definition, collapsedDomains: newDomains },
|
|
65725
|
-
});
|
|
65726
|
-
}
|
|
65727
|
-
get isCollapsed() {
|
|
65728
|
-
const pivotCell = this.env.model.getters.getPivotCellFromPosition(this.props.cellPosition);
|
|
65729
|
-
const pivotId = this.env.model.getters.getPivotIdFromPosition(this.props.cellPosition);
|
|
65730
|
-
if (!pivotId || pivotCell.type !== "HEADER") {
|
|
65731
|
-
return false;
|
|
65732
|
-
}
|
|
65733
|
-
const definition = this.env.model.getters.getPivotCoreDefinition(pivotId);
|
|
65734
|
-
const domains = definition.collapsedDomains?.[pivotCell.dimension] ?? [];
|
|
65735
|
-
return domains?.some((domain) => deepEquals(domain, pivotCell.domain));
|
|
65736
|
-
}
|
|
65737
|
-
}
|
|
65738
|
-
|
|
65739
65957
|
/**
|
|
65740
65958
|
* Registry to draw icons on cells
|
|
65741
65959
|
*/
|
|
@@ -65743,14 +65961,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65743
65961
|
iconsOnCellRegistry.add("data_validation_checkbox", (getters, position) => {
|
|
65744
65962
|
const hasIcon = getters.isCellValidCheckbox(position);
|
|
65745
65963
|
if (hasIcon) {
|
|
65964
|
+
const value = !!getters.getEvaluatedCell(position).value;
|
|
65746
65965
|
return {
|
|
65747
|
-
svg:
|
|
65966
|
+
svg: value ? CHECKBOX_CHECKED : CHECKBOX_UNCHECKED,
|
|
65967
|
+
hoverSvg: value ? CHECKBOX_CHECKED : CHECKBOX_UNCHECKED_HOVERED,
|
|
65748
65968
|
priority: 2,
|
|
65749
65969
|
horizontalAlign: "center",
|
|
65750
65970
|
size: GRID_ICON_EDGE_LENGTH,
|
|
65751
65971
|
margin: GRID_ICON_MARGIN,
|
|
65752
|
-
component: DataValidationCheckbox,
|
|
65753
65972
|
position,
|
|
65973
|
+
type: "data_validation_checkbox",
|
|
65974
|
+
onClick: (position, env) => {
|
|
65975
|
+
const cell = env.model.getters.getCell(position);
|
|
65976
|
+
const isDisabled = env.model.getters.isReadonly() || !!cell?.isFormula;
|
|
65977
|
+
if (isDisabled) {
|
|
65978
|
+
return;
|
|
65979
|
+
}
|
|
65980
|
+
const cellContent = value ? "FALSE" : "TRUE";
|
|
65981
|
+
env.model.dispatch("UPDATE_CELL", { ...position, content: cellContent });
|
|
65982
|
+
},
|
|
65754
65983
|
};
|
|
65755
65984
|
}
|
|
65756
65985
|
return undefined;
|
|
@@ -65759,13 +65988,19 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65759
65988
|
const hasIcon = !getters.isReadonly() && getters.cellHasListDataValidationIcon(position);
|
|
65760
65989
|
if (hasIcon) {
|
|
65761
65990
|
return {
|
|
65762
|
-
svg:
|
|
65991
|
+
svg: CARET_DOWN,
|
|
65992
|
+
hoverSvg: HOVERED_CARET_DOWN,
|
|
65763
65993
|
priority: 2,
|
|
65764
65994
|
horizontalAlign: "right",
|
|
65765
65995
|
size: GRID_ICON_EDGE_LENGTH,
|
|
65766
65996
|
margin: GRID_ICON_MARGIN,
|
|
65767
|
-
component: DataValidationListIcon,
|
|
65768
65997
|
position,
|
|
65998
|
+
onClick: (position, env) => {
|
|
65999
|
+
const { col, row } = position;
|
|
66000
|
+
env.model.selection.selectCell(col, row);
|
|
66001
|
+
env.startCellEdition();
|
|
66002
|
+
},
|
|
66003
|
+
type: "data_validation_list_icon",
|
|
65769
66004
|
};
|
|
65770
66005
|
}
|
|
65771
66006
|
return undefined;
|
|
@@ -65773,14 +66008,30 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65773
66008
|
iconsOnCellRegistry.add("filter_icon", (getters, position) => {
|
|
65774
66009
|
const hasIcon = getters.isFilterHeader(position);
|
|
65775
66010
|
if (hasIcon) {
|
|
66011
|
+
const isFilterActive = getters.isFilterActive(position);
|
|
66012
|
+
const cellStyle = getters.getCellComputedStyle(position);
|
|
66013
|
+
const isHighContrast = relativeLuminance(cellStyle.fillColor || "#fff") < 0.45;
|
|
65776
66014
|
return {
|
|
65777
|
-
|
|
66015
|
+
type: "filter_icon",
|
|
66016
|
+
svg: getDataFilterIcon(isFilterActive, isHighContrast, false),
|
|
66017
|
+
hoverSvg: getDataFilterIcon(isFilterActive, isHighContrast, true),
|
|
65778
66018
|
priority: 3,
|
|
65779
66019
|
horizontalAlign: "right",
|
|
65780
66020
|
size: GRID_ICON_EDGE_LENGTH,
|
|
65781
66021
|
margin: GRID_ICON_MARGIN,
|
|
65782
|
-
component: FilterIcon,
|
|
65783
66022
|
position,
|
|
66023
|
+
onClick: (position, env) => {
|
|
66024
|
+
const cellPopovers = env.getStore(CellPopoverStore);
|
|
66025
|
+
const activePopover = cellPopovers.persistentCellPopover;
|
|
66026
|
+
if (activePopover.isOpen &&
|
|
66027
|
+
activePopover.col === position.col &&
|
|
66028
|
+
activePopover.row === position.row &&
|
|
66029
|
+
activePopover.type === "FilterMenu") {
|
|
66030
|
+
cellPopovers.close();
|
|
66031
|
+
return;
|
|
66032
|
+
}
|
|
66033
|
+
cellPopovers.open(position, "FilterMenu");
|
|
66034
|
+
},
|
|
65784
66035
|
};
|
|
65785
66036
|
}
|
|
65786
66037
|
return undefined;
|
|
@@ -65790,6 +66041,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65790
66041
|
if (icon) {
|
|
65791
66042
|
const style = getters.getCellStyle(position);
|
|
65792
66043
|
return {
|
|
66044
|
+
type: "conditional_formatting",
|
|
65793
66045
|
svg: ICONS[icon].svg,
|
|
65794
66046
|
priority: 1,
|
|
65795
66047
|
horizontalAlign: "left",
|
|
@@ -65810,23 +66062,55 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65810
66062
|
const definition = getters.getPivotCoreDefinition(pivotId);
|
|
65811
66063
|
const isDashboard = getters.isDashboard();
|
|
65812
66064
|
const fields = pivotCell.dimension === "COL" ? definition.columns : definition.rows;
|
|
65813
|
-
const
|
|
66065
|
+
const hasIcon = !isDashboard && pivotCell.domain.length !== fields.length;
|
|
66066
|
+
const domains = definition.collapsedDomains?.[pivotCell.dimension] ?? [];
|
|
66067
|
+
const isCollapsed = domains.some((domain) => deepEquals(domain, pivotCell.domain));
|
|
66068
|
+
const indent = pivotCell.dimension === "ROW" ? (pivotCell.domain.length - 1) * PIVOT_INDENT : 0;
|
|
65814
66069
|
return {
|
|
66070
|
+
type: "pivot_collapse",
|
|
65815
66071
|
priority: 4,
|
|
65816
66072
|
horizontalAlign: "left",
|
|
65817
|
-
size:
|
|
65818
|
-
?
|
|
66073
|
+
size: hasIcon || (!isDashboard && pivotCell.dimension === "ROW" && definition.rows.length > 1)
|
|
66074
|
+
? PIVOT_COLLAPSE_ICON_SIZE
|
|
65819
66075
|
: 0,
|
|
65820
|
-
margin:
|
|
65821
|
-
|
|
66076
|
+
margin: hasIcon ? GRID_ICON_MARGIN * 2 + indent : indent,
|
|
66077
|
+
svg: hasIcon ? getPivotIconSvg(isCollapsed, false) : undefined,
|
|
66078
|
+
hoverSvg: hasIcon ? getPivotIconSvg(isCollapsed, true) : undefined,
|
|
65822
66079
|
position,
|
|
66080
|
+
onClick: togglePivotCollapse,
|
|
65823
66081
|
};
|
|
65824
66082
|
}
|
|
65825
66083
|
return undefined;
|
|
65826
66084
|
});
|
|
66085
|
+
function togglePivotCollapse(position, env) {
|
|
66086
|
+
const pivotCell = env.model.getters.getPivotCellFromPosition(position);
|
|
66087
|
+
const pivotId = env.model.getters.getPivotIdFromPosition(position);
|
|
66088
|
+
if (!pivotId || pivotCell.type !== "HEADER") {
|
|
66089
|
+
return;
|
|
66090
|
+
}
|
|
66091
|
+
const definition = env.model.getters.getPivotCoreDefinition(pivotId);
|
|
66092
|
+
const collapsedDomains = definition.collapsedDomains?.[pivotCell.dimension]
|
|
66093
|
+
? [...definition.collapsedDomains[pivotCell.dimension]]
|
|
66094
|
+
: [];
|
|
66095
|
+
const index = collapsedDomains.findIndex((domain) => deepEquals(domain, pivotCell.domain));
|
|
66096
|
+
if (index !== -1) {
|
|
66097
|
+
collapsedDomains.splice(index, 1);
|
|
66098
|
+
}
|
|
66099
|
+
else {
|
|
66100
|
+
collapsedDomains.push(pivotCell.domain);
|
|
66101
|
+
}
|
|
66102
|
+
const newDomains = definition.collapsedDomains
|
|
66103
|
+
? { ...definition.collapsedDomains }
|
|
66104
|
+
: { COL: [], ROW: [] };
|
|
66105
|
+
newDomains[pivotCell.dimension] = collapsedDomains;
|
|
66106
|
+
env.model.dispatch("UPDATE_PIVOT", {
|
|
66107
|
+
pivotId,
|
|
66108
|
+
pivot: { ...definition, collapsedDomains: newDomains },
|
|
66109
|
+
});
|
|
66110
|
+
}
|
|
65827
66111
|
|
|
65828
66112
|
class CellIconPlugin extends CoreViewPlugin {
|
|
65829
|
-
static getters = ["doesCellHaveGridIcon", "getCellIcons"];
|
|
66113
|
+
static getters = ["doesCellHaveGridIcon", "getCellIcons", "getCellIconRect"];
|
|
65830
66114
|
cellIconsCache = {};
|
|
65831
66115
|
handle(cmd) {
|
|
65832
66116
|
if (cmd.type !== "SET_VIEWPORT_OFFSET") {
|
|
@@ -65846,6 +66130,29 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
65846
66130
|
}
|
|
65847
66131
|
return this.cellIconsCache[position.sheetId][position.col][position.row];
|
|
65848
66132
|
}
|
|
66133
|
+
getCellIconRect(icon) {
|
|
66134
|
+
const cellPosition = icon.position;
|
|
66135
|
+
const merge = this.getters.getMerge(cellPosition);
|
|
66136
|
+
const zone = merge || positionToZone(cellPosition);
|
|
66137
|
+
const cellRect = this.getters.getRect(zone);
|
|
66138
|
+
const cell = this.getters.getCell(cellPosition);
|
|
66139
|
+
const x = this.getIconHorizontalPosition(cellRect, icon.horizontalAlign, icon);
|
|
66140
|
+
const y = this.getters.computeTextYCoordinate(cellRect, icon.size, cell?.style?.verticalAlign);
|
|
66141
|
+
return { x: x, y: y, width: icon.size, height: icon.size };
|
|
66142
|
+
}
|
|
66143
|
+
getIconHorizontalPosition(rect, align, icon) {
|
|
66144
|
+
const start = rect.x;
|
|
66145
|
+
const end = rect.x + rect.width;
|
|
66146
|
+
switch (align) {
|
|
66147
|
+
case "right":
|
|
66148
|
+
return end - icon.margin - icon.size;
|
|
66149
|
+
case "left":
|
|
66150
|
+
return start + icon.margin;
|
|
66151
|
+
default:
|
|
66152
|
+
const centeringOffset = Math.floor((end - start - icon.size) / 2);
|
|
66153
|
+
return end - icon.size - centeringOffset;
|
|
66154
|
+
}
|
|
66155
|
+
}
|
|
65849
66156
|
computeCellIcons(position) {
|
|
65850
66157
|
const icons = { left: undefined, right: undefined, center: undefined };
|
|
65851
66158
|
const callbacks = iconsOnCellRegistry.getAll();
|
|
@@ -70072,6 +70379,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
70072
70379
|
"getCellText",
|
|
70073
70380
|
"getCellMultiLineText",
|
|
70074
70381
|
"getContiguousZone",
|
|
70382
|
+
"computeTextYCoordinate",
|
|
70075
70383
|
];
|
|
70076
70384
|
ctx = document.createElement("canvas").getContext("2d");
|
|
70077
70385
|
// ---------------------------------------------------------------------------
|
|
@@ -70174,6 +70482,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
70174
70482
|
});
|
|
70175
70483
|
return splitTextToWidth(this.ctx, text, style, args.wrapText ? args.maxWidth : undefined);
|
|
70176
70484
|
}
|
|
70485
|
+
/** Computes the vertical start point from which a text line should be draw in a cell.
|
|
70486
|
+
*
|
|
70487
|
+
* Note that in case the cell does not have enough spaces to display its text lines,
|
|
70488
|
+
* (wrapping cell case) then the vertical align should be at the top.
|
|
70489
|
+
* */
|
|
70490
|
+
computeTextYCoordinate(cellRect, textLineHeight, verticalAlign = DEFAULT_VERTICAL_ALIGN, numberOfLines = 1) {
|
|
70491
|
+
const y = cellRect.y + 1; // +1 to skip the cell grid line at the top
|
|
70492
|
+
const textHeight = computeTextLinesHeight(textLineHeight, numberOfLines);
|
|
70493
|
+
const hasEnoughSpaces = cellRect.height > textHeight + MIN_CELL_TEXT_MARGIN * 2;
|
|
70494
|
+
if (hasEnoughSpaces) {
|
|
70495
|
+
if (verticalAlign === "middle") {
|
|
70496
|
+
return Math.ceil(y + (cellRect.height - textHeight) / 2);
|
|
70497
|
+
}
|
|
70498
|
+
if (verticalAlign === "bottom") {
|
|
70499
|
+
return y + cellRect.height - textHeight - MIN_CELL_TEXT_MARGIN;
|
|
70500
|
+
}
|
|
70501
|
+
}
|
|
70502
|
+
return y + MIN_CELL_TEXT_MARGIN;
|
|
70503
|
+
}
|
|
70177
70504
|
/**
|
|
70178
70505
|
* Expands the given zone until bordered by empty cells or reached the sheet boundaries.
|
|
70179
70506
|
*/
|
|
@@ -72199,6 +72526,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
72199
72526
|
"getElementsFromSelection",
|
|
72200
72527
|
"tryGetActiveSheetId",
|
|
72201
72528
|
"isGridSelectionActive",
|
|
72529
|
+
"getSelectecUnboundedZone",
|
|
72202
72530
|
];
|
|
72203
72531
|
gridSelection = {
|
|
72204
72532
|
anchor: {
|
|
@@ -72210,12 +72538,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
72210
72538
|
selectedFigureId = null;
|
|
72211
72539
|
sheetsData = {};
|
|
72212
72540
|
moveClient;
|
|
72541
|
+
isUnbounded;
|
|
72213
72542
|
// This flag is used to avoid to historize the ACTIVE_SHEET command when it's
|
|
72214
72543
|
// the main command.
|
|
72215
72544
|
activeSheet = null;
|
|
72216
72545
|
constructor(config) {
|
|
72217
72546
|
super(config);
|
|
72218
72547
|
this.moveClient = config.moveClient;
|
|
72548
|
+
this.isUnbounded = false;
|
|
72219
72549
|
}
|
|
72220
72550
|
// ---------------------------------------------------------------------------
|
|
72221
72551
|
// Command Handling
|
|
@@ -72241,6 +72571,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
72241
72571
|
handleEvent(event) {
|
|
72242
72572
|
const anchor = event.anchor;
|
|
72243
72573
|
let zones = [];
|
|
72574
|
+
this.isUnbounded = event.options?.unbounded || false;
|
|
72244
72575
|
switch (event.mode) {
|
|
72245
72576
|
case "overrideSelection":
|
|
72246
72577
|
zones = [anchor.zone];
|
|
@@ -72430,6 +72761,12 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
72430
72761
|
getSelectedZone() {
|
|
72431
72762
|
return deepCopy(this.gridSelection.anchor.zone);
|
|
72432
72763
|
}
|
|
72764
|
+
getSelectecUnboundedZone() {
|
|
72765
|
+
const zone = this.isUnbounded
|
|
72766
|
+
? this.getters.getUnboundedZone(this.activeSheet.id, this.gridSelection.anchor.zone)
|
|
72767
|
+
: this.gridSelection.anchor.zone;
|
|
72768
|
+
return deepCopy(zone);
|
|
72769
|
+
}
|
|
72433
72770
|
getSelection() {
|
|
72434
72771
|
return deepCopy(this.gridSelection);
|
|
72435
72772
|
}
|
|
@@ -72623,11 +72960,6 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
72623
72960
|
},
|
|
72624
72961
|
];
|
|
72625
72962
|
const sheetId = this.getActiveSheetId();
|
|
72626
|
-
const handler = new CellClipboardHandler(this.getters, this.dispatch);
|
|
72627
|
-
const data = handler.copy(getClipboardDataPositions(sheetId, target));
|
|
72628
|
-
if (!data) {
|
|
72629
|
-
return;
|
|
72630
|
-
}
|
|
72631
72963
|
const base = isBasedBefore ? cmd.base : cmd.base + 1;
|
|
72632
72964
|
const pasteTarget = [
|
|
72633
72965
|
{
|
|
@@ -72637,7 +72969,14 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
72637
72969
|
bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
|
|
72638
72970
|
},
|
|
72639
72971
|
];
|
|
72640
|
-
|
|
72972
|
+
for (const Handler of clipboardHandlersRegistries.cellHandlers.getAll()) {
|
|
72973
|
+
const handler = new Handler(this.getters, this.dispatch);
|
|
72974
|
+
const data = handler.copy(getClipboardDataPositions(sheetId, target));
|
|
72975
|
+
if (!data) {
|
|
72976
|
+
continue;
|
|
72977
|
+
}
|
|
72978
|
+
handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
|
|
72979
|
+
}
|
|
72641
72980
|
const selection = pasteTarget[0];
|
|
72642
72981
|
const col = selection.left;
|
|
72643
72982
|
const row = selection.top;
|
|
@@ -73183,6 +73522,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73183
73522
|
"getRect",
|
|
73184
73523
|
"getFigureUI",
|
|
73185
73524
|
"getPositionAnchorOffset",
|
|
73525
|
+
"getGridOffset",
|
|
73186
73526
|
];
|
|
73187
73527
|
viewports = {};
|
|
73188
73528
|
/**
|
|
@@ -73372,6 +73712,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
73372
73712
|
height: this.sheetViewHeight,
|
|
73373
73713
|
};
|
|
73374
73714
|
}
|
|
73715
|
+
getGridOffset() {
|
|
73716
|
+
return { x: this.gridOffsetX, y: this.gridOffsetY };
|
|
73717
|
+
}
|
|
73375
73718
|
/** type as pane, not viewport but basically pane extends viewport */
|
|
73376
73719
|
getActiveMainViewport() {
|
|
73377
73720
|
const sheetId = this.getters.getActiveSheetId();
|
|
@@ -74750,6 +75093,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
74750
75093
|
name: _t("Settings"),
|
|
74751
75094
|
sequence: 100,
|
|
74752
75095
|
execute: (env) => env.openSidePanel("Settings"),
|
|
75096
|
+
isEnabled: (env) => !env.isSmall,
|
|
74753
75097
|
icon: "o-spreadsheet-Icon.COG",
|
|
74754
75098
|
})
|
|
74755
75099
|
// ---------------------------------------------------------------------
|
|
@@ -75167,6 +75511,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75167
75511
|
execute: (env) => {
|
|
75168
75512
|
env.openSidePanel("DataValidation");
|
|
75169
75513
|
},
|
|
75514
|
+
isEnabled: (env) => !env.isSmall,
|
|
75170
75515
|
icon: "o-spreadsheet-Icon.DATA_VALIDATION",
|
|
75171
75516
|
sequence: 30,
|
|
75172
75517
|
separator: true,
|
|
@@ -75190,6 +75535,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75190
75535
|
sequence: sequence + index,
|
|
75191
75536
|
isReadonlyAllowed: true,
|
|
75192
75537
|
execute: (env) => env.openSidePanel("PivotSidePanel", { pivotId }),
|
|
75538
|
+
isEnabled: (env) => !env.isSmall,
|
|
75193
75539
|
onStartHover: (env) => env.getStore(HighlightStore).register(highlightProvider),
|
|
75194
75540
|
onStopHover: (env) => env.getStore(HighlightStore).unRegister(highlightProvider),
|
|
75195
75541
|
icon: "o-spreadsheet-Icon.PIVOT",
|
|
@@ -75461,7 +75807,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75461
75807
|
.o-sheet {
|
|
75462
75808
|
padding: 0 15px;
|
|
75463
75809
|
padding-right: 10px;
|
|
75464
|
-
height: ${
|
|
75810
|
+
height: ${DESKTOP_BOTTOMBAR_HEIGHT}px;
|
|
75465
75811
|
border-left: 1px solid #c1c1c1;
|
|
75466
75812
|
border-right: 1px solid #c1c1c1;
|
|
75467
75813
|
margin-left: -1px;
|
|
@@ -75505,6 +75851,10 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75505
75851
|
width: calc(100% - 1px);
|
|
75506
75852
|
}
|
|
75507
75853
|
}
|
|
75854
|
+
|
|
75855
|
+
.o-spreadshet-mobile .o-sheet {
|
|
75856
|
+
height: ${MOBILE_BOTTOMBAR_HEIGHT}px;
|
|
75857
|
+
}
|
|
75508
75858
|
`;
|
|
75509
75859
|
class BottomBarSheet extends owl.Component {
|
|
75510
75860
|
static template = "o-spreadsheet-BottomBarSheet";
|
|
@@ -75559,7 +75909,16 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75559
75909
|
this.stopEdition();
|
|
75560
75910
|
}
|
|
75561
75911
|
}
|
|
75912
|
+
onClick() {
|
|
75913
|
+
if (!this.env.isMobile()) {
|
|
75914
|
+
return;
|
|
75915
|
+
}
|
|
75916
|
+
this.activateSheet();
|
|
75917
|
+
}
|
|
75562
75918
|
onMouseDown(ev) {
|
|
75919
|
+
if (this.env.isMobile()) {
|
|
75920
|
+
return;
|
|
75921
|
+
}
|
|
75563
75922
|
this.activateSheet();
|
|
75564
75923
|
this.props.onMouseDown(ev);
|
|
75565
75924
|
}
|
|
@@ -75903,8 +76262,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75903
76262
|
}
|
|
75904
76263
|
}
|
|
75905
76264
|
|
|
75906
|
-
.mobile.o-spreadsheet-bottom-bar {
|
|
75907
|
-
padding-left:
|
|
76265
|
+
.o-spreadsheet-mobile .o-spreadsheet-bottom-bar {
|
|
76266
|
+
padding-left: 0;
|
|
75908
76267
|
|
|
75909
76268
|
.add-sheet-container {
|
|
75910
76269
|
order: 2;
|
|
@@ -75921,10 +76280,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
75921
76280
|
`;
|
|
75922
76281
|
class BottomBar extends owl.Component {
|
|
75923
76282
|
static template = "o-spreadsheet-BottomBar";
|
|
75924
|
-
static props = {
|
|
75925
|
-
|
|
75926
|
-
};
|
|
75927
|
-
static components = { Menu, Ripple, BottomBarSheet, BottomBarStatistic };
|
|
76283
|
+
static props = { onClick: Function };
|
|
76284
|
+
static components = { MenuPopover, Ripple, BottomBarSheet, BottomBarStatistic };
|
|
75928
76285
|
bottomBarRef = owl.useRef("bottomBar");
|
|
75929
76286
|
sheetListRef = owl.useRef("sheetList");
|
|
75930
76287
|
dragAndDrop = useDragAndDropListItems();
|
|
@@ -76061,6 +76418,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76061
76418
|
if (event.button !== 0 || this.env.model.getters.isReadonly())
|
|
76062
76419
|
return;
|
|
76063
76420
|
this.closeMenu();
|
|
76421
|
+
if (this.env.isMobile()) {
|
|
76422
|
+
return;
|
|
76423
|
+
}
|
|
76064
76424
|
const visibleSheets = this.getVisibleSheets();
|
|
76065
76425
|
const sheetRects = this.getSheetItemRects();
|
|
76066
76426
|
const sheets = visibleSheets.map((sheet, index) => ({
|
|
@@ -76180,7 +76540,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76180
76540
|
`;
|
|
76181
76541
|
class SpreadsheetDashboard extends owl.Component {
|
|
76182
76542
|
static template = "o-spreadsheet-SpreadsheetDashboard";
|
|
76183
|
-
static props = {};
|
|
76543
|
+
static props = { getGridSize: Function };
|
|
76184
76544
|
static components = {
|
|
76185
76545
|
GridOverlay,
|
|
76186
76546
|
GridPopover,
|
|
@@ -76467,7 +76827,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76467
76827
|
dimension: String,
|
|
76468
76828
|
layers: Array,
|
|
76469
76829
|
};
|
|
76470
|
-
static components = { RowGroup, ColGroup,
|
|
76830
|
+
static components = { RowGroup, ColGroup, MenuPopover };
|
|
76471
76831
|
menu = owl.useState({ isOpen: false, anchorRect: null, menuItems: [] });
|
|
76472
76832
|
getLayerOffset(layerIndex) {
|
|
76473
76833
|
return layerIndex * GROUP_LAYER_WIDTH;
|
|
@@ -76683,6 +77043,158 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76683
77043
|
}
|
|
76684
77044
|
}
|
|
76685
77045
|
|
|
77046
|
+
class RibbonMenu extends owl.Component {
|
|
77047
|
+
static template = "o-spreadsheet-RibbonMenu";
|
|
77048
|
+
static props = {
|
|
77049
|
+
onClose: Function,
|
|
77050
|
+
};
|
|
77051
|
+
static components = { Menu };
|
|
77052
|
+
rootItems = topbarMenuRegistry.getMenuItems();
|
|
77053
|
+
menuRef = owl.useRef("menu");
|
|
77054
|
+
state = owl.useState({
|
|
77055
|
+
menuItems: this.rootItems,
|
|
77056
|
+
title: _t("Menu Bar"),
|
|
77057
|
+
parentState: undefined,
|
|
77058
|
+
});
|
|
77059
|
+
setup() {
|
|
77060
|
+
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
77061
|
+
}
|
|
77062
|
+
onExternalClick(ev) {
|
|
77063
|
+
if (!this.menuRef.el?.contains(ev.target)) {
|
|
77064
|
+
this.props.onClose();
|
|
77065
|
+
}
|
|
77066
|
+
}
|
|
77067
|
+
onClickMenu(menu) {
|
|
77068
|
+
const children = menu.children(this.env);
|
|
77069
|
+
if (children.length) {
|
|
77070
|
+
this.state.parentState = { ...this.state };
|
|
77071
|
+
this.state.menuItems = children;
|
|
77072
|
+
this.state.title = menu.name(this.env);
|
|
77073
|
+
}
|
|
77074
|
+
else {
|
|
77075
|
+
this.state.menuItems = this.rootItems;
|
|
77076
|
+
this.state.title = undefined;
|
|
77077
|
+
this.state.parentState = undefined;
|
|
77078
|
+
menu.execute?.(this.env);
|
|
77079
|
+
this.props.onClose();
|
|
77080
|
+
}
|
|
77081
|
+
}
|
|
77082
|
+
get menuProps() {
|
|
77083
|
+
return {
|
|
77084
|
+
menuItems: this.state.menuItems,
|
|
77085
|
+
onClose: this.props.onClose,
|
|
77086
|
+
onClickMenu: this.onClickMenu.bind(this),
|
|
77087
|
+
};
|
|
77088
|
+
}
|
|
77089
|
+
get style() {
|
|
77090
|
+
return cssPropertiesToCss({
|
|
77091
|
+
height: `${this.props.height}px`,
|
|
77092
|
+
});
|
|
77093
|
+
}
|
|
77094
|
+
onClickBack() {
|
|
77095
|
+
if (!this.state.parentState) {
|
|
77096
|
+
this.props.onClose();
|
|
77097
|
+
return;
|
|
77098
|
+
}
|
|
77099
|
+
this.state.menuItems = this.state.parentState.menuItems;
|
|
77100
|
+
this.state.title = this.state.parentState.title;
|
|
77101
|
+
this.state.parentState = this.state.parentState.parentState;
|
|
77102
|
+
}
|
|
77103
|
+
get backTitle() {
|
|
77104
|
+
return this.state.parentState ? _t("Go to previous menu") : _t("Close menu bar");
|
|
77105
|
+
}
|
|
77106
|
+
}
|
|
77107
|
+
|
|
77108
|
+
css `
|
|
77109
|
+
.o-small-composer {
|
|
77110
|
+
z-index: ${ComponentsImportance.TopBarComposer};
|
|
77111
|
+
}
|
|
77112
|
+
`;
|
|
77113
|
+
class SmallBottomBar extends owl.Component {
|
|
77114
|
+
static components = { Composer, BottomBar, Ripple, RibbonMenu };
|
|
77115
|
+
static template = "o-spreadsheet-SmallBottomBar";
|
|
77116
|
+
static props = {
|
|
77117
|
+
onClick: Function,
|
|
77118
|
+
};
|
|
77119
|
+
composerFocusStore;
|
|
77120
|
+
composerStore;
|
|
77121
|
+
composerInterface;
|
|
77122
|
+
composerRef = owl.useRef("bottombarComposer");
|
|
77123
|
+
menuState = owl.useState({
|
|
77124
|
+
isOpen: false,
|
|
77125
|
+
});
|
|
77126
|
+
setup() {
|
|
77127
|
+
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
77128
|
+
const composerStore = useStore(CellComposerStore);
|
|
77129
|
+
this.composerStore = composerStore;
|
|
77130
|
+
this.composerInterface = {
|
|
77131
|
+
id: "bottombarComposer",
|
|
77132
|
+
get editionMode() {
|
|
77133
|
+
return composerStore.editionMode;
|
|
77134
|
+
},
|
|
77135
|
+
startEdition: this.composerStore.startEdition,
|
|
77136
|
+
setCurrentContent: this.composerStore.setCurrentContent,
|
|
77137
|
+
stopEdition: this.composerStore.stopEdition,
|
|
77138
|
+
};
|
|
77139
|
+
owl.useEffect(() => {
|
|
77140
|
+
if (
|
|
77141
|
+
// we hide the grid composer on mobile so we need to autofocus this composer
|
|
77142
|
+
this.env.isMobile() &&
|
|
77143
|
+
!this.menuState.isOpen &&
|
|
77144
|
+
this.composerStore.editionMode !== "inactive" &&
|
|
77145
|
+
this.composerFocusStore.activeComposer !== this.composerInterface) {
|
|
77146
|
+
this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
77147
|
+
focusMode: "contentFocus",
|
|
77148
|
+
});
|
|
77149
|
+
}
|
|
77150
|
+
});
|
|
77151
|
+
}
|
|
77152
|
+
get focus() {
|
|
77153
|
+
return this.composerFocusStore.activeComposer === this.composerInterface
|
|
77154
|
+
? this.composerFocusStore.focusMode
|
|
77155
|
+
: "inactive";
|
|
77156
|
+
}
|
|
77157
|
+
get rect() {
|
|
77158
|
+
return this.composerRef.el
|
|
77159
|
+
? getBoundingRectAsPOJO(this.composerRef.el)
|
|
77160
|
+
: { x: 0, y: 0, width: 0, height: 0 };
|
|
77161
|
+
}
|
|
77162
|
+
get composerProps() {
|
|
77163
|
+
const { width, height } = this.env.model.getters.getSheetViewDimensionWithHeaders();
|
|
77164
|
+
return {
|
|
77165
|
+
rect: { ...this.rect },
|
|
77166
|
+
delimitation: {
|
|
77167
|
+
width,
|
|
77168
|
+
height,
|
|
77169
|
+
},
|
|
77170
|
+
focus: this.focus,
|
|
77171
|
+
composerStore: this.composerStore,
|
|
77172
|
+
onComposerContentFocused: () => this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
77173
|
+
focusMode: "contentFocus",
|
|
77174
|
+
}),
|
|
77175
|
+
isDefaultFocus: false,
|
|
77176
|
+
inputStyle: cssPropertiesToCss({
|
|
77177
|
+
height: this.focus === "inactive" ? "26px" : "fit-content",
|
|
77178
|
+
"max-height": `130px`,
|
|
77179
|
+
}),
|
|
77180
|
+
showAssistant: !isIOS(), // Hide assistant on iOS as it breaks visually
|
|
77181
|
+
};
|
|
77182
|
+
}
|
|
77183
|
+
get symbols() {
|
|
77184
|
+
return ["=", "(", ")", ":", "-", "/", "*", ",", "+", "$", "."];
|
|
77185
|
+
}
|
|
77186
|
+
insertSymbol(symbol) {
|
|
77187
|
+
this.composerStore.replaceComposerCursorSelection(symbol);
|
|
77188
|
+
this.composerFocusStore.focusComposer(this.composerInterface, {
|
|
77189
|
+
focusMode: "contentFocus",
|
|
77190
|
+
});
|
|
77191
|
+
}
|
|
77192
|
+
toggleRibbon() {
|
|
77193
|
+
this.composerStore.cancelEdition();
|
|
77194
|
+
this.menuState.isOpen = !this.menuState.isOpen;
|
|
77195
|
+
}
|
|
77196
|
+
}
|
|
77197
|
+
|
|
76686
77198
|
const COMPOSER_MAX_HEIGHT = 100;
|
|
76687
77199
|
/* svg free of use from https://uxwing.com/formula-fx-icon/ */
|
|
76688
77200
|
const FX_SVG = /*xml*/ `
|
|
@@ -76692,7 +77204,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76692
77204
|
`;
|
|
76693
77205
|
css /* scss */ `
|
|
76694
77206
|
.o-topbar-composer-container {
|
|
76695
|
-
height: ${
|
|
77207
|
+
height: ${DESKTOP_TOPBAR_TOOLBAR_HEIGHT}px;
|
|
76696
77208
|
}
|
|
76697
77209
|
|
|
76698
77210
|
.o-topbar-composer {
|
|
@@ -76747,7 +77259,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
76747
77259
|
"max-height": `${COMPOSER_MAX_HEIGHT}px`,
|
|
76748
77260
|
"line-height": "24px",
|
|
76749
77261
|
};
|
|
76750
|
-
style.height = this.focus === "inactive" ? `${
|
|
77262
|
+
style.height = this.focus === "inactive" ? `${DESKTOP_TOPBAR_TOOLBAR_HEIGHT}px` : "fit-content";
|
|
76751
77263
|
return cssPropertiesToCss(style);
|
|
76752
77264
|
}
|
|
76753
77265
|
get containerStyle() {
|
|
@@ -77250,7 +77762,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77250
77762
|
|
|
77251
77763
|
class NumberFormatsTool extends owl.Component {
|
|
77252
77764
|
static template = "o-spreadsheet-NumberFormatsTool";
|
|
77253
|
-
static components = {
|
|
77765
|
+
static components = { MenuPopover, ActionButton };
|
|
77254
77766
|
static props = { class: String };
|
|
77255
77767
|
formatNumberMenuItemSpec = formatNumberMenuItemSpec;
|
|
77256
77768
|
topBarToolStore;
|
|
@@ -77300,7 +77812,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77300
77812
|
.addChild("edit", {
|
|
77301
77813
|
component: PaintFormatButton,
|
|
77302
77814
|
props: {
|
|
77303
|
-
class: "o-hoverable-button o-toolbar-button",
|
|
77815
|
+
class: "o-hoverable-button o-toolbar-button o-mobile-disabled",
|
|
77304
77816
|
},
|
|
77305
77817
|
sequence: 3,
|
|
77306
77818
|
})
|
|
@@ -77459,7 +77971,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77459
77971
|
.add("misc")
|
|
77460
77972
|
.addChild("misc", {
|
|
77461
77973
|
component: TableDropdownButton,
|
|
77462
|
-
props: { class: "o-toolbar-button o-hoverable-button o-menu-item-button" },
|
|
77974
|
+
props: { class: "o-toolbar-button o-hoverable-button o-menu-item-button o-mobile-disabled" },
|
|
77463
77975
|
sequence: 1,
|
|
77464
77976
|
})
|
|
77465
77977
|
.addChild("misc", {
|
|
@@ -77479,6 +77991,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77479
77991
|
border-right: 1px solid ${SEPARATOR_COLOR};
|
|
77480
77992
|
width: 0;
|
|
77481
77993
|
margin: 0 6px;
|
|
77994
|
+
height: 30px;
|
|
77482
77995
|
}
|
|
77483
77996
|
|
|
77484
77997
|
.o-toolbar-button {
|
|
@@ -77511,7 +78024,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77511
78024
|
|
|
77512
78025
|
.irregularity-map {
|
|
77513
78026
|
border-top: 1px solid ${SEPARATOR_COLOR};
|
|
77514
|
-
height: ${
|
|
78027
|
+
height: ${DESKTOP_TOPBAR_TOOLBAR_HEIGHT}px;
|
|
77515
78028
|
|
|
77516
78029
|
.alert-info {
|
|
77517
78030
|
border-left: 3px solid ${ALERT_INFO_BORDER};
|
|
@@ -77524,7 +78037,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77524
78037
|
|
|
77525
78038
|
/* Toolbar */
|
|
77526
78039
|
.o-topbar-toolbar {
|
|
77527
|
-
height: ${
|
|
78040
|
+
height: ${DESKTOP_TOPBAR_TOOLBAR_HEIGHT}px;
|
|
77528
78041
|
|
|
77529
78042
|
.o-readonly-toolbar {
|
|
77530
78043
|
background-color: ${BACKGROUND_HEADER_COLOR};
|
|
@@ -77538,6 +78051,24 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77538
78051
|
}
|
|
77539
78052
|
}
|
|
77540
78053
|
}
|
|
78054
|
+
|
|
78055
|
+
.o-spreadsheet-mobile {
|
|
78056
|
+
.o-topbar-toolbar {
|
|
78057
|
+
height: ${MOBILE_TOPBAR_TOOLBAR_HEIGHT}px;
|
|
78058
|
+
}
|
|
78059
|
+
.o-topbar-divider {
|
|
78060
|
+
border-width: 2px;
|
|
78061
|
+
border-radius: 4px;
|
|
78062
|
+
}
|
|
78063
|
+
|
|
78064
|
+
.o-toolbar-button {
|
|
78065
|
+
height: 35px;
|
|
78066
|
+
width: 31px;
|
|
78067
|
+
.o-toolbar-button.o-mobile-disabled * {
|
|
78068
|
+
color: ${DISABLED_TEXT_COLOR};
|
|
78069
|
+
cursor: not-allowed;
|
|
78070
|
+
}
|
|
78071
|
+
}
|
|
77541
78072
|
`;
|
|
77542
78073
|
class TopBar extends owl.Component {
|
|
77543
78074
|
static template = "o-spreadsheet-TopBar";
|
|
@@ -77546,7 +78077,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77546
78077
|
dropdownMaxHeight: Number,
|
|
77547
78078
|
};
|
|
77548
78079
|
static components = {
|
|
77549
|
-
|
|
78080
|
+
MenuPopover,
|
|
77550
78081
|
TopBarComposer,
|
|
77551
78082
|
Popover,
|
|
77552
78083
|
};
|
|
@@ -77626,7 +78157,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
77626
78157
|
// TODO : manage click events better. We need this piece of code
|
|
77627
78158
|
// otherwise the event opening the menu would close it on the same frame.
|
|
77628
78159
|
// And we cannot stop the event propagation because it's used in an
|
|
77629
|
-
// external listener of the
|
|
78160
|
+
// external listener of the MenuPopover component to close the context menu when
|
|
77630
78161
|
// clicking on the top bar
|
|
77631
78162
|
if (this.openedEl === ev.target) {
|
|
77632
78163
|
return;
|
|
@@ -78052,6 +78583,11 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
78052
78583
|
color: ${TEXT_BODY};
|
|
78053
78584
|
}
|
|
78054
78585
|
}
|
|
78586
|
+
|
|
78587
|
+
.o-spreadsheet-topbar-wrapper,
|
|
78588
|
+
.o-spreadsheet-bottombar-wrapper {
|
|
78589
|
+
z-index: ${ComponentsImportance.ScrollBar + 1};
|
|
78590
|
+
}
|
|
78055
78591
|
`;
|
|
78056
78592
|
class Spreadsheet extends owl.Component {
|
|
78057
78593
|
static template = "o-spreadsheet-Spreadsheet";
|
|
@@ -78065,6 +78601,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
78065
78601
|
TopBar,
|
|
78066
78602
|
Grid,
|
|
78067
78603
|
BottomBar,
|
|
78604
|
+
SmallBottomBar,
|
|
78068
78605
|
SidePanel,
|
|
78069
78606
|
SpreadsheetDashboard,
|
|
78070
78607
|
HeaderGroupContainer,
|
|
@@ -78088,12 +78625,25 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
78088
78625
|
else {
|
|
78089
78626
|
properties["grid-template-rows"] = `min-content auto min-content`;
|
|
78090
78627
|
}
|
|
78091
|
-
|
|
78628
|
+
const columnWidth = this.sidePanel.isOpen ? `${this.sidePanel.panelSize}px` : "auto";
|
|
78629
|
+
properties["grid-template-columns"] = `auto ${columnWidth}`;
|
|
78092
78630
|
return cssPropertiesToCss(properties);
|
|
78093
78631
|
}
|
|
78094
78632
|
setup() {
|
|
78633
|
+
if (!("isSmall" in this.env)) {
|
|
78634
|
+
const screenSize = useScreenWidth();
|
|
78635
|
+
owl.useSubEnv({
|
|
78636
|
+
get isSmall() {
|
|
78637
|
+
return screenSize.isSmall;
|
|
78638
|
+
},
|
|
78639
|
+
});
|
|
78640
|
+
}
|
|
78095
78641
|
const stores = useStoreProvider();
|
|
78096
78642
|
stores.inject(ModelStore, this.model);
|
|
78643
|
+
const env = this.env;
|
|
78644
|
+
stores.get(ScreenWidthStore).setSmallThreshhold(() => {
|
|
78645
|
+
return env.isSmall;
|
|
78646
|
+
});
|
|
78097
78647
|
this.notificationStore = useStore(NotificationStore);
|
|
78098
78648
|
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
78099
78649
|
this.sidePanel = useStore(SidePanelStore);
|
|
@@ -78111,15 +78661,8 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
78111
78661
|
notifyUser: (notification) => this.notificationStore.notifyUser(notification),
|
|
78112
78662
|
askConfirmation: (text, confirm, cancel) => this.notificationStore.askConfirmation(text, confirm, cancel),
|
|
78113
78663
|
raiseError: (text, cb) => this.notificationStore.raiseError(text, cb),
|
|
78664
|
+
isMobile: isMobileOS,
|
|
78114
78665
|
});
|
|
78115
|
-
if (!("isSmall" in this.env)) {
|
|
78116
|
-
const screenSize = useScreenWidth();
|
|
78117
|
-
owl.useSubEnv({
|
|
78118
|
-
get isSmall() {
|
|
78119
|
-
return screenSize.isSmall;
|
|
78120
|
-
},
|
|
78121
|
-
});
|
|
78122
|
-
}
|
|
78123
78666
|
this.notificationStore.updateNotificationCallbacks({ ...this.props });
|
|
78124
78667
|
owl.useEffect(() => {
|
|
78125
78668
|
/**
|
|
@@ -78225,6 +78768,24 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
78225
78768
|
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
78226
78769
|
return this.env.model.getters.getVisibleGroupLayers(sheetId, "COL");
|
|
78227
78770
|
}
|
|
78771
|
+
getGridSize() {
|
|
78772
|
+
const topBarHeight = this.spreadsheetRef.el
|
|
78773
|
+
?.querySelector(".o-spreadsheet-topbar-wrapper")
|
|
78774
|
+
?.getBoundingClientRect().height || 0;
|
|
78775
|
+
const bottomBarHeight = this.spreadsheetRef.el
|
|
78776
|
+
?.querySelector(".o-spreadsheet-bottombar-wrapper")
|
|
78777
|
+
?.getBoundingClientRect().height || 0;
|
|
78778
|
+
const gridWidth = this.spreadsheetRef.el?.querySelector(".o-grid")?.getBoundingClientRect().width || 0;
|
|
78779
|
+
const gridHeight = (this.spreadsheetRef.el?.getBoundingClientRect().height || 0) -
|
|
78780
|
+
(this.spreadsheetRef.el?.querySelector(".o-column-groups")?.getBoundingClientRect().height ||
|
|
78781
|
+
0) -
|
|
78782
|
+
topBarHeight -
|
|
78783
|
+
bottomBarHeight;
|
|
78784
|
+
return {
|
|
78785
|
+
width: Math.max(gridWidth - SCROLLBAR_WIDTH, 0),
|
|
78786
|
+
height: Math.max(gridHeight - SCROLLBAR_WIDTH, 0),
|
|
78787
|
+
};
|
|
78788
|
+
}
|
|
78228
78789
|
}
|
|
78229
78790
|
|
|
78230
78791
|
function inverseCommand(cmd) {
|
|
@@ -82487,7 +83048,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82487
83048
|
MIN_COL_WIDTH,
|
|
82488
83049
|
HEADER_HEIGHT,
|
|
82489
83050
|
HEADER_WIDTH,
|
|
82490
|
-
|
|
83051
|
+
DESKTOP_BOTTOMBAR_HEIGHT,
|
|
82491
83052
|
DEFAULT_CELL_WIDTH,
|
|
82492
83053
|
DEFAULT_CELL_HEIGHT,
|
|
82493
83054
|
SCROLLBAR_WIDTH,
|
|
@@ -82633,7 +83194,7 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82633
83194
|
FunnelChartDesignPanel,
|
|
82634
83195
|
ChartTypePicker,
|
|
82635
83196
|
FigureComponent,
|
|
82636
|
-
|
|
83197
|
+
MenuPopover,
|
|
82637
83198
|
Popover,
|
|
82638
83199
|
SelectionInput,
|
|
82639
83200
|
ValidationMessages,
|
|
@@ -82744,9 +83305,9 @@ stores.inject(MyMetaStore, storeInstance);
|
|
|
82744
83305
|
exports.tokenize = tokenize;
|
|
82745
83306
|
|
|
82746
83307
|
|
|
82747
|
-
__info__.version = "18.4.0-alpha.
|
|
82748
|
-
__info__.date = "2025-
|
|
82749
|
-
__info__.hash = "
|
|
83308
|
+
__info__.version = "18.4.0-alpha.7";
|
|
83309
|
+
__info__.date = "2025-06-06T09:32:44.285Z";
|
|
83310
|
+
__info__.hash = "2bfbe64";
|
|
82750
83311
|
|
|
82751
83312
|
|
|
82752
83313
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|