@odoo/o-spreadsheet 16.2.0-alpha.3 → 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} +1587 -1514
- package/dist/{o_spreadsheet.d.ts → o-spreadsheet.d.ts} +132 -132
- package/dist/{o_spreadsheet.esm.js → o-spreadsheet.esm.js} +1588 -1515
- package/dist/{o_spreadsheet.iife.js → o-spreadsheet.iife.js} +1587 -1514
- 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 -2398
|
@@ -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
|
|
@@ -2025,10 +2025,10 @@ class RangeImpl {
|
|
|
2025
2025
|
if (right !== undefined && bottom !== undefined)
|
|
2026
2026
|
return { left, top, right, bottom };
|
|
2027
2027
|
else if (bottom === undefined && right !== undefined) {
|
|
2028
|
-
return { right, top, left, bottom: this.getSheetSize(this.sheetId).
|
|
2028
|
+
return { right, top, left, bottom: this.getSheetSize(this.sheetId).numberOfRows - 1 };
|
|
2029
2029
|
}
|
|
2030
2030
|
else if (right === undefined && bottom !== undefined) {
|
|
2031
|
-
return { bottom, left, top, right: this.getSheetSize(this.sheetId).
|
|
2031
|
+
return { bottom, left, top, right: this.getSheetSize(this.sheetId).numberOfCols - 1 };
|
|
2032
2032
|
}
|
|
2033
2033
|
throw new Error(_lt("Bad zone format"));
|
|
2034
2034
|
}
|
|
@@ -2651,13 +2651,13 @@ function positionsDifference(positions, toRemove) {
|
|
|
2651
2651
|
}
|
|
2652
2652
|
function zoneToDimension(zone) {
|
|
2653
2653
|
return {
|
|
2654
|
-
|
|
2655
|
-
|
|
2654
|
+
numberOfRows: zone.bottom - zone.top + 1,
|
|
2655
|
+
numberOfCols: zone.right - zone.left + 1,
|
|
2656
2656
|
};
|
|
2657
2657
|
}
|
|
2658
2658
|
function isOneDimensional(zone) {
|
|
2659
|
-
const {
|
|
2660
|
-
return
|
|
2659
|
+
const { numberOfCols, numberOfRows } = zoneToDimension(zone);
|
|
2660
|
+
return numberOfCols === 1 || numberOfRows === 1;
|
|
2661
2661
|
}
|
|
2662
2662
|
/**
|
|
2663
2663
|
* Array of all positions in the zone.
|
|
@@ -3132,7 +3132,7 @@ class ScorecardChart$1 extends Component {
|
|
|
3132
3132
|
return this.runtime.fontColor;
|
|
3133
3133
|
}
|
|
3134
3134
|
get secondaryFontColor() {
|
|
3135
|
-
return relativeLuminance(this.
|
|
3135
|
+
return relativeLuminance(this.backgroundColor) > 0.3 ? "#525252" : "#C8C8C8";
|
|
3136
3136
|
}
|
|
3137
3137
|
get figure() {
|
|
3138
3138
|
return this.props.figure;
|
|
@@ -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,979 +5611,276 @@ 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
|
-
});
|
|
5743
|
-
}
|
|
5744
|
-
}
|
|
5745
|
-
Popover.template = "o-spreadsheet-Popover";
|
|
5746
|
-
Popover.defaultProps = {
|
|
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;
|
|
5845
|
+
}
|
|
5771
5846
|
}
|
|
5772
|
-
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
this.availableHeightDown >= this.availableHeightUp);
|
|
5847
|
+
const { col, row } = anchor;
|
|
5848
|
+
if (multiColumns) {
|
|
5849
|
+
result = env.model.dispatch("SORT_CELLS", { sheetId, col, row, zone, sortDirection });
|
|
5776
5850
|
}
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
|
|
5787
|
-
|
|
5788
|
-
|
|
5789
|
-
|
|
5790
|
-
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
|
|
5798
|
-
|
|
5799
|
-
|
|
5800
|
-
|
|
5801
|
-
|
|
5802
|
-
|
|
5803
|
-
|
|
5804
|
-
|
|
5805
|
-
|
|
5806
|
-
|
|
5807
|
-
|
|
5808
|
-
|
|
5809
|
-
|
|
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.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
|
-
}
|
|
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
|
+
}
|
|
6517
5884
|
}
|
|
6518
5885
|
if (result.isCancelledBecause(63 /* CommandResult.InvalidSortZone */)) {
|
|
6519
5886
|
const { col, row } = anchor;
|
|
@@ -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;
|
|
@@ -16337,484 +15750,1000 @@ autofillModifiersRegistry
|
|
|
16337
15750
|
y = 0;
|
|
16338
15751
|
break;
|
|
16339
15752
|
}
|
|
16340
|
-
const cell = data.cell;
|
|
16341
|
-
if (!cell || !cell.isFormula) {
|
|
16342
|
-
return { cellData: {} };
|
|
15753
|
+
const cell = data.cell;
|
|
15754
|
+
if (!cell || !cell.isFormula) {
|
|
15755
|
+
return { cellData: {} };
|
|
15756
|
+
}
|
|
15757
|
+
const sheetId = data.sheetId;
|
|
15758
|
+
const ranges = getters.createAdaptedRanges(cell.dependencies, x, y, sheetId);
|
|
15759
|
+
const content = getters.buildFormulaContent(sheetId, cell, ranges);
|
|
15760
|
+
return {
|
|
15761
|
+
cellData: {
|
|
15762
|
+
border: data.border,
|
|
15763
|
+
style: cell.style,
|
|
15764
|
+
format: cell.format,
|
|
15765
|
+
content,
|
|
15766
|
+
},
|
|
15767
|
+
tooltip: content ? { props: { content } } : undefined,
|
|
15768
|
+
};
|
|
15769
|
+
},
|
|
15770
|
+
});
|
|
15771
|
+
|
|
15772
|
+
const autofillRulesRegistry = new Registry();
|
|
15773
|
+
const numberPostfixRegExp = /(\d+)$/;
|
|
15774
|
+
const stringPrefixRegExp = /^(.*\D+)/;
|
|
15775
|
+
const alphaNumericValueRegExp = /^(.*\D+)(\d+)$/;
|
|
15776
|
+
/**
|
|
15777
|
+
* Get the consecutive evaluated cells that can pass the filter function (e.g. certain type filter).
|
|
15778
|
+
* Return the one which contains the given cell
|
|
15779
|
+
*/
|
|
15780
|
+
function getGroup(cell, cells, filter) {
|
|
15781
|
+
let group = [];
|
|
15782
|
+
let found = false;
|
|
15783
|
+
for (let x of cells) {
|
|
15784
|
+
if (x === cell) {
|
|
15785
|
+
found = true;
|
|
15786
|
+
}
|
|
15787
|
+
const cellValue = evaluateLiteral(x === null || x === void 0 ? void 0 : x.content);
|
|
15788
|
+
if (filter(cellValue)) {
|
|
15789
|
+
group.push(cellValue);
|
|
15790
|
+
}
|
|
15791
|
+
else {
|
|
15792
|
+
if (found) {
|
|
15793
|
+
return group;
|
|
15794
|
+
}
|
|
15795
|
+
group = [];
|
|
15796
|
+
}
|
|
15797
|
+
}
|
|
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";
|
|
16343
16193
|
}
|
|
16344
|
-
|
|
16345
|
-
|
|
16346
|
-
|
|
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) => {
|
|
16347
16224
|
return {
|
|
16348
|
-
|
|
16349
|
-
|
|
16350
|
-
|
|
16351
|
-
|
|
16352
|
-
content,
|
|
16353
|
-
},
|
|
16354
|
-
tooltip: content ? { props: { content } } : undefined,
|
|
16225
|
+
isOpen: true,
|
|
16226
|
+
props: { filterPosition: position },
|
|
16227
|
+
Component: FilterMenu,
|
|
16228
|
+
cellCorner: "BottomLeft",
|
|
16355
16229
|
};
|
|
16356
16230
|
},
|
|
16357
|
-
}
|
|
16231
|
+
};
|
|
16358
16232
|
|
|
16359
|
-
const autofillRulesRegistry = new Registry();
|
|
16360
|
-
const numberPostfixRegExp = /(\d+)$/;
|
|
16361
|
-
const stringPrefixRegExp = /^(.*\D+)/;
|
|
16362
|
-
const alphaNumericValueRegExp = /^(.*\D+)(\d+)$/;
|
|
16363
16233
|
/**
|
|
16364
|
-
*
|
|
16365
|
-
*
|
|
16234
|
+
* Return the o-spreadsheet element position relative
|
|
16235
|
+
* to the browser viewport.
|
|
16366
16236
|
*/
|
|
16367
|
-
function
|
|
16368
|
-
|
|
16369
|
-
let
|
|
16370
|
-
|
|
16371
|
-
|
|
16372
|
-
|
|
16373
|
-
|
|
16374
|
-
const cellValue = evaluateLiteral(x === null || x === void 0 ? void 0 : x.content);
|
|
16375
|
-
if (filter(cellValue)) {
|
|
16376
|
-
group.push(cellValue);
|
|
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");
|
|
16377
16244
|
}
|
|
16378
|
-
|
|
16379
|
-
|
|
16380
|
-
|
|
16381
|
-
|
|
16382
|
-
|
|
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;
|
|
16383
16251
|
}
|
|
16384
16252
|
}
|
|
16385
|
-
|
|
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
|
-
|
|
16591
|
-
.o-filter-menu-actions {
|
|
16592
|
-
display: flex;
|
|
16593
|
-
flex-direction: row;
|
|
16594
|
-
margin-bottom: 4px;
|
|
16595
16558
|
|
|
16596
|
-
|
|
16597
|
-
|
|
16598
|
-
|
|
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.getImageSize(this.figureId);
|
|
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
|
// ---------------------------------------------------------------------------
|
|
@@ -17236,20 +17088,105 @@ class ImageFigure extends Component {
|
|
|
17236
17088
|
}
|
|
17237
17089
|
}
|
|
17238
17090
|
ImageFigure.template = "o-spreadsheet-ImageFigure";
|
|
17239
|
-
ImageFigure.components = {
|
|
17091
|
+
ImageFigure.components = {};
|
|
17240
17092
|
ImageFigure.props = {
|
|
17241
17093
|
figure: Object,
|
|
17242
17094
|
onFigureDeleted: Function,
|
|
17243
17095
|
};
|
|
17244
17096
|
|
|
17245
17097
|
const figureRegistry = new Registry();
|
|
17246
|
-
figureRegistry.add("chart", {
|
|
17098
|
+
figureRegistry.add("chart", {
|
|
17099
|
+
Component: ChartFigure,
|
|
17100
|
+
SidePanelComponent: "ChartPanel",
|
|
17101
|
+
menuBuilder: getChartMenu,
|
|
17102
|
+
});
|
|
17247
17103
|
figureRegistry.add("image", {
|
|
17248
17104
|
Component: ImageFigure,
|
|
17249
17105
|
keepRatio: true,
|
|
17250
17106
|
minFigSize: 20,
|
|
17251
17107
|
borderWidth: 0,
|
|
17252
|
-
|
|
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
|
+
}
|
|
17253
17190
|
|
|
17254
17191
|
const inverseCommandRegistry = new Registry()
|
|
17255
17192
|
.add("ADD_COLUMNS_ROWS", inverseAddColumnsRows)
|
|
@@ -18424,7 +18361,7 @@ class ColorPicker extends Component {
|
|
|
18424
18361
|
}
|
|
18425
18362
|
onColorClick(color) {
|
|
18426
18363
|
if (color) {
|
|
18427
|
-
this.props.onColorPicked(color);
|
|
18364
|
+
this.props.onColorPicked(toHex(color));
|
|
18428
18365
|
}
|
|
18429
18366
|
}
|
|
18430
18367
|
getCheckMarkColor() {
|
|
@@ -18439,8 +18376,10 @@ class ColorPicker extends Component {
|
|
|
18439
18376
|
this.state.isCurrentColorInvalid = true;
|
|
18440
18377
|
return;
|
|
18441
18378
|
}
|
|
18379
|
+
const color = toHex(this.state.currentColor);
|
|
18442
18380
|
this.state.isCurrentColorInvalid = false;
|
|
18443
|
-
this.props.onColorPicked(
|
|
18381
|
+
this.props.onColorPicked(color);
|
|
18382
|
+
this.state.currentColor = color;
|
|
18444
18383
|
}
|
|
18445
18384
|
toggleColorPicker() {
|
|
18446
18385
|
this.state.showGradient = !this.state.showGradient;
|
|
@@ -20177,9 +20116,8 @@ css /*SCSS*/ `
|
|
|
20177
20116
|
|
|
20178
20117
|
.o-figure-menu {
|
|
20179
20118
|
right: 0px;
|
|
20119
|
+
top: 0px;
|
|
20180
20120
|
display: none;
|
|
20181
|
-
position: absolute;
|
|
20182
|
-
padding: 5px;
|
|
20183
20121
|
}
|
|
20184
20122
|
|
|
20185
20123
|
.o-figure-menu-item {
|
|
@@ -20197,7 +20135,10 @@ css /*SCSS*/ `
|
|
|
20197
20135
|
class FigureComponent extends Component {
|
|
20198
20136
|
constructor() {
|
|
20199
20137
|
super(...arguments);
|
|
20138
|
+
this.menuState = useState({ isOpen: false, position: null, menuItems: [] });
|
|
20200
20139
|
this.figureRef = useRef("figure");
|
|
20140
|
+
this.menuButtonRef = useRef("menuButton");
|
|
20141
|
+
this.menuButtonRect = useAbsoluteBoundingRect(this.menuButtonRef);
|
|
20201
20142
|
}
|
|
20202
20143
|
get isSelected() {
|
|
20203
20144
|
return this.env.model.getters.getSelectedFigureId() === this.props.figure.id;
|
|
@@ -20305,9 +20246,33 @@ class FigureComponent extends Component {
|
|
|
20305
20246
|
break;
|
|
20306
20247
|
}
|
|
20307
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
|
+
}
|
|
20308
20273
|
}
|
|
20309
20274
|
FigureComponent.template = "o-spreadsheet-FigureComponent";
|
|
20310
|
-
FigureComponent.components = {};
|
|
20275
|
+
FigureComponent.components = { Menu };
|
|
20311
20276
|
FigureComponent.defaultProps = {
|
|
20312
20277
|
onFigureDeleted: () => { },
|
|
20313
20278
|
onMouseDown: () => { },
|
|
@@ -22392,6 +22357,7 @@ const XLSX_RELATION_TYPE = {
|
|
|
22392
22357
|
theme: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme",
|
|
22393
22358
|
table: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
|
|
22394
22359
|
hyperlink: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
|
|
22360
|
+
image: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
|
|
22395
22361
|
};
|
|
22396
22362
|
const RELATIONSHIP_NSR = "http://schemas.openxmlformats.org/officeDocument/2006/relationships";
|
|
22397
22363
|
const HEIGHT_FACTOR = 0.75; // 100px => 75 u
|
|
@@ -23415,12 +23381,8 @@ function getCellType(value) {
|
|
|
23415
23381
|
return "n";
|
|
23416
23382
|
}
|
|
23417
23383
|
}
|
|
23418
|
-
/**
|
|
23419
|
-
* For some reason, Excel will only take the devicePixelRatio (i.e. interface scale on Windows desktop)
|
|
23420
|
-
* into account for the height.
|
|
23421
|
-
*/
|
|
23422
23384
|
function convertHeightToExcel(height) {
|
|
23423
|
-
return Math.round(HEIGHT_FACTOR * height *
|
|
23385
|
+
return Math.round(HEIGHT_FACTOR * height * 100) / 100;
|
|
23424
23386
|
}
|
|
23425
23387
|
function convertWidthToExcel(width) {
|
|
23426
23388
|
return Math.round(WIDTH_FACTOR * width * 100) / 100;
|
|
@@ -23562,6 +23524,19 @@ function convertChartId(chartId) {
|
|
|
23562
23524
|
}
|
|
23563
23525
|
return xlsxId + 1;
|
|
23564
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
|
+
}
|
|
23565
23540
|
/**
|
|
23566
23541
|
* Convert a value expressed in dot to EMU.
|
|
23567
23542
|
* EMU = English Metrical Unit
|
|
@@ -26323,6 +26298,7 @@ function createEmptyExcelSheet(sheetId, name) {
|
|
|
26323
26298
|
return {
|
|
26324
26299
|
...createEmptySheet(sheetId, name),
|
|
26325
26300
|
charts: [],
|
|
26301
|
+
images: [],
|
|
26326
26302
|
};
|
|
26327
26303
|
}
|
|
26328
26304
|
function createEmptyExcelWorkbookData() {
|
|
@@ -28958,7 +28934,7 @@ class FiltersPlugin extends CorePlugin {
|
|
|
28958
28934
|
filters.push(new Filter(filter.id, filterZone));
|
|
28959
28935
|
}
|
|
28960
28936
|
// Add filters for new columns
|
|
28961
|
-
if (filters.length < zoneToDimension(zone).
|
|
28937
|
+
if (filters.length < zoneToDimension(zone).numberOfCols) {
|
|
28962
28938
|
for (let col = zone.left; col <= zone.right; col++) {
|
|
28963
28939
|
if (!filters.find((filter) => filter.col === col)) {
|
|
28964
28940
|
filters.push(new Filter(this.uuidGenerator.uuidv4(), { ...zone, left: col, right: col }));
|
|
@@ -29609,6 +29585,24 @@ class ImagePlugin extends CorePlugin {
|
|
|
29609
29585
|
}
|
|
29610
29586
|
}
|
|
29611
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
|
+
}
|
|
29612
29606
|
getAllImages() {
|
|
29613
29607
|
const images = [];
|
|
29614
29608
|
for (const sheetId in this.images) {
|
|
@@ -29806,8 +29800,8 @@ class MergePlugin extends CorePlugin {
|
|
|
29806
29800
|
if (merge) {
|
|
29807
29801
|
return isEqual(zone, merge);
|
|
29808
29802
|
}
|
|
29809
|
-
const {
|
|
29810
|
-
return
|
|
29803
|
+
const { numberOfCols, numberOfRows } = zoneToDimension(zone);
|
|
29804
|
+
return numberOfCols === 1 && numberOfRows === 1;
|
|
29811
29805
|
}
|
|
29812
29806
|
// ---------------------------------------------------------------------------
|
|
29813
29807
|
// Merges
|
|
@@ -29975,8 +29969,8 @@ class MergePlugin extends CorePlugin {
|
|
|
29975
29969
|
this.removeMerge(sheetId, currentZone);
|
|
29976
29970
|
break;
|
|
29977
29971
|
default:
|
|
29978
|
-
const {
|
|
29979
|
-
if (
|
|
29972
|
+
const { numberOfCols, numberOfRows } = zoneToDimension(result.range.zone);
|
|
29973
|
+
if (numberOfCols === 1 && numberOfRows === 1) {
|
|
29980
29974
|
this.removeMerge(sheetId, currentZone);
|
|
29981
29975
|
}
|
|
29982
29976
|
else {
|
|
@@ -30735,8 +30729,8 @@ class SheetPlugin extends CorePlugin {
|
|
|
30735
30729
|
}
|
|
30736
30730
|
getSheetSize(sheetId) {
|
|
30737
30731
|
return {
|
|
30738
|
-
|
|
30739
|
-
|
|
30732
|
+
numberOfRows: this.getNumberRows(sheetId),
|
|
30733
|
+
numberOfCols: this.getNumberCols(sheetId),
|
|
30740
30734
|
};
|
|
30741
30735
|
}
|
|
30742
30736
|
getSheetZone(sheetId) {
|
|
@@ -32252,6 +32246,9 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
32252
32246
|
case "CREATE_SHEET":
|
|
32253
32247
|
this.filterValues[cmd.sheetId] = {};
|
|
32254
32248
|
break;
|
|
32249
|
+
case "HIDE_COLUMNS_ROWS":
|
|
32250
|
+
this.updateHiddenRows();
|
|
32251
|
+
break;
|
|
32255
32252
|
case "UPDATE_FILTER":
|
|
32256
32253
|
this.updateFilter(cmd);
|
|
32257
32254
|
this.updateHiddenRows();
|
|
@@ -32360,9 +32357,16 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
32360
32357
|
updateHiddenRows() {
|
|
32361
32358
|
var _a, _b;
|
|
32362
32359
|
const sheetId = this.getters.getActiveSheetId();
|
|
32363
|
-
const filters = this.getters
|
|
32360
|
+
const filters = this.getters
|
|
32361
|
+
.getFilters(sheetId)
|
|
32362
|
+
.sort((filter1, filter2) => filter1.zoneWithHeaders.top - filter2.zoneWithHeaders.top);
|
|
32364
32363
|
const hiddenRows = new Set();
|
|
32365
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;
|
|
32366
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);
|
|
32367
32371
|
if (!filteredValues || !filter.filteredZone)
|
|
32368
32372
|
continue;
|
|
@@ -32385,7 +32389,7 @@ class FilterEvaluationPlugin extends UIPlugin {
|
|
|
32385
32389
|
const tableZone = toZone(tableData.range);
|
|
32386
32390
|
const filters = [];
|
|
32387
32391
|
const headerNames = [];
|
|
32388
|
-
for (const i of range(0, zoneToDimension(tableZone).
|
|
32392
|
+
for (const i of range(0, zoneToDimension(tableZone).numberOfCols)) {
|
|
32389
32393
|
const position = {
|
|
32390
32394
|
sheetId: sheetData.id,
|
|
32391
32395
|
col: tableZone.left + i,
|
|
@@ -33896,7 +33900,7 @@ class AutomaticSumPlugin extends UIPlugin {
|
|
|
33896
33900
|
dimensionsToSum(sheetId, zone) {
|
|
33897
33901
|
const dimensions = new Set();
|
|
33898
33902
|
if (isOneDimensional(zone)) {
|
|
33899
|
-
dimensions.add(zoneToDimension(zone).
|
|
33903
|
+
dimensions.add(zoneToDimension(zone).numberOfCols === 1 ? "COL" : "ROW");
|
|
33900
33904
|
return dimensions;
|
|
33901
33905
|
}
|
|
33902
33906
|
if (this.lastColIsEmpty(sheetId, zone)) {
|
|
@@ -34484,8 +34488,8 @@ class HighlightPlugin extends UIPlugin {
|
|
|
34484
34488
|
x.zone.bottom < this.getters.getNumberRows(x.sheetId) &&
|
|
34485
34489
|
x.zone.right < this.getters.getNumberCols(x.sheetId))
|
|
34486
34490
|
.map((highlight) => {
|
|
34487
|
-
const {
|
|
34488
|
-
const zone =
|
|
34491
|
+
const { numberOfRows, numberOfCols } = zoneToDimension(highlight.zone);
|
|
34492
|
+
const zone = numberOfRows * numberOfCols === 1
|
|
34489
34493
|
? this.getters.expandZone(highlight.sheetId, highlight.zone)
|
|
34490
34494
|
: highlight.zone;
|
|
34491
34495
|
return {
|
|
@@ -36392,7 +36396,7 @@ class SortPlugin extends UIPlugin {
|
|
|
36392
36396
|
const merges = this.getters.getMerges(sheetId).filter((merge) => overlap(merge, zone));
|
|
36393
36397
|
/*Test the presence of merges of different sizes*/
|
|
36394
36398
|
const mergeDimension = zoneToDimension(merges[0]);
|
|
36395
|
-
let [widthFirst, heightFirst] = [mergeDimension.
|
|
36399
|
+
let [widthFirst, heightFirst] = [mergeDimension.numberOfCols, mergeDimension.numberOfRows];
|
|
36396
36400
|
if (!merges.every((merge) => {
|
|
36397
36401
|
let [widthCurrent, heightCurrent] = [
|
|
36398
36402
|
merge.right - merge.left + 1,
|
|
@@ -37525,9 +37529,9 @@ class ClipboardOsState extends ClipboardCellsAbstractState {
|
|
|
37525
37529
|
const values = this.values;
|
|
37526
37530
|
const pasteZone = this.getPasteZone(target);
|
|
37527
37531
|
const { left: activeCol, top: activeRow } = pasteZone;
|
|
37528
|
-
const {
|
|
37532
|
+
const { numberOfCols, numberOfRows } = zoneToDimension(pasteZone);
|
|
37529
37533
|
const sheetId = this.getters.getActiveSheetId();
|
|
37530
|
-
this.addMissingDimensions(
|
|
37534
|
+
this.addMissingDimensions(numberOfCols, numberOfRows, activeCol, activeRow);
|
|
37531
37535
|
for (let i = 0; i < values.length; i++) {
|
|
37532
37536
|
for (let j = 0; j < values[i].length; j++) {
|
|
37533
37537
|
this.dispatch("UPDATE_CELL", {
|
|
@@ -37541,8 +37545,8 @@ class ClipboardOsState extends ClipboardCellsAbstractState {
|
|
|
37541
37545
|
const zone = {
|
|
37542
37546
|
left: activeCol,
|
|
37543
37547
|
top: activeRow,
|
|
37544
|
-
right: activeCol +
|
|
37545
|
-
bottom: activeRow +
|
|
37548
|
+
right: activeCol + numberOfCols - 1,
|
|
37549
|
+
bottom: activeRow + numberOfRows - 1,
|
|
37546
37550
|
};
|
|
37547
37551
|
this.selection.selectZone({ cell: { col: activeCol, row: activeRow }, zone });
|
|
37548
37552
|
}
|
|
@@ -43641,7 +43645,7 @@ function getExcelThresholdType(type, position) {
|
|
|
43641
43645
|
}
|
|
43642
43646
|
}
|
|
43643
43647
|
|
|
43644
|
-
function createDrawing(
|
|
43648
|
+
function createDrawing(drawingRelIds, sheet, figures) {
|
|
43645
43649
|
const namespaces = [
|
|
43646
43650
|
["xmlns:xdr", NAMESPACE.drawing],
|
|
43647
43651
|
["xmlns:r", RELATIONSHIP_NSR],
|
|
@@ -43650,46 +43654,14 @@ function createDrawing(chartRelIds, sheet, figures) {
|
|
|
43650
43654
|
];
|
|
43651
43655
|
const figuresNodes = [];
|
|
43652
43656
|
for (const [figureIndex, figure] of Object.entries(figures)) {
|
|
43653
|
-
|
|
43654
|
-
|
|
43655
|
-
|
|
43656
|
-
|
|
43657
|
-
|
|
43658
|
-
|
|
43659
|
-
|
|
43660
|
-
|
|
43661
|
-
figuresNodes.push(escapeXml /*xml*/ `
|
|
43662
|
-
<xdr:twoCellAnchor>
|
|
43663
|
-
<xdr:from>
|
|
43664
|
-
<xdr:col>${from.col}</xdr:col>
|
|
43665
|
-
<xdr:colOff>${from.colOff}</xdr:colOff>
|
|
43666
|
-
<xdr:row>${from.row}</xdr:row>
|
|
43667
|
-
<xdr:rowOff>${from.rowOff}</xdr:rowOff>
|
|
43668
|
-
</xdr:from>
|
|
43669
|
-
<xdr:to>
|
|
43670
|
-
<xdr:col>${to.col}</xdr:col>
|
|
43671
|
-
<xdr:colOff>${to.colOff}</xdr:colOff>
|
|
43672
|
-
<xdr:row>${to.row}</xdr:row>
|
|
43673
|
-
<xdr:rowOff>${to.rowOff}</xdr:rowOff>
|
|
43674
|
-
</xdr:to>
|
|
43675
|
-
<xdr:graphicFrame>
|
|
43676
|
-
<xdr:nvGraphicFramePr>
|
|
43677
|
-
<xdr:cNvPr ${formatAttributes(cNvPrAttrs)} />
|
|
43678
|
-
<xdr:cNvGraphicFramePr />
|
|
43679
|
-
</xdr:nvGraphicFramePr>
|
|
43680
|
-
<xdr:xfrm>
|
|
43681
|
-
<a:off x="0" y="0"/>
|
|
43682
|
-
<a:ext cx="0" cy="0"/>
|
|
43683
|
-
</xdr:xfrm>
|
|
43684
|
-
<a:graphic>
|
|
43685
|
-
<a:graphicData uri="${DRAWING_NS_C}">
|
|
43686
|
-
<c:chart r:id="${chartRelIds[figureIndex]}" />
|
|
43687
|
-
</a:graphicData>
|
|
43688
|
-
</a:graphic>
|
|
43689
|
-
</xdr:graphicFrame>
|
|
43690
|
-
<xdr:clientData fLocksWithSheet="0"/>
|
|
43691
|
-
</xdr:twoCellAnchor>
|
|
43692
|
-
`);
|
|
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
|
+
}
|
|
43693
43665
|
}
|
|
43694
43666
|
const xml = escapeXml /*xml*/ `
|
|
43695
43667
|
<xdr:wsDr ${formatAttributes(namespaces)}>
|
|
@@ -43744,6 +43716,93 @@ function figureCoordinates(headers, position) {
|
|
|
43744
43716
|
index: headers.length - 1,
|
|
43745
43717
|
offset: convertDotValueToEMU(position - currentPosition + FIGURE_BORDER_SIZE),
|
|
43746
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
|
+
`;
|
|
43747
43806
|
}
|
|
43748
43807
|
|
|
43749
43808
|
function addNumberFormats(numFmts) {
|
|
@@ -43939,7 +43998,7 @@ function addAutoFilter(table) {
|
|
|
43939
43998
|
function addFilterColumns(table) {
|
|
43940
43999
|
const tableZone = toZone(table.range);
|
|
43941
44000
|
const columns = [];
|
|
43942
|
-
for (const i of range(0, zoneToDimension(tableZone).
|
|
44001
|
+
for (const i of range(0, zoneToDimension(tableZone).numberOfCols)) {
|
|
43943
44002
|
const filter = table.filters[i];
|
|
43944
44003
|
if (!filter || !filter.filteredValues.length) {
|
|
43945
44004
|
continue;
|
|
@@ -43965,7 +44024,7 @@ function addTableColumns(table, sheetData) {
|
|
|
43965
44024
|
var _a;
|
|
43966
44025
|
const tableZone = toZone(table.range);
|
|
43967
44026
|
const columns = [];
|
|
43968
|
-
for (const i of range(0, zoneToDimension(tableZone).
|
|
44027
|
+
for (const i of range(0, zoneToDimension(tableZone).numberOfCols)) {
|
|
43969
44028
|
const colHeaderXc = toXC(tableZone.left + i, tableZone.top);
|
|
43970
44029
|
const colName = ((_a = sheetData.cells[colHeaderXc]) === null || _a === void 0 ? void 0 : _a.content) || `col${i}`;
|
|
43971
44030
|
const colAttributes = [
|
|
@@ -44213,23 +44272,37 @@ function createWorksheets(data, construct) {
|
|
|
44213
44272
|
currentTableIndex += sheet.filterTables.length;
|
|
44214
44273
|
// Figures and Charts
|
|
44215
44274
|
let drawingNode = escapeXml ``;
|
|
44275
|
+
const drawingRelIds = [];
|
|
44216
44276
|
const charts = sheet.charts;
|
|
44217
|
-
|
|
44218
|
-
const
|
|
44219
|
-
|
|
44220
|
-
|
|
44221
|
-
|
|
44222
|
-
|
|
44223
|
-
|
|
44224
|
-
|
|
44225
|
-
|
|
44226
|
-
|
|
44227
|
-
|
|
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) {
|
|
44228
44301
|
const drawingRelId = addRelsToFile(construct.relsFiles, `xl/worksheets/_rels/sheet${sheetIndex}.xml.rels`, {
|
|
44229
44302
|
target: `../drawings/drawing${sheetIndex}.xml`,
|
|
44230
44303
|
type: XLSX_RELATION_TYPE.drawing,
|
|
44231
44304
|
});
|
|
44232
|
-
files.push(createXMLFile(createDrawing(
|
|
44305
|
+
files.push(createXMLFile(createDrawing(drawingRelIds, sheet, drawings), `xl/drawings/drawing${sheetIndex}.xml`, "drawing"));
|
|
44233
44306
|
drawingNode = escapeXml /*xml*/ `<drawing r:id="${drawingRelId}" />`;
|
|
44234
44307
|
}
|
|
44235
44308
|
const sheetXml = escapeXml /*xml*/ `
|
|
@@ -44343,7 +44416,7 @@ function createRelsFiles(relsFiles) {
|
|
|
44343
44416
|
function createContentTypes(files) {
|
|
44344
44417
|
const overrideNodes = [];
|
|
44345
44418
|
for (const file of files) {
|
|
44346
|
-
if (file.contentType) {
|
|
44419
|
+
if ("contentType" in file && file.contentType) {
|
|
44347
44420
|
overrideNodes.push(createOverride("/" + file.path, CONTENT_TYPES[file.contentType]));
|
|
44348
44421
|
}
|
|
44349
44422
|
}
|
|
@@ -44871,6 +44944,6 @@ function addFunction(functionName, functionDescription) {
|
|
|
44871
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 };
|
|
44872
44945
|
|
|
44873
44946
|
|
|
44874
|
-
__info__.version = '16.2.0-alpha.
|
|
44875
|
-
__info__.date = '2023-03-
|
|
44876
|
-
__info__.hash = '
|
|
44947
|
+
__info__.version = '16.2.0-alpha.4';
|
|
44948
|
+
__info__.date = '2023-03-14T09:24:38.219Z';
|
|
44949
|
+
__info__.hash = '2c6fe88';
|