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