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