@odoo/o-spreadsheet 16.2.0-alpha.2 → 16.2.0-alpha.4
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 → o-spreadsheet.cjs.js} +1736 -1606
- package/dist/{o_spreadsheet.d.ts → o-spreadsheet.d.ts} +209 -201
- package/dist/{o_spreadsheet.esm.js → o-spreadsheet.esm.js} +1737 -1607
- package/dist/{o_spreadsheet.iife.js → o-spreadsheet.iife.js} +1736 -1606
- package/dist/o-spreadsheet.iife.min.js +2431 -0
- package/package.json +10 -9
- package/readme.md +3 -1
- package/dist/o_spreadsheet.iife.min.js +0 -2410
|
@@ -274,7 +274,6 @@
|
|
|
274
274
|
ComponentsImportance[ComponentsImportance["Dropdown"] = 16] = "Dropdown";
|
|
275
275
|
ComponentsImportance[ComponentsImportance["GridComposer"] = 20] = "GridComposer";
|
|
276
276
|
ComponentsImportance[ComponentsImportance["TopBarComposer"] = 21] = "TopBarComposer";
|
|
277
|
-
ComponentsImportance[ComponentsImportance["ColorPicker"] = 25] = "ColorPicker";
|
|
278
277
|
ComponentsImportance[ComponentsImportance["IconPicker"] = 25] = "IconPicker";
|
|
279
278
|
ComponentsImportance[ComponentsImportance["Popover"] = 30] = "Popover";
|
|
280
279
|
ComponentsImportance[ComponentsImportance["ChartAnchor"] = 1000] = "ChartAnchor";
|
|
@@ -2027,10 +2026,10 @@
|
|
|
2027
2026
|
if (right !== undefined && bottom !== undefined)
|
|
2028
2027
|
return { left, top, right, bottom };
|
|
2029
2028
|
else if (bottom === undefined && right !== undefined) {
|
|
2030
|
-
return { right, top, left, bottom: this.getSheetSize(this.sheetId).
|
|
2029
|
+
return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
|
|
2031
2030
|
}
|
|
2032
2031
|
else if (right === undefined && bottom !== undefined) {
|
|
2033
|
-
return { bottom, left, top, right: this.getSheetSize(this.sheetId).
|
|
2032
|
+
return { bottom, left, top, right: this.getSheetSize(this.sheetId).numberOfCols - 1 };
|
|
2034
2033
|
}
|
|
2035
2034
|
throw new Error(_lt("Bad zone format"));
|
|
2036
2035
|
}
|
|
@@ -2653,13 +2652,13 @@
|
|
|
2653
2652
|
}
|
|
2654
2653
|
function zoneToDimension(zone) {
|
|
2655
2654
|
return {
|
|
2656
|
-
|
|
2657
|
-
|
|
2655
|
+
numberOfRows: zone.bottom - zone.top + 1,
|
|
2656
|
+
numberOfCols: zone.right - zone.left + 1,
|
|
2658
2657
|
};
|
|
2659
2658
|
}
|
|
2660
2659
|
function isOneDimensional(zone) {
|
|
2661
|
-
const {
|
|
2662
|
-
return
|
|
2660
|
+
const { numberOfCols, numberOfRows } = zoneToDimension(zone);
|
|
2661
|
+
return numberOfCols === 1 || numberOfRows === 1;
|
|
2663
2662
|
}
|
|
2664
2663
|
/**
|
|
2665
2664
|
* Array of all positions in the zone.
|
|
@@ -2844,7 +2843,7 @@
|
|
|
2844
2843
|
return `background-color: ${this.background}`;
|
|
2845
2844
|
}
|
|
2846
2845
|
get chartRuntime() {
|
|
2847
|
-
const runtime = this.env.model.getters.getChartRuntime(this.
|
|
2846
|
+
const runtime = this.env.model.getters.getChartRuntime(this.props.figure.id);
|
|
2848
2847
|
if (!("chartJsConfig" in runtime)) {
|
|
2849
2848
|
throw new Error("Unsupported chart runtime");
|
|
2850
2849
|
}
|
|
@@ -3109,7 +3108,7 @@
|
|
|
3109
3108
|
this.ctx = document.createElement("canvas").getContext("2d");
|
|
3110
3109
|
}
|
|
3111
3110
|
get runtime() {
|
|
3112
|
-
return this.env.model.getters.getChartRuntime(this.
|
|
3111
|
+
return this.env.model.getters.getChartRuntime(this.props.figure.id);
|
|
3113
3112
|
}
|
|
3114
3113
|
get title() {
|
|
3115
3114
|
return this.runtime.title;
|
|
@@ -3134,7 +3133,7 @@
|
|
|
3134
3133
|
return this.runtime.fontColor;
|
|
3135
3134
|
}
|
|
3136
3135
|
get secondaryFontColor() {
|
|
3137
|
-
return relativeLuminance(this.
|
|
3136
|
+
return relativeLuminance(this.backgroundColor) > 0.3 ? "#525252" : "#C8C8C8";
|
|
3138
3137
|
}
|
|
3139
3138
|
get figure() {
|
|
3140
3139
|
return this.props.figure;
|
|
@@ -3498,7 +3497,7 @@
|
|
|
3498
3497
|
CommandResult[CommandResult["InvalidRange"] = 25] = "InvalidRange";
|
|
3499
3498
|
CommandResult[CommandResult["InvalidZones"] = 26] = "InvalidZones";
|
|
3500
3499
|
CommandResult[CommandResult["InvalidSheetId"] = 27] = "InvalidSheetId";
|
|
3501
|
-
CommandResult[CommandResult["
|
|
3500
|
+
CommandResult[CommandResult["InvalidFigureId"] = 28] = "InvalidFigureId";
|
|
3502
3501
|
CommandResult[CommandResult["InputAlreadyFocused"] = 29] = "InputAlreadyFocused";
|
|
3503
3502
|
CommandResult[CommandResult["MaximumRangesReached"] = 30] = "MaximumRangesReached";
|
|
3504
3503
|
CommandResult[CommandResult["InvalidChartDefinition"] = 31] = "InvalidChartDefinition";
|
|
@@ -3555,6 +3554,7 @@
|
|
|
3555
3554
|
CommandResult[CommandResult["DuplicatedFigureId"] = 82] = "DuplicatedFigureId";
|
|
3556
3555
|
CommandResult[CommandResult["InvalidSelectionStep"] = 83] = "InvalidSelectionStep";
|
|
3557
3556
|
CommandResult[CommandResult["DuplicatedChartId"] = 84] = "DuplicatedChartId";
|
|
3557
|
+
CommandResult[CommandResult["ChartDoesNotExist"] = 85] = "ChartDoesNotExist";
|
|
3558
3558
|
})(exports.CommandResult || (exports.CommandResult = {}));
|
|
3559
3559
|
|
|
3560
3560
|
var DIRECTION;
|
|
@@ -3745,11 +3745,11 @@
|
|
|
3745
3745
|
const labelZone = (_a = ds.labelCell) === null || _a === void 0 ? void 0 : _a.zone;
|
|
3746
3746
|
let dataZone = ds.dataRange.zone;
|
|
3747
3747
|
if (labelZone) {
|
|
3748
|
-
const {
|
|
3749
|
-
if (
|
|
3748
|
+
const { numberOfRows, numberOfCols } = zoneToDimension(dataZone);
|
|
3749
|
+
if (numberOfRows === 1) {
|
|
3750
3750
|
dataZone = { ...dataZone, left: dataZone.left + 1 };
|
|
3751
3751
|
}
|
|
3752
|
-
else if (
|
|
3752
|
+
else if (numberOfCols === 1) {
|
|
3753
3753
|
dataZone = { ...dataZone, top: dataZone.top + 1 };
|
|
3754
3754
|
}
|
|
3755
3755
|
}
|
|
@@ -5462,6 +5462,76 @@
|
|
|
5462
5462
|
chartComponentRegistry.add("gauge", ChartJsComponent);
|
|
5463
5463
|
chartComponentRegistry.add("scorecard", ScorecardChart$1);
|
|
5464
5464
|
|
|
5465
|
+
// -----------------------------------------------------------------------------
|
|
5466
|
+
// STYLE
|
|
5467
|
+
// -----------------------------------------------------------------------------
|
|
5468
|
+
css /* scss */ `
|
|
5469
|
+
.o-chart-container {
|
|
5470
|
+
width: 100%;
|
|
5471
|
+
height: 100%;
|
|
5472
|
+
position: relative;
|
|
5473
|
+
}
|
|
5474
|
+
`;
|
|
5475
|
+
class ChartFigure extends owl.Component {
|
|
5476
|
+
get chartType() {
|
|
5477
|
+
return this.env.model.getters.getChartType(this.props.figure.id);
|
|
5478
|
+
}
|
|
5479
|
+
get chartComponent() {
|
|
5480
|
+
const type = this.chartType;
|
|
5481
|
+
const component = chartComponentRegistry.get(type);
|
|
5482
|
+
if (!component) {
|
|
5483
|
+
throw new Error(`Component is not defined for type ${type}`);
|
|
5484
|
+
}
|
|
5485
|
+
return component;
|
|
5486
|
+
}
|
|
5487
|
+
}
|
|
5488
|
+
ChartFigure.template = "o-spreadsheet-ChartFigure";
|
|
5489
|
+
ChartFigure.components = {};
|
|
5490
|
+
ChartFigure.props = {
|
|
5491
|
+
figure: Object,
|
|
5492
|
+
onFigureDeleted: Function,
|
|
5493
|
+
};
|
|
5494
|
+
|
|
5495
|
+
function interactiveCut(env) {
|
|
5496
|
+
const result = env.model.dispatch("CUT");
|
|
5497
|
+
if (!result.isSuccessful) {
|
|
5498
|
+
if (result.isCancelledBecause(19 /* CommandResult.WrongCutSelection */)) {
|
|
5499
|
+
env.raiseError(_lt("This operation is not allowed with multiple selections."));
|
|
5500
|
+
}
|
|
5501
|
+
}
|
|
5502
|
+
}
|
|
5503
|
+
|
|
5504
|
+
const PasteInteractiveContent = {
|
|
5505
|
+
wrongPasteSelection: _lt("This operation is not allowed with multiple selections."),
|
|
5506
|
+
willRemoveExistingMerge: _lt("This operation is not possible due to a merge. Please remove the merges first than try again."),
|
|
5507
|
+
wrongFigurePasteOption: _lt("Cannot do a special paste of a figure."),
|
|
5508
|
+
frozenPaneOverlap: _lt("Cannot paste merged cells over a frozen pane."),
|
|
5509
|
+
};
|
|
5510
|
+
function handlePasteResult(env, result) {
|
|
5511
|
+
if (!result.isSuccessful) {
|
|
5512
|
+
if (result.reasons.includes(20 /* CommandResult.WrongPasteSelection */)) {
|
|
5513
|
+
env.raiseError(PasteInteractiveContent.wrongPasteSelection);
|
|
5514
|
+
}
|
|
5515
|
+
else if (result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
|
|
5516
|
+
env.raiseError(PasteInteractiveContent.willRemoveExistingMerge);
|
|
5517
|
+
}
|
|
5518
|
+
else if (result.reasons.includes(22 /* CommandResult.WrongFigurePasteOption */)) {
|
|
5519
|
+
env.raiseError(PasteInteractiveContent.wrongFigurePasteOption);
|
|
5520
|
+
}
|
|
5521
|
+
else if (result.reasons.includes(75 /* CommandResult.FrozenPaneOverlap */)) {
|
|
5522
|
+
env.raiseError(PasteInteractiveContent.frozenPaneOverlap);
|
|
5523
|
+
}
|
|
5524
|
+
}
|
|
5525
|
+
}
|
|
5526
|
+
function interactivePaste(env, target, pasteOption) {
|
|
5527
|
+
const result = env.model.dispatch("PASTE", { target, pasteOption });
|
|
5528
|
+
handlePasteResult(env, result);
|
|
5529
|
+
}
|
|
5530
|
+
function interactivePasteFromOS(env, target, text) {
|
|
5531
|
+
const result = env.model.dispatch("PASTE_FROM_OS_CLIPBOARD", { target, text });
|
|
5532
|
+
handlePasteResult(env, result);
|
|
5533
|
+
}
|
|
5534
|
+
|
|
5465
5535
|
function createMenu(menuItems) {
|
|
5466
5536
|
return menuItems.map(createMenuItem).sort((a, b) => a.sequence - b.sequence);
|
|
5467
5537
|
}
|
|
@@ -5542,984 +5612,281 @@
|
|
|
5542
5612
|
}
|
|
5543
5613
|
|
|
5544
5614
|
/**
|
|
5545
|
-
*
|
|
5546
|
-
* to the browser viewport.
|
|
5615
|
+
* Create a function used to create a Chart based on the definition
|
|
5547
5616
|
*/
|
|
5548
|
-
function
|
|
5549
|
-
const
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
spreadsheetElement = document.querySelector(".o-spreadsheet");
|
|
5555
|
-
}
|
|
5556
|
-
if (spreadsheetElement) {
|
|
5557
|
-
const { top, left, width, height } = spreadsheetElement.getBoundingClientRect();
|
|
5558
|
-
position.x = left;
|
|
5559
|
-
position.y = top;
|
|
5560
|
-
position.width = width;
|
|
5561
|
-
position.height = height;
|
|
5617
|
+
function chartFactory(getters) {
|
|
5618
|
+
const builders = chartRegistry.getAll().sort((a, b) => a.sequence - b.sequence);
|
|
5619
|
+
function createChart(id, definition, sheetId) {
|
|
5620
|
+
const builder = builders.find((builder) => builder.match(definition.type));
|
|
5621
|
+
if (!builder) {
|
|
5622
|
+
throw new Error(`No builder for this chart: ${definition.type}`);
|
|
5562
5623
|
}
|
|
5624
|
+
return builder.createChart(definition, sheetId, getters);
|
|
5563
5625
|
}
|
|
5564
|
-
|
|
5565
|
-
owl.onPatched(updatePosition);
|
|
5566
|
-
return position;
|
|
5626
|
+
return createChart;
|
|
5567
5627
|
}
|
|
5568
5628
|
/**
|
|
5569
|
-
*
|
|
5570
|
-
*
|
|
5571
|
-
*
|
|
5572
|
-
* Note: when used with a <Portal/> component, it will
|
|
5573
|
-
* return the portal position, not the teleported position.
|
|
5629
|
+
* Create a function used to create a Chart Runtime based on the chart class
|
|
5630
|
+
* instance
|
|
5574
5631
|
*/
|
|
5575
|
-
function
|
|
5576
|
-
const
|
|
5577
|
-
function
|
|
5578
|
-
const
|
|
5579
|
-
if (
|
|
5580
|
-
|
|
5632
|
+
function chartRuntimeFactory(getters) {
|
|
5633
|
+
const builders = chartRegistry.getAll().sort((a, b) => a.sequence - b.sequence);
|
|
5634
|
+
function createRuntimeChart(chart) {
|
|
5635
|
+
const builder = builders.find((builder) => builder.match(chart.type));
|
|
5636
|
+
if (!builder) {
|
|
5637
|
+
throw new Error("No runtime builder for this chart.");
|
|
5581
5638
|
}
|
|
5582
|
-
|
|
5583
|
-
rect.x = left;
|
|
5584
|
-
rect.y = top;
|
|
5585
|
-
rect.width = width;
|
|
5586
|
-
rect.height = height;
|
|
5639
|
+
return builder.getChartRuntime(chart, getters);
|
|
5587
5640
|
}
|
|
5588
|
-
|
|
5589
|
-
owl.onPatched(updateElRect);
|
|
5590
|
-
return rect;
|
|
5641
|
+
return createRuntimeChart;
|
|
5591
5642
|
}
|
|
5592
5643
|
/**
|
|
5593
|
-
*
|
|
5594
|
-
* It's the value defined in `env.getPopoverContainerRect`, or the Rect of the "o-spreadsheet"
|
|
5595
|
-
* element by default.
|
|
5596
|
-
*
|
|
5597
|
-
* Coordinates are expressed expressed as absolute DOM position.
|
|
5644
|
+
* Validate the chart definition given in arguments
|
|
5598
5645
|
*/
|
|
5599
|
-
function
|
|
5600
|
-
const
|
|
5601
|
-
|
|
5602
|
-
|
|
5603
|
-
function updateRect() {
|
|
5604
|
-
const env = component.env;
|
|
5605
|
-
const newRect = "getPopoverContainerRect" in env ? env.getPopoverContainerRect() : spreadsheetRect;
|
|
5606
|
-
container.x = newRect.x;
|
|
5607
|
-
container.y = newRect.y;
|
|
5608
|
-
container.width = newRect.width;
|
|
5609
|
-
container.height = newRect.height;
|
|
5646
|
+
function validateChartDefinition(validator, definition) {
|
|
5647
|
+
const validators = chartRegistry.getAll().find((validator) => validator.match(definition.type));
|
|
5648
|
+
if (!validators) {
|
|
5649
|
+
throw new Error("Unknown chart type.");
|
|
5610
5650
|
}
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
owl.onPatched(updateRect);
|
|
5614
|
-
return container;
|
|
5615
|
-
}
|
|
5616
|
-
|
|
5651
|
+
return validators.validateChartDefinition(validator, definition);
|
|
5652
|
+
}
|
|
5617
5653
|
/**
|
|
5618
|
-
*
|
|
5619
|
-
*
|
|
5654
|
+
* Get a new chart definition transformed with the executed command. This
|
|
5655
|
+
* functions will be called during operational transform process
|
|
5620
5656
|
*/
|
|
5621
|
-
function
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
const spreadsheetElement = document.querySelector(".o-grid-overlay");
|
|
5626
|
-
if (spreadsheetElement) {
|
|
5627
|
-
const { top, left } = spreadsheetElement === null || spreadsheetElement === void 0 ? void 0 : spreadsheetElement.getBoundingClientRect();
|
|
5628
|
-
return { top, left };
|
|
5657
|
+
function transformDefinition(definition, executed) {
|
|
5658
|
+
const transformation = chartRegistry.getAll().find((factory) => factory.match(definition.type));
|
|
5659
|
+
if (!transformation) {
|
|
5660
|
+
throw new Error("Unknown chart type.");
|
|
5629
5661
|
}
|
|
5630
|
-
|
|
5631
|
-
}
|
|
5632
|
-
function getBoundingRectAsPOJO(el) {
|
|
5633
|
-
const rect = el.getBoundingClientRect();
|
|
5634
|
-
return {
|
|
5635
|
-
x: rect.x,
|
|
5636
|
-
y: rect.y,
|
|
5637
|
-
width: rect.width,
|
|
5638
|
-
height: rect.height,
|
|
5639
|
-
};
|
|
5662
|
+
return transformation.transformDefinition(definition, executed);
|
|
5640
5663
|
}
|
|
5641
5664
|
/**
|
|
5642
|
-
*
|
|
5665
|
+
* Get an empty definition based on the given context and the given type
|
|
5643
5666
|
*/
|
|
5644
|
-
function
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
for (let child of el.childNodes) {
|
|
5648
|
-
yield* iterateChildren(child);
|
|
5649
|
-
}
|
|
5650
|
-
}
|
|
5651
|
-
}
|
|
5652
|
-
function getElementScrollTop(el) {
|
|
5653
|
-
return (el === null || el === void 0 ? void 0 : el.scrollTop) || 0;
|
|
5667
|
+
function getChartDefinitionFromContextCreation(context, type) {
|
|
5668
|
+
const chartClass = chartRegistry.get(type);
|
|
5669
|
+
return chartClass.getChartDefinitionFromContextCreation(context);
|
|
5654
5670
|
}
|
|
5655
|
-
function
|
|
5656
|
-
|
|
5657
|
-
|
|
5658
|
-
|
|
5671
|
+
function getChartTypes() {
|
|
5672
|
+
const result = {};
|
|
5673
|
+
for (const key of chartRegistry.getKeys()) {
|
|
5674
|
+
result[key] = chartRegistry.get(key).name;
|
|
5675
|
+
}
|
|
5676
|
+
return result;
|
|
5659
5677
|
}
|
|
5660
|
-
function getOpenedMenus() {
|
|
5661
|
-
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
5662
|
-
}
|
|
5663
|
-
|
|
5664
5678
|
/**
|
|
5665
|
-
*
|
|
5679
|
+
* Return a "smart" chart definition in the given zone. The definition is "smart" because it will
|
|
5680
|
+
* use the best type of chart to display the data of the zone.
|
|
5681
|
+
*
|
|
5682
|
+
* It will also try to find labels and datasets in the range, and try to find title for the datasets.
|
|
5683
|
+
*
|
|
5684
|
+
* The type of chart will be :
|
|
5685
|
+
* - If the zone is a single non-empty cell, returns a scorecard
|
|
5686
|
+
* - If the all the labels are numbers/date, returns a line chart
|
|
5687
|
+
* - Else returns a bar chart
|
|
5666
5688
|
*/
|
|
5667
|
-
function
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5689
|
+
function getSmartChartDefinition(zone, getters) {
|
|
5690
|
+
var _a;
|
|
5691
|
+
let dataSetZone = zone;
|
|
5692
|
+
if (zone.left !== zone.right) {
|
|
5693
|
+
dataSetZone = { ...zone, left: zone.left + 1 };
|
|
5694
|
+
}
|
|
5695
|
+
const dataSets = [zoneToXc(dataSetZone)];
|
|
5696
|
+
const sheetId = getters.getActiveSheetId();
|
|
5697
|
+
const topLeftCell = getters.getCell({ sheetId, col: zone.left, row: zone.top });
|
|
5698
|
+
if (getZoneArea(zone) === 1 && (topLeftCell === null || topLeftCell === void 0 ? void 0 : topLeftCell.content)) {
|
|
5699
|
+
return {
|
|
5700
|
+
type: "scorecard",
|
|
5701
|
+
title: "",
|
|
5702
|
+
background: ((_a = topLeftCell.style) === null || _a === void 0 ? void 0 : _a.fillColor) || undefined,
|
|
5703
|
+
keyValue: zoneToXc(zone),
|
|
5704
|
+
baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
|
|
5705
|
+
baselineColorUp: DEFAULT_SCORECARD_BASELINE_COLOR_UP,
|
|
5706
|
+
baselineColorDown: DEFAULT_SCORECARD_BASELINE_COLOR_DOWN,
|
|
5707
|
+
};
|
|
5708
|
+
}
|
|
5709
|
+
let title = "";
|
|
5710
|
+
const cellsInFirstRow = getters.getEvaluatedCellsInZone(sheetId, {
|
|
5711
|
+
...dataSetZone,
|
|
5712
|
+
bottom: dataSetZone.top,
|
|
5713
|
+
});
|
|
5714
|
+
const dataSetsHaveTitle = !!cellsInFirstRow.find((cell) => cell.type !== CellValueType.empty && cell.type !== CellValueType.number);
|
|
5715
|
+
if (dataSetsHaveTitle) {
|
|
5716
|
+
const texts = cellsInFirstRow
|
|
5717
|
+
.filter((cell) => cell.type !== CellValueType.error && cell.type !== CellValueType.empty)
|
|
5718
|
+
.map((cell) => cell.formattedValue);
|
|
5719
|
+
const lastElement = texts.splice(-1)[0];
|
|
5720
|
+
title = texts.join(", ");
|
|
5721
|
+
if (lastElement) {
|
|
5722
|
+
title += (title ? " " + _t("and") + " " : "") + lastElement;
|
|
5723
|
+
}
|
|
5724
|
+
}
|
|
5725
|
+
let labelRangeXc;
|
|
5726
|
+
if (zone.left !== zone.right) {
|
|
5727
|
+
labelRangeXc = zoneToXc({
|
|
5728
|
+
...zone,
|
|
5729
|
+
right: zone.left,
|
|
5730
|
+
top: dataSetsHaveTitle ? zone.top + 1 : zone.top,
|
|
5731
|
+
});
|
|
5732
|
+
}
|
|
5733
|
+
// Only display legend for several datasets.
|
|
5734
|
+
const newLegendPos = dataSetZone.right === dataSetZone.left ? "none" : "top";
|
|
5735
|
+
const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
|
|
5736
|
+
if (canChartParseLabels(labelRange, getters)) {
|
|
5737
|
+
return {
|
|
5738
|
+
title,
|
|
5739
|
+
dataSets,
|
|
5740
|
+
labelsAsText: false,
|
|
5741
|
+
stacked: false,
|
|
5742
|
+
aggregated: false,
|
|
5743
|
+
labelRange: labelRangeXc,
|
|
5744
|
+
type: "line",
|
|
5745
|
+
dataSetsHaveTitle,
|
|
5746
|
+
verticalAxisPosition: "left",
|
|
5747
|
+
legendPosition: newLegendPos,
|
|
5748
|
+
};
|
|
5749
|
+
}
|
|
5681
5750
|
return {
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5751
|
+
title,
|
|
5752
|
+
dataSets,
|
|
5753
|
+
labelRange: labelRangeXc,
|
|
5754
|
+
type: "bar",
|
|
5755
|
+
stacked: false,
|
|
5756
|
+
aggregated: false,
|
|
5757
|
+
dataSetsHaveTitle,
|
|
5758
|
+
verticalAxisPosition: "left",
|
|
5759
|
+
legendPosition: newLegendPos,
|
|
5686
5760
|
};
|
|
5687
5761
|
}
|
|
5688
5762
|
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
|
|
5763
|
+
function centerFigurePosition(getters, size) {
|
|
5764
|
+
const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
|
|
5765
|
+
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
5766
|
+
const dim = getters.getSheetViewDimension();
|
|
5767
|
+
const rect = getters.getVisibleRect(getters.getActiveMainViewport());
|
|
5768
|
+
const scrollableViewportWidth = Math.min(rect.width, dim.width - offsetCorrectionX);
|
|
5769
|
+
const scrollableViewportHeight = Math.min(rect.height, dim.height - offsetCorrectionY);
|
|
5770
|
+
const position = {
|
|
5771
|
+
x: offsetCorrectionX + scrollX + Math.max(0, (scrollableViewportWidth - size.width) / 2),
|
|
5772
|
+
y: offsetCorrectionY + scrollY + Math.max(0, (scrollableViewportHeight - size.height) / 2),
|
|
5773
|
+
}; // Position at the center of the scrollable viewport
|
|
5774
|
+
return position;
|
|
5775
|
+
}
|
|
5776
|
+
function getMaxFigureSize(getters, figureSize) {
|
|
5777
|
+
const size = deepCopy(figureSize);
|
|
5778
|
+
const dim = getters.getSheetViewDimension();
|
|
5779
|
+
const maxWidth = dim.width;
|
|
5780
|
+
const maxHeight = dim.height;
|
|
5781
|
+
if (size.width > maxWidth) {
|
|
5782
|
+
const ratio = maxWidth / size.width;
|
|
5783
|
+
size.width = maxWidth;
|
|
5784
|
+
size.height = size.height * ratio;
|
|
5785
|
+
}
|
|
5786
|
+
if (size.height > maxHeight) {
|
|
5787
|
+
const ratio = maxHeight / size.height;
|
|
5788
|
+
size.height = maxHeight;
|
|
5789
|
+
size.width = size.width * ratio;
|
|
5790
|
+
}
|
|
5791
|
+
return size;
|
|
5697
5792
|
}
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5793
|
+
|
|
5794
|
+
const SORT_TYPES = [
|
|
5795
|
+
CellValueType.number,
|
|
5796
|
+
CellValueType.error,
|
|
5797
|
+
CellValueType.text,
|
|
5798
|
+
CellValueType.boolean,
|
|
5799
|
+
];
|
|
5800
|
+
function sortCells(cells, sortDirection, emptyCellAsZero) {
|
|
5801
|
+
const cellsWithIndex = cells.map((cell, index) => ({
|
|
5802
|
+
index,
|
|
5803
|
+
type: cell.type,
|
|
5804
|
+
value: cell.value,
|
|
5805
|
+
}));
|
|
5806
|
+
let emptyCells = cellsWithIndex.filter((x) => x.type === CellValueType.empty);
|
|
5807
|
+
let nonEmptyCells = cellsWithIndex.filter((x) => x.type !== CellValueType.empty);
|
|
5808
|
+
if (emptyCellAsZero) {
|
|
5809
|
+
nonEmptyCells.push(...emptyCells.map((emptyCell) => ({ ...emptyCell, type: CellValueType.number, value: 0 })));
|
|
5810
|
+
emptyCells = [];
|
|
5706
5811
|
}
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
throw new Error("Popover container is not defined");
|
|
5715
|
-
const el = this.popoverRef.el;
|
|
5716
|
-
const anchor = rectIntersection(this.props.anchorRect, this.containerRect);
|
|
5717
|
-
const newDisplay = anchor ? "block" : "none";
|
|
5718
|
-
if (this.currentDisplayValue !== "none" && newDisplay === "none") {
|
|
5719
|
-
(_b = (_a = this.props).onPopoverHidden) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
5812
|
+
const inverse = sortDirection === "descending" ? -1 : 1;
|
|
5813
|
+
return nonEmptyCells
|
|
5814
|
+
.sort((left, right) => {
|
|
5815
|
+
let typeOrder = SORT_TYPES.indexOf(left.type) - SORT_TYPES.indexOf(right.type);
|
|
5816
|
+
if (typeOrder === 0) {
|
|
5817
|
+
if (left.type === CellValueType.text || left.type === CellValueType.error) {
|
|
5818
|
+
typeOrder = left.value.localeCompare(right.value);
|
|
5720
5819
|
}
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5820
|
+
else
|
|
5821
|
+
typeOrder = left.value - right.value;
|
|
5822
|
+
}
|
|
5823
|
+
return inverse * typeOrder;
|
|
5824
|
+
})
|
|
5825
|
+
.concat(emptyCells);
|
|
5826
|
+
}
|
|
5827
|
+
function interactiveSortSelection(env, sheetId, anchor, zone, sortDirection) {
|
|
5828
|
+
let result = DispatchResult.Success;
|
|
5829
|
+
//several columns => bypass the contiguity check
|
|
5830
|
+
let multiColumns = zone.right > zone.left;
|
|
5831
|
+
if (env.model.getters.doesIntersectMerge(sheetId, zone)) {
|
|
5832
|
+
multiColumns = false;
|
|
5833
|
+
let table;
|
|
5834
|
+
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
5835
|
+
table = [];
|
|
5836
|
+
for (let col = zone.left; col <= zone.right; col++) {
|
|
5837
|
+
let merge = env.model.getters.getMerge({ sheetId, col, row });
|
|
5838
|
+
if (merge && !table.includes(merge.id.toString())) {
|
|
5839
|
+
table.push(merge.id.toString());
|
|
5840
|
+
}
|
|
5737
5841
|
}
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5842
|
+
if (table.length >= 2) {
|
|
5843
|
+
multiColumns = true;
|
|
5844
|
+
break;
|
|
5741
5845
|
}
|
|
5742
|
-
|
|
5743
|
-
});
|
|
5846
|
+
}
|
|
5744
5847
|
}
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
positioning: "BottomLeft",
|
|
5749
|
-
verticalOffset: 0,
|
|
5750
|
-
onMouseWheel: () => { },
|
|
5751
|
-
onPopoverMoved: () => { },
|
|
5752
|
-
onPopoverHidden: () => { },
|
|
5753
|
-
};
|
|
5754
|
-
Popover.props = {
|
|
5755
|
-
anchorRect: Object,
|
|
5756
|
-
containerRect: { type: Object, optional: true },
|
|
5757
|
-
positioning: { type: String, optional: true },
|
|
5758
|
-
maxWidth: { type: Number, optional: true },
|
|
5759
|
-
maxHeight: { type: Number, optional: true },
|
|
5760
|
-
verticalOffset: { type: Number, optional: true },
|
|
5761
|
-
onMouseWheel: { type: Function, optional: true },
|
|
5762
|
-
onPopoverHidden: { type: Function, optional: true },
|
|
5763
|
-
onPopoverMoved: { type: Function, optional: true },
|
|
5764
|
-
slots: Object,
|
|
5765
|
-
};
|
|
5766
|
-
class PopoverPositionContext {
|
|
5767
|
-
constructor(anchorRect, containerRect, propsMaxSize, spreadsheetOffset) {
|
|
5768
|
-
this.anchorRect = anchorRect;
|
|
5769
|
-
this.containerRect = containerRect;
|
|
5770
|
-
this.propsMaxSize = propsMaxSize;
|
|
5771
|
-
this.spreadsheetOffset = spreadsheetOffset;
|
|
5848
|
+
const { col, row } = anchor;
|
|
5849
|
+
if (multiColumns) {
|
|
5850
|
+
result = env.model.dispatch("SORT_CELLS", { sheetId, col, row, zone, sortDirection });
|
|
5772
5851
|
}
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
|
|
5776
|
-
|
|
5852
|
+
else {
|
|
5853
|
+
// check contiguity
|
|
5854
|
+
const contiguousZone = env.model.getters.getContiguousZone(sheetId, zone);
|
|
5855
|
+
if (isEqual(contiguousZone, zone)) {
|
|
5856
|
+
// merge as it is
|
|
5857
|
+
result = env.model.dispatch("SORT_CELLS", {
|
|
5858
|
+
sheetId,
|
|
5859
|
+
col,
|
|
5860
|
+
row,
|
|
5861
|
+
zone,
|
|
5862
|
+
sortDirection,
|
|
5863
|
+
});
|
|
5864
|
+
}
|
|
5865
|
+
else {
|
|
5866
|
+
env.askConfirmation(_lt("We found data next to your selection. Since this data was not selected, it will not be sorted. Do you want to extend your selection?"), () => {
|
|
5867
|
+
zone = contiguousZone;
|
|
5868
|
+
result = env.model.dispatch("SORT_CELLS", {
|
|
5869
|
+
sheetId,
|
|
5870
|
+
col,
|
|
5871
|
+
row,
|
|
5872
|
+
zone,
|
|
5873
|
+
sortDirection,
|
|
5874
|
+
});
|
|
5875
|
+
}, () => {
|
|
5876
|
+
result = env.model.dispatch("SORT_CELLS", {
|
|
5877
|
+
sheetId,
|
|
5878
|
+
col,
|
|
5879
|
+
row,
|
|
5880
|
+
zone,
|
|
5881
|
+
sortDirection,
|
|
5882
|
+
});
|
|
5883
|
+
});
|
|
5884
|
+
}
|
|
5777
5885
|
}
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
}
|
|
5783
|
-
getMaxHeight(elementHeight) {
|
|
5784
|
-
const shouldRenderAtBottom = this.shouldRenderAtBottom(elementHeight);
|
|
5785
|
-
const availableHeight = shouldRenderAtBottom
|
|
5786
|
-
? this.availableHeightDown
|
|
5787
|
-
: this.availableHeightUp;
|
|
5788
|
-
return this.propsMaxSize.height
|
|
5789
|
-
? Math.min(availableHeight, this.propsMaxSize.height)
|
|
5790
|
-
: availableHeight;
|
|
5791
|
-
}
|
|
5792
|
-
getMaxWidth(elementWidth) {
|
|
5793
|
-
const shouldRenderAtRight = this.shouldRenderAtRight(elementWidth);
|
|
5794
|
-
const availableWidth = shouldRenderAtRight ? this.availableWidthRight : this.availableWidthLeft;
|
|
5795
|
-
return this.propsMaxSize.width
|
|
5796
|
-
? Math.min(availableWidth, this.propsMaxSize.width)
|
|
5797
|
-
: availableWidth;
|
|
5798
|
-
}
|
|
5799
|
-
getCss(elDims, verticalOffset) {
|
|
5800
|
-
const maxHeight = this.getMaxHeight(elDims.height);
|
|
5801
|
-
const maxWidth = this.getMaxWidth(elDims.width);
|
|
5802
|
-
const actualHeight = Math.min(maxHeight, elDims.height);
|
|
5803
|
-
const actualWidth = Math.min(maxWidth, elDims.width);
|
|
5804
|
-
const shouldRenderAtBottom = this.shouldRenderAtBottom(elDims.height);
|
|
5805
|
-
const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
|
|
5806
|
-
verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
|
|
5807
|
-
const cssProperties = {
|
|
5808
|
-
"max-height": maxHeight + "px",
|
|
5809
|
-
"max-width": maxWidth + "px",
|
|
5810
|
-
top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
|
|
5811
|
-
this.spreadsheetOffset.y -
|
|
5812
|
-
verticalOffset +
|
|
5813
|
-
"px",
|
|
5814
|
-
left: this.getLeftCoordinate(actualWidth, shouldRenderAtRight) - this.spreadsheetOffset.x + "px",
|
|
5815
|
-
};
|
|
5816
|
-
return cssProperties;
|
|
5817
|
-
}
|
|
5818
|
-
getCurrentPosition(elDims) {
|
|
5819
|
-
const shouldRenderAtBottom = this.shouldRenderAtBottom(elDims.height);
|
|
5820
|
-
const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
|
|
5821
|
-
if (shouldRenderAtBottom && shouldRenderAtRight)
|
|
5822
|
-
return "BottomRight";
|
|
5823
|
-
if (shouldRenderAtBottom && !shouldRenderAtRight)
|
|
5824
|
-
return "BottomLeft";
|
|
5825
|
-
if (!shouldRenderAtBottom && shouldRenderAtRight)
|
|
5826
|
-
return "TopRight";
|
|
5827
|
-
return "TopLeft";
|
|
5828
|
-
}
|
|
5829
|
-
}
|
|
5830
|
-
class BottomLeftPopoverContext extends PopoverPositionContext {
|
|
5831
|
-
get availableHeightUp() {
|
|
5832
|
-
return this.anchorRect.y - this.containerRect.y;
|
|
5833
|
-
}
|
|
5834
|
-
get availableHeightDown() {
|
|
5835
|
-
return this.containerRect.height - this.availableHeightUp - this.anchorRect.height;
|
|
5836
|
-
}
|
|
5837
|
-
get availableWidthRight() {
|
|
5838
|
-
return this.containerRect.x + this.containerRect.width - this.anchorRect.x;
|
|
5839
|
-
}
|
|
5840
|
-
get availableWidthLeft() {
|
|
5841
|
-
return this.anchorRect.x + this.anchorRect.width - this.containerRect.x;
|
|
5842
|
-
}
|
|
5843
|
-
getTopCoordinate(elementHeight, shouldRenderAtBottom) {
|
|
5844
|
-
if (shouldRenderAtBottom) {
|
|
5845
|
-
return this.anchorRect.y + this.anchorRect.height;
|
|
5846
|
-
}
|
|
5847
|
-
else {
|
|
5848
|
-
return this.anchorRect.y - elementHeight;
|
|
5849
|
-
}
|
|
5850
|
-
}
|
|
5851
|
-
getLeftCoordinate(elementWidth, shouldRenderAtRight) {
|
|
5852
|
-
if (shouldRenderAtRight) {
|
|
5853
|
-
return this.anchorRect.x;
|
|
5854
|
-
}
|
|
5855
|
-
else {
|
|
5856
|
-
return this.anchorRect.x + this.anchorRect.width - elementWidth;
|
|
5857
|
-
}
|
|
5858
|
-
}
|
|
5859
|
-
}
|
|
5860
|
-
class TopRightPopoverContext extends PopoverPositionContext {
|
|
5861
|
-
get availableHeightUp() {
|
|
5862
|
-
return this.anchorRect.y + this.anchorRect.height - this.containerRect.y;
|
|
5863
|
-
}
|
|
5864
|
-
get availableHeightDown() {
|
|
5865
|
-
return this.containerRect.y + this.containerRect.height - this.anchorRect.y;
|
|
5866
|
-
}
|
|
5867
|
-
get availableWidthRight() {
|
|
5868
|
-
return this.containerRect.width - this.anchorRect.width - this.availableWidthLeft;
|
|
5869
|
-
}
|
|
5870
|
-
get availableWidthLeft() {
|
|
5871
|
-
return this.anchorRect.x - this.containerRect.x;
|
|
5872
|
-
}
|
|
5873
|
-
getTopCoordinate(elementHeight, shouldRenderAtBottom) {
|
|
5874
|
-
if (shouldRenderAtBottom) {
|
|
5875
|
-
return this.anchorRect.y;
|
|
5876
|
-
}
|
|
5877
|
-
else {
|
|
5878
|
-
return this.anchorRect.y + this.anchorRect.height - elementHeight;
|
|
5879
|
-
}
|
|
5880
|
-
}
|
|
5881
|
-
getLeftCoordinate(elementWidth, shouldRenderAtRight) {
|
|
5882
|
-
if (shouldRenderAtRight) {
|
|
5883
|
-
return this.anchorRect.x + this.anchorRect.width;
|
|
5884
|
-
}
|
|
5885
|
-
else {
|
|
5886
|
-
return this.anchorRect.x - elementWidth;
|
|
5887
|
-
}
|
|
5888
|
-
}
|
|
5889
|
-
}
|
|
5890
|
-
|
|
5891
|
-
//------------------------------------------------------------------------------
|
|
5892
|
-
// Context Menu Component
|
|
5893
|
-
//------------------------------------------------------------------------------
|
|
5894
|
-
css /* scss */ `
|
|
5895
|
-
.o-menu {
|
|
5896
|
-
background-color: white;
|
|
5897
|
-
padding: ${MENU_VERTICAL_PADDING}px 0px;
|
|
5898
|
-
width: ${MENU_WIDTH}px;
|
|
5899
|
-
box-sizing: border-box !important;
|
|
5900
|
-
|
|
5901
|
-
.o-menu-item {
|
|
5902
|
-
display: flex;
|
|
5903
|
-
justify-content: space-between;
|
|
5904
|
-
align-items: center;
|
|
5905
|
-
box-sizing: border-box;
|
|
5906
|
-
height: ${MENU_ITEM_HEIGHT}px;
|
|
5907
|
-
padding: 4px 16px;
|
|
5908
|
-
cursor: pointer;
|
|
5909
|
-
user-select: none;
|
|
5910
|
-
|
|
5911
|
-
.o-menu-item-name {
|
|
5912
|
-
overflow: hidden;
|
|
5913
|
-
white-space: nowrap;
|
|
5914
|
-
text-overflow: ellipsis;
|
|
5915
|
-
}
|
|
5916
|
-
|
|
5917
|
-
&.o-menu-root {
|
|
5918
|
-
display: flex;
|
|
5919
|
-
justify-content: space-between;
|
|
5920
|
-
}
|
|
5921
|
-
.o-menu-item-icon {
|
|
5922
|
-
margin-top: auto;
|
|
5923
|
-
margin-bottom: auto;
|
|
5924
|
-
}
|
|
5925
|
-
.o-icon {
|
|
5926
|
-
width: 10px;
|
|
5927
|
-
}
|
|
5928
|
-
|
|
5929
|
-
&:not(.disabled) {
|
|
5930
|
-
&:hover,
|
|
5931
|
-
&.o-menu-item-active {
|
|
5932
|
-
background-color: #ebebeb;
|
|
5933
|
-
}
|
|
5934
|
-
.o-menu-item-description {
|
|
5935
|
-
color: grey;
|
|
5936
|
-
}
|
|
5937
|
-
}
|
|
5938
|
-
&.disabled {
|
|
5939
|
-
color: ${MENU_ITEM_DISABLED_COLOR};
|
|
5940
|
-
cursor: not-allowed;
|
|
5941
|
-
}
|
|
5942
|
-
}
|
|
5943
|
-
}
|
|
5944
|
-
`;
|
|
5945
|
-
class Menu extends owl.Component {
|
|
5946
|
-
constructor() {
|
|
5947
|
-
super(...arguments);
|
|
5948
|
-
this.subMenu = owl.useState({
|
|
5949
|
-
isOpen: false,
|
|
5950
|
-
position: null,
|
|
5951
|
-
scrollOffset: 0,
|
|
5952
|
-
menuItems: [],
|
|
5953
|
-
});
|
|
5954
|
-
this.menuRef = owl.useRef("menu");
|
|
5955
|
-
this.position = useAbsoluteBoundingRect(this.menuRef);
|
|
5956
|
-
}
|
|
5957
|
-
setup() {
|
|
5958
|
-
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
5959
|
-
owl.useExternalListener(window, "contextmenu", this.onExternalClick, { capture: true });
|
|
5960
|
-
owl.onWillUpdateProps((nextProps) => {
|
|
5961
|
-
if (nextProps.menuItems !== this.props.menuItems) {
|
|
5962
|
-
this.closeSubMenu();
|
|
5963
|
-
}
|
|
5964
|
-
});
|
|
5965
|
-
}
|
|
5966
|
-
get visibleMenuItems() {
|
|
5967
|
-
return this.props.menuItems.filter((x) => x.isVisible(this.env));
|
|
5968
|
-
}
|
|
5969
|
-
get subMenuPosition() {
|
|
5970
|
-
const position = Object.assign({}, this.subMenu.position);
|
|
5971
|
-
position.y -= this.subMenu.scrollOffset || 0;
|
|
5972
|
-
return position;
|
|
5973
|
-
}
|
|
5974
|
-
get menuHeight() {
|
|
5975
|
-
const menuItems = this.visibleMenuItems;
|
|
5976
|
-
let menuItemsHeight = this.getMenuItemsHeight(menuItems);
|
|
5977
|
-
// We don't display separator at the end of a menu
|
|
5978
|
-
if (menuItems[menuItems.length - 1].separator) {
|
|
5979
|
-
menuItemsHeight -= MENU_SEPARATOR_HEIGHT;
|
|
5980
|
-
}
|
|
5981
|
-
const menuHeight = 2 * MENU_VERTICAL_PADDING + menuItemsHeight;
|
|
5982
|
-
return this.props.maxHeight ? Math.min(menuHeight, this.props.maxHeight) : menuHeight;
|
|
5983
|
-
}
|
|
5984
|
-
get popoverProps() {
|
|
5985
|
-
const isRoot = this.props.depth === 1;
|
|
5986
|
-
return {
|
|
5987
|
-
anchorRect: {
|
|
5988
|
-
x: this.props.position.x - MENU_WIDTH * (this.props.depth - 1),
|
|
5989
|
-
y: this.props.position.y,
|
|
5990
|
-
width: isRoot ? 0 : MENU_WIDTH,
|
|
5991
|
-
height: isRoot ? 0 : MENU_ITEM_HEIGHT,
|
|
5992
|
-
},
|
|
5993
|
-
positioning: "TopRight",
|
|
5994
|
-
verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
|
|
5995
|
-
onPopoverHidden: () => this.closeSubMenu(),
|
|
5996
|
-
onPopoverMoved: () => this.closeSubMenu(),
|
|
5997
|
-
maxHeight: this.menuHeight,
|
|
5998
|
-
};
|
|
5999
|
-
}
|
|
6000
|
-
getColor(menu) {
|
|
6001
|
-
return menu.textColor ? `color: ${menu.textColor}` : undefined;
|
|
6002
|
-
}
|
|
6003
|
-
async activateMenu(menu) {
|
|
6004
|
-
var _a, _b, _c;
|
|
6005
|
-
const result = await ((_a = menu.action) === null || _a === void 0 ? void 0 : _a.call(menu, this.env));
|
|
6006
|
-
this.close();
|
|
6007
|
-
(_c = (_b = this.props).onMenuClicked) === null || _c === void 0 ? void 0 : _c.call(_b, { detail: result });
|
|
6008
|
-
}
|
|
6009
|
-
close() {
|
|
6010
|
-
this.closeSubMenu();
|
|
6011
|
-
this.props.onClose();
|
|
6012
|
-
}
|
|
6013
|
-
/**
|
|
6014
|
-
* Return the number of pixels between the top of the menu
|
|
6015
|
-
* and the menu item at a given index.
|
|
6016
|
-
*/
|
|
6017
|
-
subMenuVerticalPosition(menuIndex) {
|
|
6018
|
-
const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
|
|
6019
|
-
return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
|
|
6020
|
-
}
|
|
6021
|
-
onExternalClick(ev) {
|
|
6022
|
-
// Don't close a root menu when clicked to open the submenus.
|
|
6023
|
-
const el = this.menuRef.el;
|
|
6024
|
-
if (el && getOpenedMenus().some((el) => isChildEvent(el, ev))) {
|
|
6025
|
-
return;
|
|
6026
|
-
}
|
|
6027
|
-
ev.closedMenuId = this.props.menuId;
|
|
6028
|
-
this.close();
|
|
6029
|
-
}
|
|
6030
|
-
getMenuItemsHeight(menuItems) {
|
|
6031
|
-
const numberOfSeparators = menuItems.filter((m) => m.separator).length;
|
|
6032
|
-
return MENU_ITEM_HEIGHT * menuItems.length + MENU_SEPARATOR_HEIGHT * numberOfSeparators;
|
|
6033
|
-
}
|
|
6034
|
-
getName(menu) {
|
|
6035
|
-
return menu.name(this.env);
|
|
6036
|
-
}
|
|
6037
|
-
isRoot(menu) {
|
|
6038
|
-
return !menu.action;
|
|
6039
|
-
}
|
|
6040
|
-
isEnabled(menu) {
|
|
6041
|
-
if (menu.isEnabled(this.env)) {
|
|
6042
|
-
return this.env.model.getters.isReadonly() ? menu.isReadonlyAllowed : true;
|
|
6043
|
-
}
|
|
6044
|
-
return false;
|
|
6045
|
-
}
|
|
6046
|
-
onScroll(ev) {
|
|
6047
|
-
this.subMenu.scrollOffset = ev.target.scrollTop;
|
|
6048
|
-
}
|
|
6049
|
-
/**
|
|
6050
|
-
* If the given menu is not disabled, open it's submenu at the
|
|
6051
|
-
* correct position according to available surrounding space.
|
|
6052
|
-
*/
|
|
6053
|
-
openSubMenu(menu, menuIndex) {
|
|
6054
|
-
const y = this.subMenuVerticalPosition(menuIndex);
|
|
6055
|
-
this.subMenu.position = {
|
|
6056
|
-
x: this.position.x + this.props.depth * MENU_WIDTH,
|
|
6057
|
-
y: y - (this.subMenu.scrollOffset || 0),
|
|
6058
|
-
};
|
|
6059
|
-
this.subMenu.menuItems = menu.children(this.env);
|
|
6060
|
-
this.subMenu.isOpen = true;
|
|
6061
|
-
this.subMenu.parentMenu = menu;
|
|
6062
|
-
}
|
|
6063
|
-
isParentMenu(subMenu, menuItem) {
|
|
6064
|
-
var _a;
|
|
6065
|
-
return ((_a = subMenu.parentMenu) === null || _a === void 0 ? void 0 : _a.id) === menuItem.id;
|
|
6066
|
-
}
|
|
6067
|
-
closeSubMenu() {
|
|
6068
|
-
this.subMenu.isOpen = false;
|
|
6069
|
-
this.subMenu.parentMenu = undefined;
|
|
6070
|
-
}
|
|
6071
|
-
onClickMenu(menu, menuIndex) {
|
|
6072
|
-
if (this.isEnabled(menu)) {
|
|
6073
|
-
if (this.isRoot(menu)) {
|
|
6074
|
-
this.openSubMenu(menu, menuIndex);
|
|
6075
|
-
}
|
|
6076
|
-
else {
|
|
6077
|
-
this.activateMenu(menu);
|
|
6078
|
-
}
|
|
6079
|
-
}
|
|
6080
|
-
}
|
|
6081
|
-
onMouseOver(menu, position) {
|
|
6082
|
-
if (menu.isEnabled(this.env)) {
|
|
6083
|
-
if (this.isRoot(menu)) {
|
|
6084
|
-
this.openSubMenu(menu, position);
|
|
6085
|
-
}
|
|
6086
|
-
else {
|
|
6087
|
-
this.closeSubMenu();
|
|
6088
|
-
}
|
|
6089
|
-
}
|
|
6090
|
-
}
|
|
6091
|
-
}
|
|
6092
|
-
Menu.template = "o-spreadsheet-Menu";
|
|
6093
|
-
Menu.components = { Menu, Popover };
|
|
6094
|
-
Menu.defaultProps = {
|
|
6095
|
-
depth: 1,
|
|
6096
|
-
};
|
|
6097
|
-
Menu.props = {
|
|
6098
|
-
position: Object,
|
|
6099
|
-
menuItems: Array,
|
|
6100
|
-
depth: { type: Number, optional: true },
|
|
6101
|
-
maxHeight: { type: Number, optional: true },
|
|
6102
|
-
onClose: Function,
|
|
6103
|
-
onMenuClicked: { type: Function, optional: true },
|
|
6104
|
-
menuId: { type: String, optional: true },
|
|
6105
|
-
};
|
|
6106
|
-
|
|
6107
|
-
// -----------------------------------------------------------------------------
|
|
6108
|
-
// STYLE
|
|
6109
|
-
// -----------------------------------------------------------------------------
|
|
6110
|
-
css /* scss */ `
|
|
6111
|
-
.o-chart-container {
|
|
6112
|
-
width: 100%;
|
|
6113
|
-
height: 100%;
|
|
6114
|
-
position: relative;
|
|
6115
|
-
}
|
|
6116
|
-
`;
|
|
6117
|
-
class ChartFigure extends owl.Component {
|
|
6118
|
-
constructor() {
|
|
6119
|
-
super(...arguments);
|
|
6120
|
-
this.menuState = owl.useState({ isOpen: false, position: null, menuItems: [] });
|
|
6121
|
-
this.chartContainerRef = owl.useRef("chartContainer");
|
|
6122
|
-
this.menuButtonRef = owl.useRef("menuButton");
|
|
6123
|
-
this.menuButtonRect = useAbsoluteBoundingRect(this.menuButtonRef);
|
|
6124
|
-
this.position = useAbsoluteBoundingRect(this.chartContainerRef);
|
|
6125
|
-
}
|
|
6126
|
-
getMenuItemRegistry() {
|
|
6127
|
-
const registry = new MenuItemRegistry();
|
|
6128
|
-
registry.add("edit", {
|
|
6129
|
-
name: _lt("Edit"),
|
|
6130
|
-
sequence: 1,
|
|
6131
|
-
action: () => {
|
|
6132
|
-
this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
|
|
6133
|
-
this.env.openSidePanel("ChartPanel");
|
|
6134
|
-
},
|
|
6135
|
-
});
|
|
6136
|
-
registry.add("copy", {
|
|
6137
|
-
name: _lt("Copy"),
|
|
6138
|
-
sequence: 2,
|
|
6139
|
-
action: async () => {
|
|
6140
|
-
this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
|
|
6141
|
-
this.env.model.dispatch("COPY");
|
|
6142
|
-
await this.env.clipboard.write(this.env.model.getters.getClipboardContent());
|
|
6143
|
-
},
|
|
6144
|
-
});
|
|
6145
|
-
registry.add("cut", {
|
|
6146
|
-
name: _lt("Cut"),
|
|
6147
|
-
sequence: 3,
|
|
6148
|
-
action: async () => {
|
|
6149
|
-
this.env.model.dispatch("SELECT_FIGURE", { id: this.props.figure.id });
|
|
6150
|
-
this.env.model.dispatch("CUT");
|
|
6151
|
-
await this.env.clipboard.write(this.env.model.getters.getClipboardContent());
|
|
6152
|
-
},
|
|
6153
|
-
});
|
|
6154
|
-
registry.add("delete", {
|
|
6155
|
-
name: _lt("Delete"),
|
|
6156
|
-
sequence: 10,
|
|
6157
|
-
action: () => {
|
|
6158
|
-
this.env.model.dispatch("DELETE_FIGURE", {
|
|
6159
|
-
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
6160
|
-
id: this.props.figure.id,
|
|
6161
|
-
});
|
|
6162
|
-
this.props.onFigureDeleted();
|
|
6163
|
-
},
|
|
6164
|
-
});
|
|
6165
|
-
return registry;
|
|
6166
|
-
}
|
|
6167
|
-
get chartType() {
|
|
6168
|
-
return this.env.model.getters.getChartType(this.env.model.getters.getActiveSheetId(), this.props.figure.id);
|
|
6169
|
-
}
|
|
6170
|
-
onContextMenu(ev) {
|
|
6171
|
-
const position = {
|
|
6172
|
-
x: this.position.x + ev.offsetX,
|
|
6173
|
-
y: this.position.y + ev.offsetY,
|
|
6174
|
-
};
|
|
6175
|
-
this.openContextMenu(position);
|
|
6176
|
-
}
|
|
6177
|
-
showMenu() {
|
|
6178
|
-
const { x, y, width } = this.menuButtonRect;
|
|
6179
|
-
const menuPosition = {
|
|
6180
|
-
x: x >= MENU_WIDTH ? x - MENU_WIDTH : x + width,
|
|
6181
|
-
y: y,
|
|
6182
|
-
};
|
|
6183
|
-
this.openContextMenu(menuPosition);
|
|
6184
|
-
}
|
|
6185
|
-
openContextMenu(position) {
|
|
6186
|
-
const registry = this.getMenuItemRegistry();
|
|
6187
|
-
this.menuState.isOpen = true;
|
|
6188
|
-
this.menuState.menuItems = registry.getMenuItems();
|
|
6189
|
-
this.menuState.position = position;
|
|
6190
|
-
}
|
|
6191
|
-
get chartComponent() {
|
|
6192
|
-
const type = this.chartType;
|
|
6193
|
-
const component = chartComponentRegistry.get(type);
|
|
6194
|
-
if (!component) {
|
|
6195
|
-
throw new Error(`Component is not defined for type ${type}`);
|
|
6196
|
-
}
|
|
6197
|
-
return component;
|
|
6198
|
-
}
|
|
6199
|
-
}
|
|
6200
|
-
ChartFigure.template = "o-spreadsheet-ChartFigure";
|
|
6201
|
-
ChartFigure.components = { Menu };
|
|
6202
|
-
ChartFigure.props = {
|
|
6203
|
-
figure: Object,
|
|
6204
|
-
onFigureDeleted: Function,
|
|
6205
|
-
};
|
|
6206
|
-
|
|
6207
|
-
function interactiveCut(env) {
|
|
6208
|
-
const result = env.model.dispatch("CUT");
|
|
6209
|
-
if (!result.isSuccessful) {
|
|
6210
|
-
if (result.isCancelledBecause(19 /* CommandResult.WrongCutSelection */)) {
|
|
6211
|
-
env.raiseError(_lt("This operation is not allowed with multiple selections."));
|
|
6212
|
-
}
|
|
6213
|
-
}
|
|
6214
|
-
}
|
|
6215
|
-
|
|
6216
|
-
const PasteInteractiveContent = {
|
|
6217
|
-
wrongPasteSelection: _lt("This operation is not allowed with multiple selections."),
|
|
6218
|
-
willRemoveExistingMerge: _lt("This operation is not possible due to a merge. Please remove the merges first than try again."),
|
|
6219
|
-
wrongFigurePasteOption: _lt("Cannot do a special paste of a figure."),
|
|
6220
|
-
frozenPaneOverlap: _lt("Cannot paste merged cells over a frozen pane."),
|
|
6221
|
-
};
|
|
6222
|
-
function handlePasteResult(env, result) {
|
|
6223
|
-
if (!result.isSuccessful) {
|
|
6224
|
-
if (result.reasons.includes(20 /* CommandResult.WrongPasteSelection */)) {
|
|
6225
|
-
env.raiseError(PasteInteractiveContent.wrongPasteSelection);
|
|
6226
|
-
}
|
|
6227
|
-
else if (result.reasons.includes(2 /* CommandResult.WillRemoveExistingMerge */)) {
|
|
6228
|
-
env.raiseError(PasteInteractiveContent.willRemoveExistingMerge);
|
|
6229
|
-
}
|
|
6230
|
-
else if (result.reasons.includes(22 /* CommandResult.WrongFigurePasteOption */)) {
|
|
6231
|
-
env.raiseError(PasteInteractiveContent.wrongFigurePasteOption);
|
|
6232
|
-
}
|
|
6233
|
-
else if (result.reasons.includes(75 /* CommandResult.FrozenPaneOverlap */)) {
|
|
6234
|
-
env.raiseError(PasteInteractiveContent.frozenPaneOverlap);
|
|
6235
|
-
}
|
|
6236
|
-
}
|
|
6237
|
-
}
|
|
6238
|
-
function interactivePaste(env, target, pasteOption) {
|
|
6239
|
-
const result = env.model.dispatch("PASTE", { target, pasteOption });
|
|
6240
|
-
handlePasteResult(env, result);
|
|
6241
|
-
}
|
|
6242
|
-
function interactivePasteFromOS(env, target, text) {
|
|
6243
|
-
const result = env.model.dispatch("PASTE_FROM_OS_CLIPBOARD", { target, text });
|
|
6244
|
-
handlePasteResult(env, result);
|
|
6245
|
-
}
|
|
6246
|
-
|
|
6247
|
-
/**
|
|
6248
|
-
* Create a function used to create a Chart based on the definition
|
|
6249
|
-
*/
|
|
6250
|
-
function chartFactory(getters) {
|
|
6251
|
-
const builders = chartRegistry.getAll().sort((a, b) => a.sequence - b.sequence);
|
|
6252
|
-
function createChart(id, definition, sheetId) {
|
|
6253
|
-
const builder = builders.find((builder) => builder.match(definition.type));
|
|
6254
|
-
if (!builder) {
|
|
6255
|
-
throw new Error(`No builder for this chart: ${definition.type}`);
|
|
6256
|
-
}
|
|
6257
|
-
return builder.createChart(definition, sheetId, getters);
|
|
6258
|
-
}
|
|
6259
|
-
return createChart;
|
|
6260
|
-
}
|
|
6261
|
-
/**
|
|
6262
|
-
* Create a function used to create a Chart Runtime based on the chart class
|
|
6263
|
-
* instance
|
|
6264
|
-
*/
|
|
6265
|
-
function chartRuntimeFactory(getters) {
|
|
6266
|
-
const builders = chartRegistry.getAll().sort((a, b) => a.sequence - b.sequence);
|
|
6267
|
-
function createRuntimeChart(chart) {
|
|
6268
|
-
const builder = builders.find((builder) => builder.match(chart.type));
|
|
6269
|
-
if (!builder) {
|
|
6270
|
-
throw new Error("No runtime builder for this chart.");
|
|
6271
|
-
}
|
|
6272
|
-
return builder.getChartRuntime(chart, getters);
|
|
6273
|
-
}
|
|
6274
|
-
return createRuntimeChart;
|
|
6275
|
-
}
|
|
6276
|
-
/**
|
|
6277
|
-
* Validate the chart definition given in arguments
|
|
6278
|
-
*/
|
|
6279
|
-
function validateChartDefinition(validator, definition) {
|
|
6280
|
-
const validators = chartRegistry.getAll().find((validator) => validator.match(definition.type));
|
|
6281
|
-
if (!validators) {
|
|
6282
|
-
throw new Error("Unknown chart type.");
|
|
6283
|
-
}
|
|
6284
|
-
return validators.validateChartDefinition(validator, definition);
|
|
6285
|
-
}
|
|
6286
|
-
/**
|
|
6287
|
-
* Get a new chart definition transformed with the executed command. This
|
|
6288
|
-
* functions will be called during operational transform process
|
|
6289
|
-
*/
|
|
6290
|
-
function transformDefinition(definition, executed) {
|
|
6291
|
-
const transformation = chartRegistry.getAll().find((factory) => factory.match(definition.type));
|
|
6292
|
-
if (!transformation) {
|
|
6293
|
-
throw new Error("Unknown chart type.");
|
|
6294
|
-
}
|
|
6295
|
-
return transformation.transformDefinition(definition, executed);
|
|
6296
|
-
}
|
|
6297
|
-
/**
|
|
6298
|
-
* Get an empty definition based on the given context and the given type
|
|
6299
|
-
*/
|
|
6300
|
-
function getChartDefinitionFromContextCreation(context, type) {
|
|
6301
|
-
const chartClass = chartRegistry.get(type);
|
|
6302
|
-
return chartClass.getChartDefinitionFromContextCreation(context);
|
|
6303
|
-
}
|
|
6304
|
-
function getChartTypes() {
|
|
6305
|
-
const result = {};
|
|
6306
|
-
for (const key of chartRegistry.getKeys()) {
|
|
6307
|
-
result[key] = chartRegistry.get(key).name;
|
|
6308
|
-
}
|
|
6309
|
-
return result;
|
|
6310
|
-
}
|
|
6311
|
-
/**
|
|
6312
|
-
* Return a "smart" chart definition in the given zone. The definition is "smart" because it will
|
|
6313
|
-
* use the best type of chart to display the data of the zone.
|
|
6314
|
-
*
|
|
6315
|
-
* It will also try to find labels and datasets in the range, and try to find title for the datasets.
|
|
6316
|
-
*
|
|
6317
|
-
* The type of chart will be :
|
|
6318
|
-
* - If the zone is a single non-empty cell, returns a scorecard
|
|
6319
|
-
* - If the all the labels are numbers/date, returns a line chart
|
|
6320
|
-
* - Else returns a bar chart
|
|
6321
|
-
*/
|
|
6322
|
-
function getSmartChartDefinition(zone, getters) {
|
|
6323
|
-
var _a;
|
|
6324
|
-
let dataSetZone = zone;
|
|
6325
|
-
if (zone.left !== zone.right) {
|
|
6326
|
-
dataSetZone = { ...zone, left: zone.left + 1 };
|
|
6327
|
-
}
|
|
6328
|
-
const dataSets = [zoneToXc(dataSetZone)];
|
|
6329
|
-
const sheetId = getters.getActiveSheetId();
|
|
6330
|
-
const topLeftCell = getters.getCell({ sheetId, col: zone.left, row: zone.top });
|
|
6331
|
-
if (getZoneArea(zone) === 1 && (topLeftCell === null || topLeftCell === void 0 ? void 0 : topLeftCell.content)) {
|
|
6332
|
-
return {
|
|
6333
|
-
type: "scorecard",
|
|
6334
|
-
title: "",
|
|
6335
|
-
background: ((_a = topLeftCell.style) === null || _a === void 0 ? void 0 : _a.fillColor) || undefined,
|
|
6336
|
-
keyValue: zoneToXc(zone),
|
|
6337
|
-
baselineMode: DEFAULT_SCORECARD_BASELINE_MODE,
|
|
6338
|
-
baselineColorUp: DEFAULT_SCORECARD_BASELINE_COLOR_UP,
|
|
6339
|
-
baselineColorDown: DEFAULT_SCORECARD_BASELINE_COLOR_DOWN,
|
|
6340
|
-
};
|
|
6341
|
-
}
|
|
6342
|
-
let title = "";
|
|
6343
|
-
const cellsInFirstRow = getters.getEvaluatedCellsInZone(sheetId, {
|
|
6344
|
-
...dataSetZone,
|
|
6345
|
-
bottom: dataSetZone.top,
|
|
6346
|
-
});
|
|
6347
|
-
const dataSetsHaveTitle = !!cellsInFirstRow.find((cell) => cell.type !== CellValueType.empty && cell.type !== CellValueType.number);
|
|
6348
|
-
if (dataSetsHaveTitle) {
|
|
6349
|
-
const texts = cellsInFirstRow
|
|
6350
|
-
.filter((cell) => cell.type !== CellValueType.error && cell.type !== CellValueType.empty)
|
|
6351
|
-
.map((cell) => cell.formattedValue);
|
|
6352
|
-
const lastElement = texts.splice(-1)[0];
|
|
6353
|
-
title = texts.join(", ");
|
|
6354
|
-
if (lastElement) {
|
|
6355
|
-
title += (title ? " " + _t("and") + " " : "") + lastElement;
|
|
6356
|
-
}
|
|
6357
|
-
}
|
|
6358
|
-
let labelRangeXc;
|
|
6359
|
-
if (zone.left !== zone.right) {
|
|
6360
|
-
labelRangeXc = zoneToXc({
|
|
6361
|
-
...zone,
|
|
6362
|
-
right: zone.left,
|
|
6363
|
-
top: dataSetsHaveTitle ? zone.top + 1 : zone.top,
|
|
6364
|
-
});
|
|
6365
|
-
}
|
|
6366
|
-
// Only display legend for several datasets.
|
|
6367
|
-
const newLegendPos = dataSetZone.right === dataSetZone.left ? "none" : "top";
|
|
6368
|
-
const labelRange = labelRangeXc ? getters.getRangeFromSheetXC(sheetId, labelRangeXc) : undefined;
|
|
6369
|
-
if (canChartParseLabels(labelRange, getters)) {
|
|
6370
|
-
return {
|
|
6371
|
-
title,
|
|
6372
|
-
dataSets,
|
|
6373
|
-
labelsAsText: false,
|
|
6374
|
-
stacked: false,
|
|
6375
|
-
aggregated: false,
|
|
6376
|
-
labelRange: labelRangeXc,
|
|
6377
|
-
type: "line",
|
|
6378
|
-
dataSetsHaveTitle,
|
|
6379
|
-
verticalAxisPosition: "left",
|
|
6380
|
-
legendPosition: newLegendPos,
|
|
6381
|
-
};
|
|
6382
|
-
}
|
|
6383
|
-
return {
|
|
6384
|
-
title,
|
|
6385
|
-
dataSets,
|
|
6386
|
-
labelRange: labelRangeXc,
|
|
6387
|
-
type: "bar",
|
|
6388
|
-
stacked: false,
|
|
6389
|
-
aggregated: false,
|
|
6390
|
-
dataSetsHaveTitle,
|
|
6391
|
-
verticalAxisPosition: "left",
|
|
6392
|
-
legendPosition: newLegendPos,
|
|
6393
|
-
};
|
|
6394
|
-
}
|
|
6395
|
-
|
|
6396
|
-
function centerFigurePosition(getters, size) {
|
|
6397
|
-
const { x: offsetCorrectionX, y: offsetCorrectionY } = getters.getMainViewportCoordinates();
|
|
6398
|
-
const { scrollX, scrollY } = getters.getActiveSheetScrollInfo();
|
|
6399
|
-
const dim = getters.getSheetViewDimension();
|
|
6400
|
-
const rect = getters.getVisibleRect(getters.getActiveMainViewport());
|
|
6401
|
-
const scrollableViewportWidth = Math.min(rect.width, dim.width - offsetCorrectionX);
|
|
6402
|
-
const scrollableViewportHeight = Math.min(rect.height, dim.height - offsetCorrectionY);
|
|
6403
|
-
const position = {
|
|
6404
|
-
x: offsetCorrectionX + scrollX + Math.max(0, (scrollableViewportWidth - size.width) / 2),
|
|
6405
|
-
y: offsetCorrectionY + scrollY + Math.max(0, (scrollableViewportHeight - size.height) / 2),
|
|
6406
|
-
}; // Position at the center of the scrollable viewport
|
|
6407
|
-
return position;
|
|
6408
|
-
}
|
|
6409
|
-
function getMaxFigureSize(getters, figureSize) {
|
|
6410
|
-
const size = deepCopy(figureSize);
|
|
6411
|
-
const dim = getters.getSheetViewDimension();
|
|
6412
|
-
const maxWidth = dim.width;
|
|
6413
|
-
const maxHeight = dim.height;
|
|
6414
|
-
if (size.width > maxWidth) {
|
|
6415
|
-
const ratio = maxWidth / size.width;
|
|
6416
|
-
size.width = maxWidth;
|
|
6417
|
-
size.height = size.height * ratio;
|
|
6418
|
-
}
|
|
6419
|
-
if (size.height > maxHeight) {
|
|
6420
|
-
const ratio = maxHeight / size.height;
|
|
6421
|
-
size.height = maxHeight;
|
|
6422
|
-
size.width = size.width * ratio;
|
|
6423
|
-
}
|
|
6424
|
-
return size;
|
|
6425
|
-
}
|
|
6426
|
-
|
|
6427
|
-
const SORT_TYPES = [
|
|
6428
|
-
CellValueType.number,
|
|
6429
|
-
CellValueType.error,
|
|
6430
|
-
CellValueType.text,
|
|
6431
|
-
CellValueType.boolean,
|
|
6432
|
-
];
|
|
6433
|
-
function sortCells(cells, sortDirection, emptyCellAsZero) {
|
|
6434
|
-
const cellsWithIndex = cells.map((cell, index) => ({
|
|
6435
|
-
index,
|
|
6436
|
-
type: cell.type,
|
|
6437
|
-
value: cell.value,
|
|
6438
|
-
}));
|
|
6439
|
-
let emptyCells = cellsWithIndex.filter((x) => x.type === CellValueType.empty);
|
|
6440
|
-
let nonEmptyCells = cellsWithIndex.filter((x) => x.type !== CellValueType.empty);
|
|
6441
|
-
if (emptyCellAsZero) {
|
|
6442
|
-
nonEmptyCells.push(...emptyCells.map((emptyCell) => ({ ...emptyCell, type: CellValueType.number, value: 0 })));
|
|
6443
|
-
emptyCells = [];
|
|
6444
|
-
}
|
|
6445
|
-
const inverse = sortDirection === "descending" ? -1 : 1;
|
|
6446
|
-
return nonEmptyCells
|
|
6447
|
-
.sort((left, right) => {
|
|
6448
|
-
let typeOrder = SORT_TYPES.indexOf(left.type) - SORT_TYPES.indexOf(right.type);
|
|
6449
|
-
if (typeOrder === 0) {
|
|
6450
|
-
if (left.type === CellValueType.text || left.type === CellValueType.error) {
|
|
6451
|
-
typeOrder = left.value.localeCompare(right.value);
|
|
6452
|
-
}
|
|
6453
|
-
else
|
|
6454
|
-
typeOrder = left.value - right.value;
|
|
6455
|
-
}
|
|
6456
|
-
return inverse * typeOrder;
|
|
6457
|
-
})
|
|
6458
|
-
.concat(emptyCells);
|
|
6459
|
-
}
|
|
6460
|
-
function interactiveSortSelection(env, sheetId, anchor, zone, sortDirection) {
|
|
6461
|
-
let result = DispatchResult.Success;
|
|
6462
|
-
//several columns => bypass the contiguity check
|
|
6463
|
-
let multiColumns = zone.right > zone.left;
|
|
6464
|
-
if (env.model.getters.doesIntersectMerge(sheetId, zone)) {
|
|
6465
|
-
multiColumns = false;
|
|
6466
|
-
let table;
|
|
6467
|
-
for (let row = zone.top; row <= zone.bottom; row++) {
|
|
6468
|
-
table = [];
|
|
6469
|
-
for (let col = zone.left; col <= zone.right; col++) {
|
|
6470
|
-
let merge = env.model.getters.getMerge({ sheetId, col, row });
|
|
6471
|
-
if (merge && !table.includes(merge.id.toString())) {
|
|
6472
|
-
table.push(merge.id.toString());
|
|
6473
|
-
}
|
|
6474
|
-
}
|
|
6475
|
-
if (table.length >= 2) {
|
|
6476
|
-
multiColumns = true;
|
|
6477
|
-
break;
|
|
6478
|
-
}
|
|
6479
|
-
}
|
|
6480
|
-
}
|
|
6481
|
-
const { col, row } = anchor;
|
|
6482
|
-
if (multiColumns) {
|
|
6483
|
-
result = env.model.dispatch("SORT_CELLS", { sheetId, col, row, zone, sortDirection });
|
|
6484
|
-
}
|
|
6485
|
-
else {
|
|
6486
|
-
// check contiguity
|
|
6487
|
-
const contiguousZone = env.model.getters.getContiguousZone(sheetId, zone);
|
|
6488
|
-
if (isEqual(contiguousZone, zone)) {
|
|
6489
|
-
// merge as it is
|
|
6490
|
-
result = env.model.dispatch("SORT_CELLS", {
|
|
6491
|
-
sheetId,
|
|
6492
|
-
col,
|
|
6493
|
-
row,
|
|
6494
|
-
zone,
|
|
6495
|
-
sortDirection,
|
|
6496
|
-
});
|
|
6497
|
-
}
|
|
6498
|
-
else {
|
|
6499
|
-
env.askConfirmation(_lt("We found data next to your selection. Since this data was not selected, it will not be sorted. Do you want to extend your selection?"), () => {
|
|
6500
|
-
zone = contiguousZone;
|
|
6501
|
-
result = env.model.dispatch("SORT_CELLS", {
|
|
6502
|
-
sheetId,
|
|
6503
|
-
col,
|
|
6504
|
-
row,
|
|
6505
|
-
zone,
|
|
6506
|
-
sortDirection,
|
|
6507
|
-
});
|
|
6508
|
-
}, () => {
|
|
6509
|
-
result = env.model.dispatch("SORT_CELLS", {
|
|
6510
|
-
sheetId,
|
|
6511
|
-
col,
|
|
6512
|
-
row,
|
|
6513
|
-
zone,
|
|
6514
|
-
sortDirection,
|
|
6515
|
-
});
|
|
6516
|
-
});
|
|
6517
|
-
}
|
|
6518
|
-
}
|
|
6519
|
-
if (result.isCancelledBecause(63 /* CommandResult.InvalidSortZone */)) {
|
|
6520
|
-
const { col, row } = anchor;
|
|
6521
|
-
env.model.selection.selectZone({ cell: { col, row }, zone });
|
|
6522
|
-
env.raiseError(_lt("Cannot sort. To sort, select only cells or only merges that have the same size."));
|
|
5886
|
+
if (result.isCancelledBecause(63 /* CommandResult.InvalidSortZone */)) {
|
|
5887
|
+
const { col, row } = anchor;
|
|
5888
|
+
env.model.selection.selectZone({ cell: { col, row }, zone });
|
|
5889
|
+
env.raiseError(_lt("Cannot sort. To sort, select only cells or only merges that have the same size."));
|
|
6523
5890
|
}
|
|
6524
5891
|
}
|
|
6525
5892
|
|
|
@@ -7441,6 +6808,53 @@
|
|
|
7441
6808
|
action: OPEN_CF_SIDEPANEL_ACTION,
|
|
7442
6809
|
});
|
|
7443
6810
|
|
|
6811
|
+
/**
|
|
6812
|
+
* Return true if the event was triggered from
|
|
6813
|
+
* a child element.
|
|
6814
|
+
*/
|
|
6815
|
+
function isChildEvent(parent, ev) {
|
|
6816
|
+
return !!ev.target && parent.contains(ev.target);
|
|
6817
|
+
}
|
|
6818
|
+
function gridOverlayPosition() {
|
|
6819
|
+
const spreadsheetElement = document.querySelector(".o-grid-overlay");
|
|
6820
|
+
if (spreadsheetElement) {
|
|
6821
|
+
const { top, left } = spreadsheetElement === null || spreadsheetElement === void 0 ? void 0 : spreadsheetElement.getBoundingClientRect();
|
|
6822
|
+
return { top, left };
|
|
6823
|
+
}
|
|
6824
|
+
throw new Error("Can't find spreadsheet position");
|
|
6825
|
+
}
|
|
6826
|
+
function getBoundingRectAsPOJO(el) {
|
|
6827
|
+
const rect = el.getBoundingClientRect();
|
|
6828
|
+
return {
|
|
6829
|
+
x: rect.x,
|
|
6830
|
+
y: rect.y,
|
|
6831
|
+
width: rect.width,
|
|
6832
|
+
height: rect.height,
|
|
6833
|
+
};
|
|
6834
|
+
}
|
|
6835
|
+
/**
|
|
6836
|
+
* Iterate over all the children of `el` in the dom tree starting at `el`, depth first.
|
|
6837
|
+
*/
|
|
6838
|
+
function* iterateChildren(el) {
|
|
6839
|
+
yield el;
|
|
6840
|
+
if (el.hasChildNodes()) {
|
|
6841
|
+
for (let child of el.childNodes) {
|
|
6842
|
+
yield* iterateChildren(child);
|
|
6843
|
+
}
|
|
6844
|
+
}
|
|
6845
|
+
}
|
|
6846
|
+
function getElementScrollTop(el) {
|
|
6847
|
+
return (el === null || el === void 0 ? void 0 : el.scrollTop) || 0;
|
|
6848
|
+
}
|
|
6849
|
+
function setElementScrollTop(el, scroll) {
|
|
6850
|
+
if (!el)
|
|
6851
|
+
return;
|
|
6852
|
+
el.scrollTop = scroll;
|
|
6853
|
+
}
|
|
6854
|
+
function getOpenedMenus() {
|
|
6855
|
+
return Array.from(document.querySelectorAll(".o-spreadsheet .o-menu"));
|
|
6856
|
+
}
|
|
6857
|
+
|
|
7444
6858
|
function startDnd(onMouseMove, onMouseUp, onMouseDown = () => { }) {
|
|
7445
6859
|
const _onMouseDown = (ev) => {
|
|
7446
6860
|
ev.preventDefault();
|
|
@@ -15720,8 +15134,7 @@
|
|
|
15720
15134
|
return false;
|
|
15721
15135
|
const range = this.env.model.getters.getRangeFromSheetXC(refSheet, xc);
|
|
15722
15136
|
let zone = range.zone;
|
|
15723
|
-
|
|
15724
|
-
zone = height * width === 1 ? this.env.model.getters.expandZone(refSheet, zone) : zone;
|
|
15137
|
+
zone = getZoneArea(zone) === 1 ? this.env.model.getters.expandZone(refSheet, zone) : zone;
|
|
15725
15138
|
return isEqual(zone, highlight.zone);
|
|
15726
15139
|
});
|
|
15727
15140
|
return highlight && highlight.color ? highlight.color : undefined;
|
|
@@ -16383,439 +15796,955 @@
|
|
|
16383
15796
|
group = [];
|
|
16384
15797
|
}
|
|
16385
15798
|
}
|
|
16386
|
-
return group;
|
|
15799
|
+
return group;
|
|
15800
|
+
}
|
|
15801
|
+
/**
|
|
15802
|
+
* Get the average steps between numbers
|
|
15803
|
+
*/
|
|
15804
|
+
function getAverageIncrement(group) {
|
|
15805
|
+
const averages = [];
|
|
15806
|
+
let last = group[0];
|
|
15807
|
+
for (let i = 1; i < group.length; i++) {
|
|
15808
|
+
const current = group[i];
|
|
15809
|
+
averages.push(current - last);
|
|
15810
|
+
last = current;
|
|
15811
|
+
}
|
|
15812
|
+
return averages.reduce((a, b) => a + b, 0) / averages.length;
|
|
15813
|
+
}
|
|
15814
|
+
/**
|
|
15815
|
+
* Get the step for a group
|
|
15816
|
+
*/
|
|
15817
|
+
function calculateIncrementBasedOnGroup(group) {
|
|
15818
|
+
let increment = 1;
|
|
15819
|
+
if (group.length >= 2) {
|
|
15820
|
+
increment = getAverageIncrement(group) * group.length;
|
|
15821
|
+
}
|
|
15822
|
+
return increment;
|
|
15823
|
+
}
|
|
15824
|
+
autofillRulesRegistry
|
|
15825
|
+
.add("simple_value_copy", {
|
|
15826
|
+
condition: (cell, cells) => {
|
|
15827
|
+
var _a;
|
|
15828
|
+
return cells.length === 1 && !cell.isFormula && !((_a = cell.format) === null || _a === void 0 ? void 0 : _a.match(DATETIME_FORMAT));
|
|
15829
|
+
},
|
|
15830
|
+
generateRule: () => {
|
|
15831
|
+
return { type: "COPY_MODIFIER" };
|
|
15832
|
+
},
|
|
15833
|
+
sequence: 10,
|
|
15834
|
+
})
|
|
15835
|
+
.add("increment_alphanumeric_value", {
|
|
15836
|
+
condition: (cell) => !cell.isFormula &&
|
|
15837
|
+
evaluateLiteral(cell.content).type === CellValueType.text &&
|
|
15838
|
+
alphaNumericValueRegExp.test(cell.content),
|
|
15839
|
+
generateRule: (cell, cells) => {
|
|
15840
|
+
const numberPostfix = parseInt(cell.content.match(numberPostfixRegExp)[0]);
|
|
15841
|
+
const prefix = cell.content.match(stringPrefixRegExp)[0];
|
|
15842
|
+
const numberPostfixLength = cell.content.length - prefix.length;
|
|
15843
|
+
const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.text &&
|
|
15844
|
+
alphaNumericValueRegExp.test(evaluatedCell.value)) // get consecutive alphanumeric cells, no matter what the prefix is
|
|
15845
|
+
.filter((cell) => prefix === cell.value.toString().match(stringPrefixRegExp)[0])
|
|
15846
|
+
.map((cell) => parseInt(cell.value.toString().match(numberPostfixRegExp)[0]));
|
|
15847
|
+
const increment = calculateIncrementBasedOnGroup(group);
|
|
15848
|
+
return {
|
|
15849
|
+
type: "ALPHANUMERIC_INCREMENT_MODIFIER",
|
|
15850
|
+
prefix,
|
|
15851
|
+
current: numberPostfix,
|
|
15852
|
+
increment,
|
|
15853
|
+
numberPostfixLength,
|
|
15854
|
+
};
|
|
15855
|
+
},
|
|
15856
|
+
sequence: 15,
|
|
15857
|
+
})
|
|
15858
|
+
.add("copy_text", {
|
|
15859
|
+
condition: (cell) => !cell.isFormula && evaluateLiteral(cell.content).type === CellValueType.text,
|
|
15860
|
+
generateRule: () => {
|
|
15861
|
+
return { type: "COPY_MODIFIER" };
|
|
15862
|
+
},
|
|
15863
|
+
sequence: 20,
|
|
15864
|
+
})
|
|
15865
|
+
.add("update_formula", {
|
|
15866
|
+
condition: (cell) => cell.isFormula,
|
|
15867
|
+
generateRule: (_, cells) => {
|
|
15868
|
+
return { type: "FORMULA_MODIFIER", increment: cells.length, current: 0 };
|
|
15869
|
+
},
|
|
15870
|
+
sequence: 30,
|
|
15871
|
+
})
|
|
15872
|
+
.add("increment_number", {
|
|
15873
|
+
condition: (cell) => !cell.isFormula && evaluateLiteral(cell.content).type === CellValueType.number,
|
|
15874
|
+
generateRule: (cell, cells) => {
|
|
15875
|
+
const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number).map((cell) => Number(cell.value));
|
|
15876
|
+
const increment = calculateIncrementBasedOnGroup(group);
|
|
15877
|
+
const evaluation = evaluateLiteral(cell.content);
|
|
15878
|
+
return {
|
|
15879
|
+
type: "INCREMENT_MODIFIER",
|
|
15880
|
+
increment,
|
|
15881
|
+
current: evaluation.type === CellValueType.number ? evaluation.value : 0,
|
|
15882
|
+
};
|
|
15883
|
+
},
|
|
15884
|
+
sequence: 40,
|
|
15885
|
+
});
|
|
15886
|
+
|
|
15887
|
+
const ERROR_TOOLTIP_MAX_HEIGHT = 80;
|
|
15888
|
+
const ERROR_TOOLTIP_WIDTH = 180;
|
|
15889
|
+
css /* scss */ `
|
|
15890
|
+
.o-error-tooltip {
|
|
15891
|
+
font-size: 13px;
|
|
15892
|
+
background-color: white;
|
|
15893
|
+
border-left: 3px solid red;
|
|
15894
|
+
padding: 10px;
|
|
15895
|
+
width: ${ERROR_TOOLTIP_WIDTH}px;
|
|
15896
|
+
box-sizing: border-box !important;
|
|
15897
|
+
}
|
|
15898
|
+
`;
|
|
15899
|
+
class ErrorToolTip extends owl.Component {
|
|
15900
|
+
}
|
|
15901
|
+
ErrorToolTip.maxSize = { maxHeight: ERROR_TOOLTIP_MAX_HEIGHT };
|
|
15902
|
+
ErrorToolTip.template = "o-spreadsheet-ErrorToolTip";
|
|
15903
|
+
ErrorToolTip.components = {};
|
|
15904
|
+
ErrorToolTip.props = {
|
|
15905
|
+
text: String,
|
|
15906
|
+
onClosed: { type: Function, optional: true },
|
|
15907
|
+
};
|
|
15908
|
+
const ErrorToolTipPopoverBuilder = {
|
|
15909
|
+
onHover: (position, getters) => {
|
|
15910
|
+
const cell = getters.getEvaluatedCell(position);
|
|
15911
|
+
if (cell.type === CellValueType.error && cell.error.logLevel > CellErrorLevel.silent) {
|
|
15912
|
+
return {
|
|
15913
|
+
isOpen: true,
|
|
15914
|
+
props: { text: cell.error.message },
|
|
15915
|
+
Component: ErrorToolTip,
|
|
15916
|
+
cellCorner: "TopRight",
|
|
15917
|
+
};
|
|
15918
|
+
}
|
|
15919
|
+
return { isOpen: false };
|
|
15920
|
+
},
|
|
15921
|
+
};
|
|
15922
|
+
|
|
15923
|
+
css /*SCSS*/ `
|
|
15924
|
+
.o-filter-menu-value {
|
|
15925
|
+
padding: 4px;
|
|
15926
|
+
line-height: 20px;
|
|
15927
|
+
height: 28px;
|
|
15928
|
+
.o-filter-menu-value-checked {
|
|
15929
|
+
width: 20px;
|
|
15930
|
+
}
|
|
15931
|
+
}
|
|
15932
|
+
`;
|
|
15933
|
+
class FilterMenuValueItem extends owl.Component {
|
|
15934
|
+
constructor() {
|
|
15935
|
+
super(...arguments);
|
|
15936
|
+
this.itemRef = owl.useRef("menuValueItem");
|
|
15937
|
+
}
|
|
15938
|
+
setup() {
|
|
15939
|
+
owl.onWillPatch(() => {
|
|
15940
|
+
if (this.props.scrolledTo) {
|
|
15941
|
+
this.scrollListToSelectedValue();
|
|
15942
|
+
}
|
|
15943
|
+
});
|
|
15944
|
+
}
|
|
15945
|
+
scrollListToSelectedValue() {
|
|
15946
|
+
var _a, _b;
|
|
15947
|
+
if (!this.itemRef.el) {
|
|
15948
|
+
return;
|
|
15949
|
+
}
|
|
15950
|
+
(_b = (_a = this.itemRef.el).scrollIntoView) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
|
15951
|
+
block: this.props.scrolledTo === "bottom" ? "end" : "start",
|
|
15952
|
+
});
|
|
15953
|
+
}
|
|
15954
|
+
}
|
|
15955
|
+
FilterMenuValueItem.template = "o-spreadsheet-FilterMenuValueItem";
|
|
15956
|
+
FilterMenuValueItem.props = {
|
|
15957
|
+
value: String,
|
|
15958
|
+
isChecked: Boolean,
|
|
15959
|
+
isSelected: Boolean,
|
|
15960
|
+
onMouseMove: Function,
|
|
15961
|
+
onClick: Function,
|
|
15962
|
+
scrolledTo: { type: String, optional: true },
|
|
15963
|
+
};
|
|
15964
|
+
|
|
15965
|
+
const FILTER_MENU_HEIGHT = 295;
|
|
15966
|
+
const CSS = css /* scss */ `
|
|
15967
|
+
.o-filter-menu {
|
|
15968
|
+
box-sizing: border-box;
|
|
15969
|
+
padding: 8px 16px;
|
|
15970
|
+
height: ${FILTER_MENU_HEIGHT}px;
|
|
15971
|
+
line-height: 1;
|
|
15972
|
+
|
|
15973
|
+
.o-filter-menu-item {
|
|
15974
|
+
display: flex;
|
|
15975
|
+
box-sizing: border-box;
|
|
15976
|
+
height: ${MENU_ITEM_HEIGHT}px;
|
|
15977
|
+
padding: 4px 4px 4px 0px;
|
|
15978
|
+
cursor: pointer;
|
|
15979
|
+
user-select: none;
|
|
15980
|
+
|
|
15981
|
+
&.selected {
|
|
15982
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
15983
|
+
}
|
|
15984
|
+
}
|
|
15985
|
+
|
|
15986
|
+
input {
|
|
15987
|
+
box-sizing: border-box;
|
|
15988
|
+
margin-bottom: 5px;
|
|
15989
|
+
border: 1px solid #949494;
|
|
15990
|
+
height: 24px;
|
|
15991
|
+
padding-right: 28px;
|
|
15992
|
+
}
|
|
15993
|
+
|
|
15994
|
+
.o-search-icon {
|
|
15995
|
+
right: 5px;
|
|
15996
|
+
top: 4px;
|
|
15997
|
+
|
|
15998
|
+
svg {
|
|
15999
|
+
height: 16px;
|
|
16000
|
+
width: 16px;
|
|
16001
|
+
vertical-align: middle;
|
|
16002
|
+
}
|
|
16003
|
+
}
|
|
16004
|
+
|
|
16005
|
+
.o-filter-menu-actions {
|
|
16006
|
+
display: flex;
|
|
16007
|
+
flex-direction: row;
|
|
16008
|
+
margin-bottom: 4px;
|
|
16009
|
+
|
|
16010
|
+
.o-filter-menu-action-text {
|
|
16011
|
+
cursor: pointer;
|
|
16012
|
+
margin-right: 10px;
|
|
16013
|
+
color: blue;
|
|
16014
|
+
text-decoration: underline;
|
|
16015
|
+
}
|
|
16016
|
+
}
|
|
16017
|
+
|
|
16018
|
+
.o-filter-menu-list {
|
|
16019
|
+
flex: auto;
|
|
16020
|
+
overflow-y: auto;
|
|
16021
|
+
border: 1px solid #949494;
|
|
16022
|
+
|
|
16023
|
+
.o-filter-menu-no-values {
|
|
16024
|
+
color: #949494;
|
|
16025
|
+
font-style: italic;
|
|
16026
|
+
}
|
|
16027
|
+
}
|
|
16028
|
+
|
|
16029
|
+
.o-filter-menu-buttons {
|
|
16030
|
+
margin-top: 9px;
|
|
16031
|
+
|
|
16032
|
+
.o-filter-menu-button {
|
|
16033
|
+
border: 1px solid lightgrey;
|
|
16034
|
+
padding: 6px 10px;
|
|
16035
|
+
cursor: pointer;
|
|
16036
|
+
border-radius: 4px;
|
|
16037
|
+
font-weight: 500;
|
|
16038
|
+
line-height: 16px;
|
|
16039
|
+
}
|
|
16040
|
+
|
|
16041
|
+
.o-filter-menu-button-cancel {
|
|
16042
|
+
background: white;
|
|
16043
|
+
&:hover {
|
|
16044
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
16045
|
+
}
|
|
16046
|
+
}
|
|
16047
|
+
|
|
16048
|
+
.o-filter-menu-button-primary {
|
|
16049
|
+
background-color: #188038;
|
|
16050
|
+
&:hover {
|
|
16051
|
+
background-color: #1d9641;
|
|
16052
|
+
}
|
|
16053
|
+
color: white;
|
|
16054
|
+
font-weight: bold;
|
|
16055
|
+
margin-left: 10px;
|
|
16056
|
+
}
|
|
16057
|
+
}
|
|
16058
|
+
}
|
|
16059
|
+
`;
|
|
16060
|
+
class FilterMenu extends owl.Component {
|
|
16061
|
+
constructor() {
|
|
16062
|
+
super(...arguments);
|
|
16063
|
+
this.state = owl.useState({
|
|
16064
|
+
values: [],
|
|
16065
|
+
textFilter: "",
|
|
16066
|
+
selectedValue: undefined,
|
|
16067
|
+
});
|
|
16068
|
+
this.searchBar = owl.useRef("filterMenuSearchBar");
|
|
16069
|
+
}
|
|
16070
|
+
setup() {
|
|
16071
|
+
owl.onWillUpdateProps((nextProps) => {
|
|
16072
|
+
if (!deepEquals(nextProps.filterPosition, this.props.filterPosition)) {
|
|
16073
|
+
this.state.values = this.getFilterValues(nextProps.filterPosition);
|
|
16074
|
+
}
|
|
16075
|
+
});
|
|
16076
|
+
this.state.values = this.getFilterValues(this.props.filterPosition);
|
|
16077
|
+
}
|
|
16078
|
+
getFilterValues(position) {
|
|
16079
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
16080
|
+
const filter = this.env.model.getters.getFilter({ sheetId, ...position });
|
|
16081
|
+
if (!filter) {
|
|
16082
|
+
return [];
|
|
16083
|
+
}
|
|
16084
|
+
const cellValues = (filter.filteredZone ? positions(filter.filteredZone) : [])
|
|
16085
|
+
.filter(({ row }) => !this.env.model.getters.isRowHidden(sheetId, row))
|
|
16086
|
+
.map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
|
|
16087
|
+
const filterValues = this.env.model.getters.getFilterValues({ sheetId, ...position });
|
|
16088
|
+
const strValues = [...cellValues, ...filterValues];
|
|
16089
|
+
const normalizedFilteredValues = filterValues.map(toLowerCase);
|
|
16090
|
+
// Set with lowercase values to avoid duplicates
|
|
16091
|
+
const normalizedValues = [...new Set(strValues.map(toLowerCase))];
|
|
16092
|
+
const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
|
|
16093
|
+
return sortedValues.map((normalizedValue) => {
|
|
16094
|
+
const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
|
|
16095
|
+
-1;
|
|
16096
|
+
return {
|
|
16097
|
+
checked,
|
|
16098
|
+
string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
|
|
16099
|
+
};
|
|
16100
|
+
});
|
|
16101
|
+
}
|
|
16102
|
+
checkValue(value) {
|
|
16103
|
+
var _a;
|
|
16104
|
+
this.state.selectedValue = value.string;
|
|
16105
|
+
value.checked = !value.checked;
|
|
16106
|
+
(_a = this.searchBar.el) === null || _a === void 0 ? void 0 : _a.focus();
|
|
16107
|
+
}
|
|
16108
|
+
onMouseMove(value) {
|
|
16109
|
+
this.state.selectedValue = value.string;
|
|
16110
|
+
}
|
|
16111
|
+
selectAll() {
|
|
16112
|
+
this.state.values.forEach((value) => (value.checked = true));
|
|
16113
|
+
}
|
|
16114
|
+
clearAll() {
|
|
16115
|
+
this.state.values.forEach((value) => (value.checked = false));
|
|
16116
|
+
}
|
|
16117
|
+
get filterTable() {
|
|
16118
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
16119
|
+
const position = this.props.filterPosition;
|
|
16120
|
+
return this.env.model.getters.getFilterTable({ sheetId, ...position });
|
|
16121
|
+
}
|
|
16122
|
+
get displayedValues() {
|
|
16123
|
+
if (!this.state.textFilter) {
|
|
16124
|
+
return this.state.values;
|
|
16125
|
+
}
|
|
16126
|
+
return fuzzyLookup(this.state.textFilter, this.state.values, (val) => val.string);
|
|
16127
|
+
}
|
|
16128
|
+
confirm() {
|
|
16129
|
+
var _a, _b;
|
|
16130
|
+
const position = this.props.filterPosition;
|
|
16131
|
+
this.env.model.dispatch("UPDATE_FILTER", {
|
|
16132
|
+
...position,
|
|
16133
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
16134
|
+
values: this.state.values.filter((val) => !val.checked).map((val) => val.string),
|
|
16135
|
+
});
|
|
16136
|
+
(_b = (_a = this.props).onClosed) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
16137
|
+
}
|
|
16138
|
+
cancel() {
|
|
16139
|
+
var _a, _b;
|
|
16140
|
+
(_b = (_a = this.props).onClosed) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
16141
|
+
}
|
|
16142
|
+
onKeyDown(ev) {
|
|
16143
|
+
const displayedValues = this.displayedValues;
|
|
16144
|
+
if (displayedValues.length === 0)
|
|
16145
|
+
return;
|
|
16146
|
+
let selectedIndex = undefined;
|
|
16147
|
+
if (this.state.selectedValue !== undefined) {
|
|
16148
|
+
const index = displayedValues.findIndex((val) => val.string === this.state.selectedValue);
|
|
16149
|
+
selectedIndex = index === -1 ? undefined : index;
|
|
16150
|
+
}
|
|
16151
|
+
switch (ev.key) {
|
|
16152
|
+
case "ArrowDown":
|
|
16153
|
+
if (selectedIndex === undefined) {
|
|
16154
|
+
selectedIndex = 0;
|
|
16155
|
+
}
|
|
16156
|
+
else {
|
|
16157
|
+
selectedIndex = Math.min(selectedIndex + 1, displayedValues.length - 1);
|
|
16158
|
+
}
|
|
16159
|
+
ev.preventDefault();
|
|
16160
|
+
ev.stopPropagation();
|
|
16161
|
+
break;
|
|
16162
|
+
case "ArrowUp":
|
|
16163
|
+
if (selectedIndex === undefined) {
|
|
16164
|
+
selectedIndex = displayedValues.length - 1;
|
|
16165
|
+
}
|
|
16166
|
+
else {
|
|
16167
|
+
selectedIndex = Math.max(selectedIndex - 1, 0);
|
|
16168
|
+
}
|
|
16169
|
+
ev.preventDefault();
|
|
16170
|
+
ev.stopPropagation();
|
|
16171
|
+
break;
|
|
16172
|
+
case "Enter":
|
|
16173
|
+
if (selectedIndex !== undefined) {
|
|
16174
|
+
this.checkValue(displayedValues[selectedIndex]);
|
|
16175
|
+
}
|
|
16176
|
+
ev.stopPropagation();
|
|
16177
|
+
ev.preventDefault();
|
|
16178
|
+
break;
|
|
16179
|
+
}
|
|
16180
|
+
this.state.selectedValue =
|
|
16181
|
+
selectedIndex !== undefined ? displayedValues[selectedIndex].string : undefined;
|
|
16182
|
+
if (ev.key === "ArrowUp" || ev.key === "ArrowDown") {
|
|
16183
|
+
this.scrollListToSelectedValue(ev.key);
|
|
16184
|
+
}
|
|
16185
|
+
}
|
|
16186
|
+
clearScrolledToValue() {
|
|
16187
|
+
this.state.values.forEach((val) => (val.scrolledTo = undefined));
|
|
16188
|
+
}
|
|
16189
|
+
scrollListToSelectedValue(arrow) {
|
|
16190
|
+
this.clearScrolledToValue();
|
|
16191
|
+
const selectedValue = this.state.values.find((val) => val.string === this.state.selectedValue);
|
|
16192
|
+
if (selectedValue) {
|
|
16193
|
+
selectedValue.scrolledTo = arrow === "ArrowUp" ? "top" : "bottom";
|
|
16194
|
+
}
|
|
16195
|
+
}
|
|
16196
|
+
sortFilterZone(sortDirection) {
|
|
16197
|
+
var _a, _b;
|
|
16198
|
+
const filterPosition = this.props.filterPosition;
|
|
16199
|
+
const filterTable = this.filterTable;
|
|
16200
|
+
if (!filterPosition || !filterTable || !filterTable.contentZone) {
|
|
16201
|
+
return;
|
|
16202
|
+
}
|
|
16203
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
16204
|
+
this.env.model.dispatch("SORT_CELLS", {
|
|
16205
|
+
sheetId,
|
|
16206
|
+
col: filterPosition.col,
|
|
16207
|
+
row: filterTable.contentZone.top,
|
|
16208
|
+
zone: filterTable.contentZone,
|
|
16209
|
+
sortDirection,
|
|
16210
|
+
sortOptions: { emptyCellAsZero: true, sortHeaders: true },
|
|
16211
|
+
});
|
|
16212
|
+
(_b = (_a = this.props).onClosed) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
16213
|
+
}
|
|
16214
|
+
}
|
|
16215
|
+
FilterMenu.size = { width: MENU_WIDTH, height: FILTER_MENU_HEIGHT };
|
|
16216
|
+
FilterMenu.template = "o-spreadsheet-FilterMenu";
|
|
16217
|
+
FilterMenu.style = CSS;
|
|
16218
|
+
FilterMenu.components = { FilterMenuValueItem };
|
|
16219
|
+
FilterMenu.props = {
|
|
16220
|
+
filterPosition: Object,
|
|
16221
|
+
onClosed: { type: Function, optional: true },
|
|
16222
|
+
};
|
|
16223
|
+
const FilterMenuPopoverBuilder = {
|
|
16224
|
+
onOpen: (position, getters) => {
|
|
16225
|
+
return {
|
|
16226
|
+
isOpen: true,
|
|
16227
|
+
props: { filterPosition: position },
|
|
16228
|
+
Component: FilterMenu,
|
|
16229
|
+
cellCorner: "BottomLeft",
|
|
16230
|
+
};
|
|
16231
|
+
},
|
|
16232
|
+
};
|
|
16233
|
+
|
|
16234
|
+
/**
|
|
16235
|
+
* Return the o-spreadsheet element position relative
|
|
16236
|
+
* to the browser viewport.
|
|
16237
|
+
*/
|
|
16238
|
+
function useSpreadsheetRect() {
|
|
16239
|
+
const position = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
|
|
16240
|
+
let spreadsheetElement = document.querySelector(".o-spreadsheet");
|
|
16241
|
+
updatePosition();
|
|
16242
|
+
function updatePosition() {
|
|
16243
|
+
if (!spreadsheetElement) {
|
|
16244
|
+
spreadsheetElement = document.querySelector(".o-spreadsheet");
|
|
16245
|
+
}
|
|
16246
|
+
if (spreadsheetElement) {
|
|
16247
|
+
const { top, left, width, height } = spreadsheetElement.getBoundingClientRect();
|
|
16248
|
+
position.x = left;
|
|
16249
|
+
position.y = top;
|
|
16250
|
+
position.width = width;
|
|
16251
|
+
position.height = height;
|
|
16252
|
+
}
|
|
16253
|
+
}
|
|
16254
|
+
owl.onMounted(updatePosition);
|
|
16255
|
+
owl.onPatched(updatePosition);
|
|
16256
|
+
return position;
|
|
16387
16257
|
}
|
|
16388
16258
|
/**
|
|
16389
|
-
*
|
|
16259
|
+
* Return the component (or ref's component) BoundingRect, relative
|
|
16260
|
+
* to the upper left corner of the screen (<body> element).
|
|
16261
|
+
*
|
|
16262
|
+
* Note: when used with a <Portal/> component, it will
|
|
16263
|
+
* return the portal position, not the teleported position.
|
|
16390
16264
|
*/
|
|
16391
|
-
function
|
|
16392
|
-
const
|
|
16393
|
-
|
|
16394
|
-
|
|
16395
|
-
|
|
16396
|
-
|
|
16397
|
-
|
|
16265
|
+
function useAbsoluteBoundingRect(ref) {
|
|
16266
|
+
const rect = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
|
|
16267
|
+
function updateElRect() {
|
|
16268
|
+
const el = ref.el;
|
|
16269
|
+
if (el === null) {
|
|
16270
|
+
return;
|
|
16271
|
+
}
|
|
16272
|
+
const { top, left, width, height } = el.getBoundingClientRect();
|
|
16273
|
+
rect.x = left;
|
|
16274
|
+
rect.y = top;
|
|
16275
|
+
rect.width = width;
|
|
16276
|
+
rect.height = height;
|
|
16398
16277
|
}
|
|
16399
|
-
|
|
16278
|
+
owl.onMounted(updateElRect);
|
|
16279
|
+
owl.onPatched(updateElRect);
|
|
16280
|
+
return rect;
|
|
16400
16281
|
}
|
|
16401
16282
|
/**
|
|
16402
|
-
* Get the
|
|
16283
|
+
* Get the rectangle inside which a popover should stay when being displayed.
|
|
16284
|
+
* It's the value defined in `env.getPopoverContainerRect`, or the Rect of the "o-spreadsheet"
|
|
16285
|
+
* element by default.
|
|
16286
|
+
*
|
|
16287
|
+
* Coordinates are expressed expressed as absolute DOM position.
|
|
16403
16288
|
*/
|
|
16404
|
-
function
|
|
16405
|
-
|
|
16406
|
-
|
|
16407
|
-
|
|
16289
|
+
function usePopoverContainer() {
|
|
16290
|
+
const container = owl.useState({ x: 0, y: 0, width: 0, height: 0 });
|
|
16291
|
+
const component = owl.useComponent();
|
|
16292
|
+
const spreadsheetRect = useSpreadsheetRect();
|
|
16293
|
+
function updateRect() {
|
|
16294
|
+
const env = component.env;
|
|
16295
|
+
const newRect = "getPopoverContainerRect" in env ? env.getPopoverContainerRect() : spreadsheetRect;
|
|
16296
|
+
container.x = newRect.x;
|
|
16297
|
+
container.y = newRect.y;
|
|
16298
|
+
container.width = newRect.width;
|
|
16299
|
+
container.height = newRect.height;
|
|
16408
16300
|
}
|
|
16409
|
-
|
|
16410
|
-
|
|
16411
|
-
|
|
16412
|
-
|
|
16413
|
-
condition: (cell, cells) => {
|
|
16414
|
-
var _a;
|
|
16415
|
-
return cells.length === 1 && !cell.isFormula && !((_a = cell.format) === null || _a === void 0 ? void 0 : _a.match(DATETIME_FORMAT));
|
|
16416
|
-
},
|
|
16417
|
-
generateRule: () => {
|
|
16418
|
-
return { type: "COPY_MODIFIER" };
|
|
16419
|
-
},
|
|
16420
|
-
sequence: 10,
|
|
16421
|
-
})
|
|
16422
|
-
.add("increment_alphanumeric_value", {
|
|
16423
|
-
condition: (cell) => !cell.isFormula &&
|
|
16424
|
-
evaluateLiteral(cell.content).type === CellValueType.text &&
|
|
16425
|
-
alphaNumericValueRegExp.test(cell.content),
|
|
16426
|
-
generateRule: (cell, cells) => {
|
|
16427
|
-
const numberPostfix = parseInt(cell.content.match(numberPostfixRegExp)[0]);
|
|
16428
|
-
const prefix = cell.content.match(stringPrefixRegExp)[0];
|
|
16429
|
-
const numberPostfixLength = cell.content.length - prefix.length;
|
|
16430
|
-
const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.text &&
|
|
16431
|
-
alphaNumericValueRegExp.test(evaluatedCell.value)) // get consecutive alphanumeric cells, no matter what the prefix is
|
|
16432
|
-
.filter((cell) => prefix === cell.value.toString().match(stringPrefixRegExp)[0])
|
|
16433
|
-
.map((cell) => parseInt(cell.value.toString().match(numberPostfixRegExp)[0]));
|
|
16434
|
-
const increment = calculateIncrementBasedOnGroup(group);
|
|
16435
|
-
return {
|
|
16436
|
-
type: "ALPHANUMERIC_INCREMENT_MODIFIER",
|
|
16437
|
-
prefix,
|
|
16438
|
-
current: numberPostfix,
|
|
16439
|
-
increment,
|
|
16440
|
-
numberPostfixLength,
|
|
16441
|
-
};
|
|
16442
|
-
},
|
|
16443
|
-
sequence: 15,
|
|
16444
|
-
})
|
|
16445
|
-
.add("copy_text", {
|
|
16446
|
-
condition: (cell) => !cell.isFormula && evaluateLiteral(cell.content).type === CellValueType.text,
|
|
16447
|
-
generateRule: () => {
|
|
16448
|
-
return { type: "COPY_MODIFIER" };
|
|
16449
|
-
},
|
|
16450
|
-
sequence: 20,
|
|
16451
|
-
})
|
|
16452
|
-
.add("update_formula", {
|
|
16453
|
-
condition: (cell) => cell.isFormula,
|
|
16454
|
-
generateRule: (_, cells) => {
|
|
16455
|
-
return { type: "FORMULA_MODIFIER", increment: cells.length, current: 0 };
|
|
16456
|
-
},
|
|
16457
|
-
sequence: 30,
|
|
16458
|
-
})
|
|
16459
|
-
.add("increment_number", {
|
|
16460
|
-
condition: (cell) => !cell.isFormula && evaluateLiteral(cell.content).type === CellValueType.number,
|
|
16461
|
-
generateRule: (cell, cells) => {
|
|
16462
|
-
const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number).map((cell) => Number(cell.value));
|
|
16463
|
-
const increment = calculateIncrementBasedOnGroup(group);
|
|
16464
|
-
const evaluation = evaluateLiteral(cell.content);
|
|
16465
|
-
return {
|
|
16466
|
-
type: "INCREMENT_MODIFIER",
|
|
16467
|
-
increment,
|
|
16468
|
-
current: evaluation.type === CellValueType.number ? evaluation.value : 0,
|
|
16469
|
-
};
|
|
16470
|
-
},
|
|
16471
|
-
sequence: 40,
|
|
16472
|
-
});
|
|
16473
|
-
|
|
16474
|
-
const ERROR_TOOLTIP_MAX_HEIGHT = 80;
|
|
16475
|
-
const ERROR_TOOLTIP_WIDTH = 180;
|
|
16476
|
-
css /* scss */ `
|
|
16477
|
-
.o-error-tooltip {
|
|
16478
|
-
font-size: 13px;
|
|
16479
|
-
background-color: white;
|
|
16480
|
-
border-left: 3px solid red;
|
|
16481
|
-
padding: 10px;
|
|
16482
|
-
width: ${ERROR_TOOLTIP_WIDTH}px;
|
|
16483
|
-
box-sizing: border-box !important;
|
|
16301
|
+
updateRect();
|
|
16302
|
+
owl.onMounted(updateRect);
|
|
16303
|
+
owl.onPatched(updateRect);
|
|
16304
|
+
return container;
|
|
16484
16305
|
}
|
|
16485
|
-
|
|
16486
|
-
|
|
16306
|
+
|
|
16307
|
+
/**
|
|
16308
|
+
* Compute the intersection of two rectangles. Returns nothing if the two rectangles don't overlap
|
|
16309
|
+
*/
|
|
16310
|
+
function rectIntersection(rect1, rect2) {
|
|
16311
|
+
return zoneToRect(intersection(rectToZone(rect1), rectToZone(rect2)));
|
|
16487
16312
|
}
|
|
16488
|
-
|
|
16489
|
-
|
|
16490
|
-
|
|
16491
|
-
|
|
16492
|
-
|
|
16493
|
-
|
|
16494
|
-
|
|
16495
|
-
|
|
16496
|
-
|
|
16497
|
-
|
|
16498
|
-
|
|
16499
|
-
|
|
16500
|
-
|
|
16501
|
-
|
|
16502
|
-
|
|
16503
|
-
|
|
16504
|
-
|
|
16505
|
-
|
|
16506
|
-
return { isOpen: false };
|
|
16507
|
-
},
|
|
16508
|
-
};
|
|
16313
|
+
function rectToZone(rect) {
|
|
16314
|
+
return {
|
|
16315
|
+
left: rect.x,
|
|
16316
|
+
top: rect.y,
|
|
16317
|
+
right: rect.x + rect.width,
|
|
16318
|
+
bottom: rect.y + rect.height,
|
|
16319
|
+
};
|
|
16320
|
+
}
|
|
16321
|
+
function zoneToRect(zone) {
|
|
16322
|
+
if (!zone)
|
|
16323
|
+
return undefined;
|
|
16324
|
+
return {
|
|
16325
|
+
x: zone.left,
|
|
16326
|
+
y: zone.top,
|
|
16327
|
+
width: zone.right - zone.left,
|
|
16328
|
+
height: zone.bottom - zone.top,
|
|
16329
|
+
};
|
|
16330
|
+
}
|
|
16509
16331
|
|
|
16510
|
-
css /*
|
|
16511
|
-
.o-
|
|
16512
|
-
|
|
16513
|
-
|
|
16514
|
-
|
|
16515
|
-
|
|
16516
|
-
|
|
16517
|
-
|
|
16332
|
+
css /* scss */ `
|
|
16333
|
+
.o-popover {
|
|
16334
|
+
position: absolute;
|
|
16335
|
+
z-index: ${ComponentsImportance.Popover};
|
|
16336
|
+
overflow: auto;
|
|
16337
|
+
box-shadow: 1px 2px 5px 2px rgb(51 51 51 / 15%);
|
|
16338
|
+
width: fit-content;
|
|
16339
|
+
height: fit-content;
|
|
16518
16340
|
}
|
|
16519
16341
|
`;
|
|
16520
|
-
class
|
|
16342
|
+
class Popover extends owl.Component {
|
|
16521
16343
|
constructor() {
|
|
16522
16344
|
super(...arguments);
|
|
16523
|
-
this.
|
|
16345
|
+
this.popoverRef = owl.useRef("popover");
|
|
16346
|
+
this.currentPosition = undefined;
|
|
16347
|
+
this.currentDisplayValue = undefined;
|
|
16348
|
+
this.spreadsheetRect = useSpreadsheetRect();
|
|
16524
16349
|
}
|
|
16525
16350
|
setup() {
|
|
16526
|
-
|
|
16527
|
-
|
|
16528
|
-
|
|
16351
|
+
this.containerRect = usePopoverContainer();
|
|
16352
|
+
// useEffect occurs after the DOM is created and the element width/height are computed, but before
|
|
16353
|
+
// the element in rendered, so we can still set its position
|
|
16354
|
+
owl.useEffect(() => {
|
|
16355
|
+
var _a, _b, _c, _d;
|
|
16356
|
+
if (!this.containerRect)
|
|
16357
|
+
throw new Error("Popover container is not defined");
|
|
16358
|
+
const el = this.popoverRef.el;
|
|
16359
|
+
const anchor = rectIntersection(this.props.anchorRect, this.containerRect);
|
|
16360
|
+
const newDisplay = anchor ? "block" : "none";
|
|
16361
|
+
if (this.currentDisplayValue !== "none" && newDisplay === "none") {
|
|
16362
|
+
(_b = (_a = this.props).onPopoverHidden) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
16363
|
+
}
|
|
16364
|
+
el.style.display = newDisplay;
|
|
16365
|
+
this.currentDisplayValue = newDisplay;
|
|
16366
|
+
if (!anchor)
|
|
16367
|
+
return;
|
|
16368
|
+
const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
|
|
16369
|
+
const elDims = {
|
|
16370
|
+
width: el.getBoundingClientRect().width,
|
|
16371
|
+
height: el.getBoundingClientRect().height,
|
|
16372
|
+
};
|
|
16373
|
+
const spreadsheetRect = this.spreadsheetRect;
|
|
16374
|
+
const popoverPositionHelper = this.props.positioning === "BottomLeft"
|
|
16375
|
+
? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
|
|
16376
|
+
: new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
|
|
16377
|
+
const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
|
|
16378
|
+
for (const property of Object.keys(style)) {
|
|
16379
|
+
el.style[property] = style[property];
|
|
16380
|
+
}
|
|
16381
|
+
const newPosition = popoverPositionHelper.getCurrentPosition(elDims);
|
|
16382
|
+
if (this.currentPosition && newPosition !== this.currentPosition) {
|
|
16383
|
+
(_d = (_c = this.props).onPopoverMoved) === null || _d === void 0 ? void 0 : _d.call(_c);
|
|
16529
16384
|
}
|
|
16385
|
+
this.currentPosition = newPosition;
|
|
16530
16386
|
});
|
|
16531
16387
|
}
|
|
16532
|
-
|
|
16533
|
-
|
|
16534
|
-
|
|
16535
|
-
|
|
16388
|
+
}
|
|
16389
|
+
Popover.template = "o-spreadsheet-Popover";
|
|
16390
|
+
Popover.defaultProps = {
|
|
16391
|
+
positioning: "BottomLeft",
|
|
16392
|
+
verticalOffset: 0,
|
|
16393
|
+
onMouseWheel: () => { },
|
|
16394
|
+
onPopoverMoved: () => { },
|
|
16395
|
+
onPopoverHidden: () => { },
|
|
16396
|
+
};
|
|
16397
|
+
Popover.props = {
|
|
16398
|
+
anchorRect: Object,
|
|
16399
|
+
containerRect: { type: Object, optional: true },
|
|
16400
|
+
positioning: { type: String, optional: true },
|
|
16401
|
+
maxWidth: { type: Number, optional: true },
|
|
16402
|
+
maxHeight: { type: Number, optional: true },
|
|
16403
|
+
verticalOffset: { type: Number, optional: true },
|
|
16404
|
+
onMouseWheel: { type: Function, optional: true },
|
|
16405
|
+
onPopoverHidden: { type: Function, optional: true },
|
|
16406
|
+
onPopoverMoved: { type: Function, optional: true },
|
|
16407
|
+
slots: Object,
|
|
16408
|
+
};
|
|
16409
|
+
class PopoverPositionContext {
|
|
16410
|
+
constructor(anchorRect, containerRect, propsMaxSize, spreadsheetOffset) {
|
|
16411
|
+
this.anchorRect = anchorRect;
|
|
16412
|
+
this.containerRect = containerRect;
|
|
16413
|
+
this.propsMaxSize = propsMaxSize;
|
|
16414
|
+
this.spreadsheetOffset = spreadsheetOffset;
|
|
16415
|
+
}
|
|
16416
|
+
/** Check if there is enough space for the popover to be rendered at the bottom of the anchorRect */
|
|
16417
|
+
shouldRenderAtBottom(elementHeight) {
|
|
16418
|
+
return (elementHeight <= this.availableHeightDown ||
|
|
16419
|
+
this.availableHeightDown >= this.availableHeightUp);
|
|
16420
|
+
}
|
|
16421
|
+
/** Check if there is enough space for the popover to be rendered at the right of the anchorRect */
|
|
16422
|
+
shouldRenderAtRight(elementWidth) {
|
|
16423
|
+
return (elementWidth <= this.availableWidthRight ||
|
|
16424
|
+
this.availableWidthRight >= this.availableWidthLeft);
|
|
16425
|
+
}
|
|
16426
|
+
getMaxHeight(elementHeight) {
|
|
16427
|
+
const shouldRenderAtBottom = this.shouldRenderAtBottom(elementHeight);
|
|
16428
|
+
const availableHeight = shouldRenderAtBottom
|
|
16429
|
+
? this.availableHeightDown
|
|
16430
|
+
: this.availableHeightUp;
|
|
16431
|
+
return this.propsMaxSize.height
|
|
16432
|
+
? Math.min(availableHeight, this.propsMaxSize.height)
|
|
16433
|
+
: availableHeight;
|
|
16434
|
+
}
|
|
16435
|
+
getMaxWidth(elementWidth) {
|
|
16436
|
+
const shouldRenderAtRight = this.shouldRenderAtRight(elementWidth);
|
|
16437
|
+
const availableWidth = shouldRenderAtRight ? this.availableWidthRight : this.availableWidthLeft;
|
|
16438
|
+
return this.propsMaxSize.width
|
|
16439
|
+
? Math.min(availableWidth, this.propsMaxSize.width)
|
|
16440
|
+
: availableWidth;
|
|
16441
|
+
}
|
|
16442
|
+
getCss(elDims, verticalOffset) {
|
|
16443
|
+
const maxHeight = this.getMaxHeight(elDims.height);
|
|
16444
|
+
const maxWidth = this.getMaxWidth(elDims.width);
|
|
16445
|
+
const actualHeight = Math.min(maxHeight, elDims.height);
|
|
16446
|
+
const actualWidth = Math.min(maxWidth, elDims.width);
|
|
16447
|
+
const shouldRenderAtBottom = this.shouldRenderAtBottom(elDims.height);
|
|
16448
|
+
const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
|
|
16449
|
+
verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
|
|
16450
|
+
const cssProperties = {
|
|
16451
|
+
"max-height": maxHeight + "px",
|
|
16452
|
+
"max-width": maxWidth + "px",
|
|
16453
|
+
top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
|
|
16454
|
+
this.spreadsheetOffset.y -
|
|
16455
|
+
verticalOffset +
|
|
16456
|
+
"px",
|
|
16457
|
+
left: this.getLeftCoordinate(actualWidth, shouldRenderAtRight) - this.spreadsheetOffset.x + "px",
|
|
16458
|
+
};
|
|
16459
|
+
return cssProperties;
|
|
16460
|
+
}
|
|
16461
|
+
getCurrentPosition(elDims) {
|
|
16462
|
+
const shouldRenderAtBottom = this.shouldRenderAtBottom(elDims.height);
|
|
16463
|
+
const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
|
|
16464
|
+
if (shouldRenderAtBottom && shouldRenderAtRight)
|
|
16465
|
+
return "BottomRight";
|
|
16466
|
+
if (shouldRenderAtBottom && !shouldRenderAtRight)
|
|
16467
|
+
return "BottomLeft";
|
|
16468
|
+
if (!shouldRenderAtBottom && shouldRenderAtRight)
|
|
16469
|
+
return "TopRight";
|
|
16470
|
+
return "TopLeft";
|
|
16471
|
+
}
|
|
16472
|
+
}
|
|
16473
|
+
class BottomLeftPopoverContext extends PopoverPositionContext {
|
|
16474
|
+
get availableHeightUp() {
|
|
16475
|
+
return this.anchorRect.y - this.containerRect.y;
|
|
16476
|
+
}
|
|
16477
|
+
get availableHeightDown() {
|
|
16478
|
+
return this.containerRect.height - this.availableHeightUp - this.anchorRect.height;
|
|
16479
|
+
}
|
|
16480
|
+
get availableWidthRight() {
|
|
16481
|
+
return this.containerRect.x + this.containerRect.width - this.anchorRect.x;
|
|
16482
|
+
}
|
|
16483
|
+
get availableWidthLeft() {
|
|
16484
|
+
return this.anchorRect.x + this.anchorRect.width - this.containerRect.x;
|
|
16485
|
+
}
|
|
16486
|
+
getTopCoordinate(elementHeight, shouldRenderAtBottom) {
|
|
16487
|
+
if (shouldRenderAtBottom) {
|
|
16488
|
+
return this.anchorRect.y + this.anchorRect.height;
|
|
16489
|
+
}
|
|
16490
|
+
else {
|
|
16491
|
+
return this.anchorRect.y - elementHeight;
|
|
16492
|
+
}
|
|
16493
|
+
}
|
|
16494
|
+
getLeftCoordinate(elementWidth, shouldRenderAtRight) {
|
|
16495
|
+
if (shouldRenderAtRight) {
|
|
16496
|
+
return this.anchorRect.x;
|
|
16497
|
+
}
|
|
16498
|
+
else {
|
|
16499
|
+
return this.anchorRect.x + this.anchorRect.width - elementWidth;
|
|
16536
16500
|
}
|
|
16537
|
-
(_b = (_a = this.itemRef.el).scrollIntoView) === null || _b === void 0 ? void 0 : _b.call(_a, {
|
|
16538
|
-
block: this.props.scrolledTo === "bottom" ? "end" : "start",
|
|
16539
|
-
});
|
|
16540
16501
|
}
|
|
16541
16502
|
}
|
|
16542
|
-
|
|
16543
|
-
|
|
16544
|
-
|
|
16545
|
-
|
|
16546
|
-
|
|
16547
|
-
|
|
16548
|
-
|
|
16549
|
-
|
|
16550
|
-
|
|
16503
|
+
class TopRightPopoverContext extends PopoverPositionContext {
|
|
16504
|
+
get availableHeightUp() {
|
|
16505
|
+
return this.anchorRect.y + this.anchorRect.height - this.containerRect.y;
|
|
16506
|
+
}
|
|
16507
|
+
get availableHeightDown() {
|
|
16508
|
+
return this.containerRect.y + this.containerRect.height - this.anchorRect.y;
|
|
16509
|
+
}
|
|
16510
|
+
get availableWidthRight() {
|
|
16511
|
+
return this.containerRect.width - this.anchorRect.width - this.availableWidthLeft;
|
|
16512
|
+
}
|
|
16513
|
+
get availableWidthLeft() {
|
|
16514
|
+
return this.anchorRect.x - this.containerRect.x;
|
|
16515
|
+
}
|
|
16516
|
+
getTopCoordinate(elementHeight, shouldRenderAtBottom) {
|
|
16517
|
+
if (shouldRenderAtBottom) {
|
|
16518
|
+
return this.anchorRect.y;
|
|
16519
|
+
}
|
|
16520
|
+
else {
|
|
16521
|
+
return this.anchorRect.y + this.anchorRect.height - elementHeight;
|
|
16522
|
+
}
|
|
16523
|
+
}
|
|
16524
|
+
getLeftCoordinate(elementWidth, shouldRenderAtRight) {
|
|
16525
|
+
if (shouldRenderAtRight) {
|
|
16526
|
+
return this.anchorRect.x + this.anchorRect.width;
|
|
16527
|
+
}
|
|
16528
|
+
else {
|
|
16529
|
+
return this.anchorRect.x - elementWidth;
|
|
16530
|
+
}
|
|
16531
|
+
}
|
|
16532
|
+
}
|
|
16551
16533
|
|
|
16552
|
-
|
|
16553
|
-
|
|
16554
|
-
|
|
16555
|
-
|
|
16556
|
-
|
|
16557
|
-
|
|
16558
|
-
|
|
16534
|
+
//------------------------------------------------------------------------------
|
|
16535
|
+
// Context Menu Component
|
|
16536
|
+
//------------------------------------------------------------------------------
|
|
16537
|
+
css /* scss */ `
|
|
16538
|
+
.o-menu {
|
|
16539
|
+
background-color: white;
|
|
16540
|
+
padding: ${MENU_VERTICAL_PADDING}px 0px;
|
|
16541
|
+
width: ${MENU_WIDTH}px;
|
|
16542
|
+
box-sizing: border-box !important;
|
|
16559
16543
|
|
|
16560
|
-
.o-
|
|
16544
|
+
.o-menu-item {
|
|
16561
16545
|
display: flex;
|
|
16546
|
+
justify-content: space-between;
|
|
16547
|
+
align-items: center;
|
|
16562
16548
|
box-sizing: border-box;
|
|
16563
16549
|
height: ${MENU_ITEM_HEIGHT}px;
|
|
16564
|
-
padding: 4px
|
|
16550
|
+
padding: 4px 16px;
|
|
16565
16551
|
cursor: pointer;
|
|
16566
16552
|
user-select: none;
|
|
16567
16553
|
|
|
16568
|
-
|
|
16569
|
-
|
|
16570
|
-
|
|
16571
|
-
|
|
16572
|
-
|
|
16573
|
-
input {
|
|
16574
|
-
box-sizing: border-box;
|
|
16575
|
-
margin-bottom: 5px;
|
|
16576
|
-
border: 1px solid #949494;
|
|
16577
|
-
height: 24px;
|
|
16578
|
-
padding-right: 28px;
|
|
16579
|
-
}
|
|
16580
|
-
|
|
16581
|
-
.o-search-icon {
|
|
16582
|
-
right: 5px;
|
|
16583
|
-
top: 4px;
|
|
16584
|
-
|
|
16585
|
-
svg {
|
|
16586
|
-
height: 16px;
|
|
16587
|
-
width: 16px;
|
|
16588
|
-
vertical-align: middle;
|
|
16554
|
+
.o-menu-item-name {
|
|
16555
|
+
overflow: hidden;
|
|
16556
|
+
white-space: nowrap;
|
|
16557
|
+
text-overflow: ellipsis;
|
|
16589
16558
|
}
|
|
16590
|
-
}
|
|
16591
16559
|
|
|
16592
|
-
|
|
16593
|
-
|
|
16594
|
-
|
|
16595
|
-
margin-bottom: 4px;
|
|
16596
|
-
|
|
16597
|
-
.o-filter-menu-action-text {
|
|
16598
|
-
cursor: pointer;
|
|
16599
|
-
margin-right: 10px;
|
|
16600
|
-
color: blue;
|
|
16601
|
-
text-decoration: underline;
|
|
16560
|
+
&.o-menu-root {
|
|
16561
|
+
display: flex;
|
|
16562
|
+
justify-content: space-between;
|
|
16602
16563
|
}
|
|
16603
|
-
|
|
16604
|
-
|
|
16605
|
-
|
|
16606
|
-
flex: auto;
|
|
16607
|
-
overflow-y: auto;
|
|
16608
|
-
border: 1px solid #949494;
|
|
16609
|
-
|
|
16610
|
-
.o-filter-menu-no-values {
|
|
16611
|
-
color: #949494;
|
|
16612
|
-
font-style: italic;
|
|
16564
|
+
.o-menu-item-icon {
|
|
16565
|
+
margin-top: auto;
|
|
16566
|
+
margin-bottom: auto;
|
|
16613
16567
|
}
|
|
16614
|
-
|
|
16615
|
-
|
|
16616
|
-
.o-filter-menu-buttons {
|
|
16617
|
-
margin-top: 9px;
|
|
16618
|
-
|
|
16619
|
-
.o-filter-menu-button {
|
|
16620
|
-
border: 1px solid lightgrey;
|
|
16621
|
-
padding: 6px 10px;
|
|
16622
|
-
cursor: pointer;
|
|
16623
|
-
border-radius: 4px;
|
|
16624
|
-
font-weight: 500;
|
|
16625
|
-
line-height: 16px;
|
|
16568
|
+
.o-icon {
|
|
16569
|
+
width: 10px;
|
|
16626
16570
|
}
|
|
16627
16571
|
|
|
16628
|
-
.
|
|
16629
|
-
|
|
16630
|
-
|
|
16631
|
-
background-color:
|
|
16572
|
+
&:not(.disabled) {
|
|
16573
|
+
&:hover,
|
|
16574
|
+
&.o-menu-item-active {
|
|
16575
|
+
background-color: #ebebeb;
|
|
16632
16576
|
}
|
|
16633
|
-
|
|
16634
|
-
|
|
16635
|
-
.o-filter-menu-button-primary {
|
|
16636
|
-
background-color: #188038;
|
|
16637
|
-
&:hover {
|
|
16638
|
-
background-color: #1d9641;
|
|
16577
|
+
.o-menu-item-description {
|
|
16578
|
+
color: grey;
|
|
16639
16579
|
}
|
|
16640
|
-
|
|
16641
|
-
|
|
16642
|
-
|
|
16580
|
+
}
|
|
16581
|
+
&.disabled {
|
|
16582
|
+
color: ${MENU_ITEM_DISABLED_COLOR};
|
|
16583
|
+
cursor: not-allowed;
|
|
16643
16584
|
}
|
|
16644
16585
|
}
|
|
16645
16586
|
}
|
|
16646
16587
|
`;
|
|
16647
|
-
class
|
|
16588
|
+
class Menu extends owl.Component {
|
|
16648
16589
|
constructor() {
|
|
16649
16590
|
super(...arguments);
|
|
16650
|
-
this.
|
|
16651
|
-
|
|
16652
|
-
|
|
16653
|
-
|
|
16591
|
+
this.subMenu = owl.useState({
|
|
16592
|
+
isOpen: false,
|
|
16593
|
+
position: null,
|
|
16594
|
+
scrollOffset: 0,
|
|
16595
|
+
menuItems: [],
|
|
16654
16596
|
});
|
|
16655
|
-
this.
|
|
16597
|
+
this.menuRef = owl.useRef("menu");
|
|
16598
|
+
this.position = useAbsoluteBoundingRect(this.menuRef);
|
|
16656
16599
|
}
|
|
16657
16600
|
setup() {
|
|
16601
|
+
owl.useExternalListener(window, "click", this.onExternalClick, { capture: true });
|
|
16602
|
+
owl.useExternalListener(window, "contextmenu", this.onExternalClick, { capture: true });
|
|
16658
16603
|
owl.onWillUpdateProps((nextProps) => {
|
|
16659
|
-
if (
|
|
16660
|
-
this.
|
|
16604
|
+
if (nextProps.menuItems !== this.props.menuItems) {
|
|
16605
|
+
this.closeSubMenu();
|
|
16661
16606
|
}
|
|
16662
16607
|
});
|
|
16663
|
-
this.state.values = this.getFilterValues(this.props.filterPosition);
|
|
16664
16608
|
}
|
|
16665
|
-
|
|
16666
|
-
|
|
16667
|
-
|
|
16668
|
-
|
|
16669
|
-
|
|
16609
|
+
get visibleMenuItems() {
|
|
16610
|
+
return this.props.menuItems.filter((x) => x.isVisible(this.env));
|
|
16611
|
+
}
|
|
16612
|
+
get subMenuPosition() {
|
|
16613
|
+
const position = Object.assign({}, this.subMenu.position);
|
|
16614
|
+
position.y -= this.subMenu.scrollOffset || 0;
|
|
16615
|
+
return position;
|
|
16616
|
+
}
|
|
16617
|
+
get menuHeight() {
|
|
16618
|
+
const menuItems = this.visibleMenuItems;
|
|
16619
|
+
let menuItemsHeight = this.getMenuItemsHeight(menuItems);
|
|
16620
|
+
// We don't display separator at the end of a menu
|
|
16621
|
+
if (menuItems[menuItems.length - 1].separator) {
|
|
16622
|
+
menuItemsHeight -= MENU_SEPARATOR_HEIGHT;
|
|
16670
16623
|
}
|
|
16671
|
-
const
|
|
16672
|
-
|
|
16673
|
-
.map(({ col, row }) => this.env.model.getters.getEvaluatedCell({ sheetId, col, row }).formattedValue);
|
|
16674
|
-
const filterValues = this.env.model.getters.getFilterValues({ sheetId, ...position });
|
|
16675
|
-
const strValues = [...cellValues, ...filterValues];
|
|
16676
|
-
const normalizedFilteredValues = filterValues.map(toLowerCase);
|
|
16677
|
-
// Set with lowercase values to avoid duplicates
|
|
16678
|
-
const normalizedValues = [...new Set(strValues.map(toLowerCase))];
|
|
16679
|
-
const sortedValues = normalizedValues.sort((val1, val2) => val1.localeCompare(val2, undefined, { numeric: true, sensitivity: "base" }));
|
|
16680
|
-
return sortedValues.map((normalizedValue) => {
|
|
16681
|
-
const checked = normalizedFilteredValues.findIndex((filteredValue) => filteredValue === normalizedValue) ===
|
|
16682
|
-
-1;
|
|
16683
|
-
return {
|
|
16684
|
-
checked,
|
|
16685
|
-
string: strValues.find((val) => toLowerCase(val) === normalizedValue) || "",
|
|
16686
|
-
};
|
|
16687
|
-
});
|
|
16624
|
+
const menuHeight = 2 * MENU_VERTICAL_PADDING + menuItemsHeight;
|
|
16625
|
+
return this.props.maxHeight ? Math.min(menuHeight, this.props.maxHeight) : menuHeight;
|
|
16688
16626
|
}
|
|
16689
|
-
|
|
16690
|
-
|
|
16691
|
-
|
|
16692
|
-
|
|
16693
|
-
|
|
16627
|
+
get popoverProps() {
|
|
16628
|
+
const isRoot = this.props.depth === 1;
|
|
16629
|
+
return {
|
|
16630
|
+
anchorRect: {
|
|
16631
|
+
x: this.props.position.x - MENU_WIDTH * (this.props.depth - 1),
|
|
16632
|
+
y: this.props.position.y,
|
|
16633
|
+
width: isRoot ? 0 : MENU_WIDTH,
|
|
16634
|
+
height: isRoot ? 0 : MENU_ITEM_HEIGHT,
|
|
16635
|
+
},
|
|
16636
|
+
positioning: "TopRight",
|
|
16637
|
+
verticalOffset: isRoot ? 0 : MENU_VERTICAL_PADDING,
|
|
16638
|
+
onPopoverHidden: () => this.closeSubMenu(),
|
|
16639
|
+
onPopoverMoved: () => this.closeSubMenu(),
|
|
16640
|
+
maxHeight: this.menuHeight,
|
|
16641
|
+
};
|
|
16694
16642
|
}
|
|
16695
|
-
|
|
16696
|
-
|
|
16643
|
+
getColor(menu) {
|
|
16644
|
+
return menu.textColor ? `color: ${menu.textColor}` : undefined;
|
|
16697
16645
|
}
|
|
16698
|
-
|
|
16699
|
-
|
|
16646
|
+
async activateMenu(menu) {
|
|
16647
|
+
var _a, _b, _c;
|
|
16648
|
+
const result = await ((_a = menu.action) === null || _a === void 0 ? void 0 : _a.call(menu, this.env));
|
|
16649
|
+
this.close();
|
|
16650
|
+
(_c = (_b = this.props).onMenuClicked) === null || _c === void 0 ? void 0 : _c.call(_b, { detail: result });
|
|
16700
16651
|
}
|
|
16701
|
-
|
|
16702
|
-
this.
|
|
16652
|
+
close() {
|
|
16653
|
+
this.closeSubMenu();
|
|
16654
|
+
this.props.onClose();
|
|
16703
16655
|
}
|
|
16704
|
-
|
|
16705
|
-
|
|
16706
|
-
|
|
16707
|
-
|
|
16656
|
+
/**
|
|
16657
|
+
* Return the number of pixels between the top of the menu
|
|
16658
|
+
* and the menu item at a given index.
|
|
16659
|
+
*/
|
|
16660
|
+
subMenuVerticalPosition(menuIndex) {
|
|
16661
|
+
const menusAbove = this.visibleMenuItems.slice(0, menuIndex);
|
|
16662
|
+
return this.position.y + this.getMenuItemsHeight(menusAbove) + MENU_VERTICAL_PADDING;
|
|
16708
16663
|
}
|
|
16709
|
-
|
|
16710
|
-
|
|
16711
|
-
|
|
16664
|
+
onExternalClick(ev) {
|
|
16665
|
+
// Don't close a root menu when clicked to open the submenus.
|
|
16666
|
+
const el = this.menuRef.el;
|
|
16667
|
+
if (el && getOpenedMenus().some((el) => isChildEvent(el, ev))) {
|
|
16668
|
+
return;
|
|
16712
16669
|
}
|
|
16713
|
-
|
|
16670
|
+
ev.closedMenuId = this.props.menuId;
|
|
16671
|
+
this.close();
|
|
16714
16672
|
}
|
|
16715
|
-
|
|
16716
|
-
|
|
16717
|
-
|
|
16718
|
-
this.env.model.dispatch("UPDATE_FILTER", {
|
|
16719
|
-
...position,
|
|
16720
|
-
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
16721
|
-
values: this.state.values.filter((val) => !val.checked).map((val) => val.string),
|
|
16722
|
-
});
|
|
16723
|
-
(_b = (_a = this.props).onClosed) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
16673
|
+
getMenuItemsHeight(menuItems) {
|
|
16674
|
+
const numberOfSeparators = menuItems.filter((m) => m.separator).length;
|
|
16675
|
+
return MENU_ITEM_HEIGHT * menuItems.length + MENU_SEPARATOR_HEIGHT * numberOfSeparators;
|
|
16724
16676
|
}
|
|
16725
|
-
|
|
16726
|
-
|
|
16727
|
-
(_b = (_a = this.props).onClosed) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
16677
|
+
getName(menu) {
|
|
16678
|
+
return menu.name(this.env);
|
|
16728
16679
|
}
|
|
16729
|
-
|
|
16730
|
-
|
|
16731
|
-
|
|
16732
|
-
|
|
16733
|
-
|
|
16734
|
-
|
|
16735
|
-
const index = displayedValues.findIndex((val) => val.string === this.state.selectedValue);
|
|
16736
|
-
selectedIndex = index === -1 ? undefined : index;
|
|
16737
|
-
}
|
|
16738
|
-
switch (ev.key) {
|
|
16739
|
-
case "ArrowDown":
|
|
16740
|
-
if (selectedIndex === undefined) {
|
|
16741
|
-
selectedIndex = 0;
|
|
16742
|
-
}
|
|
16743
|
-
else {
|
|
16744
|
-
selectedIndex = Math.min(selectedIndex + 1, displayedValues.length - 1);
|
|
16745
|
-
}
|
|
16746
|
-
ev.preventDefault();
|
|
16747
|
-
ev.stopPropagation();
|
|
16748
|
-
break;
|
|
16749
|
-
case "ArrowUp":
|
|
16750
|
-
if (selectedIndex === undefined) {
|
|
16751
|
-
selectedIndex = displayedValues.length - 1;
|
|
16752
|
-
}
|
|
16753
|
-
else {
|
|
16754
|
-
selectedIndex = Math.max(selectedIndex - 1, 0);
|
|
16755
|
-
}
|
|
16756
|
-
ev.preventDefault();
|
|
16757
|
-
ev.stopPropagation();
|
|
16758
|
-
break;
|
|
16759
|
-
case "Enter":
|
|
16760
|
-
if (selectedIndex !== undefined) {
|
|
16761
|
-
this.checkValue(displayedValues[selectedIndex]);
|
|
16762
|
-
}
|
|
16763
|
-
ev.stopPropagation();
|
|
16764
|
-
ev.preventDefault();
|
|
16765
|
-
break;
|
|
16766
|
-
}
|
|
16767
|
-
this.state.selectedValue =
|
|
16768
|
-
selectedIndex !== undefined ? displayedValues[selectedIndex].string : undefined;
|
|
16769
|
-
if (ev.key === "ArrowUp" || ev.key === "ArrowDown") {
|
|
16770
|
-
this.scrollListToSelectedValue(ev.key);
|
|
16680
|
+
isRoot(menu) {
|
|
16681
|
+
return !menu.action;
|
|
16682
|
+
}
|
|
16683
|
+
isEnabled(menu) {
|
|
16684
|
+
if (menu.isEnabled(this.env)) {
|
|
16685
|
+
return this.env.model.getters.isReadonly() ? menu.isReadonlyAllowed : true;
|
|
16771
16686
|
}
|
|
16687
|
+
return false;
|
|
16772
16688
|
}
|
|
16773
|
-
|
|
16774
|
-
this.
|
|
16689
|
+
onScroll(ev) {
|
|
16690
|
+
this.subMenu.scrollOffset = ev.target.scrollTop;
|
|
16775
16691
|
}
|
|
16776
|
-
|
|
16777
|
-
|
|
16778
|
-
|
|
16779
|
-
|
|
16780
|
-
|
|
16692
|
+
/**
|
|
16693
|
+
* If the given menu is not disabled, open it's submenu at the
|
|
16694
|
+
* correct position according to available surrounding space.
|
|
16695
|
+
*/
|
|
16696
|
+
openSubMenu(menu, menuIndex) {
|
|
16697
|
+
const y = this.subMenuVerticalPosition(menuIndex);
|
|
16698
|
+
this.subMenu.position = {
|
|
16699
|
+
x: this.position.x + this.props.depth * MENU_WIDTH,
|
|
16700
|
+
y: y - (this.subMenu.scrollOffset || 0),
|
|
16701
|
+
};
|
|
16702
|
+
this.subMenu.menuItems = menu.children(this.env);
|
|
16703
|
+
this.subMenu.isOpen = true;
|
|
16704
|
+
this.subMenu.parentMenu = menu;
|
|
16705
|
+
}
|
|
16706
|
+
isParentMenu(subMenu, menuItem) {
|
|
16707
|
+
var _a;
|
|
16708
|
+
return ((_a = subMenu.parentMenu) === null || _a === void 0 ? void 0 : _a.id) === menuItem.id;
|
|
16709
|
+
}
|
|
16710
|
+
closeSubMenu() {
|
|
16711
|
+
this.subMenu.isOpen = false;
|
|
16712
|
+
this.subMenu.parentMenu = undefined;
|
|
16713
|
+
}
|
|
16714
|
+
onClickMenu(menu, menuIndex) {
|
|
16715
|
+
if (this.isEnabled(menu)) {
|
|
16716
|
+
if (this.isRoot(menu)) {
|
|
16717
|
+
this.openSubMenu(menu, menuIndex);
|
|
16718
|
+
}
|
|
16719
|
+
else {
|
|
16720
|
+
this.activateMenu(menu);
|
|
16721
|
+
}
|
|
16781
16722
|
}
|
|
16782
16723
|
}
|
|
16783
|
-
|
|
16784
|
-
|
|
16785
|
-
|
|
16786
|
-
|
|
16787
|
-
|
|
16788
|
-
|
|
16724
|
+
onMouseOver(menu, position) {
|
|
16725
|
+
if (menu.isEnabled(this.env)) {
|
|
16726
|
+
if (this.isRoot(menu)) {
|
|
16727
|
+
this.openSubMenu(menu, position);
|
|
16728
|
+
}
|
|
16729
|
+
else {
|
|
16730
|
+
this.closeSubMenu();
|
|
16731
|
+
}
|
|
16789
16732
|
}
|
|
16790
|
-
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
16791
|
-
this.env.model.dispatch("SORT_CELLS", {
|
|
16792
|
-
sheetId,
|
|
16793
|
-
col: filterPosition.col,
|
|
16794
|
-
row: filterTable.contentZone.top,
|
|
16795
|
-
zone: filterTable.contentZone,
|
|
16796
|
-
sortDirection,
|
|
16797
|
-
sortOptions: { emptyCellAsZero: true, sortHeaders: true },
|
|
16798
|
-
});
|
|
16799
|
-
(_b = (_a = this.props).onClosed) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
16800
16733
|
}
|
|
16801
16734
|
}
|
|
16802
|
-
|
|
16803
|
-
|
|
16804
|
-
|
|
16805
|
-
|
|
16806
|
-
FilterMenu.props = {
|
|
16807
|
-
filterPosition: Object,
|
|
16808
|
-
onClosed: { type: Function, optional: true },
|
|
16735
|
+
Menu.template = "o-spreadsheet-Menu";
|
|
16736
|
+
Menu.components = { Menu, Popover };
|
|
16737
|
+
Menu.defaultProps = {
|
|
16738
|
+
depth: 1,
|
|
16809
16739
|
};
|
|
16810
|
-
|
|
16811
|
-
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
},
|
|
16740
|
+
Menu.props = {
|
|
16741
|
+
position: Object,
|
|
16742
|
+
menuItems: Array,
|
|
16743
|
+
depth: { type: Number, optional: true },
|
|
16744
|
+
maxHeight: { type: Number, optional: true },
|
|
16745
|
+
onClose: Function,
|
|
16746
|
+
onMenuClicked: { type: Function, optional: true },
|
|
16747
|
+
menuId: { type: String, optional: true },
|
|
16819
16748
|
};
|
|
16820
16749
|
|
|
16821
16750
|
const LINK_TOOLTIP_HEIGHT = 32;
|
|
@@ -17149,83 +17078,6 @@
|
|
|
17149
17078
|
const currenciesRegistry = new Registry();
|
|
17150
17079
|
|
|
17151
17080
|
class ImageFigure extends owl.Component {
|
|
17152
|
-
constructor() {
|
|
17153
|
-
super(...arguments);
|
|
17154
|
-
this.menuState = owl.useState({
|
|
17155
|
-
isOpen: false,
|
|
17156
|
-
position: null,
|
|
17157
|
-
});
|
|
17158
|
-
this.imageContainerRef = owl.useRef("o-image");
|
|
17159
|
-
this.menuButtonRef = owl.useRef("menuButton");
|
|
17160
|
-
this.menuButtonRect = useAbsoluteBoundingRect(this.menuButtonRef);
|
|
17161
|
-
this.position = useAbsoluteBoundingRect(this.imageContainerRef);
|
|
17162
|
-
this.menuItems = createMenu([
|
|
17163
|
-
{
|
|
17164
|
-
id: "copy",
|
|
17165
|
-
name: _lt("Copy"),
|
|
17166
|
-
description: "Ctrl+C",
|
|
17167
|
-
action: async () => {
|
|
17168
|
-
this.env.model.dispatch("SELECT_FIGURE", { id: this.figureId });
|
|
17169
|
-
this.env.model.dispatch("COPY");
|
|
17170
|
-
await this.env.clipboard.write(this.env.model.getters.getClipboardContent());
|
|
17171
|
-
},
|
|
17172
|
-
},
|
|
17173
|
-
{
|
|
17174
|
-
id: "cut",
|
|
17175
|
-
name: _lt("Cut"),
|
|
17176
|
-
description: "Ctrl+X",
|
|
17177
|
-
action: async () => {
|
|
17178
|
-
this.env.model.dispatch("SELECT_FIGURE", { id: this.figureId });
|
|
17179
|
-
this.env.model.dispatch("CUT");
|
|
17180
|
-
await this.env.clipboard.write(this.env.model.getters.getClipboardContent());
|
|
17181
|
-
},
|
|
17182
|
-
},
|
|
17183
|
-
{
|
|
17184
|
-
id: "reset_size",
|
|
17185
|
-
name: _lt("Reset size"),
|
|
17186
|
-
action: () => {
|
|
17187
|
-
const size = this.env.model.getters.getImage(this.env.model.getters.getActiveSheetId(), this.figureId).size;
|
|
17188
|
-
const { height, width } = getMaxFigureSize(this.env.model.getters, size);
|
|
17189
|
-
this.env.model.dispatch("UPDATE_FIGURE", {
|
|
17190
|
-
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
17191
|
-
id: this.figureId,
|
|
17192
|
-
height,
|
|
17193
|
-
width,
|
|
17194
|
-
});
|
|
17195
|
-
},
|
|
17196
|
-
},
|
|
17197
|
-
{
|
|
17198
|
-
id: "delete",
|
|
17199
|
-
name: _lt("Delete image"),
|
|
17200
|
-
description: "delete",
|
|
17201
|
-
action: () => {
|
|
17202
|
-
this.env.model.dispatch("DELETE_FIGURE", {
|
|
17203
|
-
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
17204
|
-
id: this.figureId,
|
|
17205
|
-
});
|
|
17206
|
-
},
|
|
17207
|
-
},
|
|
17208
|
-
]);
|
|
17209
|
-
}
|
|
17210
|
-
onContextMenu(ev) {
|
|
17211
|
-
const position = {
|
|
17212
|
-
x: this.position.x + ev.offsetX,
|
|
17213
|
-
y: this.position.y + ev.offsetY,
|
|
17214
|
-
};
|
|
17215
|
-
this.openContextMenu(position);
|
|
17216
|
-
}
|
|
17217
|
-
showMenu() {
|
|
17218
|
-
const { x, y, width } = this.menuButtonRect;
|
|
17219
|
-
const menuPosition = {
|
|
17220
|
-
x: x >= MENU_WIDTH ? x - MENU_WIDTH : x + width,
|
|
17221
|
-
y: y,
|
|
17222
|
-
};
|
|
17223
|
-
this.openContextMenu(menuPosition);
|
|
17224
|
-
}
|
|
17225
|
-
openContextMenu(position) {
|
|
17226
|
-
this.menuState.isOpen = true;
|
|
17227
|
-
this.menuState.position = position;
|
|
17228
|
-
}
|
|
17229
17081
|
// ---------------------------------------------------------------------------
|
|
17230
17082
|
// Getters
|
|
17231
17083
|
// ---------------------------------------------------------------------------
|
|
@@ -17233,25 +17085,109 @@
|
|
|
17233
17085
|
return this.props.figure.id;
|
|
17234
17086
|
}
|
|
17235
17087
|
get getImagePath() {
|
|
17236
|
-
return this.env.model.getters.
|
|
17237
|
-
.path;
|
|
17088
|
+
return this.env.model.getters.getImagePath(this.figureId);
|
|
17238
17089
|
}
|
|
17239
17090
|
}
|
|
17240
17091
|
ImageFigure.template = "o-spreadsheet-ImageFigure";
|
|
17241
|
-
ImageFigure.components = {
|
|
17092
|
+
ImageFigure.components = {};
|
|
17242
17093
|
ImageFigure.props = {
|
|
17243
17094
|
figure: Object,
|
|
17244
17095
|
onFigureDeleted: Function,
|
|
17245
17096
|
};
|
|
17246
17097
|
|
|
17247
17098
|
const figureRegistry = new Registry();
|
|
17248
|
-
figureRegistry.add("chart", {
|
|
17099
|
+
figureRegistry.add("chart", {
|
|
17100
|
+
Component: ChartFigure,
|
|
17101
|
+
SidePanelComponent: "ChartPanel",
|
|
17102
|
+
menuBuilder: getChartMenu,
|
|
17103
|
+
});
|
|
17249
17104
|
figureRegistry.add("image", {
|
|
17250
17105
|
Component: ImageFigure,
|
|
17251
17106
|
keepRatio: true,
|
|
17252
17107
|
minFigSize: 20,
|
|
17253
17108
|
borderWidth: 0,
|
|
17254
|
-
|
|
17109
|
+
menuBuilder: getImageMenuRegistry,
|
|
17110
|
+
});
|
|
17111
|
+
function getChartMenu(figureId, onFigureDeleted, env) {
|
|
17112
|
+
const menuItemSpecs = [
|
|
17113
|
+
{
|
|
17114
|
+
id: "edit",
|
|
17115
|
+
name: _lt("Edit"),
|
|
17116
|
+
sequence: 1,
|
|
17117
|
+
action: () => {
|
|
17118
|
+
env.model.dispatch("SELECT_FIGURE", { id: figureId });
|
|
17119
|
+
env.openSidePanel("ChartPanel");
|
|
17120
|
+
},
|
|
17121
|
+
},
|
|
17122
|
+
getCopyMenuItem(figureId, env),
|
|
17123
|
+
getCutMenuItem(figureId, env),
|
|
17124
|
+
getDeleteMenuItem(figureId, onFigureDeleted, env),
|
|
17125
|
+
];
|
|
17126
|
+
return createMenu(menuItemSpecs);
|
|
17127
|
+
}
|
|
17128
|
+
function getImageMenuRegistry(figureId, onFigureDeleted, env) {
|
|
17129
|
+
const menuItemSpecs = [
|
|
17130
|
+
getCopyMenuItem(figureId, env),
|
|
17131
|
+
getCutMenuItem(figureId, env),
|
|
17132
|
+
{
|
|
17133
|
+
id: "reset_size",
|
|
17134
|
+
name: _lt("Reset size"),
|
|
17135
|
+
sequence: 4,
|
|
17136
|
+
action: () => {
|
|
17137
|
+
const size = env.model.getters.getImageSize(figureId);
|
|
17138
|
+
const { height, width } = getMaxFigureSize(env.model.getters, size);
|
|
17139
|
+
env.model.dispatch("UPDATE_FIGURE", {
|
|
17140
|
+
sheetId: env.model.getters.getActiveSheetId(),
|
|
17141
|
+
id: figureId,
|
|
17142
|
+
height,
|
|
17143
|
+
width,
|
|
17144
|
+
});
|
|
17145
|
+
},
|
|
17146
|
+
},
|
|
17147
|
+
getDeleteMenuItem(figureId, onFigureDeleted, env),
|
|
17148
|
+
];
|
|
17149
|
+
return createMenu(menuItemSpecs);
|
|
17150
|
+
}
|
|
17151
|
+
function getCopyMenuItem(figureId, env) {
|
|
17152
|
+
return {
|
|
17153
|
+
id: "copy",
|
|
17154
|
+
name: _lt("Copy"),
|
|
17155
|
+
sequence: 2,
|
|
17156
|
+
description: "Ctrl+C",
|
|
17157
|
+
action: async () => {
|
|
17158
|
+
env.model.dispatch("SELECT_FIGURE", { id: figureId });
|
|
17159
|
+
env.model.dispatch("COPY");
|
|
17160
|
+
await env.clipboard.write(env.model.getters.getClipboardContent());
|
|
17161
|
+
},
|
|
17162
|
+
};
|
|
17163
|
+
}
|
|
17164
|
+
function getCutMenuItem(figureId, env) {
|
|
17165
|
+
return {
|
|
17166
|
+
id: "cut",
|
|
17167
|
+
name: _lt("Cut"),
|
|
17168
|
+
sequence: 3,
|
|
17169
|
+
description: "Ctrl+X",
|
|
17170
|
+
action: async () => {
|
|
17171
|
+
env.model.dispatch("SELECT_FIGURE", { id: figureId });
|
|
17172
|
+
env.model.dispatch("CUT");
|
|
17173
|
+
await env.clipboard.write(env.model.getters.getClipboardContent());
|
|
17174
|
+
},
|
|
17175
|
+
};
|
|
17176
|
+
}
|
|
17177
|
+
function getDeleteMenuItem(figureId, onFigureDeleted, env) {
|
|
17178
|
+
return {
|
|
17179
|
+
id: "delete",
|
|
17180
|
+
name: _lt("Delete"),
|
|
17181
|
+
sequence: 10,
|
|
17182
|
+
action: () => {
|
|
17183
|
+
env.model.dispatch("DELETE_FIGURE", {
|
|
17184
|
+
sheetId: env.model.getters.getActiveSheetId(),
|
|
17185
|
+
id: figureId,
|
|
17186
|
+
});
|
|
17187
|
+
onFigureDeleted();
|
|
17188
|
+
},
|
|
17189
|
+
};
|
|
17190
|
+
}
|
|
17255
17191
|
|
|
17256
17192
|
const inverseCommandRegistry = new Registry()
|
|
17257
17193
|
.add("ADD_COLUMNS_ROWS", inverseAddColumnsRows)
|
|
@@ -18039,9 +17975,9 @@
|
|
|
18039
17975
|
const ranges = existingSelectionRange.length
|
|
18040
17976
|
? existingSelectionRange
|
|
18041
17977
|
: this.props.ranges
|
|
18042
|
-
? this.props.ranges.map((xc,
|
|
17978
|
+
? this.props.ranges.map((xc, id) => ({
|
|
18043
17979
|
xc,
|
|
18044
|
-
id
|
|
17980
|
+
id,
|
|
18045
17981
|
isFocused: false,
|
|
18046
17982
|
}))
|
|
18047
17983
|
: [];
|
|
@@ -18107,6 +18043,7 @@
|
|
|
18107
18043
|
else if (ev.key === "Enter") {
|
|
18108
18044
|
const target = ev.target;
|
|
18109
18045
|
target.blur();
|
|
18046
|
+
this.confirm();
|
|
18110
18047
|
}
|
|
18111
18048
|
}
|
|
18112
18049
|
focus(rangeId) {
|
|
@@ -18135,7 +18072,7 @@
|
|
|
18135
18072
|
});
|
|
18136
18073
|
this.triggerChange();
|
|
18137
18074
|
}
|
|
18138
|
-
|
|
18075
|
+
confirm() {
|
|
18139
18076
|
var _a, _b;
|
|
18140
18077
|
this.env.model.dispatch("UNFOCUS_SELECTION_INPUT");
|
|
18141
18078
|
const ranges = this.env.model.getters.getSelectionInputValue(this.id);
|
|
@@ -18230,7 +18167,6 @@
|
|
|
18230
18167
|
LineBarPieConfigPanel.template = "o-spreadsheet-LineBarPieConfigPanel";
|
|
18231
18168
|
LineBarPieConfigPanel.components = { SelectionInput };
|
|
18232
18169
|
LineBarPieConfigPanel.props = {
|
|
18233
|
-
sheetId: String,
|
|
18234
18170
|
figureId: String,
|
|
18235
18171
|
definition: Object,
|
|
18236
18172
|
updateChart: Function,
|
|
@@ -18263,9 +18199,6 @@
|
|
|
18263
18199
|
const GRADIENT_HEIGHT = PICKER_WIDTH - 50;
|
|
18264
18200
|
css /* scss */ `
|
|
18265
18201
|
.o-color-picker {
|
|
18266
|
-
position: absolute;
|
|
18267
|
-
top: calc(100% + 5px);
|
|
18268
|
-
z-index: ${ComponentsImportance.ColorPicker};
|
|
18269
18202
|
padding: ${PICKER_PADDING}px 0px;
|
|
18270
18203
|
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
|
|
18271
18204
|
background-color: white;
|
|
@@ -18380,15 +18313,6 @@
|
|
|
18380
18313
|
width: 100%;
|
|
18381
18314
|
}
|
|
18382
18315
|
}
|
|
18383
|
-
&.right {
|
|
18384
|
-
left: 0;
|
|
18385
|
-
}
|
|
18386
|
-
&.left {
|
|
18387
|
-
right: 0;
|
|
18388
|
-
}
|
|
18389
|
-
&.center {
|
|
18390
|
-
left: calc(50% - ${PICKER_WIDTH / 2}px);
|
|
18391
|
-
}
|
|
18392
18316
|
}
|
|
18393
18317
|
.o-magnifier-glass {
|
|
18394
18318
|
position: absolute;
|
|
@@ -18423,18 +18347,22 @@
|
|
|
18423
18347
|
});
|
|
18424
18348
|
}
|
|
18425
18349
|
get colorPickerStyle() {
|
|
18426
|
-
if (this.props.maxHeight
|
|
18427
|
-
return "";
|
|
18428
|
-
if (this.props.maxHeight <= 0) {
|
|
18350
|
+
if (this.props.maxHeight !== undefined && this.props.maxHeight <= 0) {
|
|
18429
18351
|
return cssPropertiesToCss({ display: "none" });
|
|
18430
18352
|
}
|
|
18431
|
-
return
|
|
18432
|
-
|
|
18433
|
-
|
|
18353
|
+
return "";
|
|
18354
|
+
}
|
|
18355
|
+
get popoverProps() {
|
|
18356
|
+
return {
|
|
18357
|
+
anchorRect: this.props.anchorRect,
|
|
18358
|
+
maxHeight: this.props.maxHeight,
|
|
18359
|
+
positioning: "BottomLeft",
|
|
18360
|
+
verticalOffset: 0,
|
|
18361
|
+
};
|
|
18434
18362
|
}
|
|
18435
18363
|
onColorClick(color) {
|
|
18436
18364
|
if (color) {
|
|
18437
|
-
this.props.onColorPicked(color);
|
|
18365
|
+
this.props.onColorPicked(toHex(color));
|
|
18438
18366
|
}
|
|
18439
18367
|
}
|
|
18440
18368
|
getCheckMarkColor() {
|
|
@@ -18449,8 +18377,10 @@
|
|
|
18449
18377
|
this.state.isCurrentColorInvalid = true;
|
|
18450
18378
|
return;
|
|
18451
18379
|
}
|
|
18380
|
+
const color = toHex(this.state.currentColor);
|
|
18452
18381
|
this.state.isCurrentColorInvalid = false;
|
|
18453
|
-
this.props.onColorPicked(
|
|
18382
|
+
this.props.onColorPicked(color);
|
|
18383
|
+
this.state.currentColor = color;
|
|
18454
18384
|
}
|
|
18455
18385
|
toggleColorPicker() {
|
|
18456
18386
|
this.state.showGradient = !this.state.showGradient;
|
|
@@ -18485,11 +18415,12 @@
|
|
|
18485
18415
|
ColorPicker.defaultProps = {
|
|
18486
18416
|
currentColor: "", //TODO Change it to false instead of empty string
|
|
18487
18417
|
};
|
|
18418
|
+
ColorPicker.components = { Popover };
|
|
18488
18419
|
ColorPicker.props = {
|
|
18489
|
-
dropdownDirection: { type: String, optional: true },
|
|
18490
18420
|
onColorPicked: Function,
|
|
18491
18421
|
currentColor: { type: String, optional: true },
|
|
18492
18422
|
maxHeight: { type: Number, optional: true },
|
|
18423
|
+
anchorRect: Object,
|
|
18493
18424
|
};
|
|
18494
18425
|
|
|
18495
18426
|
css /* scss */ `
|
|
@@ -18525,11 +18456,25 @@
|
|
|
18525
18456
|
}
|
|
18526
18457
|
`;
|
|
18527
18458
|
class ColorPickerWidget extends owl.Component {
|
|
18459
|
+
constructor() {
|
|
18460
|
+
super(...arguments);
|
|
18461
|
+
this.colorPickerButtonRef = owl.useRef("colorPickerButton");
|
|
18462
|
+
}
|
|
18528
18463
|
get iconStyle() {
|
|
18529
18464
|
return this.props.currentColor
|
|
18530
18465
|
? `border-color: ${this.props.currentColor}`
|
|
18531
18466
|
: "border-bottom-style: hidden";
|
|
18532
18467
|
}
|
|
18468
|
+
get colorPickerAnchorRect() {
|
|
18469
|
+
const button = this.colorPickerButtonRef.el;
|
|
18470
|
+
const buttonRect = button.getBoundingClientRect();
|
|
18471
|
+
return {
|
|
18472
|
+
x: buttonRect.x,
|
|
18473
|
+
y: buttonRect.y,
|
|
18474
|
+
width: buttonRect.width,
|
|
18475
|
+
height: buttonRect.height,
|
|
18476
|
+
};
|
|
18477
|
+
}
|
|
18533
18478
|
}
|
|
18534
18479
|
ColorPickerWidget.template = "o-spreadsheet-ColorPickerWidget";
|
|
18535
18480
|
ColorPickerWidget.components = { ColorPicker };
|
|
@@ -18539,7 +18484,6 @@
|
|
|
18539
18484
|
showColorPicker: Boolean,
|
|
18540
18485
|
onColorPicked: Function,
|
|
18541
18486
|
icon: String,
|
|
18542
|
-
dropdownDirection: { type: String, optional: true },
|
|
18543
18487
|
title: { type: String, optional: true },
|
|
18544
18488
|
disabled: { type: Boolean, optional: true },
|
|
18545
18489
|
dropdownMaxHeight: { type: Number, optional: true },
|
|
@@ -18619,7 +18563,6 @@
|
|
|
18619
18563
|
GaugeChartConfigPanel.template = "o-spreadsheet-GaugeChartConfigPanel";
|
|
18620
18564
|
GaugeChartConfigPanel.components = { SelectionInput };
|
|
18621
18565
|
GaugeChartConfigPanel.props = {
|
|
18622
|
-
sheetId: String,
|
|
18623
18566
|
figureId: String,
|
|
18624
18567
|
definition: Object,
|
|
18625
18568
|
updateChart: Function,
|
|
@@ -18766,7 +18709,7 @@
|
|
|
18766
18709
|
|
|
18767
18710
|
class LineConfigPanel extends LineBarPieConfigPanel {
|
|
18768
18711
|
get canTreatLabelsAsText() {
|
|
18769
|
-
const chart = this.env.model.getters.getChart(this.props.
|
|
18712
|
+
const chart = this.env.model.getters.getChart(this.props.figureId);
|
|
18770
18713
|
if (chart && chart instanceof LineChart) {
|
|
18771
18714
|
return canChartParseLabels(chart.labelRange, this.env.model.getters);
|
|
18772
18715
|
}
|
|
@@ -18843,7 +18786,6 @@
|
|
|
18843
18786
|
ScorecardChartConfigPanel.template = "o-spreadsheet-ScorecardChartConfigPanel";
|
|
18844
18787
|
ScorecardChartConfigPanel.components = { SelectionInput };
|
|
18845
18788
|
ScorecardChartConfigPanel.props = {
|
|
18846
|
-
sheetId: String,
|
|
18847
18789
|
figureId: String,
|
|
18848
18790
|
definition: Object,
|
|
18849
18791
|
updateChart: Function,
|
|
@@ -18979,7 +18921,7 @@
|
|
|
18979
18921
|
else {
|
|
18980
18922
|
this.shouldUpdateChart = true;
|
|
18981
18923
|
}
|
|
18982
|
-
if (!this.env.model.getters.isChartDefined(this.
|
|
18924
|
+
if (!this.env.model.getters.isChartDefined(this.figureId)) {
|
|
18983
18925
|
this.props.onCloseSidePanel();
|
|
18984
18926
|
return;
|
|
18985
18927
|
}
|
|
@@ -19000,7 +18942,7 @@
|
|
|
19000
18942
|
});
|
|
19001
18943
|
}
|
|
19002
18944
|
onTypeChange(type) {
|
|
19003
|
-
const context = this.env.model.getters.getContextCreationChart(this.
|
|
18945
|
+
const context = this.env.model.getters.getContextCreationChart(this.figureId);
|
|
19004
18946
|
if (!context) {
|
|
19005
18947
|
throw new Error("Chart not defined.");
|
|
19006
18948
|
}
|
|
@@ -19012,7 +18954,7 @@
|
|
|
19012
18954
|
});
|
|
19013
18955
|
}
|
|
19014
18956
|
get chartPanel() {
|
|
19015
|
-
const type = this.env.model.getters.getChartType(this.
|
|
18957
|
+
const type = this.env.model.getters.getChartType(this.figureId);
|
|
19016
18958
|
if (!type) {
|
|
19017
18959
|
throw new Error("Chart not defined.");
|
|
19018
18960
|
}
|
|
@@ -19022,8 +18964,8 @@
|
|
|
19022
18964
|
}
|
|
19023
18965
|
return chartPanel;
|
|
19024
18966
|
}
|
|
19025
|
-
getChartDefinition() {
|
|
19026
|
-
return this.env.model.getters.getChartDefinition(
|
|
18967
|
+
getChartDefinition(figureId = this.figureId) {
|
|
18968
|
+
return this.env.model.getters.getChartDefinition(figureId);
|
|
19027
18969
|
}
|
|
19028
18970
|
get chartTypes() {
|
|
19029
18971
|
return getChartTypes();
|
|
@@ -20175,9 +20117,8 @@
|
|
|
20175
20117
|
|
|
20176
20118
|
.o-figure-menu {
|
|
20177
20119
|
right: 0px;
|
|
20120
|
+
top: 0px;
|
|
20178
20121
|
display: none;
|
|
20179
|
-
position: absolute;
|
|
20180
|
-
padding: 5px;
|
|
20181
20122
|
}
|
|
20182
20123
|
|
|
20183
20124
|
.o-figure-menu-item {
|
|
@@ -20195,7 +20136,10 @@
|
|
|
20195
20136
|
class FigureComponent extends owl.Component {
|
|
20196
20137
|
constructor() {
|
|
20197
20138
|
super(...arguments);
|
|
20139
|
+
this.menuState = owl.useState({ isOpen: false, position: null, menuItems: [] });
|
|
20198
20140
|
this.figureRef = owl.useRef("figure");
|
|
20141
|
+
this.menuButtonRef = owl.useRef("menuButton");
|
|
20142
|
+
this.menuButtonRect = useAbsoluteBoundingRect(this.menuButtonRef);
|
|
20199
20143
|
}
|
|
20200
20144
|
get isSelected() {
|
|
20201
20145
|
return this.env.model.getters.getSelectedFigureId() === this.props.figure.id;
|
|
@@ -20303,9 +20247,33 @@
|
|
|
20303
20247
|
break;
|
|
20304
20248
|
}
|
|
20305
20249
|
}
|
|
20250
|
+
onContextMenu(ev) {
|
|
20251
|
+
if (this.env.isDashboard())
|
|
20252
|
+
return;
|
|
20253
|
+
const position = {
|
|
20254
|
+
x: ev.clientX,
|
|
20255
|
+
y: ev.clientY,
|
|
20256
|
+
};
|
|
20257
|
+
this.openContextMenu(position);
|
|
20258
|
+
}
|
|
20259
|
+
showMenu() {
|
|
20260
|
+
const { x, y, width } = this.menuButtonRect;
|
|
20261
|
+
const menuPosition = {
|
|
20262
|
+
x: x >= MENU_WIDTH ? x - MENU_WIDTH : x + width,
|
|
20263
|
+
y: y,
|
|
20264
|
+
};
|
|
20265
|
+
this.openContextMenu(menuPosition);
|
|
20266
|
+
}
|
|
20267
|
+
openContextMenu(position) {
|
|
20268
|
+
this.menuState.isOpen = true;
|
|
20269
|
+
this.menuState.position = position;
|
|
20270
|
+
this.menuState.menuItems = figureRegistry
|
|
20271
|
+
.get(this.props.figure.tag)
|
|
20272
|
+
.menuBuilder(this.props.figure.id, this.props.onFigureDeleted, this.env);
|
|
20273
|
+
}
|
|
20306
20274
|
}
|
|
20307
20275
|
FigureComponent.template = "o-spreadsheet-FigureComponent";
|
|
20308
|
-
FigureComponent.components = {};
|
|
20276
|
+
FigureComponent.components = { Menu };
|
|
20309
20277
|
FigureComponent.defaultProps = {
|
|
20310
20278
|
onFigureDeleted: () => { },
|
|
20311
20279
|
onMouseDown: () => { },
|
|
@@ -22390,6 +22358,7 @@
|
|
|
22390
22358
|
theme: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",
|
|
22391
22359
|
table: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
|
|
22392
22360
|
hyperlink: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
|
22361
|
+
image: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
22393
22362
|
};
|
|
22394
22363
|
const RELATIONSHIP_NSR = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
22395
22364
|
const HEIGHT_FACTOR = 0.75; // 100px => 75 u
|
|
@@ -23413,12 +23382,8 @@
|
|
|
23413
23382
|
return "n";
|
|
23414
23383
|
}
|
|
23415
23384
|
}
|
|
23416
|
-
/**
|
|
23417
|
-
* For some reason, Excel will only take the devicePixelRatio (i.e. interface scale on Windows desktop)
|
|
23418
|
-
* into account for the height.
|
|
23419
|
-
*/
|
|
23420
23385
|
function convertHeightToExcel(height) {
|
|
23421
|
-
return Math.round(HEIGHT_FACTOR * height *
|
|
23386
|
+
return Math.round(HEIGHT_FACTOR * height * 100) / 100;
|
|
23422
23387
|
}
|
|
23423
23388
|
function convertWidthToExcel(width) {
|
|
23424
23389
|
return Math.round(WIDTH_FACTOR * width * 100) / 100;
|
|
@@ -23560,6 +23525,19 @@
|
|
|
23560
23525
|
}
|
|
23561
23526
|
return xlsxId + 1;
|
|
23562
23527
|
}
|
|
23528
|
+
const imageIds = [];
|
|
23529
|
+
/**
|
|
23530
|
+
* Convert a image o-spreadsheet id to a xlsx id which
|
|
23531
|
+
* are unsigned integers (starting from 1).
|
|
23532
|
+
*/
|
|
23533
|
+
function convertImageId(imageId) {
|
|
23534
|
+
const xlsxId = imageIds.findIndex((id) => id === imageId);
|
|
23535
|
+
if (xlsxId === -1) {
|
|
23536
|
+
imageIds.push(imageId);
|
|
23537
|
+
return imageIds.length;
|
|
23538
|
+
}
|
|
23539
|
+
return xlsxId + 1;
|
|
23540
|
+
}
|
|
23563
23541
|
/**
|
|
23564
23542
|
* Convert a value expressed in dot to EMU.
|
|
23565
23543
|
* EMU = English Metrical Unit
|
|
@@ -25895,13 +25873,7 @@
|
|
|
25895
25873
|
data = migrate(data);
|
|
25896
25874
|
}
|
|
25897
25875
|
}
|
|
25898
|
-
|
|
25899
|
-
// sensible default values
|
|
25900
|
-
data = Object.assign(createEmptyWorkbookData(), data, { version: CURRENT_VERSION });
|
|
25901
|
-
data.sheets = data.sheets.map((s, i) => Object.assign(createEmptySheet(`Sheet${i + 1}`, `Sheet${i + 1}`), s));
|
|
25902
|
-
if (data.sheets.length === 0) {
|
|
25903
|
-
data.sheets.push(createEmptySheet(INITIAL_SHEET_ID, "Sheet1"));
|
|
25904
|
-
}
|
|
25876
|
+
data = repairData(data);
|
|
25905
25877
|
return data;
|
|
25906
25878
|
}
|
|
25907
25879
|
function migrate(data) {
|
|
@@ -26139,6 +26111,48 @@
|
|
|
26139
26111
|
},
|
|
26140
26112
|
},
|
|
26141
26113
|
];
|
|
26114
|
+
/**
|
|
26115
|
+
* This function is used to repair faulty data independently of the migration.
|
|
26116
|
+
*/
|
|
26117
|
+
function repairData(data) {
|
|
26118
|
+
data = forceUnicityOfFigure(data);
|
|
26119
|
+
data = setDefaults(data);
|
|
26120
|
+
return data;
|
|
26121
|
+
}
|
|
26122
|
+
/**
|
|
26123
|
+
* Force the unicity of figure ids accross sheets
|
|
26124
|
+
*/
|
|
26125
|
+
function forceUnicityOfFigure(data) {
|
|
26126
|
+
if (data.uniqueFigureIds) {
|
|
26127
|
+
return data;
|
|
26128
|
+
}
|
|
26129
|
+
const figureIds = new Set();
|
|
26130
|
+
const uuidGenerator = new UuidGenerator();
|
|
26131
|
+
for (const sheet of data.sheets || []) {
|
|
26132
|
+
for (const figure of sheet.figures || []) {
|
|
26133
|
+
if (figureIds.has(figure.id)) {
|
|
26134
|
+
figure.id += uuidGenerator.uuidv4();
|
|
26135
|
+
}
|
|
26136
|
+
figureIds.add(figure.id);
|
|
26137
|
+
}
|
|
26138
|
+
}
|
|
26139
|
+
data.uniqueFigureIds = true;
|
|
26140
|
+
return data;
|
|
26141
|
+
}
|
|
26142
|
+
/**
|
|
26143
|
+
* sanity check: try to fix missing fields/corrupted state by providing
|
|
26144
|
+
* sensible default values
|
|
26145
|
+
*/
|
|
26146
|
+
function setDefaults(data) {
|
|
26147
|
+
data = Object.assign(createEmptyWorkbookData(), data, { version: CURRENT_VERSION });
|
|
26148
|
+
data.sheets = data.sheets
|
|
26149
|
+
? data.sheets.map((s, i) => Object.assign(createEmptySheet(`Sheet${i + 1}`, `Sheet${i + 1}`), s))
|
|
26150
|
+
: [];
|
|
26151
|
+
if (data.sheets.length === 0) {
|
|
26152
|
+
data.sheets.push(createEmptySheet(INITIAL_SHEET_ID, "Sheet1"));
|
|
26153
|
+
}
|
|
26154
|
+
return data;
|
|
26155
|
+
}
|
|
26142
26156
|
/**
|
|
26143
26157
|
* The goal of this function is to repair corrupted/wrong initial messages caused by
|
|
26144
26158
|
* a bug.
|
|
@@ -26277,6 +26291,7 @@
|
|
|
26277
26291
|
formats: {},
|
|
26278
26292
|
borders: {},
|
|
26279
26293
|
revisionId: DEFAULT_REVISION_ID,
|
|
26294
|
+
uniqueFigureIds: true,
|
|
26280
26295
|
};
|
|
26281
26296
|
return data;
|
|
26282
26297
|
}
|
|
@@ -26284,6 +26299,7 @@
|
|
|
26284
26299
|
return {
|
|
26285
26300
|
...createEmptySheet(sheetId, name),
|
|
26286
26301
|
charts: [],
|
|
26302
|
+
images: [],
|
|
26287
26303
|
};
|
|
26288
26304
|
}
|
|
26289
26305
|
function createEmptyExcelWorkbookData() {
|
|
@@ -28056,10 +28072,8 @@
|
|
|
28056
28072
|
this.validateChartDefinition = (cmd) => validateChartDefinition(this, cmd.definition);
|
|
28057
28073
|
}
|
|
28058
28074
|
adaptRanges(applyChange) {
|
|
28059
|
-
for (const
|
|
28060
|
-
|
|
28061
|
-
this.history.update("charts", sheetId, chartId, chart === null || chart === void 0 ? void 0 : chart.updateRanges(applyChange));
|
|
28062
|
-
}
|
|
28075
|
+
for (const [chartId, chart] of Object.entries(this.charts)) {
|
|
28076
|
+
this.history.update("charts", chartId, chart === null || chart === void 0 ? void 0 : chart.updateRanges(applyChange));
|
|
28063
28077
|
}
|
|
28064
28078
|
}
|
|
28065
28079
|
// ---------------------------------------------------------------------------
|
|
@@ -28070,20 +28084,20 @@
|
|
|
28070
28084
|
case "CREATE_CHART":
|
|
28071
28085
|
return this.checkValidations(cmd, this.chainValidations(this.validateChartDefinition, this.checkChartDuplicate));
|
|
28072
28086
|
case "UPDATE_CHART":
|
|
28073
|
-
return this.
|
|
28087
|
+
return this.checkValidations(cmd, this.chainValidations(this.validateChartDefinition, this.checkChartExists));
|
|
28074
28088
|
default:
|
|
28075
28089
|
return 0 /* CommandResult.Success */;
|
|
28076
28090
|
}
|
|
28077
28091
|
}
|
|
28078
28092
|
handle(cmd) {
|
|
28079
|
-
var _a
|
|
28093
|
+
var _a;
|
|
28080
28094
|
switch (cmd.type) {
|
|
28081
28095
|
case "CREATE_CHART":
|
|
28082
28096
|
this.addFigure(cmd.id, cmd.sheetId, cmd.position, cmd.size);
|
|
28083
|
-
this.addChart(cmd.id, cmd.
|
|
28097
|
+
this.addChart(cmd.id, cmd.definition);
|
|
28084
28098
|
break;
|
|
28085
28099
|
case "UPDATE_CHART": {
|
|
28086
|
-
this.addChart(cmd.id, cmd.
|
|
28100
|
+
this.addChart(cmd.id, cmd.definition);
|
|
28087
28101
|
break;
|
|
28088
28102
|
}
|
|
28089
28103
|
case "DUPLICATE_SHEET": {
|
|
@@ -28092,7 +28106,7 @@
|
|
|
28092
28106
|
if (fig.tag === "chart") {
|
|
28093
28107
|
const figureIdBase = fig.id.split(FIGURE_ID_SPLITTER).pop();
|
|
28094
28108
|
const duplicatedFigureId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${figureIdBase}`;
|
|
28095
|
-
const chart = (
|
|
28109
|
+
const chart = (_a = this.charts[fig.id]) === null || _a === void 0 ? void 0 : _a.copyForSheetId(cmd.sheetIdTo);
|
|
28096
28110
|
if (chart) {
|
|
28097
28111
|
this.dispatch("CREATE_CHART", {
|
|
28098
28112
|
id: duplicatedFigureId,
|
|
@@ -28107,41 +28121,44 @@
|
|
|
28107
28121
|
break;
|
|
28108
28122
|
}
|
|
28109
28123
|
case "DELETE_FIGURE":
|
|
28110
|
-
this.history.update("charts", cmd.
|
|
28124
|
+
this.history.update("charts", cmd.id, undefined);
|
|
28111
28125
|
break;
|
|
28112
28126
|
case "DELETE_SHEET":
|
|
28113
|
-
this.
|
|
28127
|
+
for (let id of this.getChartIds(cmd.sheetId)) {
|
|
28128
|
+
this.history.update("charts", id, undefined);
|
|
28129
|
+
}
|
|
28114
28130
|
break;
|
|
28115
28131
|
}
|
|
28116
28132
|
}
|
|
28117
28133
|
// ---------------------------------------------------------------------------
|
|
28118
28134
|
// Getters
|
|
28119
28135
|
// ---------------------------------------------------------------------------
|
|
28120
|
-
getContextCreationChart(
|
|
28121
|
-
var _a, _b;
|
|
28122
|
-
return (_b = (_a = this.charts[sheetId]) === null || _a === void 0 ? void 0 : _a[figureId]) === null || _b === void 0 ? void 0 : _b.getContextCreation();
|
|
28123
|
-
}
|
|
28124
|
-
getChart(sheetId, figureId) {
|
|
28136
|
+
getContextCreationChart(figureId) {
|
|
28125
28137
|
var _a;
|
|
28126
|
-
return (_a = this.charts[
|
|
28138
|
+
return (_a = this.charts[figureId]) === null || _a === void 0 ? void 0 : _a.getContextCreation();
|
|
28127
28139
|
}
|
|
28128
|
-
|
|
28129
|
-
|
|
28130
|
-
|
|
28140
|
+
getChart(figureId) {
|
|
28141
|
+
return this.charts[figureId];
|
|
28142
|
+
}
|
|
28143
|
+
getChartType(figureId) {
|
|
28144
|
+
var _a;
|
|
28145
|
+
const type = (_a = this.charts[figureId]) === null || _a === void 0 ? void 0 : _a.type;
|
|
28131
28146
|
if (!type) {
|
|
28132
28147
|
throw new Error("Chart not defined.");
|
|
28133
28148
|
}
|
|
28134
28149
|
return type;
|
|
28135
28150
|
}
|
|
28136
|
-
isChartDefined(
|
|
28137
|
-
return figureId in
|
|
28151
|
+
isChartDefined(figureId) {
|
|
28152
|
+
return figureId in this.charts && this.charts !== undefined;
|
|
28138
28153
|
}
|
|
28139
28154
|
getChartIds(sheetId) {
|
|
28140
|
-
return Object.
|
|
28155
|
+
return Object.entries(this.charts)
|
|
28156
|
+
.filter(([, chart]) => (chart === null || chart === void 0 ? void 0 : chart.sheetId) === sheetId)
|
|
28157
|
+
.map(([id]) => id);
|
|
28141
28158
|
}
|
|
28142
|
-
getChartDefinition(
|
|
28143
|
-
var _a
|
|
28144
|
-
const definition = (
|
|
28159
|
+
getChartDefinition(figureId) {
|
|
28160
|
+
var _a;
|
|
28161
|
+
const definition = (_a = this.charts[figureId]) === null || _a === void 0 ? void 0 : _a.getDefinition();
|
|
28145
28162
|
if (!definition) {
|
|
28146
28163
|
throw new Error(`There is no chart with the given figureId: ${figureId}`);
|
|
28147
28164
|
}
|
|
@@ -28153,28 +28170,35 @@
|
|
|
28153
28170
|
import(data) {
|
|
28154
28171
|
for (let sheet of data.sheets) {
|
|
28155
28172
|
if (sheet.figures) {
|
|
28156
|
-
const charts = {};
|
|
28157
28173
|
for (let figure of sheet.figures) {
|
|
28158
28174
|
// TODO:
|
|
28159
28175
|
// figure data should be external IMO => chart should be in sheet.chart
|
|
28160
28176
|
// instead of in figure.data
|
|
28161
28177
|
if (figure.tag === "chart") {
|
|
28162
|
-
charts[figure.id] = this.createChart(figure.id, figure.data, sheet.id);
|
|
28178
|
+
this.charts[figure.id] = this.createChart(figure.id, figure.data, sheet.id);
|
|
28163
28179
|
}
|
|
28164
28180
|
}
|
|
28165
|
-
this.charts[sheet.id] = charts;
|
|
28166
28181
|
}
|
|
28167
28182
|
}
|
|
28168
28183
|
}
|
|
28169
28184
|
export(data) {
|
|
28185
|
+
var _a;
|
|
28170
28186
|
if (data.sheets) {
|
|
28171
28187
|
for (let sheet of data.sheets) {
|
|
28172
28188
|
// TODO This code is false, if two plugins want ot insert figures on the sheet, it will crash !
|
|
28173
28189
|
const sheetFigures = this.getters.getFigures(sheet.id);
|
|
28174
|
-
const figures =
|
|
28175
|
-
for (let
|
|
28190
|
+
const figures = [];
|
|
28191
|
+
for (let sheetFigure of sheetFigures) {
|
|
28192
|
+
const figure = sheetFigure;
|
|
28176
28193
|
if (figure && figure.tag === "chart") {
|
|
28177
|
-
|
|
28194
|
+
const data = (_a = this.charts[figure.id]) === null || _a === void 0 ? void 0 : _a.getDefinition();
|
|
28195
|
+
if (data) {
|
|
28196
|
+
figure.data = data;
|
|
28197
|
+
figures.push(figure);
|
|
28198
|
+
}
|
|
28199
|
+
}
|
|
28200
|
+
else {
|
|
28201
|
+
figures.push(figure);
|
|
28178
28202
|
}
|
|
28179
28203
|
}
|
|
28180
28204
|
sheet.figures = figures;
|
|
@@ -28182,13 +28206,13 @@
|
|
|
28182
28206
|
}
|
|
28183
28207
|
}
|
|
28184
28208
|
exportForExcel(data) {
|
|
28185
|
-
var _a
|
|
28209
|
+
var _a;
|
|
28186
28210
|
for (let sheet of data.sheets) {
|
|
28187
28211
|
const sheetFigures = this.getters.getFigures(sheet.id);
|
|
28188
28212
|
const figures = [];
|
|
28189
28213
|
for (let figure of sheetFigures) {
|
|
28190
28214
|
if (figure && figure.tag === "chart") {
|
|
28191
|
-
const figureData = (
|
|
28215
|
+
const figureData = (_a = this.charts[figure.id]) === null || _a === void 0 ? void 0 : _a.getDefinitionForExcel();
|
|
28192
28216
|
if (figureData) {
|
|
28193
28217
|
figures.push({
|
|
28194
28218
|
...figure,
|
|
@@ -28227,15 +28251,21 @@
|
|
|
28227
28251
|
* Add a chart in the local state. If a chart already exists, this chart is
|
|
28228
28252
|
* replaced
|
|
28229
28253
|
*/
|
|
28230
|
-
addChart(id,
|
|
28231
|
-
|
|
28254
|
+
addChart(id, definition) {
|
|
28255
|
+
const sheetId = this.getters.getFigureSheetId(id);
|
|
28256
|
+
if (sheetId) {
|
|
28257
|
+
this.history.update("charts", id, this.createChart(id, definition, sheetId));
|
|
28258
|
+
}
|
|
28232
28259
|
}
|
|
28233
28260
|
checkChartDuplicate(cmd) {
|
|
28234
|
-
|
|
28235
|
-
|
|
28236
|
-
|
|
28237
|
-
|
|
28238
|
-
|
|
28261
|
+
return this.getters.getFigureSheetId(cmd.id)
|
|
28262
|
+
? 84 /* CommandResult.DuplicatedChartId */
|
|
28263
|
+
: 0 /* CommandResult.Success */;
|
|
28264
|
+
}
|
|
28265
|
+
checkChartExists(cmd) {
|
|
28266
|
+
return this.getters.getFigureSheetId(cmd.id)
|
|
28267
|
+
? 0 /* CommandResult.Success */
|
|
28268
|
+
: 85 /* CommandResult.ChartDoesNotExist */;
|
|
28239
28269
|
}
|
|
28240
28270
|
}
|
|
28241
28271
|
ChartPlugin.getters = [
|
|
@@ -28616,7 +28646,7 @@
|
|
|
28616
28646
|
allowDispatch(cmd) {
|
|
28617
28647
|
switch (cmd.type) {
|
|
28618
28648
|
case "CREATE_FIGURE":
|
|
28619
|
-
return this.checkFigureDuplicate(cmd.
|
|
28649
|
+
return this.checkFigureDuplicate(cmd.figure.id);
|
|
28620
28650
|
case "UPDATE_FIGURE":
|
|
28621
28651
|
case "DELETE_FIGURE":
|
|
28622
28652
|
return this.checkFigureExists(cmd.sheetId, cmd.id);
|
|
@@ -28682,9 +28712,8 @@
|
|
|
28682
28712
|
}
|
|
28683
28713
|
return 0 /* CommandResult.Success */;
|
|
28684
28714
|
}
|
|
28685
|
-
checkFigureDuplicate(
|
|
28686
|
-
|
|
28687
|
-
if ((_a = this.figures[sheetId]) === null || _a === void 0 ? void 0 : _a[figureId]) {
|
|
28715
|
+
checkFigureDuplicate(figureId) {
|
|
28716
|
+
if (Object.values(this.figures).find((sheet) => sheet === null || sheet === void 0 ? void 0 : sheet[figureId])) {
|
|
28688
28717
|
return 82 /* CommandResult.DuplicatedFigureId */;
|
|
28689
28718
|
}
|
|
28690
28719
|
return 0 /* CommandResult.Success */;
|
|
@@ -28699,6 +28728,9 @@
|
|
|
28699
28728
|
var _a;
|
|
28700
28729
|
return (_a = this.figures[sheetId]) === null || _a === void 0 ? void 0 : _a[figureId];
|
|
28701
28730
|
}
|
|
28731
|
+
getFigureSheetId(figureId) {
|
|
28732
|
+
return Object.keys(this.figures).find((sheetId) => { var _a; return ((_a = this.figures[sheetId]) === null || _a === void 0 ? void 0 : _a[figureId]) !== undefined; });
|
|
28733
|
+
}
|
|
28702
28734
|
// ---------------------------------------------------------------------------
|
|
28703
28735
|
// Import/Export
|
|
28704
28736
|
// ---------------------------------------------------------------------------
|
|
@@ -28723,7 +28755,7 @@
|
|
|
28723
28755
|
this.export(data);
|
|
28724
28756
|
}
|
|
28725
28757
|
}
|
|
28726
|
-
FigurePlugin.getters = ["getFigures", "getFigure"];
|
|
28758
|
+
FigurePlugin.getters = ["getFigures", "getFigure", "getFigureSheetId"];
|
|
28727
28759
|
|
|
28728
28760
|
class FilterTable {
|
|
28729
28761
|
constructor(zone) {
|
|
@@ -28903,7 +28935,7 @@
|
|
|
28903
28935
|
filters.push(new Filter(filter.id, filterZone));
|
|
28904
28936
|
}
|
|
28905
28937
|
// Add filters for new columns
|
|
28906
|
-
if (filters.length < zoneToDimension(zone).
|
|
28938
|
+
if (filters.length < zoneToDimension(zone).numberOfCols) {
|
|
28907
28939
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
28908
28940
|
if (!filters.find((filter) => filter.col === col)) {
|
|
28909
28941
|
filters.push(new Filter(this.uuidGenerator.uuidv4(), { ...zone, left: col, right: col }));
|
|
@@ -29450,7 +29482,7 @@
|
|
|
29450
29482
|
switch (cmd.type) {
|
|
29451
29483
|
case "CREATE_IMAGE":
|
|
29452
29484
|
if (this.getters.getFigure(cmd.sheetId, cmd.figureId)) {
|
|
29453
|
-
return 28 /* CommandResult.
|
|
29485
|
+
return 28 /* CommandResult.InvalidFigureId */;
|
|
29454
29486
|
}
|
|
29455
29487
|
return 0 /* CommandResult.Success */;
|
|
29456
29488
|
default:
|
|
@@ -29470,7 +29502,7 @@
|
|
|
29470
29502
|
if (fig.tag === "image") {
|
|
29471
29503
|
const figureIdBase = fig.id.split(FIGURE_ID_SPLITTER).pop();
|
|
29472
29504
|
const duplicatedFigureId = `${cmd.sheetIdTo}${FIGURE_ID_SPLITTER}${figureIdBase}`;
|
|
29473
|
-
const image = this.getImage(
|
|
29505
|
+
const image = this.getImage(fig.id);
|
|
29474
29506
|
if (image) {
|
|
29475
29507
|
const size = { width: fig.width, height: fig.height };
|
|
29476
29508
|
this.dispatch("CREATE_IMAGE", {
|
|
@@ -29508,13 +29540,19 @@
|
|
|
29508
29540
|
// ---------------------------------------------------------------------------
|
|
29509
29541
|
// Getters
|
|
29510
29542
|
// ---------------------------------------------------------------------------
|
|
29511
|
-
getImage(
|
|
29512
|
-
|
|
29513
|
-
|
|
29514
|
-
|
|
29515
|
-
|
|
29543
|
+
getImage(figureId) {
|
|
29544
|
+
for (const sheet of Object.values(this.images)) {
|
|
29545
|
+
if (sheet && sheet[figureId]) {
|
|
29546
|
+
return sheet[figureId];
|
|
29547
|
+
}
|
|
29516
29548
|
}
|
|
29517
|
-
|
|
29549
|
+
throw new Error(`There is no image with the given figureId: ${figureId}`);
|
|
29550
|
+
}
|
|
29551
|
+
getImagePath(figureId) {
|
|
29552
|
+
return this.getImage(figureId).path;
|
|
29553
|
+
}
|
|
29554
|
+
getImageSize(figureId) {
|
|
29555
|
+
return this.getImage(figureId).size;
|
|
29518
29556
|
}
|
|
29519
29557
|
// ---------------------------------------------------------------------------
|
|
29520
29558
|
// Private
|
|
@@ -29548,6 +29586,24 @@
|
|
|
29548
29586
|
}
|
|
29549
29587
|
}
|
|
29550
29588
|
}
|
|
29589
|
+
exportForExcel(data) {
|
|
29590
|
+
for (const sheet of data.sheets) {
|
|
29591
|
+
const figures = this.getters.getFigures(sheet.id);
|
|
29592
|
+
const images = [];
|
|
29593
|
+
for (const figure of figures) {
|
|
29594
|
+
if ((figure === null || figure === void 0 ? void 0 : figure.tag) === "image") {
|
|
29595
|
+
const image = this.getImage(figure.id);
|
|
29596
|
+
if (image) {
|
|
29597
|
+
images.push({
|
|
29598
|
+
...figure,
|
|
29599
|
+
data: deepCopy(image),
|
|
29600
|
+
});
|
|
29601
|
+
}
|
|
29602
|
+
}
|
|
29603
|
+
}
|
|
29604
|
+
sheet.images = images;
|
|
29605
|
+
}
|
|
29606
|
+
}
|
|
29551
29607
|
getAllImages() {
|
|
29552
29608
|
const images = [];
|
|
29553
29609
|
for (const sheetId in this.images) {
|
|
@@ -29556,7 +29612,7 @@
|
|
|
29556
29612
|
return images;
|
|
29557
29613
|
}
|
|
29558
29614
|
}
|
|
29559
|
-
ImagePlugin.getters = ["getImage"];
|
|
29615
|
+
ImagePlugin.getters = ["getImage", "getImagePath", "getImageSize"];
|
|
29560
29616
|
|
|
29561
29617
|
class MergePlugin extends CorePlugin {
|
|
29562
29618
|
constructor() {
|
|
@@ -29745,8 +29801,8 @@
|
|
|
29745
29801
|
if (merge) {
|
|
29746
29802
|
return isEqual(zone, merge);
|
|
29747
29803
|
}
|
|
29748
|
-
const {
|
|
29749
|
-
return
|
|
29804
|
+
const { numberOfCols, numberOfRows } = zoneToDimension(zone);
|
|
29805
|
+
return numberOfCols === 1 && numberOfRows === 1;
|
|
29750
29806
|
}
|
|
29751
29807
|
// ---------------------------------------------------------------------------
|
|
29752
29808
|
// Merges
|
|
@@ -29914,8 +29970,8 @@
|
|
|
29914
29970
|
this.removeMerge(sheetId, currentZone);
|
|
29915
29971
|
break;
|
|
29916
29972
|
default:
|
|
29917
|
-
const {
|
|
29918
|
-
if (
|
|
29973
|
+
const { numberOfCols, numberOfRows } = zoneToDimension(result.range.zone);
|
|
29974
|
+
if (numberOfCols === 1 && numberOfRows === 1) {
|
|
29919
29975
|
this.removeMerge(sheetId, currentZone);
|
|
29920
29976
|
}
|
|
29921
29977
|
else {
|
|
@@ -30674,8 +30730,8 @@
|
|
|
30674
30730
|
}
|
|
30675
30731
|
getSheetSize(sheetId) {
|
|
30676
30732
|
return {
|
|
30677
|
-
|
|
30678
|
-
|
|
30733
|
+
numberOfRows: this.getNumberRows(sheetId),
|
|
30734
|
+
numberOfCols: this.getNumberCols(sheetId),
|
|
30679
30735
|
};
|
|
30680
30736
|
}
|
|
30681
30737
|
getSheetZone(sheetId) {
|
|
@@ -31362,9 +31418,7 @@
|
|
|
31362
31418
|
return formatColors.filter(isDefined$1);
|
|
31363
31419
|
}
|
|
31364
31420
|
getChartColors(sheetId) {
|
|
31365
|
-
const charts = this.getters
|
|
31366
|
-
.getChartIds(sheetId)
|
|
31367
|
-
.map((cid) => this.getters.getChart(sheetId, cid));
|
|
31421
|
+
const charts = this.getters.getChartIds(sheetId).map((cid) => this.getters.getChart(cid));
|
|
31368
31422
|
let chartsColors = new Set();
|
|
31369
31423
|
for (let chart of charts) {
|
|
31370
31424
|
if (chart === undefined) {
|
|
@@ -31730,37 +31784,34 @@
|
|
|
31730
31784
|
invalidateCFEvaluationCommands.has(cmd.type) ||
|
|
31731
31785
|
cmd.type === "EVALUATE_CELLS" ||
|
|
31732
31786
|
cmd.type === "UPDATE_CELL") {
|
|
31733
|
-
for (const
|
|
31734
|
-
|
|
31735
|
-
this.charts[sheetId][chartId] = undefined;
|
|
31736
|
-
}
|
|
31787
|
+
for (const chartId in this.charts) {
|
|
31788
|
+
this.charts[chartId] = undefined;
|
|
31737
31789
|
}
|
|
31738
31790
|
}
|
|
31739
31791
|
switch (cmd.type) {
|
|
31740
31792
|
case "UPDATE_CHART":
|
|
31741
31793
|
case "CREATE_CHART":
|
|
31742
31794
|
case "DELETE_FIGURE":
|
|
31743
|
-
|
|
31744
|
-
this.charts[cmd.sheetId][cmd.id] = undefined;
|
|
31745
|
-
}
|
|
31795
|
+
this.charts[cmd.id] = undefined;
|
|
31746
31796
|
break;
|
|
31747
31797
|
case "DELETE_SHEET":
|
|
31748
|
-
|
|
31798
|
+
for (let chartId in this.charts) {
|
|
31799
|
+
if (!this.getters.isChartDefined(chartId)) {
|
|
31800
|
+
this.charts[chartId] = undefined;
|
|
31801
|
+
}
|
|
31802
|
+
}
|
|
31749
31803
|
break;
|
|
31750
31804
|
}
|
|
31751
31805
|
}
|
|
31752
|
-
getChartRuntime(
|
|
31753
|
-
|
|
31754
|
-
|
|
31755
|
-
const chart = this.getters.getChart(sheetId, figureId);
|
|
31806
|
+
getChartRuntime(figureId) {
|
|
31807
|
+
if (!this.charts[figureId]) {
|
|
31808
|
+
const chart = this.getters.getChart(figureId);
|
|
31756
31809
|
if (!chart) {
|
|
31757
31810
|
throw new Error(`No chart for the given id: ${figureId}`);
|
|
31758
31811
|
}
|
|
31759
|
-
|
|
31760
|
-
this.charts[sheetId] = {};
|
|
31761
|
-
this.charts[sheetId][figureId] = this.createRuntimeChart(chart);
|
|
31812
|
+
this.charts[figureId] = this.createRuntimeChart(chart);
|
|
31762
31813
|
}
|
|
31763
|
-
return this.charts[
|
|
31814
|
+
return this.charts[figureId];
|
|
31764
31815
|
}
|
|
31765
31816
|
/**
|
|
31766
31817
|
* Get the background color of a chart based on the color of the first cell of the main range
|
|
@@ -32196,6 +32247,9 @@
|
|
|
32196
32247
|
case "CREATE_SHEET":
|
|
32197
32248
|
this.filterValues[cmd.sheetId] = {};
|
|
32198
32249
|
break;
|
|
32250
|
+
case "HIDE_COLUMNS_ROWS":
|
|
32251
|
+
this.updateHiddenRows();
|
|
32252
|
+
break;
|
|
32199
32253
|
case "UPDATE_FILTER":
|
|
32200
32254
|
this.updateFilter(cmd);
|
|
32201
32255
|
this.updateHiddenRows();
|
|
@@ -32304,9 +32358,16 @@
|
|
|
32304
32358
|
updateHiddenRows() {
|
|
32305
32359
|
var _a, _b;
|
|
32306
32360
|
const sheetId = this.getters.getActiveSheetId();
|
|
32307
|
-
const filters = this.getters
|
|
32361
|
+
const filters = this.getters
|
|
32362
|
+
.getFilters(sheetId)
|
|
32363
|
+
.sort((filter1, filter2) => filter1.zoneWithHeaders.top - filter2.zoneWithHeaders.top);
|
|
32308
32364
|
const hiddenRows = new Set();
|
|
32309
32365
|
for (let filter of filters) {
|
|
32366
|
+
// Disable filters whose header are hidden
|
|
32367
|
+
if (this.getters.isRowHiddenByUser(sheetId, filter.zoneWithHeaders.top))
|
|
32368
|
+
continue;
|
|
32369
|
+
if (hiddenRows.has(filter.zoneWithHeaders.top))
|
|
32370
|
+
continue;
|
|
32310
32371
|
const filteredValues = (_b = (_a = this.filterValues[sheetId]) === null || _a === void 0 ? void 0 : _a[filter.id]) === null || _b === void 0 ? void 0 : _b.map(toLowerCase);
|
|
32311
32372
|
if (!filteredValues || !filter.filteredZone)
|
|
32312
32373
|
continue;
|
|
@@ -32329,7 +32390,7 @@
|
|
|
32329
32390
|
const tableZone = toZone(tableData.range);
|
|
32330
32391
|
const filters = [];
|
|
32331
32392
|
const headerNames = [];
|
|
32332
|
-
for (const i of range(0, zoneToDimension(tableZone).
|
|
32393
|
+
for (const i of range(0, zoneToDimension(tableZone).numberOfCols)) {
|
|
32333
32394
|
const position = {
|
|
32334
32395
|
sheetId: sheetData.id,
|
|
32335
32396
|
col: tableZone.left + i,
|
|
@@ -33840,7 +33901,7 @@
|
|
|
33840
33901
|
dimensionsToSum(sheetId, zone) {
|
|
33841
33902
|
const dimensions = new Set();
|
|
33842
33903
|
if (isOneDimensional(zone)) {
|
|
33843
|
-
dimensions.add(zoneToDimension(zone).
|
|
33904
|
+
dimensions.add(zoneToDimension(zone).numberOfCols === 1 ? "COL" : "ROW");
|
|
33844
33905
|
return dimensions;
|
|
33845
33906
|
}
|
|
33846
33907
|
if (this.lastColIsEmpty(sheetId, zone)) {
|
|
@@ -34428,8 +34489,8 @@
|
|
|
34428
34489
|
x.zone.bottom < this.getters.getNumberRows(x.sheetId) &&
|
|
34429
34490
|
x.zone.right < this.getters.getNumberCols(x.sheetId))
|
|
34430
34491
|
.map((highlight) => {
|
|
34431
|
-
const {
|
|
34432
|
-
const zone =
|
|
34492
|
+
const { numberOfRows, numberOfCols } = zoneToDimension(highlight.zone);
|
|
34493
|
+
const zone = numberOfRows * numberOfCols === 1
|
|
34433
34494
|
? this.getters.expandZone(highlight.sheetId, highlight.zone)
|
|
34434
34495
|
: highlight.zone;
|
|
34435
34496
|
return {
|
|
@@ -35245,8 +35306,8 @@
|
|
|
35245
35306
|
const currentMaxId = Math.max(0, ...this.ranges.map((range) => Number(range.id)));
|
|
35246
35307
|
this.ranges.splice(index, 0, ...values.map((xc, i) => ({
|
|
35247
35308
|
xc,
|
|
35248
|
-
id:
|
|
35249
|
-
color: colors$1[(currentMaxId +
|
|
35309
|
+
id: currentMaxId + i + 1,
|
|
35310
|
+
color: colors$1[(currentMaxId + i) % colors$1.length],
|
|
35250
35311
|
})));
|
|
35251
35312
|
}
|
|
35252
35313
|
/**
|
|
@@ -36336,7 +36397,7 @@
|
|
|
36336
36397
|
const merges = this.getters.getMerges(sheetId).filter((merge) => overlap(merge, zone));
|
|
36337
36398
|
/*Test the presence of merges of different sizes*/
|
|
36338
36399
|
const mergeDimension = zoneToDimension(merges[0]);
|
|
36339
|
-
let [widthFirst, heightFirst] = [mergeDimension.
|
|
36400
|
+
let [widthFirst, heightFirst] = [mergeDimension.numberOfCols, mergeDimension.numberOfRows];
|
|
36340
36401
|
if (!merges.every((merge) => {
|
|
36341
36402
|
let [widthCurrent, heightCurrent] = [
|
|
36342
36403
|
merge.right - merge.left + 1,
|
|
@@ -37412,7 +37473,7 @@
|
|
|
37412
37473
|
constructor(dispatch, getters, sheetId, copiedFigureId) {
|
|
37413
37474
|
this.dispatch = dispatch;
|
|
37414
37475
|
this.sheetId = sheetId;
|
|
37415
|
-
const chart = getters.getChart(
|
|
37476
|
+
const chart = getters.getChart(copiedFigureId);
|
|
37416
37477
|
if (!chart) {
|
|
37417
37478
|
throw new Error(`No chart for the given id: ${copiedFigureId}`);
|
|
37418
37479
|
}
|
|
@@ -37433,7 +37494,7 @@
|
|
|
37433
37494
|
constructor(dispatch, getters, sheetId, copiedFigureId) {
|
|
37434
37495
|
this.dispatch = dispatch;
|
|
37435
37496
|
this.sheetId = sheetId;
|
|
37436
|
-
const image = getters.getImage(
|
|
37497
|
+
const image = getters.getImage(copiedFigureId);
|
|
37437
37498
|
this.copiedImage = deepCopy(image);
|
|
37438
37499
|
}
|
|
37439
37500
|
paste(sheetId, figureId, position, size) {
|
|
@@ -37469,9 +37530,9 @@
|
|
|
37469
37530
|
const values = this.values;
|
|
37470
37531
|
const pasteZone = this.getPasteZone(target);
|
|
37471
37532
|
const { left: activeCol, top: activeRow } = pasteZone;
|
|
37472
|
-
const {
|
|
37533
|
+
const { numberOfCols, numberOfRows } = zoneToDimension(pasteZone);
|
|
37473
37534
|
const sheetId = this.getters.getActiveSheetId();
|
|
37474
|
-
this.addMissingDimensions(
|
|
37535
|
+
this.addMissingDimensions(numberOfCols, numberOfRows, activeCol, activeRow);
|
|
37475
37536
|
for (let i = 0; i < values.length; i++) {
|
|
37476
37537
|
for (let j = 0; j < values[i].length; j++) {
|
|
37477
37538
|
this.dispatch("UPDATE_CELL", {
|
|
@@ -37485,8 +37546,8 @@
|
|
|
37485
37546
|
const zone = {
|
|
37486
37547
|
left: activeCol,
|
|
37487
37548
|
top: activeRow,
|
|
37488
|
-
right: activeCol +
|
|
37489
|
-
bottom: activeRow +
|
|
37549
|
+
right: activeCol + numberOfCols - 1,
|
|
37550
|
+
bottom: activeRow + numberOfRows - 1,
|
|
37490
37551
|
};
|
|
37491
37552
|
this.selection.selectZone({ cell: { col: activeCol, row: activeRow }, zone });
|
|
37492
37553
|
}
|
|
@@ -43585,7 +43646,7 @@
|
|
|
43585
43646
|
}
|
|
43586
43647
|
}
|
|
43587
43648
|
|
|
43588
|
-
function createDrawing(
|
|
43649
|
+
function createDrawing(drawingRelIds, sheet, figures) {
|
|
43589
43650
|
const namespaces = [
|
|
43590
43651
|
["xmlns:xdr", NAMESPACE.drawing],
|
|
43591
43652
|
["xmlns:r", RELATIONSHIP_NSR],
|
|
@@ -43594,46 +43655,14 @@
|
|
|
43594
43655
|
];
|
|
43595
43656
|
const figuresNodes = [];
|
|
43596
43657
|
for (const [figureIndex, figure] of Object.entries(figures)) {
|
|
43597
|
-
|
|
43598
|
-
|
|
43599
|
-
|
|
43600
|
-
|
|
43601
|
-
|
|
43602
|
-
|
|
43603
|
-
|
|
43604
|
-
|
|
43605
|
-
figuresNodes.push(escapeXml /*xml*/ `
|
|
43606
|
-
<xdr:twoCellAnchor>
|
|
43607
|
-
<xdr:from>
|
|
43608
|
-
<xdr:col>${from.col}</xdr:col>
|
|
43609
|
-
<xdr:colOff>${from.colOff}</xdr:colOff>
|
|
43610
|
-
<xdr:row>${from.row}</xdr:row>
|
|
43611
|
-
<xdr:rowOff>${from.rowOff}</xdr:rowOff>
|
|
43612
|
-
</xdr:from>
|
|
43613
|
-
<xdr:to>
|
|
43614
|
-
<xdr:col>${to.col}</xdr:col>
|
|
43615
|
-
<xdr:colOff>${to.colOff}</xdr:colOff>
|
|
43616
|
-
<xdr:row>${to.row}</xdr:row>
|
|
43617
|
-
<xdr:rowOff>${to.rowOff}</xdr:rowOff>
|
|
43618
|
-
</xdr:to>
|
|
43619
|
-
<xdr:graphicFrame>
|
|
43620
|
-
<xdr:nvGraphicFramePr>
|
|
43621
|
-
<xdr:cNvPr ${formatAttributes(cNvPrAttrs)} />
|
|
43622
|
-
<xdr:cNvGraphicFramePr />
|
|
43623
|
-
</xdr:nvGraphicFramePr>
|
|
43624
|
-
<xdr:xfrm>
|
|
43625
|
-
<a:off x="0" y="0"/>
|
|
43626
|
-
<a:ext cx="0" cy="0"/>
|
|
43627
|
-
</xdr:xfrm>
|
|
43628
|
-
<a:graphic>
|
|
43629
|
-
<a:graphicData uri="${DRAWING_NS_C}">
|
|
43630
|
-
<c:chart r:id="${chartRelIds[figureIndex]}" />
|
|
43631
|
-
</a:graphicData>
|
|
43632
|
-
</a:graphic>
|
|
43633
|
-
</xdr:graphicFrame>
|
|
43634
|
-
<xdr:clientData fLocksWithSheet="0"/>
|
|
43635
|
-
</xdr:twoCellAnchor>
|
|
43636
|
-
`);
|
|
43658
|
+
switch (figure === null || figure === void 0 ? void 0 : figure.tag) {
|
|
43659
|
+
case "chart":
|
|
43660
|
+
figuresNodes.push(createChartDrawing(figure, sheet, drawingRelIds[figureIndex]));
|
|
43661
|
+
break;
|
|
43662
|
+
case "image":
|
|
43663
|
+
figuresNodes.push(createImageDrawing(figure, sheet, drawingRelIds[figureIndex]));
|
|
43664
|
+
break;
|
|
43665
|
+
}
|
|
43637
43666
|
}
|
|
43638
43667
|
const xml = escapeXml /*xml*/ `
|
|
43639
43668
|
<xdr:wsDr ${formatAttributes(namespaces)}>
|
|
@@ -43688,6 +43717,93 @@
|
|
|
43688
43717
|
index: headers.length - 1,
|
|
43689
43718
|
offset: convertDotValueToEMU(position - currentPosition + FIGURE_BORDER_SIZE),
|
|
43690
43719
|
};
|
|
43720
|
+
}
|
|
43721
|
+
function createChartDrawing(figure, sheet, chartRelId) {
|
|
43722
|
+
// position
|
|
43723
|
+
const { from, to } = convertFigureData(figure, sheet);
|
|
43724
|
+
const chartId = convertChartId(figure.id);
|
|
43725
|
+
const cNvPrAttrs = [
|
|
43726
|
+
["id", chartId],
|
|
43727
|
+
["name", `Chart ${chartId}`],
|
|
43728
|
+
["title", "Chart"],
|
|
43729
|
+
];
|
|
43730
|
+
return escapeXml /*xml*/ `
|
|
43731
|
+
<xdr:twoCellAnchor>
|
|
43732
|
+
<xdr:from>
|
|
43733
|
+
<xdr:col>${from.col}</xdr:col>
|
|
43734
|
+
<xdr:colOff>${from.colOff}</xdr:colOff>
|
|
43735
|
+
<xdr:row>${from.row}</xdr:row>
|
|
43736
|
+
<xdr:rowOff>${from.rowOff}</xdr:rowOff>
|
|
43737
|
+
</xdr:from>
|
|
43738
|
+
<xdr:to>
|
|
43739
|
+
<xdr:col>${to.col}</xdr:col>
|
|
43740
|
+
<xdr:colOff>${to.colOff}</xdr:colOff>
|
|
43741
|
+
<xdr:row>${to.row}</xdr:row>
|
|
43742
|
+
<xdr:rowOff>${to.rowOff}</xdr:rowOff>
|
|
43743
|
+
</xdr:to>
|
|
43744
|
+
<xdr:graphicFrame>
|
|
43745
|
+
<xdr:nvGraphicFramePr>
|
|
43746
|
+
<xdr:cNvPr ${formatAttributes(cNvPrAttrs)} />
|
|
43747
|
+
<xdr:cNvGraphicFramePr />
|
|
43748
|
+
</xdr:nvGraphicFramePr>
|
|
43749
|
+
<xdr:xfrm>
|
|
43750
|
+
<a:off x="0" y="0"/>
|
|
43751
|
+
<a:ext cx="0" cy="0"/>
|
|
43752
|
+
</xdr:xfrm>
|
|
43753
|
+
<a:graphic>
|
|
43754
|
+
<a:graphicData uri="${DRAWING_NS_C}">
|
|
43755
|
+
<c:chart r:id="${chartRelId}" />
|
|
43756
|
+
</a:graphicData>
|
|
43757
|
+
</a:graphic>
|
|
43758
|
+
</xdr:graphicFrame>
|
|
43759
|
+
<xdr:clientData fLocksWithSheet="0"/>
|
|
43760
|
+
</xdr:twoCellAnchor>
|
|
43761
|
+
`;
|
|
43762
|
+
}
|
|
43763
|
+
function createImageDrawing(figure, sheet, imageRelId) {
|
|
43764
|
+
// position
|
|
43765
|
+
const { from, to } = convertFigureData(figure, sheet);
|
|
43766
|
+
const imageId = convertImageId(figure.id);
|
|
43767
|
+
const cNvPrAttrs = [
|
|
43768
|
+
["id", imageId],
|
|
43769
|
+
["name", `Image ${imageId}`],
|
|
43770
|
+
["title", "Image"],
|
|
43771
|
+
];
|
|
43772
|
+
return escapeXml /*xml*/ `
|
|
43773
|
+
<xdr:twoCellAnchor editAs="oneCell">
|
|
43774
|
+
<xdr:from>
|
|
43775
|
+
<xdr:col>${from.col}</xdr:col>
|
|
43776
|
+
<xdr:colOff>${from.colOff}</xdr:colOff>
|
|
43777
|
+
<xdr:row>${from.row}</xdr:row>
|
|
43778
|
+
<xdr:rowOff>${from.rowOff}</xdr:rowOff>
|
|
43779
|
+
</xdr:from>
|
|
43780
|
+
<xdr:to>
|
|
43781
|
+
<xdr:col>${to.col}</xdr:col>
|
|
43782
|
+
<xdr:colOff>${to.colOff}</xdr:colOff>
|
|
43783
|
+
<xdr:row>${to.row}</xdr:row>
|
|
43784
|
+
<xdr:rowOff>${to.rowOff}</xdr:rowOff>
|
|
43785
|
+
</xdr:to>
|
|
43786
|
+
<xdr:pic>
|
|
43787
|
+
<xdr:nvPicPr>
|
|
43788
|
+
<xdr:cNvPr ${formatAttributes(cNvPrAttrs)}/>
|
|
43789
|
+
<xdr:cNvPicPr preferRelativeResize="0"/>
|
|
43790
|
+
</xdr:nvPicPr>
|
|
43791
|
+
<xdr:blipFill>
|
|
43792
|
+
<a:blip cstate="print" r:embed="${imageRelId}"/>
|
|
43793
|
+
<a:stretch>
|
|
43794
|
+
<a:fillRect/>
|
|
43795
|
+
</a:stretch>
|
|
43796
|
+
</xdr:blipFill>
|
|
43797
|
+
<xdr:spPr>
|
|
43798
|
+
<a:prstGeom prst="rect">
|
|
43799
|
+
<a:avLst/>
|
|
43800
|
+
</a:prstGeom>
|
|
43801
|
+
<a:noFill/>
|
|
43802
|
+
</xdr:spPr>
|
|
43803
|
+
</xdr:pic>
|
|
43804
|
+
<xdr:clientData fLocksWithSheet="0"/>
|
|
43805
|
+
</xdr:twoCellAnchor>
|
|
43806
|
+
`;
|
|
43691
43807
|
}
|
|
43692
43808
|
|
|
43693
43809
|
function addNumberFormats(numFmts) {
|
|
@@ -43883,7 +43999,7 @@
|
|
|
43883
43999
|
function addFilterColumns(table) {
|
|
43884
44000
|
const tableZone = toZone(table.range);
|
|
43885
44001
|
const columns = [];
|
|
43886
|
-
for (const i of range(0, zoneToDimension(tableZone).
|
|
44002
|
+
for (const i of range(0, zoneToDimension(tableZone).numberOfCols)) {
|
|
43887
44003
|
const filter = table.filters[i];
|
|
43888
44004
|
if (!filter || !filter.filteredValues.length) {
|
|
43889
44005
|
continue;
|
|
@@ -43909,7 +44025,7 @@
|
|
|
43909
44025
|
var _a;
|
|
43910
44026
|
const tableZone = toZone(table.range);
|
|
43911
44027
|
const columns = [];
|
|
43912
|
-
for (const i of range(0, zoneToDimension(tableZone).
|
|
44028
|
+
for (const i of range(0, zoneToDimension(tableZone).numberOfCols)) {
|
|
43913
44029
|
const colHeaderXc = toXC(tableZone.left + i, tableZone.top);
|
|
43914
44030
|
const colName = ((_a = sheetData.cells[colHeaderXc]) === null || _a === void 0 ? void 0 : _a.content) || `col${i}`;
|
|
43915
44031
|
const colAttributes = [
|
|
@@ -44157,23 +44273,37 @@
|
|
|
44157
44273
|
currentTableIndex += sheet.filterTables.length;
|
|
44158
44274
|
// Figures and Charts
|
|
44159
44275
|
let drawingNode = escapeXml ``;
|
|
44276
|
+
const drawingRelIds = [];
|
|
44160
44277
|
const charts = sheet.charts;
|
|
44161
|
-
|
|
44162
|
-
const
|
|
44163
|
-
|
|
44164
|
-
|
|
44165
|
-
|
|
44166
|
-
|
|
44167
|
-
|
|
44168
|
-
|
|
44169
|
-
|
|
44170
|
-
|
|
44171
|
-
|
|
44278
|
+
for (const chart of charts) {
|
|
44279
|
+
const xlsxChartId = convertChartId(chart.id);
|
|
44280
|
+
const chartRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
|
|
44281
|
+
target: `../charts/chart${xlsxChartId}.xml`,
|
|
44282
|
+
type: XLSX_RELATION_TYPE.chart,
|
|
44283
|
+
});
|
|
44284
|
+
drawingRelIds.push(chartRelId);
|
|
44285
|
+
files.push(createXMLFile(createChart(chart, sheetIndex, data), `xl/charts/chart${xlsxChartId}.xml`, "chart"));
|
|
44286
|
+
}
|
|
44287
|
+
const images = sheet.images;
|
|
44288
|
+
for (const image of images) {
|
|
44289
|
+
const xlsxImageId = convertImageId(image.id);
|
|
44290
|
+
const imageRelId = addRelsToFile(construct.relsFiles, `xl/drawings/_rels/drawing${sheetIndex}.xml.rels`, {
|
|
44291
|
+
target: `../media/image${xlsxImageId}`,
|
|
44292
|
+
type: XLSX_RELATION_TYPE.image,
|
|
44293
|
+
});
|
|
44294
|
+
drawingRelIds.push(imageRelId);
|
|
44295
|
+
files.push({
|
|
44296
|
+
path: `xl/media/image${xlsxImageId}`,
|
|
44297
|
+
imagePath: image.data.path,
|
|
44298
|
+
});
|
|
44299
|
+
}
|
|
44300
|
+
const drawings = [...charts, ...images];
|
|
44301
|
+
if (drawings.length) {
|
|
44172
44302
|
const drawingRelId = addRelsToFile(construct.relsFiles, `xl/worksheets/_rels/sheet${sheetIndex}.xml.rels`, {
|
|
44173
44303
|
target: `../drawings/drawing${sheetIndex}.xml`,
|
|
44174
44304
|
type: XLSX_RELATION_TYPE.drawing,
|
|
44175
44305
|
});
|
|
44176
|
-
files.push(createXMLFile(createDrawing(
|
|
44306
|
+
files.push(createXMLFile(createDrawing(drawingRelIds, sheet, drawings), `xl/drawings/drawing${sheetIndex}.xml`, "drawing"));
|
|
44177
44307
|
drawingNode = escapeXml /*xml*/ `<drawing r:id="${drawingRelId}" />`;
|
|
44178
44308
|
}
|
|
44179
44309
|
const sheetXml = escapeXml /*xml*/ `
|
|
@@ -44287,7 +44417,7 @@
|
|
|
44287
44417
|
function createContentTypes(files) {
|
|
44288
44418
|
const overrideNodes = [];
|
|
44289
44419
|
for (const file of files) {
|
|
44290
|
-
if (file.contentType) {
|
|
44420
|
+
if ("contentType" in file && file.contentType) {
|
|
44291
44421
|
overrideNodes.push(createOverride("/" + file.path, CONTENT_TYPES[file.contentType]));
|
|
44292
44422
|
}
|
|
44293
44423
|
}
|
|
@@ -44845,9 +44975,9 @@
|
|
|
44845
44975
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
44846
44976
|
|
|
44847
44977
|
|
|
44848
|
-
__info__.version = '16.2.0-alpha.
|
|
44849
|
-
__info__.date = '2023-03-
|
|
44850
|
-
__info__.hash = '
|
|
44978
|
+
__info__.version = '16.2.0-alpha.4';
|
|
44979
|
+
__info__.date = '2023-03-14T09:24:38.219Z';
|
|
44980
|
+
__info__.hash = '2c6fe88';
|
|
44851
44981
|
|
|
44852
44982
|
|
|
44853
44983
|
})(this.o_spreadsheet = this.o_spreadsheet || {}, owl);
|