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