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