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