@odoo/o-spreadsheet 18.2.0-alpha.6 → 18.2.0-alpha.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/o-spreadsheet.cjs.js +1855 -1712
- package/dist/o-spreadsheet.d.ts +408 -384
- package/dist/o-spreadsheet.esm.js +1855 -1712
- package/dist/o-spreadsheet.iife.js +1852 -1709
- package/dist/o-spreadsheet.iife.min.js +328 -328
- package/dist/o_spreadsheet.xml +28 -28
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.2.0-alpha.
|
|
6
|
-
* @date 2025-02-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.2.0-alpha.7
|
|
6
|
+
* @date 2025-02-10T09:01:19.353Z
|
|
7
|
+
* @hash 0432f17
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, App, blockDom, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
|
|
@@ -769,9 +769,16 @@ function deepEqualsArray(arr1, arr2) {
|
|
|
769
769
|
}
|
|
770
770
|
return true;
|
|
771
771
|
}
|
|
772
|
-
/**
|
|
772
|
+
/**
|
|
773
|
+
* Check if the given array contains all the values of the other array.
|
|
774
|
+
* It makes the assumption that both array do not contain duplicates.
|
|
775
|
+
*/
|
|
773
776
|
function includesAll(arr, values) {
|
|
774
|
-
|
|
777
|
+
if (arr.length < values.length) {
|
|
778
|
+
return false;
|
|
779
|
+
}
|
|
780
|
+
const set = new Set(arr);
|
|
781
|
+
return values.every((value) => set.has(value));
|
|
775
782
|
}
|
|
776
783
|
/**
|
|
777
784
|
* Return an object with all the keys in the object that have a falsy value removed.
|
|
@@ -3645,10 +3652,8 @@ var CommandResult;
|
|
|
3645
3652
|
CommandResult["GaugeRangeMinNaN"] = "GaugeRangeMinNaN";
|
|
3646
3653
|
CommandResult["EmptyGaugeRangeMax"] = "EmptyGaugeRangeMax";
|
|
3647
3654
|
CommandResult["GaugeRangeMaxNaN"] = "GaugeRangeMaxNaN";
|
|
3648
|
-
CommandResult["GaugeRangeMinBiggerThanRangeMax"] = "GaugeRangeMinBiggerThanRangeMax";
|
|
3649
3655
|
CommandResult["GaugeLowerInflectionPointNaN"] = "GaugeLowerInflectionPointNaN";
|
|
3650
3656
|
CommandResult["GaugeUpperInflectionPointNaN"] = "GaugeUpperInflectionPointNaN";
|
|
3651
|
-
CommandResult["GaugeLowerBiggerThanUpper"] = "GaugeLowerBiggerThanUpper";
|
|
3652
3657
|
CommandResult["InvalidAutofillSelection"] = "InvalidAutofillSelection";
|
|
3653
3658
|
CommandResult["MinBiggerThanMax"] = "MinBiggerThanMax";
|
|
3654
3659
|
CommandResult["LowerBiggerThanUpper"] = "LowerBiggerThanUpper";
|
|
@@ -27948,7 +27953,6 @@ const ChartTerms = {
|
|
|
27948
27953
|
["GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */]: _t("The minimum range limit value must be a number"),
|
|
27949
27954
|
["EmptyGaugeRangeMax" /* CommandResult.EmptyGaugeRangeMax */]: _t("A maximum range limit value is needed"),
|
|
27950
27955
|
["GaugeRangeMaxNaN" /* CommandResult.GaugeRangeMaxNaN */]: _t("The maximum range limit value must be a number"),
|
|
27951
|
-
["GaugeRangeMinBiggerThanRangeMax" /* CommandResult.GaugeRangeMinBiggerThanRangeMax */]: _t("Minimum range limit must be smaller than maximum range limit"),
|
|
27952
27956
|
["GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */]: _t("The lower inflection point value must be a number"),
|
|
27953
27957
|
["GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */]: _t("The upper inflection point value must be a number"),
|
|
27954
27958
|
},
|
|
@@ -29770,6 +29774,8 @@ function getGeoChartTooltip(definition, args) {
|
|
|
29770
29774
|
const { locale, axisFormats } = args;
|
|
29771
29775
|
const format = axisFormats?.y || axisFormats?.y1;
|
|
29772
29776
|
return {
|
|
29777
|
+
enabled: false,
|
|
29778
|
+
external: customTooltipHandler,
|
|
29773
29779
|
filter: function (tooltipItem) {
|
|
29774
29780
|
return tooltipItem.raw.value !== undefined;
|
|
29775
29781
|
},
|
|
@@ -30223,14 +30229,6 @@ function checkInflectionPointsValue(check, batchValidations) {
|
|
|
30223
30229
|
return "Success" /* CommandResult.Success */;
|
|
30224
30230
|
});
|
|
30225
30231
|
}
|
|
30226
|
-
function checkRangeMinBiggerThanRangeMax(definition) {
|
|
30227
|
-
if (definition.sectionRule) {
|
|
30228
|
-
if (Number(definition.sectionRule.rangeMin) >= Number(definition.sectionRule.rangeMax)) {
|
|
30229
|
-
return "GaugeRangeMinBiggerThanRangeMax" /* CommandResult.GaugeRangeMinBiggerThanRangeMax */;
|
|
30230
|
-
}
|
|
30231
|
-
}
|
|
30232
|
-
return "Success" /* CommandResult.Success */;
|
|
30233
|
-
}
|
|
30234
30232
|
function checkEmpty(value, valueName) {
|
|
30235
30233
|
if (value === "") {
|
|
30236
30234
|
switch (valueName) {
|
|
@@ -30242,7 +30240,10 @@ function checkEmpty(value, valueName) {
|
|
|
30242
30240
|
}
|
|
30243
30241
|
return "Success" /* CommandResult.Success */;
|
|
30244
30242
|
}
|
|
30245
|
-
function
|
|
30243
|
+
function checkValueIsNumberOrFormula(value, valueName) {
|
|
30244
|
+
if (value.startsWith("=")) {
|
|
30245
|
+
return "Success" /* CommandResult.Success */;
|
|
30246
|
+
}
|
|
30246
30247
|
if (isNaN(value)) {
|
|
30247
30248
|
switch (valueName) {
|
|
30248
30249
|
case "rangeMin":
|
|
@@ -30269,7 +30270,7 @@ class GaugeChart extends AbstractChart {
|
|
|
30269
30270
|
this.background = definition.background;
|
|
30270
30271
|
}
|
|
30271
30272
|
static validateChartDefinition(validator, definition) {
|
|
30272
|
-
return validator.checkValidations(definition, isDataRangeValid, validator.chainValidations(checkRangeLimits(checkEmpty, validator.batchValidations), checkRangeLimits(
|
|
30273
|
+
return validator.checkValidations(definition, isDataRangeValid, validator.chainValidations(checkRangeLimits(checkEmpty, validator.batchValidations), checkRangeLimits(checkValueIsNumberOrFormula, validator.batchValidations)), validator.chainValidations(checkInflectionPointsValue(checkValueIsNumberOrFormula, validator.batchValidations)));
|
|
30273
30274
|
}
|
|
30274
30275
|
static transformDefinition(definition, executed) {
|
|
30275
30276
|
let dataRangeZone;
|
|
@@ -30310,20 +30311,24 @@ class GaugeChart extends AbstractChart {
|
|
|
30310
30311
|
}
|
|
30311
30312
|
duplicateInDuplicatedSheet(newSheetId) {
|
|
30312
30313
|
const dataRange = duplicateLabelRangeInDuplicatedSheet(this.sheetId, newSheetId, this.dataRange);
|
|
30313
|
-
const
|
|
30314
|
+
const adaptFormula = (formula) => this.getters.copyFormulaStringForSheet(this.sheetId, newSheetId, formula, "moveReference");
|
|
30315
|
+
const sectionRule = adaptSectionRuleFormulas(this.sectionRule, adaptFormula);
|
|
30316
|
+
const definition = this.getDefinitionWithSpecificRanges(dataRange, sectionRule, newSheetId);
|
|
30314
30317
|
return new GaugeChart(definition, newSheetId, this.getters);
|
|
30315
30318
|
}
|
|
30316
30319
|
copyInSheetId(sheetId) {
|
|
30317
|
-
const
|
|
30320
|
+
const adaptFormula = (formula) => this.getters.copyFormulaStringForSheet(this.sheetId, sheetId, formula, "keepSameReference");
|
|
30321
|
+
const sectionRule = adaptSectionRuleFormulas(this.sectionRule, adaptFormula);
|
|
30322
|
+
const definition = this.getDefinitionWithSpecificRanges(this.dataRange, sectionRule, sheetId);
|
|
30318
30323
|
return new GaugeChart(definition, sheetId, this.getters);
|
|
30319
30324
|
}
|
|
30320
30325
|
getDefinition() {
|
|
30321
|
-
return this.getDefinitionWithSpecificRanges(this.dataRange);
|
|
30326
|
+
return this.getDefinitionWithSpecificRanges(this.dataRange, this.sectionRule);
|
|
30322
30327
|
}
|
|
30323
|
-
getDefinitionWithSpecificRanges(dataRange, targetSheetId) {
|
|
30328
|
+
getDefinitionWithSpecificRanges(dataRange, sectionRule, targetSheetId) {
|
|
30324
30329
|
return {
|
|
30325
30330
|
background: this.background,
|
|
30326
|
-
sectionRule:
|
|
30331
|
+
sectionRule: sectionRule,
|
|
30327
30332
|
title: this.title,
|
|
30328
30333
|
type: "gauge",
|
|
30329
30334
|
dataRange: dataRange
|
|
@@ -30344,11 +30349,10 @@ class GaugeChart extends AbstractChart {
|
|
|
30344
30349
|
};
|
|
30345
30350
|
}
|
|
30346
30351
|
updateRanges(applyChange) {
|
|
30347
|
-
const
|
|
30348
|
-
|
|
30349
|
-
|
|
30350
|
-
|
|
30351
|
-
const definition = this.getDefinitionWithSpecificRanges(range);
|
|
30352
|
+
const dataRange = adaptChartRange(this.dataRange, applyChange);
|
|
30353
|
+
const adaptFormula = (formula) => this.getters.adaptFormulaStringDependencies(this.sheetId, formula, applyChange);
|
|
30354
|
+
const sectionRule = adaptSectionRuleFormulas(this.sectionRule, adaptFormula);
|
|
30355
|
+
const definition = this.getDefinitionWithSpecificRanges(dataRange, sectionRule);
|
|
30352
30356
|
return new GaugeChart(definition, this.sheetId, this.getters);
|
|
30353
30357
|
}
|
|
30354
30358
|
}
|
|
@@ -30371,12 +30375,18 @@ function createGaugeChartRuntime(chart, getters) {
|
|
|
30371
30375
|
format = cell.format;
|
|
30372
30376
|
}
|
|
30373
30377
|
}
|
|
30374
|
-
|
|
30375
|
-
|
|
30378
|
+
let minValue = getFormulaNumberValue(chart.sheetId, chart.sectionRule.rangeMin, getters);
|
|
30379
|
+
let maxValue = getFormulaNumberValue(chart.sheetId, chart.sectionRule.rangeMax, getters);
|
|
30380
|
+
if (minValue === undefined || maxValue === undefined) {
|
|
30381
|
+
return getInvalidGaugeRuntime(chart, getters);
|
|
30382
|
+
}
|
|
30383
|
+
if (maxValue < minValue) {
|
|
30384
|
+
[minValue, maxValue] = [maxValue, minValue];
|
|
30385
|
+
}
|
|
30376
30386
|
const lowerPoint = chart.sectionRule.lowerInflectionPoint;
|
|
30377
30387
|
const upperPoint = chart.sectionRule.upperInflectionPoint;
|
|
30378
|
-
const lowerPointValue = getSectionThresholdValue(
|
|
30379
|
-
const upperPointValue = getSectionThresholdValue(
|
|
30388
|
+
const lowerPointValue = getSectionThresholdValue(chart.sheetId, chart.sectionRule.lowerInflectionPoint, minValue, maxValue, getters);
|
|
30389
|
+
const upperPointValue = getSectionThresholdValue(chart.sheetId, chart.sectionRule.upperInflectionPoint, minValue, maxValue, getters);
|
|
30380
30390
|
const inflectionValues = [];
|
|
30381
30391
|
const colors = [];
|
|
30382
30392
|
if (lowerPointValue !== undefined) {
|
|
@@ -30424,16 +30434,46 @@ function createGaugeChartRuntime(chart, getters) {
|
|
|
30424
30434
|
colors,
|
|
30425
30435
|
};
|
|
30426
30436
|
}
|
|
30427
|
-
function getSectionThresholdValue(threshold, minValue, maxValue) {
|
|
30428
|
-
|
|
30437
|
+
function getSectionThresholdValue(sheetId, threshold, minValue, maxValue, getters) {
|
|
30438
|
+
const numberValue = getFormulaNumberValue(sheetId, threshold.value, getters);
|
|
30439
|
+
if (numberValue === undefined) {
|
|
30429
30440
|
return undefined;
|
|
30430
30441
|
}
|
|
30431
|
-
const numberValue = Number(threshold.value);
|
|
30432
30442
|
const value = threshold.type === "number"
|
|
30433
30443
|
? numberValue
|
|
30434
30444
|
: minValue + ((maxValue - minValue) * numberValue) / 100;
|
|
30435
30445
|
return clip(value, minValue, maxValue);
|
|
30436
30446
|
}
|
|
30447
|
+
function getFormulaNumberValue(sheetId, formula, getters) {
|
|
30448
|
+
const value = getters.evaluateFormula(sheetId, formula);
|
|
30449
|
+
return isMatrix(value) ? undefined : tryToNumber(value, getters.getLocale());
|
|
30450
|
+
}
|
|
30451
|
+
function getInvalidGaugeRuntime(chart, getters) {
|
|
30452
|
+
return {
|
|
30453
|
+
background: getters.getStyleOfSingleCellChart(chart.background, chart.dataRange).background,
|
|
30454
|
+
title: chart.title ?? { text: "" },
|
|
30455
|
+
minValue: { value: 0, label: "" },
|
|
30456
|
+
maxValue: { value: 100, label: "" },
|
|
30457
|
+
gaugeValue: { value: 0, label: CellErrorType.GenericError },
|
|
30458
|
+
inflectionValues: [],
|
|
30459
|
+
colors: [],
|
|
30460
|
+
};
|
|
30461
|
+
}
|
|
30462
|
+
function adaptSectionRuleFormulas(sectionRule, adaptCallback) {
|
|
30463
|
+
return {
|
|
30464
|
+
...sectionRule,
|
|
30465
|
+
rangeMin: adaptCallback(sectionRule.rangeMin),
|
|
30466
|
+
rangeMax: adaptCallback(sectionRule.rangeMax),
|
|
30467
|
+
lowerInflectionPoint: {
|
|
30468
|
+
...sectionRule.lowerInflectionPoint,
|
|
30469
|
+
value: adaptCallback(sectionRule.lowerInflectionPoint.value),
|
|
30470
|
+
},
|
|
30471
|
+
upperInflectionPoint: {
|
|
30472
|
+
...sectionRule.upperInflectionPoint,
|
|
30473
|
+
value: adaptCallback(sectionRule.upperInflectionPoint.value),
|
|
30474
|
+
},
|
|
30475
|
+
};
|
|
30476
|
+
}
|
|
30437
30477
|
|
|
30438
30478
|
class GeoChart extends AbstractChart {
|
|
30439
30479
|
dataSets;
|
|
@@ -37321,8 +37361,8 @@ function useDragAndDropListItems() {
|
|
|
37321
37361
|
document.body.style.cursor = "move";
|
|
37322
37362
|
state.draggedItemId = args.draggedItemId;
|
|
37323
37363
|
const container = direction === "horizontal"
|
|
37324
|
-
? new HorizontalContainer(args.
|
|
37325
|
-
: new VerticalContainer(args.
|
|
37364
|
+
? new HorizontalContainer(args.scrollableContainerEl)
|
|
37365
|
+
: new VerticalContainer(args.scrollableContainerEl);
|
|
37326
37366
|
dndHelper = new DOMDndHelper({
|
|
37327
37367
|
...args,
|
|
37328
37368
|
container,
|
|
@@ -37333,8 +37373,8 @@ function useDragAndDropListItems() {
|
|
|
37333
37373
|
const stopListening = startDnd(dndHelper.onMouseMove.bind(dndHelper), dndHelper.onMouseUp.bind(dndHelper));
|
|
37334
37374
|
cleanupFns.push(stopListening);
|
|
37335
37375
|
const onScroll = dndHelper.onScroll.bind(dndHelper);
|
|
37336
|
-
args.
|
|
37337
|
-
cleanupFns.push(() => args.
|
|
37376
|
+
args.scrollableContainerEl.addEventListener("scroll", onScroll);
|
|
37377
|
+
cleanupFns.push(() => args.scrollableContainerEl.removeEventListener("scroll", onScroll));
|
|
37338
37378
|
cleanupFns.push(dndHelper.destroy.bind(dndHelper));
|
|
37339
37379
|
};
|
|
37340
37380
|
onWillUnmount(() => {
|
|
@@ -38045,7 +38085,7 @@ class SelectionInput extends Component {
|
|
|
38045
38085
|
draggedItemId: rangeId.toString(),
|
|
38046
38086
|
initialMousePosition: event.clientY,
|
|
38047
38087
|
items: draggableItems,
|
|
38048
|
-
|
|
38088
|
+
scrollableContainerEl: this.selectionRef.el,
|
|
38049
38089
|
onDragEnd: (dimensionName, finalIndex) => {
|
|
38050
38090
|
const originalIndex = draggableIds.findIndex((id) => id === rangeId);
|
|
38051
38091
|
if (originalIndex === finalIndex) {
|
|
@@ -39614,1897 +39654,1954 @@ class GaugeChartConfigPanel extends Component {
|
|
|
39614
39654
|
}
|
|
39615
39655
|
}
|
|
39616
39656
|
|
|
39617
|
-
|
|
39618
|
-
|
|
39619
|
-
|
|
39620
|
-
|
|
39621
|
-
|
|
39622
|
-
display: table;
|
|
39623
|
-
text-align: left;
|
|
39624
|
-
font-size: 12px;
|
|
39625
|
-
line-height: 18px;
|
|
39626
|
-
width: 100%;
|
|
39627
|
-
font-size: 12px;
|
|
39657
|
+
class DOMFocusableElementStore {
|
|
39658
|
+
mutators = ["setFocusableElement"];
|
|
39659
|
+
focusableElement = undefined;
|
|
39660
|
+
setFocusableElement(element) {
|
|
39661
|
+
this.focusableElement = element;
|
|
39628
39662
|
}
|
|
39663
|
+
}
|
|
39629
39664
|
|
|
39630
|
-
|
|
39631
|
-
|
|
39632
|
-
|
|
39633
|
-
|
|
39634
|
-
|
|
39635
|
-
|
|
39636
|
-
|
|
39637
|
-
|
|
39638
|
-
|
|
39639
|
-
|
|
39640
|
-
}
|
|
39641
|
-
th.o-gauge-color-set-operator {
|
|
39642
|
-
width: 10%;
|
|
39643
|
-
}
|
|
39644
|
-
th.o-gauge-color-set-value {
|
|
39645
|
-
width: 22%;
|
|
39646
|
-
}
|
|
39647
|
-
th.o-gauge-color-set-type {
|
|
39648
|
-
width: 30%;
|
|
39665
|
+
css /* scss */ `
|
|
39666
|
+
.o-autocomplete-dropdown {
|
|
39667
|
+
pointer-events: auto;
|
|
39668
|
+
cursor: pointer;
|
|
39669
|
+
background-color: #fff;
|
|
39670
|
+
max-width: 400px;
|
|
39671
|
+
z-index: 1;
|
|
39672
|
+
|
|
39673
|
+
.o-autocomplete-value-focus {
|
|
39674
|
+
background-color: #f2f2f2;
|
|
39649
39675
|
}
|
|
39650
|
-
|
|
39651
|
-
|
|
39652
|
-
|
|
39653
|
-
|
|
39654
|
-
|
|
39676
|
+
|
|
39677
|
+
& > div {
|
|
39678
|
+
padding: 1px 5px 5px 5px;
|
|
39679
|
+
.o-autocomplete-description {
|
|
39680
|
+
padding-left: 5px;
|
|
39681
|
+
font-size: 11px;
|
|
39682
|
+
}
|
|
39655
39683
|
}
|
|
39656
39684
|
}
|
|
39657
39685
|
`;
|
|
39658
|
-
class
|
|
39659
|
-
static template = "o-spreadsheet-
|
|
39660
|
-
static components = {
|
|
39661
|
-
SidePanelCollapsible,
|
|
39662
|
-
Section,
|
|
39663
|
-
RoundColorPicker,
|
|
39664
|
-
GeneralDesignEditor,
|
|
39665
|
-
ChartErrorSection,
|
|
39666
|
-
};
|
|
39686
|
+
class TextValueProvider extends Component {
|
|
39687
|
+
static template = "o-spreadsheet-TextValueProvider";
|
|
39667
39688
|
static props = {
|
|
39668
|
-
|
|
39669
|
-
|
|
39670
|
-
|
|
39671
|
-
|
|
39689
|
+
proposals: Array,
|
|
39690
|
+
selectedIndex: { type: Number, optional: true },
|
|
39691
|
+
onValueSelected: Function,
|
|
39692
|
+
onValueHovered: Function,
|
|
39672
39693
|
};
|
|
39673
|
-
|
|
39694
|
+
autoCompleteListRef = useRef("autoCompleteList");
|
|
39674
39695
|
setup() {
|
|
39675
|
-
|
|
39676
|
-
|
|
39677
|
-
|
|
39678
|
-
|
|
39696
|
+
useEffect(() => {
|
|
39697
|
+
const selectedIndex = this.props.selectedIndex;
|
|
39698
|
+
if (selectedIndex === undefined) {
|
|
39699
|
+
return;
|
|
39700
|
+
}
|
|
39701
|
+
const selectedElement = this.autoCompleteListRef.el?.children[selectedIndex];
|
|
39702
|
+
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
39703
|
+
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
39679
39704
|
}
|
|
39680
|
-
|
|
39681
|
-
|
|
39682
|
-
|
|
39705
|
+
}
|
|
39706
|
+
|
|
39707
|
+
class AutoCompleteStore extends SpreadsheetStore {
|
|
39708
|
+
mutators = ["useProvider", "moveSelection", "hide", "selectIndex"];
|
|
39709
|
+
selectedIndex = undefined;
|
|
39710
|
+
provider;
|
|
39711
|
+
get selectedProposal() {
|
|
39712
|
+
if (this.selectedIndex === undefined || this.provider === undefined) {
|
|
39713
|
+
return undefined;
|
|
39714
|
+
}
|
|
39715
|
+
return this.provider.proposals[this.selectedIndex];
|
|
39683
39716
|
}
|
|
39684
|
-
|
|
39685
|
-
|
|
39686
|
-
|
|
39687
|
-
this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeRangeMinBiggerThanRangeMax" /* CommandResult.GaugeRangeMinBiggerThanRangeMax */));
|
|
39717
|
+
useProvider(provider) {
|
|
39718
|
+
this.provider = provider;
|
|
39719
|
+
this.selectedIndex = provider.autoSelectFirstProposal ? 0 : undefined;
|
|
39688
39720
|
}
|
|
39689
|
-
|
|
39690
|
-
|
|
39691
|
-
|
|
39692
|
-
this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeRangeMinBiggerThanRangeMax" /* CommandResult.GaugeRangeMinBiggerThanRangeMax */));
|
|
39721
|
+
hide() {
|
|
39722
|
+
this.provider = undefined;
|
|
39723
|
+
this.selectedIndex = undefined;
|
|
39693
39724
|
}
|
|
39694
|
-
|
|
39695
|
-
|
|
39696
|
-
// ---------------------------------------------------------------------------
|
|
39697
|
-
get isLowerInflectionPointInvalid() {
|
|
39698
|
-
return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */) ||
|
|
39699
|
-
this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeLowerBiggerThanUpper" /* CommandResult.GaugeLowerBiggerThanUpper */));
|
|
39725
|
+
selectIndex(index) {
|
|
39726
|
+
this.selectedIndex = index;
|
|
39700
39727
|
}
|
|
39701
|
-
|
|
39702
|
-
|
|
39703
|
-
|
|
39728
|
+
moveSelection(direction) {
|
|
39729
|
+
if (!this.provider) {
|
|
39730
|
+
return;
|
|
39731
|
+
}
|
|
39732
|
+
if (this.selectedIndex === undefined) {
|
|
39733
|
+
this.selectedIndex = 0;
|
|
39734
|
+
return;
|
|
39735
|
+
}
|
|
39736
|
+
if (direction === "previous") {
|
|
39737
|
+
this.selectedIndex--;
|
|
39738
|
+
if (this.selectedIndex < 0) {
|
|
39739
|
+
this.selectedIndex = this.provider.proposals.length - 1;
|
|
39740
|
+
}
|
|
39741
|
+
}
|
|
39742
|
+
else {
|
|
39743
|
+
this.selectedIndex = (this.selectedIndex + 1) % this.provider.proposals.length;
|
|
39744
|
+
}
|
|
39704
39745
|
}
|
|
39705
|
-
|
|
39706
|
-
|
|
39707
|
-
|
|
39708
|
-
|
|
39746
|
+
}
|
|
39747
|
+
|
|
39748
|
+
class ContentEditableHelper {
|
|
39749
|
+
// todo make el private and expose dedicated methods
|
|
39750
|
+
el;
|
|
39751
|
+
constructor(el) {
|
|
39752
|
+
this.el = el;
|
|
39709
39753
|
}
|
|
39710
|
-
|
|
39711
|
-
this.
|
|
39712
|
-
|
|
39713
|
-
|
|
39714
|
-
|
|
39715
|
-
|
|
39754
|
+
updateEl(el) {
|
|
39755
|
+
this.el = el;
|
|
39756
|
+
}
|
|
39757
|
+
/**
|
|
39758
|
+
* select the text at position start to end, no matter the children
|
|
39759
|
+
*/
|
|
39760
|
+
selectRange(start, end) {
|
|
39761
|
+
let selection = window.getSelection();
|
|
39762
|
+
const { start: currentStart, end: currentEnd } = this.getCurrentSelection();
|
|
39763
|
+
if (currentStart === start && currentEnd === end) {
|
|
39764
|
+
return;
|
|
39765
|
+
}
|
|
39766
|
+
if (selection.rangeCount === 0) {
|
|
39767
|
+
const range = document.createRange();
|
|
39768
|
+
selection.addRange(range);
|
|
39769
|
+
}
|
|
39770
|
+
const currentRange = selection.getRangeAt(0);
|
|
39771
|
+
let range;
|
|
39772
|
+
if (this.el.contains(currentRange.startContainer)) {
|
|
39773
|
+
range = currentRange;
|
|
39774
|
+
}
|
|
39775
|
+
else {
|
|
39776
|
+
range = document.createRange();
|
|
39777
|
+
selection.removeAllRanges();
|
|
39778
|
+
selection.addRange(range);
|
|
39779
|
+
}
|
|
39780
|
+
if (start === end && start === 0) {
|
|
39781
|
+
range.setStart(this.el, 0);
|
|
39782
|
+
range.setEnd(this.el, 0);
|
|
39783
|
+
}
|
|
39784
|
+
else {
|
|
39785
|
+
const textLength = this.getText().length;
|
|
39786
|
+
if (start < 0 || end > textLength) {
|
|
39787
|
+
console.warn(`wrong selection asked start ${start}, end ${end}, text content length ${textLength}`);
|
|
39788
|
+
if (start < 0)
|
|
39789
|
+
start = 0;
|
|
39790
|
+
if (end > textLength)
|
|
39791
|
+
end = textLength;
|
|
39792
|
+
if (start > textLength)
|
|
39793
|
+
start = textLength;
|
|
39794
|
+
}
|
|
39795
|
+
let startNode = this.findChildAtCharacterIndex(start);
|
|
39796
|
+
let endNode = this.findChildAtCharacterIndex(end);
|
|
39797
|
+
range.setStart(startNode.node, startNode.offset);
|
|
39798
|
+
range.setEnd(endNode.node, endNode.offset);
|
|
39716
39799
|
}
|
|
39717
39800
|
}
|
|
39718
|
-
|
|
39719
|
-
|
|
39720
|
-
|
|
39721
|
-
|
|
39801
|
+
/**
|
|
39802
|
+
* finds the dom element that contains the character at `offset`
|
|
39803
|
+
*/
|
|
39804
|
+
findChildAtCharacterIndex(offset) {
|
|
39805
|
+
let it = iterateChildren(this.el);
|
|
39806
|
+
let current, previous;
|
|
39807
|
+
let usedCharacters = offset;
|
|
39808
|
+
let isFirstParagraph = true;
|
|
39809
|
+
do {
|
|
39810
|
+
current = it.next();
|
|
39811
|
+
if (!current.done && !current.value.hasChildNodes()) {
|
|
39812
|
+
if (current.value.textContent && current.value.textContent.length < usedCharacters) {
|
|
39813
|
+
usedCharacters -= current.value.textContent.length;
|
|
39814
|
+
}
|
|
39815
|
+
else if (current.value.textContent &&
|
|
39816
|
+
current.value.textContent.length >= usedCharacters) {
|
|
39817
|
+
it.return(current.value);
|
|
39818
|
+
}
|
|
39819
|
+
previous = current.value;
|
|
39820
|
+
}
|
|
39821
|
+
// One new paragraph = one new line character, except for the first paragraph
|
|
39822
|
+
if (!current.done && current.value.nodeName === "P") {
|
|
39823
|
+
if (isFirstParagraph) {
|
|
39824
|
+
isFirstParagraph = false;
|
|
39825
|
+
}
|
|
39826
|
+
else {
|
|
39827
|
+
usedCharacters--;
|
|
39828
|
+
}
|
|
39829
|
+
}
|
|
39830
|
+
} while (!current.done && usedCharacters);
|
|
39831
|
+
if (current.value) {
|
|
39832
|
+
return { node: current.value, offset: usedCharacters };
|
|
39833
|
+
}
|
|
39834
|
+
return { node: previous, offset: usedCharacters };
|
|
39722
39835
|
}
|
|
39723
|
-
|
|
39724
|
-
|
|
39725
|
-
|
|
39726
|
-
|
|
39727
|
-
|
|
39728
|
-
|
|
39729
|
-
|
|
39730
|
-
|
|
39731
|
-
|
|
39732
|
-
|
|
39733
|
-
|
|
39734
|
-
|
|
39735
|
-
|
|
39836
|
+
/**
|
|
39837
|
+
* Sets (or Replaces all) the text inside the root element in the form of distinctive paragraphs and
|
|
39838
|
+
* span for each element provided in `contents`.
|
|
39839
|
+
*
|
|
39840
|
+
* The function will apply the diff between the current content and the new content to avoid the systematic
|
|
39841
|
+
* destruction of DOM elements which interferes with IME[1]
|
|
39842
|
+
*
|
|
39843
|
+
* Each line of text will be encapsulated in a paragraph element.
|
|
39844
|
+
* Each span will have its own fontcolor and specific class if provided in the HtmlContent object.
|
|
39845
|
+
*
|
|
39846
|
+
* [1] https://developer.mozilla.org/en-US/docs/Glossary/Input_method_editor
|
|
39847
|
+
*/
|
|
39848
|
+
setText(contents) {
|
|
39849
|
+
if (contents.length === 0) {
|
|
39850
|
+
this.removeAll();
|
|
39851
|
+
return;
|
|
39852
|
+
}
|
|
39853
|
+
const childElements = Array.from(this.el.childNodes);
|
|
39854
|
+
const contentLength = contents.length;
|
|
39855
|
+
for (let i = 0; i < contentLength; i++) {
|
|
39856
|
+
const line = contents[i];
|
|
39857
|
+
const childElement = childElements[i];
|
|
39858
|
+
let newChild = false;
|
|
39859
|
+
let p;
|
|
39860
|
+
if (childElement && childElement.nodeName === "P") {
|
|
39861
|
+
p = childElement;
|
|
39862
|
+
}
|
|
39863
|
+
else {
|
|
39864
|
+
newChild = true;
|
|
39865
|
+
p = document.createElement("p");
|
|
39866
|
+
}
|
|
39867
|
+
const lineLength = line.length;
|
|
39868
|
+
const existingChildren = Array.from(p.childNodes);
|
|
39869
|
+
for (let j = 0; j < lineLength; j++) {
|
|
39870
|
+
const content = line[j];
|
|
39871
|
+
const child = existingChildren[j];
|
|
39872
|
+
// child nodes can be multiple types of nodes: Span, Text, Div, etc...
|
|
39873
|
+
// We can only modify a node in place if it has the same type as the content
|
|
39874
|
+
// that we would insert, which are spans.
|
|
39875
|
+
// Otherwise, it means that the node has been input by the user, through the keyboard or a copy/paste
|
|
39876
|
+
// @ts-ignore (somehow required because jest does not like child.tagName despite the prior check)
|
|
39877
|
+
const childIsSpan = child && "tagName" in child && child.tagName === "SPAN";
|
|
39878
|
+
if (childIsSpan && compareContentToSpanElement(content, child)) {
|
|
39879
|
+
continue;
|
|
39880
|
+
}
|
|
39881
|
+
// this is an empty line in the content
|
|
39882
|
+
if (!content.value && !content.class) {
|
|
39883
|
+
if (child)
|
|
39884
|
+
p.removeChild(child);
|
|
39885
|
+
continue;
|
|
39886
|
+
}
|
|
39887
|
+
const span = document.createElement("span");
|
|
39888
|
+
span.innerText = content.value;
|
|
39889
|
+
span.style.color = content.color || "";
|
|
39890
|
+
if (content.class) {
|
|
39891
|
+
span.classList.add(content.class);
|
|
39892
|
+
}
|
|
39893
|
+
if (child) {
|
|
39894
|
+
p.replaceChild(span, child);
|
|
39895
|
+
}
|
|
39896
|
+
else {
|
|
39897
|
+
p.appendChild(span);
|
|
39898
|
+
}
|
|
39899
|
+
}
|
|
39900
|
+
if (existingChildren.length > lineLength) {
|
|
39901
|
+
for (let i = lineLength; i < existingChildren.length; i++) {
|
|
39902
|
+
p.removeChild(existingChildren[i]);
|
|
39903
|
+
}
|
|
39904
|
+
}
|
|
39905
|
+
// Empty line
|
|
39906
|
+
if (!p.hasChildNodes()) {
|
|
39907
|
+
const span = document.createElement("span");
|
|
39908
|
+
span.appendChild(document.createElement("br"));
|
|
39909
|
+
p.appendChild(span);
|
|
39910
|
+
}
|
|
39911
|
+
// replace p if necessary
|
|
39912
|
+
if (newChild) {
|
|
39913
|
+
if (childElement) {
|
|
39914
|
+
this.el.replaceChild(p, childElement);
|
|
39915
|
+
}
|
|
39916
|
+
else {
|
|
39917
|
+
this.el.appendChild(p);
|
|
39918
|
+
}
|
|
39919
|
+
}
|
|
39920
|
+
}
|
|
39921
|
+
if (childElements.length > contentLength) {
|
|
39922
|
+
for (let i = contentLength; i < childElements.length; i++) {
|
|
39923
|
+
this.el.removeChild(childElements[i]);
|
|
39924
|
+
}
|
|
39925
|
+
}
|
|
39736
39926
|
}
|
|
39737
|
-
|
|
39738
|
-
|
|
39927
|
+
scrollSelectionIntoView() {
|
|
39928
|
+
const focusedNode = document.getSelection()?.focusNode;
|
|
39929
|
+
if (!focusedNode || !this.el.contains(focusedNode))
|
|
39930
|
+
return;
|
|
39931
|
+
const element = focusedNode instanceof HTMLElement ? focusedNode : focusedNode.parentElement;
|
|
39932
|
+
element?.scrollIntoView?.({ block: "nearest" });
|
|
39739
39933
|
}
|
|
39740
|
-
|
|
39741
|
-
|
|
39934
|
+
/**
|
|
39935
|
+
* remove the current selection of the user
|
|
39936
|
+
* */
|
|
39937
|
+
removeSelection() {
|
|
39938
|
+
let selection = window.getSelection();
|
|
39939
|
+
selection.removeAllRanges();
|
|
39742
39940
|
}
|
|
39743
|
-
|
|
39744
|
-
|
|
39745
|
-
|
|
39746
|
-
|
|
39747
|
-
|
|
39748
|
-
|
|
39749
|
-
return this.getDataSeriesRanges().slice(0, 1);
|
|
39941
|
+
removeAll() {
|
|
39942
|
+
if (this.el) {
|
|
39943
|
+
while (this.el.firstChild) {
|
|
39944
|
+
this.el.removeChild(this.el.firstChild);
|
|
39945
|
+
}
|
|
39946
|
+
}
|
|
39750
39947
|
}
|
|
39751
|
-
|
|
39752
|
-
|
|
39753
|
-
|
|
39754
|
-
|
|
39755
|
-
|
|
39948
|
+
/**
|
|
39949
|
+
* finds the indexes of the current selection.
|
|
39950
|
+
* */
|
|
39951
|
+
getCurrentSelection() {
|
|
39952
|
+
return getCurrentSelection(this.el);
|
|
39756
39953
|
}
|
|
39757
|
-
|
|
39758
|
-
|
|
39759
|
-
|
|
39760
|
-
|
|
39761
|
-
|
|
39762
|
-
|
|
39763
|
-
|
|
39764
|
-
|
|
39765
|
-
|
|
39954
|
+
getText() {
|
|
39955
|
+
let text = "";
|
|
39956
|
+
let it = iterateChildren(this.el);
|
|
39957
|
+
let current = it.next();
|
|
39958
|
+
let isFirstParagraph = true;
|
|
39959
|
+
while (!current.done) {
|
|
39960
|
+
if (!current.value.hasChildNodes()) {
|
|
39961
|
+
text += current.value.textContent;
|
|
39962
|
+
}
|
|
39963
|
+
if (current.value.nodeName === "P" ||
|
|
39964
|
+
(current.value.nodeName === "DIV" && current.value !== this.el) // On paste, the HTML may contain <div> instead of <p>
|
|
39965
|
+
) {
|
|
39966
|
+
if (isFirstParagraph) {
|
|
39967
|
+
isFirstParagraph = false;
|
|
39968
|
+
}
|
|
39969
|
+
else {
|
|
39970
|
+
text += NEWLINE;
|
|
39971
|
+
}
|
|
39972
|
+
}
|
|
39973
|
+
current = it.next();
|
|
39974
|
+
}
|
|
39975
|
+
return text;
|
|
39766
39976
|
}
|
|
39767
39977
|
}
|
|
39978
|
+
function compareContentToSpanElement(content, node) {
|
|
39979
|
+
const contentColor = content.color ? toHex(content.color) : "";
|
|
39980
|
+
const nodeColor = node.style?.color ? toHex(node.style.color) : "";
|
|
39981
|
+
const sameColor = contentColor === nodeColor;
|
|
39982
|
+
const sameClass = deepEquals([content.class], [...node.classList]);
|
|
39983
|
+
const sameContent = node.innerText === content.value;
|
|
39984
|
+
return sameColor && sameClass && sameContent;
|
|
39985
|
+
}
|
|
39768
39986
|
|
|
39769
|
-
|
|
39770
|
-
|
|
39771
|
-
|
|
39772
|
-
|
|
39773
|
-
|
|
39774
|
-
|
|
39775
|
-
|
|
39776
|
-
|
|
39777
|
-
|
|
39778
|
-
updateColorScaleType(ev) {
|
|
39779
|
-
const value = ev.target.value;
|
|
39780
|
-
value === "custom"
|
|
39781
|
-
? this.updateColorScale(DEFAULT_CUSTOM_COLOR_SCALE)
|
|
39782
|
-
: this.updateColorScale(value);
|
|
39987
|
+
// -----------------------------------------------------------------------------
|
|
39988
|
+
// Formula Assistant component
|
|
39989
|
+
// -----------------------------------------------------------------------------
|
|
39990
|
+
css /* scss */ `
|
|
39991
|
+
.o-formula-assistant {
|
|
39992
|
+
background: #ffffff;
|
|
39993
|
+
.o-formula-assistant-head {
|
|
39994
|
+
background-color: #f2f2f2;
|
|
39995
|
+
padding: 10px;
|
|
39783
39996
|
}
|
|
39784
|
-
|
|
39785
|
-
|
|
39997
|
+
.collapsed {
|
|
39998
|
+
transform: rotate(180deg);
|
|
39786
39999
|
}
|
|
39787
|
-
|
|
39788
|
-
|
|
40000
|
+
.o-formula-assistant-core {
|
|
40001
|
+
border-bottom: 1px solid gray;
|
|
39789
40002
|
}
|
|
39790
|
-
|
|
39791
|
-
|
|
39792
|
-
this.props.updateChart(this.props.figureId, { legendPosition: value });
|
|
40003
|
+
.o-formula-assistant-arg-description {
|
|
40004
|
+
font-size: 85%;
|
|
39793
40005
|
}
|
|
39794
|
-
|
|
39795
|
-
|
|
39796
|
-
|
|
39797
|
-
|
|
40006
|
+
.o-formula-assistant-focus {
|
|
40007
|
+
div:first-child,
|
|
40008
|
+
span {
|
|
40009
|
+
color: ${COMPOSER_ASSISTANT_COLOR};
|
|
40010
|
+
text-shadow: 0px 0px 1px ${COMPOSER_ASSISTANT_COLOR};
|
|
40011
|
+
}
|
|
40012
|
+
div:last-child {
|
|
40013
|
+
color: black;
|
|
40014
|
+
}
|
|
39798
40015
|
}
|
|
39799
|
-
|
|
39800
|
-
|
|
40016
|
+
.o-formula-assistant-gray {
|
|
40017
|
+
color: gray;
|
|
39801
40018
|
}
|
|
39802
|
-
|
|
39803
|
-
|
|
39804
|
-
|
|
39805
|
-
|
|
39806
|
-
|
|
40019
|
+
}
|
|
40020
|
+
`;
|
|
40021
|
+
class FunctionDescriptionProvider extends Component {
|
|
40022
|
+
static template = "o-spreadsheet-FunctionDescriptionProvider";
|
|
40023
|
+
static props = {
|
|
40024
|
+
functionName: String,
|
|
40025
|
+
functionDescription: Object,
|
|
40026
|
+
argToFocus: Number,
|
|
40027
|
+
};
|
|
40028
|
+
getContext() {
|
|
40029
|
+
return this.props;
|
|
39807
40030
|
}
|
|
39808
|
-
|
|
39809
|
-
return this.
|
|
39810
|
-
}
|
|
39811
|
-
setCustomColorScaleColor(colorType, color) {
|
|
39812
|
-
if (!color && colorType !== "midColor") {
|
|
39813
|
-
color = "#fff";
|
|
39814
|
-
}
|
|
39815
|
-
const customColorScale = this.customColorScale;
|
|
39816
|
-
if (!customColorScale) {
|
|
39817
|
-
return;
|
|
39818
|
-
}
|
|
39819
|
-
this.updateColorScale({ ...customColorScale, [colorType]: color });
|
|
40031
|
+
get formulaArgSeparator() {
|
|
40032
|
+
return this.env.model.getters.getLocale().formulaArgSeparator + " ";
|
|
39820
40033
|
}
|
|
39821
40034
|
}
|
|
39822
40035
|
|
|
39823
|
-
|
|
39824
|
-
|
|
39825
|
-
|
|
39826
|
-
|
|
39827
|
-
|
|
39828
|
-
|
|
39829
|
-
|
|
39830
|
-
|
|
39831
|
-
|
|
39832
|
-
|
|
39833
|
-
|
|
39834
|
-
|
|
39835
|
-
|
|
39836
|
-
|
|
39837
|
-
}
|
|
39838
|
-
getLabelRangeOptions() {
|
|
39839
|
-
const options = super.getLabelRangeOptions();
|
|
39840
|
-
if (this.canTreatLabelsAsText) {
|
|
39841
|
-
options.push({
|
|
39842
|
-
name: "labelsAsText",
|
|
39843
|
-
value: this.props.definition.labelsAsText,
|
|
39844
|
-
label: this.chartTerms.TreatLabelsAsText,
|
|
39845
|
-
onChange: this.onUpdateLabelsAsText.bind(this),
|
|
39846
|
-
});
|
|
39847
|
-
}
|
|
39848
|
-
return options;
|
|
39849
|
-
}
|
|
39850
|
-
onUpdateLabelsAsText(labelsAsText) {
|
|
39851
|
-
this.props.updateChart(this.props.figureId, {
|
|
39852
|
-
labelsAsText,
|
|
39853
|
-
});
|
|
39854
|
-
}
|
|
39855
|
-
onUpdateStacked(stacked) {
|
|
39856
|
-
this.props.updateChart(this.props.figureId, {
|
|
39857
|
-
stacked,
|
|
39858
|
-
});
|
|
39859
|
-
}
|
|
39860
|
-
onUpdateCumulative(cumulative) {
|
|
39861
|
-
this.props.updateChart(this.props.figureId, {
|
|
39862
|
-
cumulative,
|
|
39863
|
-
});
|
|
39864
|
-
}
|
|
39865
|
-
}
|
|
40036
|
+
const functions = functionRegistry.content;
|
|
40037
|
+
const ASSISTANT_WIDTH = 300;
|
|
40038
|
+
const CLOSE_ICON_RADIUS = 9;
|
|
40039
|
+
const selectionIndicatorClass = "selector-flag";
|
|
40040
|
+
const backgroundClass = "background-flag";
|
|
40041
|
+
const selectionIndicatorColor = "#a9a9a9";
|
|
40042
|
+
const selectionIndicator = "␣";
|
|
40043
|
+
css /* scss */ `
|
|
40044
|
+
.o-composer-container {
|
|
40045
|
+
.o-composer {
|
|
40046
|
+
overflow-y: auto;
|
|
40047
|
+
overflow-x: hidden;
|
|
40048
|
+
word-break: break-all;
|
|
40049
|
+
padding-right: 2px;
|
|
39866
40050
|
|
|
39867
|
-
|
|
39868
|
-
static template = "o-spreadsheet-PieChartDesignPanel";
|
|
39869
|
-
static components = {
|
|
39870
|
-
GeneralDesignEditor,
|
|
39871
|
-
Section,
|
|
39872
|
-
Checkbox,
|
|
39873
|
-
ChartLegend,
|
|
39874
|
-
};
|
|
39875
|
-
static props = {
|
|
39876
|
-
figureId: String,
|
|
39877
|
-
definition: Object,
|
|
39878
|
-
updateChart: Function,
|
|
39879
|
-
canUpdateChart: { type: Function, optional: true },
|
|
39880
|
-
};
|
|
39881
|
-
}
|
|
40051
|
+
box-sizing: border-box;
|
|
39882
40052
|
|
|
39883
|
-
|
|
39884
|
-
|
|
39885
|
-
|
|
39886
|
-
|
|
39887
|
-
SeriesDesignEditor,
|
|
39888
|
-
Section,
|
|
39889
|
-
Checkbox,
|
|
39890
|
-
ChartLegend,
|
|
39891
|
-
};
|
|
39892
|
-
static props = {
|
|
39893
|
-
figureId: String,
|
|
39894
|
-
definition: Object,
|
|
39895
|
-
canUpdateChart: Function,
|
|
39896
|
-
updateChart: Function,
|
|
39897
|
-
};
|
|
39898
|
-
}
|
|
40053
|
+
caret-color: black;
|
|
40054
|
+
padding-left: 3px;
|
|
40055
|
+
padding-right: 3px;
|
|
40056
|
+
outline: none;
|
|
39899
40057
|
|
|
39900
|
-
|
|
39901
|
-
|
|
39902
|
-
get canTreatLabelsAsText() {
|
|
39903
|
-
const chart = this.env.model.getters.getChart(this.props.figureId);
|
|
39904
|
-
if (chart && chart instanceof ScatterChart) {
|
|
39905
|
-
return canChartParseLabels(chart.labelRange, this.env.model.getters);
|
|
39906
|
-
}
|
|
39907
|
-
return false;
|
|
39908
|
-
}
|
|
39909
|
-
onUpdateLabelsAsText(labelsAsText) {
|
|
39910
|
-
this.props.updateChart(this.props.figureId, {
|
|
39911
|
-
labelsAsText,
|
|
39912
|
-
});
|
|
39913
|
-
}
|
|
39914
|
-
getLabelRangeOptions() {
|
|
39915
|
-
const options = super.getLabelRangeOptions();
|
|
39916
|
-
if (this.canTreatLabelsAsText) {
|
|
39917
|
-
options.push({
|
|
39918
|
-
name: "labelsAsText",
|
|
39919
|
-
value: this.props.definition.labelsAsText,
|
|
39920
|
-
label: this.chartTerms.TreatLabelsAsText,
|
|
39921
|
-
onChange: this.onUpdateLabelsAsText.bind(this),
|
|
39922
|
-
});
|
|
39923
|
-
}
|
|
39924
|
-
return options;
|
|
39925
|
-
}
|
|
39926
|
-
}
|
|
40058
|
+
p {
|
|
40059
|
+
margin-bottom: 0px;
|
|
39927
40060
|
|
|
39928
|
-
|
|
39929
|
-
|
|
39930
|
-
static components = { SelectionInput, ChartErrorSection, Section };
|
|
39931
|
-
static props = {
|
|
39932
|
-
figureId: String,
|
|
39933
|
-
definition: Object,
|
|
39934
|
-
updateChart: Function,
|
|
39935
|
-
canUpdateChart: Function,
|
|
39936
|
-
};
|
|
39937
|
-
state = useState({
|
|
39938
|
-
keyValueDispatchResult: undefined,
|
|
39939
|
-
baselineDispatchResult: undefined,
|
|
39940
|
-
});
|
|
39941
|
-
keyValue = this.props.definition.keyValue;
|
|
39942
|
-
baseline = this.props.definition.baseline;
|
|
39943
|
-
get errorMessages() {
|
|
39944
|
-
const cancelledReasons = [
|
|
39945
|
-
...(this.state.keyValueDispatchResult?.reasons || []),
|
|
39946
|
-
...(this.state.baselineDispatchResult?.reasons || []),
|
|
39947
|
-
];
|
|
39948
|
-
return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
|
|
39949
|
-
}
|
|
39950
|
-
get isKeyValueInvalid() {
|
|
39951
|
-
return !!this.state.keyValueDispatchResult?.isCancelledBecause("InvalidScorecardKeyValue" /* CommandResult.InvalidScorecardKeyValue */);
|
|
39952
|
-
}
|
|
39953
|
-
get isBaselineInvalid() {
|
|
39954
|
-
return !!this.state.keyValueDispatchResult?.isCancelledBecause("InvalidScorecardBaseline" /* CommandResult.InvalidScorecardBaseline */);
|
|
39955
|
-
}
|
|
39956
|
-
onKeyValueRangeChanged(ranges) {
|
|
39957
|
-
this.keyValue = ranges[0];
|
|
39958
|
-
this.state.keyValueDispatchResult = this.props.canUpdateChart(this.props.figureId, {
|
|
39959
|
-
keyValue: this.keyValue,
|
|
39960
|
-
});
|
|
39961
|
-
}
|
|
39962
|
-
updateKeyValueRange() {
|
|
39963
|
-
this.state.keyValueDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
39964
|
-
keyValue: this.keyValue,
|
|
39965
|
-
});
|
|
39966
|
-
}
|
|
39967
|
-
getKeyValueRange() {
|
|
39968
|
-
return this.keyValue || "";
|
|
39969
|
-
}
|
|
39970
|
-
onBaselineRangeChanged(ranges) {
|
|
39971
|
-
this.baseline = ranges[0];
|
|
39972
|
-
this.state.baselineDispatchResult = this.props.canUpdateChart(this.props.figureId, {
|
|
39973
|
-
baseline: this.baseline,
|
|
39974
|
-
});
|
|
39975
|
-
}
|
|
39976
|
-
updateBaselineRange() {
|
|
39977
|
-
this.state.baselineDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
39978
|
-
baseline: this.baseline,
|
|
39979
|
-
});
|
|
39980
|
-
}
|
|
39981
|
-
getBaselineRange() {
|
|
39982
|
-
return this.baseline || "";
|
|
39983
|
-
}
|
|
39984
|
-
updateBaselineMode(ev) {
|
|
39985
|
-
this.props.updateChart(this.props.figureId, { baselineMode: ev.target.value });
|
|
39986
|
-
}
|
|
39987
|
-
}
|
|
40061
|
+
span {
|
|
40062
|
+
white-space: pre-wrap;
|
|
39988
40063
|
|
|
39989
|
-
|
|
39990
|
-
|
|
39991
|
-
|
|
39992
|
-
|
|
39993
|
-
RoundColorPicker,
|
|
39994
|
-
SidePanelCollapsible,
|
|
39995
|
-
Section,
|
|
39996
|
-
Checkbox,
|
|
39997
|
-
};
|
|
39998
|
-
static props = {
|
|
39999
|
-
figureId: String,
|
|
40000
|
-
definition: Object,
|
|
40001
|
-
updateChart: Function,
|
|
40002
|
-
canUpdateChart: { type: Function, optional: true },
|
|
40003
|
-
};
|
|
40004
|
-
get colorsSectionTitle() {
|
|
40005
|
-
return this.props.definition.baselineMode === "progress"
|
|
40006
|
-
? _t("Progress bar colors")
|
|
40007
|
-
: _t("Baseline colors");
|
|
40008
|
-
}
|
|
40009
|
-
get humanizeNumbersLabel() {
|
|
40010
|
-
return _t("Humanize numbers");
|
|
40011
|
-
}
|
|
40012
|
-
get defaultScorecardTitleFontSize() {
|
|
40013
|
-
return SCORECARD_CHART_TITLE_FONT_SIZE;
|
|
40014
|
-
}
|
|
40015
|
-
updateHumanizeNumbers(humanize) {
|
|
40016
|
-
this.props.updateChart(this.props.figureId, { humanize });
|
|
40017
|
-
}
|
|
40018
|
-
translate(term) {
|
|
40019
|
-
return _t(term);
|
|
40020
|
-
}
|
|
40021
|
-
updateBaselineDescr(ev) {
|
|
40022
|
-
this.props.updateChart(this.props.figureId, { baselineDescr: ev.target.value });
|
|
40023
|
-
}
|
|
40024
|
-
setColor(color, colorPickerId) {
|
|
40025
|
-
switch (colorPickerId) {
|
|
40026
|
-
case "backgroundColor":
|
|
40027
|
-
this.props.updateChart(this.props.figureId, { background: color });
|
|
40028
|
-
break;
|
|
40029
|
-
case "baselineColorDown":
|
|
40030
|
-
this.props.updateChart(this.props.figureId, { baselineColorDown: color });
|
|
40031
|
-
break;
|
|
40032
|
-
case "baselineColorUp":
|
|
40033
|
-
this.props.updateChart(this.props.figureId, { baselineColorUp: color });
|
|
40034
|
-
break;
|
|
40035
|
-
}
|
|
40036
|
-
}
|
|
40037
|
-
}
|
|
40064
|
+
&.${selectionIndicatorClass}:after {
|
|
40065
|
+
content: "${selectionIndicator}";
|
|
40066
|
+
color: ${selectionIndicatorColor};
|
|
40067
|
+
}
|
|
40038
40068
|
|
|
40039
|
-
|
|
40040
|
-
|
|
40041
|
-
|
|
40042
|
-
|
|
40043
|
-
|
|
40044
|
-
|
|
40045
|
-
|
|
40046
|
-
RoundColorPicker,
|
|
40047
|
-
AxisDesignEditor,
|
|
40048
|
-
RadioSelection,
|
|
40049
|
-
ChartLegend,
|
|
40050
|
-
};
|
|
40051
|
-
static props = {
|
|
40052
|
-
figureId: String,
|
|
40053
|
-
definition: Object,
|
|
40054
|
-
updateChart: Function,
|
|
40055
|
-
canUpdateChart: { type: Function, optional: true },
|
|
40056
|
-
};
|
|
40057
|
-
axisChoices = CHART_AXIS_CHOICES;
|
|
40058
|
-
onUpdateShowSubTotals(showSubTotals) {
|
|
40059
|
-
this.props.updateChart(this.props.figureId, { showSubTotals });
|
|
40060
|
-
}
|
|
40061
|
-
onUpdateShowConnectorLines(showConnectorLines) {
|
|
40062
|
-
this.props.updateChart(this.props.figureId, { showConnectorLines });
|
|
40063
|
-
}
|
|
40064
|
-
onUpdateFirstValueAsSubtotal(firstValueAsSubtotal) {
|
|
40065
|
-
this.props.updateChart(this.props.figureId, { firstValueAsSubtotal });
|
|
40066
|
-
}
|
|
40067
|
-
updateColor(colorName, color) {
|
|
40068
|
-
this.props.updateChart(this.props.figureId, { [colorName]: color });
|
|
40069
|
-
}
|
|
40070
|
-
get axesList() {
|
|
40071
|
-
return [
|
|
40072
|
-
{ id: "x", name: _t("Horizontal axis") },
|
|
40073
|
-
{ id: "y", name: _t("Vertical axis") },
|
|
40074
|
-
];
|
|
40075
|
-
}
|
|
40076
|
-
get positiveValuesColor() {
|
|
40077
|
-
return (this.props.definition.positiveValuesColor ||
|
|
40078
|
-
CHART_WATERFALL_POSITIVE_COLOR);
|
|
40079
|
-
}
|
|
40080
|
-
get negativeValuesColor() {
|
|
40081
|
-
return (this.props.definition.negativeValuesColor ||
|
|
40082
|
-
CHART_WATERFALL_NEGATIVE_COLOR);
|
|
40069
|
+
&.${backgroundClass} {
|
|
40070
|
+
border-radius: 5px;
|
|
40071
|
+
background-color: lightgray;
|
|
40072
|
+
padding: 0px 1.5px 1.5px 1.5px;
|
|
40073
|
+
}
|
|
40074
|
+
}
|
|
40075
|
+
}
|
|
40083
40076
|
}
|
|
40084
|
-
|
|
40085
|
-
|
|
40086
|
-
|
|
40077
|
+
.o-composer[placeholder]:empty:not(:focus):not(.active)::before {
|
|
40078
|
+
content: attr(placeholder);
|
|
40079
|
+
color: #bdbdbd;
|
|
40080
|
+
position: relative;
|
|
40081
|
+
top: 0%;
|
|
40082
|
+
pointer-events: none;
|
|
40087
40083
|
}
|
|
40088
|
-
|
|
40089
|
-
|
|
40090
|
-
|
|
40091
|
-
|
|
40084
|
+
|
|
40085
|
+
.fa-stack {
|
|
40086
|
+
/* reset stack size which is doubled by default */
|
|
40087
|
+
width: ${CLOSE_ICON_RADIUS * 2}px;
|
|
40088
|
+
height: ${CLOSE_ICON_RADIUS * 2}px;
|
|
40089
|
+
line-height: ${CLOSE_ICON_RADIUS * 2}px;
|
|
40092
40090
|
}
|
|
40093
|
-
}
|
|
40094
40091
|
|
|
40095
|
-
|
|
40096
|
-
|
|
40097
|
-
|
|
40098
|
-
configuration: LineConfigPanel,
|
|
40099
|
-
design: ChartWithAxisDesignPanel,
|
|
40100
|
-
})
|
|
40101
|
-
.add("scatter", {
|
|
40102
|
-
configuration: ScatterConfigPanel,
|
|
40103
|
-
design: ChartWithAxisDesignPanel,
|
|
40104
|
-
})
|
|
40105
|
-
.add("bar", {
|
|
40106
|
-
configuration: BarConfigPanel,
|
|
40107
|
-
design: ChartWithAxisDesignPanel,
|
|
40108
|
-
})
|
|
40109
|
-
.add("combo", {
|
|
40110
|
-
configuration: GenericChartConfigPanel,
|
|
40111
|
-
design: ComboChartDesignPanel,
|
|
40112
|
-
})
|
|
40113
|
-
.add("pie", {
|
|
40114
|
-
configuration: GenericChartConfigPanel,
|
|
40115
|
-
design: PieChartDesignPanel,
|
|
40116
|
-
})
|
|
40117
|
-
.add("gauge", {
|
|
40118
|
-
configuration: GaugeChartConfigPanel,
|
|
40119
|
-
design: GaugeChartDesignPanel,
|
|
40120
|
-
})
|
|
40121
|
-
.add("scorecard", {
|
|
40122
|
-
configuration: ScorecardChartConfigPanel,
|
|
40123
|
-
design: ScorecardChartDesignPanel,
|
|
40124
|
-
})
|
|
40125
|
-
.add("waterfall", {
|
|
40126
|
-
configuration: GenericChartConfigPanel,
|
|
40127
|
-
design: WaterfallChartDesignPanel,
|
|
40128
|
-
})
|
|
40129
|
-
.add("pyramid", {
|
|
40130
|
-
configuration: GenericChartConfigPanel,
|
|
40131
|
-
design: ChartWithAxisDesignPanel,
|
|
40132
|
-
})
|
|
40133
|
-
.add("radar", {
|
|
40134
|
-
configuration: GenericChartConfigPanel,
|
|
40135
|
-
design: RadarChartDesignPanel,
|
|
40136
|
-
})
|
|
40137
|
-
.add("geo", {
|
|
40138
|
-
configuration: GeoChartConfigPanel,
|
|
40139
|
-
design: GeoChartDesignPanel,
|
|
40140
|
-
});
|
|
40092
|
+
.force-open-assistant {
|
|
40093
|
+
left: -1px;
|
|
40094
|
+
top: -1px;
|
|
40141
40095
|
|
|
40142
|
-
|
|
40143
|
-
|
|
40144
|
-
|
|
40145
|
-
padding-left: 35px;
|
|
40146
|
-
padding-top: 5px;
|
|
40147
|
-
}
|
|
40148
|
-
.o-type-selector-preview {
|
|
40149
|
-
left: 5px;
|
|
40150
|
-
top: 3px;
|
|
40151
|
-
.o-chart-preview {
|
|
40152
|
-
width: 24px;
|
|
40153
|
-
height: 24px;
|
|
40096
|
+
.fa-question-circle {
|
|
40097
|
+
color: ${PRIMARY_BUTTON_BG};
|
|
40098
|
+
}
|
|
40154
40099
|
}
|
|
40155
|
-
}
|
|
40156
40100
|
|
|
40157
|
-
|
|
40158
|
-
|
|
40159
|
-
|
|
40160
|
-
|
|
40161
|
-
|
|
40162
|
-
|
|
40163
|
-
|
|
40164
|
-
|
|
40165
|
-
|
|
40166
|
-
border: 1px solid ${ACTION_COLOR};
|
|
40167
|
-
background: ${BADGE_SELECTED_COLOR};
|
|
40168
|
-
padding: 2px 5px;
|
|
40169
|
-
}
|
|
40170
|
-
.o-chart-preview {
|
|
40171
|
-
width: 48px;
|
|
40172
|
-
height: 48px;
|
|
40101
|
+
.o-composer-assistant {
|
|
40102
|
+
position: absolute;
|
|
40103
|
+
margin: 1px 4px;
|
|
40104
|
+
|
|
40105
|
+
.o-semi-bold {
|
|
40106
|
+
/* FIXME: to remove in favor of Bootstrap
|
|
40107
|
+
* 'fw-semibold' when we upgrade to Bootstrap 5.2
|
|
40108
|
+
*/
|
|
40109
|
+
font-weight: 600 !important;
|
|
40173
40110
|
}
|
|
40174
40111
|
}
|
|
40175
40112
|
}
|
|
40176
40113
|
`;
|
|
40177
|
-
class
|
|
40178
|
-
static template = "o-spreadsheet-
|
|
40179
|
-
static
|
|
40180
|
-
|
|
40181
|
-
|
|
40182
|
-
|
|
40183
|
-
|
|
40184
|
-
|
|
40185
|
-
|
|
40186
|
-
|
|
40187
|
-
|
|
40188
|
-
|
|
40189
|
-
|
|
40190
|
-
|
|
40114
|
+
class Composer extends Component {
|
|
40115
|
+
static template = "o-spreadsheet-Composer";
|
|
40116
|
+
static props = {
|
|
40117
|
+
focus: {
|
|
40118
|
+
validate: (value) => ["inactive", "cellFocus", "contentFocus"].includes(value),
|
|
40119
|
+
},
|
|
40120
|
+
inputStyle: { type: String, optional: true },
|
|
40121
|
+
rect: { type: Object, optional: true },
|
|
40122
|
+
delimitation: { type: Object, optional: true },
|
|
40123
|
+
onComposerCellFocused: { type: Function, optional: true },
|
|
40124
|
+
onComposerContentFocused: Function,
|
|
40125
|
+
isDefaultFocus: { type: Boolean, optional: true },
|
|
40126
|
+
onInputContextMenu: { type: Function, optional: true },
|
|
40127
|
+
composerStore: Object,
|
|
40128
|
+
placeholder: { type: String, optional: true },
|
|
40129
|
+
};
|
|
40130
|
+
static components = { TextValueProvider, FunctionDescriptionProvider };
|
|
40131
|
+
static defaultProps = {
|
|
40132
|
+
inputStyle: "",
|
|
40133
|
+
isDefaultFocus: false,
|
|
40134
|
+
};
|
|
40135
|
+
DOMFocusableElementStore;
|
|
40136
|
+
composerRef = useRef("o_composer");
|
|
40137
|
+
contentHelper = new ContentEditableHelper(this.composerRef.el);
|
|
40138
|
+
composerState = useState({
|
|
40139
|
+
positionStart: 0,
|
|
40140
|
+
positionEnd: 0,
|
|
40141
|
+
});
|
|
40142
|
+
autoCompleteState;
|
|
40143
|
+
functionDescriptionState = useState({
|
|
40144
|
+
showDescription: false,
|
|
40145
|
+
functionName: "",
|
|
40146
|
+
functionDescription: {},
|
|
40147
|
+
argToFocus: 0,
|
|
40148
|
+
});
|
|
40149
|
+
assistant = useState({
|
|
40150
|
+
forcedClosed: false,
|
|
40151
|
+
});
|
|
40152
|
+
compositionActive = false;
|
|
40153
|
+
spreadsheetRect = useSpreadsheetRect();
|
|
40154
|
+
get assistantStyle() {
|
|
40155
|
+
const composerRect = this.composerRef.el.getBoundingClientRect();
|
|
40156
|
+
const assistantStyle = {};
|
|
40157
|
+
assistantStyle["min-width"] = `${this.props.rect?.width || ASSISTANT_WIDTH}px`;
|
|
40158
|
+
const proposals = this.autoCompleteState.provider?.proposals;
|
|
40159
|
+
const proposalsHaveDescription = proposals?.some((proposal) => proposal.description);
|
|
40160
|
+
if (this.functionDescriptionState.showDescription || proposalsHaveDescription) {
|
|
40161
|
+
assistantStyle.width = `${ASSISTANT_WIDTH}px`;
|
|
40162
|
+
}
|
|
40163
|
+
if (this.props.delimitation && this.props.rect) {
|
|
40164
|
+
const { x: cellX, y: cellY, height: cellHeight } = this.props.rect;
|
|
40165
|
+
const remainingHeight = this.props.delimitation.height - (cellY + cellHeight);
|
|
40166
|
+
assistantStyle["max-height"] = `${remainingHeight}px`;
|
|
40167
|
+
if (cellY > remainingHeight) {
|
|
40168
|
+
const availableSpaceAbove = cellY;
|
|
40169
|
+
assistantStyle["max-height"] = `${availableSpaceAbove - CLOSE_ICON_RADIUS}px`;
|
|
40170
|
+
// render top
|
|
40171
|
+
// We compensate 2 px of margin on the assistant style + 1px for design reasons
|
|
40172
|
+
assistantStyle.top = `-3px`;
|
|
40173
|
+
assistantStyle.transform = `translate(0, -100%)`;
|
|
40191
40174
|
}
|
|
40192
|
-
|
|
40193
|
-
|
|
40175
|
+
if (cellX + ASSISTANT_WIDTH > this.props.delimitation.width) {
|
|
40176
|
+
// render left
|
|
40177
|
+
assistantStyle.right = `0px`;
|
|
40194
40178
|
}
|
|
40195
40179
|
}
|
|
40196
|
-
|
|
40197
|
-
|
|
40198
|
-
|
|
40199
|
-
|
|
40200
|
-
|
|
40180
|
+
else {
|
|
40181
|
+
assistantStyle["max-height"] = `${this.spreadsheetRect.height - composerRect.bottom}px`;
|
|
40182
|
+
if (composerRect.left + ASSISTANT_WIDTH + SCROLLBAR_WIDTH + CLOSE_ICON_RADIUS >
|
|
40183
|
+
this.spreadsheetRect.width) {
|
|
40184
|
+
assistantStyle.right = `${CLOSE_ICON_RADIUS}px`;
|
|
40185
|
+
}
|
|
40201
40186
|
}
|
|
40202
|
-
|
|
40203
|
-
}
|
|
40204
|
-
onTypeChange(type) {
|
|
40205
|
-
this.props.chartPanelStore.changeChartType(this.props.figureId, type);
|
|
40206
|
-
this.closePopover();
|
|
40207
|
-
}
|
|
40208
|
-
getChartDefinition(figureId) {
|
|
40209
|
-
return this.env.model.getters.getChartDefinition(figureId);
|
|
40187
|
+
return cssPropertiesToCss(assistantStyle);
|
|
40210
40188
|
}
|
|
40211
|
-
|
|
40212
|
-
|
|
40213
|
-
|
|
40214
|
-
|
|
40215
|
-
|
|
40216
|
-
|
|
40189
|
+
// we can't allow input events to be triggered while we remove and add back the content of the composer in processContent
|
|
40190
|
+
shouldProcessInputEvents = false;
|
|
40191
|
+
tokens = [];
|
|
40192
|
+
keyMapping = {
|
|
40193
|
+
Enter: (ev) => this.processEnterKey(ev, "down"),
|
|
40194
|
+
"Shift+Enter": (ev) => this.processEnterKey(ev, "up"),
|
|
40195
|
+
"Alt+Enter": this.processNewLineEvent,
|
|
40196
|
+
"Ctrl+Enter": this.processNewLineEvent,
|
|
40197
|
+
Escape: this.processEscapeKey,
|
|
40198
|
+
F2: (ev) => this.toggleEditionMode(ev),
|
|
40199
|
+
F4: (ev) => this.processF4Key(ev),
|
|
40200
|
+
Tab: (ev) => this.processTabKey(ev, "right"),
|
|
40201
|
+
"Shift+Tab": (ev) => this.processTabKey(ev, "left"),
|
|
40202
|
+
};
|
|
40203
|
+
keyCodeMapping = {
|
|
40204
|
+
NumpadDecimal: this.processNumpadDecimal,
|
|
40205
|
+
};
|
|
40206
|
+
setup() {
|
|
40207
|
+
this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
|
|
40208
|
+
this.autoCompleteState = useLocalStore(AutoCompleteStore);
|
|
40209
|
+
onMounted(() => {
|
|
40210
|
+
const el = this.composerRef.el;
|
|
40211
|
+
if (this.props.isDefaultFocus) {
|
|
40212
|
+
this.DOMFocusableElementStore.setFocusableElement(el);
|
|
40213
|
+
}
|
|
40214
|
+
this.contentHelper.updateEl(el);
|
|
40215
|
+
});
|
|
40216
|
+
this.env.model.selection.observe(this, {
|
|
40217
|
+
handleEvent: () => this.autoCompleteState.hide(),
|
|
40218
|
+
});
|
|
40219
|
+
onWillUnmount(() => {
|
|
40220
|
+
this.env.model.selection.detachObserver(this);
|
|
40221
|
+
});
|
|
40222
|
+
useEffect(() => {
|
|
40223
|
+
this.processContent();
|
|
40224
|
+
if (document.activeElement === this.contentHelper.el &&
|
|
40225
|
+
this.props.composerStore.editionMode === "inactive" &&
|
|
40226
|
+
!this.props.isDefaultFocus) {
|
|
40227
|
+
this.DOMFocusableElementStore.focusableElement?.focus();
|
|
40228
|
+
}
|
|
40229
|
+
});
|
|
40230
|
+
useEffect(() => {
|
|
40231
|
+
this.processTokenAtCursor();
|
|
40232
|
+
}, () => [this.props.composerStore.editionMode !== "inactive"]);
|
|
40217
40233
|
}
|
|
40218
|
-
|
|
40219
|
-
|
|
40220
|
-
|
|
40234
|
+
// ---------------------------------------------------------------------------
|
|
40235
|
+
// Handlers
|
|
40236
|
+
// ---------------------------------------------------------------------------
|
|
40237
|
+
processArrowKeys(ev) {
|
|
40238
|
+
const tokenAtCursor = this.props.composerStore.tokenAtCursor;
|
|
40239
|
+
if ((this.props.composerStore.isSelectingRange ||
|
|
40240
|
+
this.props.composerStore.editionMode === "inactive") &&
|
|
40241
|
+
!(["ArrowUp", "ArrowDown"].includes(ev.key) &&
|
|
40242
|
+
this.autoCompleteState.provider &&
|
|
40243
|
+
tokenAtCursor?.type !== "REFERENCE")) {
|
|
40244
|
+
this.functionDescriptionState.showDescription = false;
|
|
40245
|
+
this.autoCompleteState.hide();
|
|
40246
|
+
// Prevent the default content editable behavior which moves the cursor
|
|
40247
|
+
ev.preventDefault();
|
|
40248
|
+
ev.stopPropagation();
|
|
40249
|
+
updateSelectionWithArrowKeys(ev, this.env.model.selection);
|
|
40221
40250
|
return;
|
|
40222
40251
|
}
|
|
40223
|
-
const
|
|
40224
|
-
|
|
40225
|
-
|
|
40226
|
-
|
|
40227
|
-
|
|
40228
|
-
|
|
40229
|
-
}
|
|
40230
|
-
|
|
40231
|
-
|
|
40232
|
-
|
|
40233
|
-
this.
|
|
40252
|
+
const content = this.props.composerStore.currentContent;
|
|
40253
|
+
if (this.props.focus === "cellFocus" &&
|
|
40254
|
+
!this.autoCompleteState.provider &&
|
|
40255
|
+
!content.startsWith("=")) {
|
|
40256
|
+
this.props.composerStore.stopEdition();
|
|
40257
|
+
return;
|
|
40258
|
+
}
|
|
40259
|
+
// All arrow keys are processed: up and down should move autocomplete, left
|
|
40260
|
+
// and right should move the cursor.
|
|
40261
|
+
ev.stopPropagation();
|
|
40262
|
+
this.handleArrowKeysForAutocomplete(ev);
|
|
40234
40263
|
}
|
|
40235
|
-
|
|
40236
|
-
|
|
40237
|
-
|
|
40238
|
-
|
|
40239
|
-
|
|
40240
|
-
|
|
40241
|
-
activatePanel(panel) {
|
|
40242
|
-
this.panel = panel;
|
|
40264
|
+
handleArrowKeysForAutocomplete(ev) {
|
|
40265
|
+
// only for arrow up and down
|
|
40266
|
+
if (["ArrowUp", "ArrowDown"].includes(ev.key) && this.autoCompleteState.provider) {
|
|
40267
|
+
ev.preventDefault();
|
|
40268
|
+
this.autoCompleteState.moveSelection(ev.key === "ArrowDown" ? "next" : "previous");
|
|
40269
|
+
}
|
|
40243
40270
|
}
|
|
40244
|
-
|
|
40245
|
-
|
|
40246
|
-
|
|
40247
|
-
|
|
40248
|
-
|
|
40249
|
-
|
|
40271
|
+
processTabKey(ev, direction) {
|
|
40272
|
+
ev.preventDefault();
|
|
40273
|
+
ev.stopPropagation();
|
|
40274
|
+
if (this.props.composerStore.editionMode !== "inactive") {
|
|
40275
|
+
const state = this.autoCompleteState;
|
|
40276
|
+
if (state.provider && state.selectedIndex !== undefined) {
|
|
40277
|
+
const autoCompleteValue = state.provider.proposals[state.selectedIndex]?.text;
|
|
40278
|
+
if (autoCompleteValue) {
|
|
40279
|
+
this.autoComplete(autoCompleteValue);
|
|
40280
|
+
return;
|
|
40281
|
+
}
|
|
40282
|
+
}
|
|
40283
|
+
this.props.composerStore.stopEdition(direction);
|
|
40250
40284
|
}
|
|
40251
|
-
|
|
40252
|
-
|
|
40253
|
-
|
|
40254
|
-
|
|
40255
|
-
|
|
40256
|
-
|
|
40257
|
-
|
|
40258
|
-
|
|
40285
|
+
}
|
|
40286
|
+
processEnterKey(ev, direction) {
|
|
40287
|
+
ev.preventDefault();
|
|
40288
|
+
ev.stopPropagation();
|
|
40289
|
+
const state = this.autoCompleteState;
|
|
40290
|
+
if (state.provider && state.selectedIndex !== undefined) {
|
|
40291
|
+
const autoCompleteValue = state.provider.proposals[state.selectedIndex]?.text;
|
|
40292
|
+
if (autoCompleteValue) {
|
|
40293
|
+
this.autoComplete(autoCompleteValue);
|
|
40294
|
+
return;
|
|
40295
|
+
}
|
|
40259
40296
|
}
|
|
40260
|
-
|
|
40261
|
-
|
|
40262
|
-
|
|
40263
|
-
|
|
40264
|
-
|
|
40297
|
+
this.props.composerStore.stopEdition(direction);
|
|
40298
|
+
}
|
|
40299
|
+
processNewLineEvent(ev) {
|
|
40300
|
+
ev.preventDefault();
|
|
40301
|
+
ev.stopPropagation();
|
|
40302
|
+
const content = this.contentHelper.getText();
|
|
40303
|
+
const selection = this.contentHelper.getCurrentSelection();
|
|
40304
|
+
const start = Math.min(selection.start, selection.end);
|
|
40305
|
+
const end = Math.max(selection.start, selection.end);
|
|
40306
|
+
this.props.composerStore.stopComposerRangeSelection();
|
|
40307
|
+
this.props.composerStore.setCurrentContent(content.slice(0, start) + NEWLINE + content.slice(end), {
|
|
40308
|
+
start: start + 1,
|
|
40309
|
+
end: start + 1,
|
|
40265
40310
|
});
|
|
40311
|
+
this.processContent();
|
|
40266
40312
|
}
|
|
40267
|
-
|
|
40268
|
-
|
|
40269
|
-
|
|
40270
|
-
|
|
40271
|
-
...ChartClass.getChartDefinitionFromContextCreation(this.creationContexts[figureId]),
|
|
40272
|
-
...newChartInfo.subtypeDefinition,
|
|
40273
|
-
};
|
|
40313
|
+
processEscapeKey(ev) {
|
|
40314
|
+
this.props.composerStore.cancelEdition();
|
|
40315
|
+
ev.stopPropagation();
|
|
40316
|
+
ev.preventDefault();
|
|
40274
40317
|
}
|
|
40275
|
-
|
|
40276
|
-
|
|
40277
|
-
|
|
40278
|
-
|
|
40279
|
-
.o-panel {
|
|
40280
|
-
display: flex;
|
|
40281
|
-
.o-panel-element {
|
|
40282
|
-
flex: 1 0 auto;
|
|
40283
|
-
padding: 8px 0px;
|
|
40284
|
-
text-align: center;
|
|
40285
|
-
cursor: pointer;
|
|
40286
|
-
border-right: 1px solid ${GRAY_300};
|
|
40287
|
-
|
|
40288
|
-
&.inactive {
|
|
40289
|
-
color: ${TEXT_BODY};
|
|
40290
|
-
background-color: ${GRAY_100};
|
|
40291
|
-
border-bottom: 1px solid ${GRAY_300};
|
|
40292
|
-
}
|
|
40293
|
-
|
|
40294
|
-
&:not(.inactive) {
|
|
40295
|
-
color: ${TEXT_HEADING};
|
|
40296
|
-
border-bottom: 1px solid #fff;
|
|
40297
|
-
}
|
|
40298
|
-
|
|
40299
|
-
.fa {
|
|
40300
|
-
margin-right: 4px;
|
|
40301
|
-
}
|
|
40302
|
-
}
|
|
40303
|
-
.o-panel-element:last-child {
|
|
40304
|
-
border-right: none;
|
|
40305
|
-
}
|
|
40318
|
+
processF4Key(ev) {
|
|
40319
|
+
ev.stopPropagation();
|
|
40320
|
+
this.props.composerStore.cycleReferences();
|
|
40321
|
+
this.processContent();
|
|
40306
40322
|
}
|
|
40307
|
-
|
|
40308
|
-
|
|
40309
|
-
|
|
40310
|
-
|
|
40311
|
-
static components = { Section, ChartTypePicker };
|
|
40312
|
-
static props = { onCloseSidePanel: Function, figureId: String };
|
|
40313
|
-
store;
|
|
40314
|
-
get figureId() {
|
|
40315
|
-
return this.props.figureId;
|
|
40323
|
+
toggleEditionMode(ev) {
|
|
40324
|
+
ev.stopPropagation();
|
|
40325
|
+
this.props.composerStore.toggleEditionMode();
|
|
40326
|
+
this.processContent();
|
|
40316
40327
|
}
|
|
40317
|
-
|
|
40318
|
-
|
|
40328
|
+
processNumpadDecimal(ev) {
|
|
40329
|
+
ev.stopPropagation();
|
|
40330
|
+
ev.preventDefault();
|
|
40331
|
+
const locale = this.env.model.getters.getLocale();
|
|
40332
|
+
const selection = this.contentHelper.getCurrentSelection();
|
|
40333
|
+
const currentContent = this.props.composerStore.currentContent;
|
|
40334
|
+
const content = currentContent.slice(0, selection.start) +
|
|
40335
|
+
locale.decimalSeparator +
|
|
40336
|
+
currentContent.slice(selection.end);
|
|
40337
|
+
// Update composer even by hand rather than dispatching an InputEvent because untrusted inputs
|
|
40338
|
+
// events aren't handled natively by contentEditable
|
|
40339
|
+
this.props.composerStore.setCurrentContent(content, {
|
|
40340
|
+
start: selection.start + 1,
|
|
40341
|
+
end: selection.start + 1,
|
|
40342
|
+
});
|
|
40343
|
+
// We need to do the process content here in case there is no render between the keyDown and the
|
|
40344
|
+
// keyUp event
|
|
40345
|
+
this.processContent();
|
|
40319
40346
|
}
|
|
40320
|
-
|
|
40321
|
-
|
|
40347
|
+
onCompositionStart() {
|
|
40348
|
+
this.compositionActive = true;
|
|
40349
|
+
}
|
|
40350
|
+
onCompositionEnd() {
|
|
40351
|
+
this.compositionActive = false;
|
|
40352
|
+
}
|
|
40353
|
+
onKeydown(ev) {
|
|
40354
|
+
if (this.props.composerStore.editionMode === "inactive") {
|
|
40322
40355
|
return;
|
|
40323
40356
|
}
|
|
40324
|
-
|
|
40325
|
-
|
|
40326
|
-
|
|
40327
|
-
}
|
|
40328
|
-
|
|
40329
|
-
|
|
40330
|
-
|
|
40331
|
-
|
|
40332
|
-
}
|
|
40357
|
+
if (ev.key.startsWith("Arrow")) {
|
|
40358
|
+
this.processArrowKeys(ev);
|
|
40359
|
+
return;
|
|
40360
|
+
}
|
|
40361
|
+
let handler = this.keyMapping[keyboardEventToShortcutString(ev)] ||
|
|
40362
|
+
this.keyCodeMapping[keyboardEventToShortcutString(ev, "code")];
|
|
40363
|
+
if (handler) {
|
|
40364
|
+
handler.call(this, ev);
|
|
40365
|
+
}
|
|
40366
|
+
else {
|
|
40367
|
+
ev.stopPropagation();
|
|
40368
|
+
}
|
|
40333
40369
|
}
|
|
40334
|
-
|
|
40335
|
-
if (
|
|
40336
|
-
|
|
40370
|
+
onPaste(ev) {
|
|
40371
|
+
if (this.props.composerStore.editionMode !== "inactive") {
|
|
40372
|
+
// let the browser clipboard work
|
|
40373
|
+
ev.stopPropagation();
|
|
40374
|
+
}
|
|
40375
|
+
else {
|
|
40376
|
+
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
40377
|
+
// While we're not editing, we still have the focus and should therefore prevent
|
|
40378
|
+
// the native "paste" to occur.
|
|
40379
|
+
ev.preventDefault();
|
|
40337
40380
|
}
|
|
40338
|
-
const definition = {
|
|
40339
|
-
...this.getChartDefinition(this.figureId),
|
|
40340
|
-
...updateDefinition,
|
|
40341
|
-
};
|
|
40342
|
-
return this.env.model.canDispatch("UPDATE_CHART", {
|
|
40343
|
-
definition,
|
|
40344
|
-
id: figureId,
|
|
40345
|
-
sheetId: this.env.model.getters.getFigureSheetId(figureId),
|
|
40346
|
-
});
|
|
40347
40381
|
}
|
|
40348
|
-
|
|
40349
|
-
|
|
40382
|
+
/*
|
|
40383
|
+
* Triggered automatically by the content-editable between the keydown and key up
|
|
40384
|
+
* */
|
|
40385
|
+
onInput(ev) {
|
|
40386
|
+
if (!this.shouldProcessInputEvents) {
|
|
40350
40387
|
return;
|
|
40351
40388
|
}
|
|
40352
|
-
|
|
40353
|
-
|
|
40354
|
-
|
|
40355
|
-
|
|
40356
|
-
throw new Error("Chart not defined.");
|
|
40389
|
+
ev.stopPropagation();
|
|
40390
|
+
let content;
|
|
40391
|
+
if (this.props.composerStore.editionMode === "inactive") {
|
|
40392
|
+
content = ev.data || "";
|
|
40357
40393
|
}
|
|
40358
|
-
|
|
40359
|
-
|
|
40360
|
-
throw new Error("Chart not defined.");
|
|
40394
|
+
else {
|
|
40395
|
+
content = this.contentHelper.getText();
|
|
40361
40396
|
}
|
|
40362
|
-
|
|
40363
|
-
|
|
40364
|
-
throw new Error(`Component is not defined for type ${type}`);
|
|
40397
|
+
if (this.props.focus === "inactive") {
|
|
40398
|
+
return this.props.onComposerCellFocused?.(content);
|
|
40365
40399
|
}
|
|
40366
|
-
|
|
40367
|
-
|
|
40368
|
-
|
|
40369
|
-
|
|
40370
|
-
}
|
|
40371
|
-
}
|
|
40372
|
-
|
|
40373
|
-
class DOMFocusableElementStore {
|
|
40374
|
-
mutators = ["setFocusableElement"];
|
|
40375
|
-
focusableElement = undefined;
|
|
40376
|
-
setFocusableElement(element) {
|
|
40377
|
-
this.focusableElement = element;
|
|
40378
|
-
}
|
|
40379
|
-
}
|
|
40380
|
-
|
|
40381
|
-
css /* scss */ `
|
|
40382
|
-
.o-autocomplete-dropdown {
|
|
40383
|
-
pointer-events: auto;
|
|
40384
|
-
cursor: pointer;
|
|
40385
|
-
background-color: #fff;
|
|
40386
|
-
max-width: 400px;
|
|
40387
|
-
z-index: 1;
|
|
40388
|
-
|
|
40389
|
-
.o-autocomplete-value-focus {
|
|
40390
|
-
background-color: #f2f2f2;
|
|
40391
|
-
}
|
|
40392
|
-
|
|
40393
|
-
& > div {
|
|
40394
|
-
padding: 1px 5px 5px 5px;
|
|
40395
|
-
.o-autocomplete-description {
|
|
40396
|
-
padding-left: 5px;
|
|
40397
|
-
font-size: 11px;
|
|
40398
|
-
}
|
|
40400
|
+
let selection = this.contentHelper.getCurrentSelection();
|
|
40401
|
+
this.props.composerStore.stopComposerRangeSelection();
|
|
40402
|
+
this.props.composerStore.setCurrentContent(content, selection);
|
|
40403
|
+
this.processTokenAtCursor();
|
|
40399
40404
|
}
|
|
40400
|
-
|
|
40401
|
-
|
|
40402
|
-
|
|
40403
|
-
static template = "o-spreadsheet-TextValueProvider";
|
|
40404
|
-
static props = {
|
|
40405
|
-
proposals: Array,
|
|
40406
|
-
selectedIndex: { type: Number, optional: true },
|
|
40407
|
-
onValueSelected: Function,
|
|
40408
|
-
onValueHovered: Function,
|
|
40409
|
-
};
|
|
40410
|
-
autoCompleteListRef = useRef("autoCompleteList");
|
|
40411
|
-
setup() {
|
|
40412
|
-
useEffect(() => {
|
|
40413
|
-
const selectedIndex = this.props.selectedIndex;
|
|
40414
|
-
if (selectedIndex === undefined) {
|
|
40405
|
+
onKeyup(ev) {
|
|
40406
|
+
if (this.contentHelper.el === document.activeElement) {
|
|
40407
|
+
if (this.autoCompleteState.provider && ["ArrowUp", "ArrowDown"].includes(ev.key)) {
|
|
40415
40408
|
return;
|
|
40416
40409
|
}
|
|
40417
|
-
|
|
40418
|
-
|
|
40419
|
-
|
|
40420
|
-
|
|
40421
|
-
}
|
|
40422
|
-
|
|
40423
|
-
|
|
40424
|
-
|
|
40425
|
-
|
|
40426
|
-
provider;
|
|
40427
|
-
get selectedProposal() {
|
|
40428
|
-
if (this.selectedIndex === undefined || this.provider === undefined) {
|
|
40429
|
-
return undefined;
|
|
40410
|
+
if (this.props.composerStore.isSelectingRange && ev.key?.startsWith("Arrow")) {
|
|
40411
|
+
return;
|
|
40412
|
+
}
|
|
40413
|
+
const { start: oldStart, end: oldEnd } = this.props.composerStore.composerSelection;
|
|
40414
|
+
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
40415
|
+
if (start !== oldStart || end !== oldEnd) {
|
|
40416
|
+
this.props.composerStore.changeComposerCursorSelection(start, end);
|
|
40417
|
+
}
|
|
40418
|
+
this.processTokenAtCursor();
|
|
40430
40419
|
}
|
|
40431
|
-
return this.provider.proposals[this.selectedIndex];
|
|
40432
|
-
}
|
|
40433
|
-
useProvider(provider) {
|
|
40434
|
-
this.provider = provider;
|
|
40435
|
-
this.selectedIndex = provider.autoSelectFirstProposal ? 0 : undefined;
|
|
40436
|
-
}
|
|
40437
|
-
hide() {
|
|
40438
|
-
this.provider = undefined;
|
|
40439
|
-
this.selectedIndex = undefined;
|
|
40440
|
-
}
|
|
40441
|
-
selectIndex(index) {
|
|
40442
|
-
this.selectedIndex = index;
|
|
40443
40420
|
}
|
|
40444
|
-
|
|
40445
|
-
if (
|
|
40421
|
+
onBlur(ev) {
|
|
40422
|
+
if (this.props.composerStore.editionMode === "inactive") {
|
|
40446
40423
|
return;
|
|
40447
40424
|
}
|
|
40448
|
-
|
|
40449
|
-
|
|
40425
|
+
const target = ev.relatedTarget;
|
|
40426
|
+
if (!target || !(target instanceof HTMLElement)) {
|
|
40427
|
+
this.props.composerStore.stopEdition();
|
|
40450
40428
|
return;
|
|
40451
40429
|
}
|
|
40452
|
-
if (
|
|
40453
|
-
this.
|
|
40454
|
-
|
|
40455
|
-
this.selectedIndex = this.provider.proposals.length - 1;
|
|
40456
|
-
}
|
|
40430
|
+
if (target.attributes.getNamedItem("composerFocusableElement")) {
|
|
40431
|
+
this.contentHelper.el.focus();
|
|
40432
|
+
return;
|
|
40457
40433
|
}
|
|
40458
|
-
|
|
40459
|
-
|
|
40434
|
+
if (target.classList.contains("o-composer")) {
|
|
40435
|
+
return;
|
|
40460
40436
|
}
|
|
40437
|
+
this.props.composerStore.stopEdition();
|
|
40461
40438
|
}
|
|
40462
|
-
|
|
40463
|
-
|
|
40464
|
-
class ContentEditableHelper {
|
|
40465
|
-
// todo make el private and expose dedicated methods
|
|
40466
|
-
el;
|
|
40467
|
-
constructor(el) {
|
|
40468
|
-
this.el = el;
|
|
40469
|
-
}
|
|
40470
|
-
updateEl(el) {
|
|
40471
|
-
this.el = el;
|
|
40439
|
+
updateAutoCompleteIndex(index) {
|
|
40440
|
+
this.autoCompleteState.selectIndex(clip(0, index, 10));
|
|
40472
40441
|
}
|
|
40473
40442
|
/**
|
|
40474
|
-
*
|
|
40443
|
+
* This is required to ensure the content helper selection is
|
|
40444
|
+
* properly updated on "onclick" events. Depending on the browser,
|
|
40445
|
+
* the callback onClick from the composer will be executed before
|
|
40446
|
+
* the selection was updated in the dom, which means we capture an
|
|
40447
|
+
* wrong selection which is then forced upon the content helper on
|
|
40448
|
+
* processContent.
|
|
40475
40449
|
*/
|
|
40476
|
-
|
|
40477
|
-
|
|
40478
|
-
|
|
40479
|
-
if (currentStart === start && currentEnd === end) {
|
|
40450
|
+
onMousedown(ev) {
|
|
40451
|
+
if (ev.button > 0) {
|
|
40452
|
+
// not main button, probably a context menu
|
|
40480
40453
|
return;
|
|
40481
40454
|
}
|
|
40482
|
-
|
|
40483
|
-
|
|
40484
|
-
|
|
40455
|
+
this.contentHelper.removeSelection();
|
|
40456
|
+
}
|
|
40457
|
+
onClick() {
|
|
40458
|
+
if (this.env.model.getters.isReadonly()) {
|
|
40459
|
+
return;
|
|
40485
40460
|
}
|
|
40486
|
-
const
|
|
40487
|
-
|
|
40488
|
-
|
|
40489
|
-
|
|
40461
|
+
const newSelection = this.contentHelper.getCurrentSelection();
|
|
40462
|
+
this.props.composerStore.stopComposerRangeSelection();
|
|
40463
|
+
this.props.onComposerContentFocused();
|
|
40464
|
+
this.props.composerStore.changeComposerCursorSelection(newSelection.start, newSelection.end);
|
|
40465
|
+
this.processTokenAtCursor();
|
|
40466
|
+
}
|
|
40467
|
+
onDblClick() {
|
|
40468
|
+
if (this.env.model.getters.isReadonly()) {
|
|
40469
|
+
return;
|
|
40490
40470
|
}
|
|
40491
|
-
|
|
40492
|
-
|
|
40493
|
-
|
|
40494
|
-
|
|
40471
|
+
const composerContent = this.props.composerStore.currentContent;
|
|
40472
|
+
const isValidFormula = composerContent.startsWith("=");
|
|
40473
|
+
if (isValidFormula) {
|
|
40474
|
+
const tokens = this.props.composerStore.currentTokens;
|
|
40475
|
+
const currentSelection = this.contentHelper.getCurrentSelection();
|
|
40476
|
+
if (currentSelection.start === currentSelection.end)
|
|
40477
|
+
return;
|
|
40478
|
+
const currentSelectedText = composerContent.substring(currentSelection.start, currentSelection.end);
|
|
40479
|
+
const token = tokens.filter((token) => token.value.includes(currentSelectedText) &&
|
|
40480
|
+
token.start <= currentSelection.start &&
|
|
40481
|
+
token.end >= currentSelection.end)[0];
|
|
40482
|
+
if (!token) {
|
|
40483
|
+
return;
|
|
40484
|
+
}
|
|
40485
|
+
if (token.type === "REFERENCE") {
|
|
40486
|
+
this.props.composerStore.changeComposerCursorSelection(token.start, token.end);
|
|
40487
|
+
}
|
|
40495
40488
|
}
|
|
40496
|
-
|
|
40497
|
-
|
|
40498
|
-
|
|
40489
|
+
}
|
|
40490
|
+
onContextMenu(ev) {
|
|
40491
|
+
if (this.props.composerStore.editionMode === "inactive") {
|
|
40492
|
+
this.props.onInputContextMenu?.(ev);
|
|
40499
40493
|
}
|
|
40500
|
-
|
|
40501
|
-
|
|
40502
|
-
|
|
40503
|
-
|
|
40504
|
-
|
|
40505
|
-
|
|
40506
|
-
|
|
40507
|
-
|
|
40508
|
-
|
|
40509
|
-
|
|
40494
|
+
}
|
|
40495
|
+
closeAssistant() {
|
|
40496
|
+
this.assistant.forcedClosed = true;
|
|
40497
|
+
}
|
|
40498
|
+
openAssistant() {
|
|
40499
|
+
this.assistant.forcedClosed = false;
|
|
40500
|
+
}
|
|
40501
|
+
// ---------------------------------------------------------------------------
|
|
40502
|
+
// Private
|
|
40503
|
+
// ---------------------------------------------------------------------------
|
|
40504
|
+
processContent() {
|
|
40505
|
+
if (this.compositionActive) {
|
|
40506
|
+
return;
|
|
40507
|
+
}
|
|
40508
|
+
this.shouldProcessInputEvents = false;
|
|
40509
|
+
if (this.props.focus !== "inactive" && document.activeElement !== this.contentHelper.el) {
|
|
40510
|
+
this.contentHelper.el.focus();
|
|
40511
|
+
}
|
|
40512
|
+
const content = this.getContentLines();
|
|
40513
|
+
this.contentHelper.setText(content);
|
|
40514
|
+
if (content.length !== 0 && content.length[0] !== 0) {
|
|
40515
|
+
if (this.props.focus !== "inactive") {
|
|
40516
|
+
// Put the cursor back where it was before the rendering
|
|
40517
|
+
const { start, end } = this.props.composerStore.composerSelection;
|
|
40518
|
+
this.contentHelper.selectRange(start, end);
|
|
40510
40519
|
}
|
|
40511
|
-
|
|
40512
|
-
let endNode = this.findChildAtCharacterIndex(end);
|
|
40513
|
-
range.setStart(startNode.node, startNode.offset);
|
|
40514
|
-
range.setEnd(endNode.node, endNode.offset);
|
|
40520
|
+
this.contentHelper.scrollSelectionIntoView();
|
|
40515
40521
|
}
|
|
40522
|
+
this.shouldProcessInputEvents = true;
|
|
40516
40523
|
}
|
|
40517
40524
|
/**
|
|
40518
|
-
*
|
|
40525
|
+
* Get the HTML content corresponding to the current composer token, divided by lines.
|
|
40519
40526
|
*/
|
|
40520
|
-
|
|
40521
|
-
let
|
|
40522
|
-
|
|
40523
|
-
|
|
40524
|
-
|
|
40525
|
-
|
|
40526
|
-
|
|
40527
|
-
|
|
40528
|
-
|
|
40529
|
-
|
|
40530
|
-
|
|
40531
|
-
|
|
40532
|
-
|
|
40533
|
-
|
|
40534
|
-
|
|
40535
|
-
|
|
40527
|
+
getContentLines() {
|
|
40528
|
+
let value = this.props.composerStore.currentContent;
|
|
40529
|
+
const isValidFormula = value.startsWith("=");
|
|
40530
|
+
if (value === "") {
|
|
40531
|
+
return [];
|
|
40532
|
+
}
|
|
40533
|
+
else if (isValidFormula && this.props.focus !== "inactive") {
|
|
40534
|
+
return this.splitHtmlContentIntoLines(this.getHtmlContentFromTokens());
|
|
40535
|
+
}
|
|
40536
|
+
return this.splitHtmlContentIntoLines([{ value }]);
|
|
40537
|
+
}
|
|
40538
|
+
getHtmlContentFromTokens() {
|
|
40539
|
+
const tokens = this.props.composerStore.currentTokens;
|
|
40540
|
+
const result = [];
|
|
40541
|
+
const { end, start } = this.props.composerStore.composerSelection;
|
|
40542
|
+
for (const token of tokens) {
|
|
40543
|
+
let color = token.color || DEFAULT_TOKEN_COLOR;
|
|
40544
|
+
if (token.isBlurred) {
|
|
40545
|
+
color = setColorAlpha(color, 0.5);
|
|
40536
40546
|
}
|
|
40537
|
-
|
|
40538
|
-
if (
|
|
40539
|
-
|
|
40540
|
-
|
|
40541
|
-
|
|
40542
|
-
|
|
40543
|
-
|
|
40544
|
-
|
|
40547
|
+
result.push({ value: token.value, color });
|
|
40548
|
+
if (token.type === "REFERENCE" &&
|
|
40549
|
+
this.props.composerStore.tokenAtCursor === token &&
|
|
40550
|
+
this.props.composerStore.editionMode === "selecting") {
|
|
40551
|
+
result[result.length - 1].class = "text-decoration-underline";
|
|
40552
|
+
}
|
|
40553
|
+
if (end === start && token.isParenthesisLinkedToCursor) {
|
|
40554
|
+
result[result.length - 1].class = backgroundClass;
|
|
40555
|
+
}
|
|
40556
|
+
if (this.props.composerStore.showSelectionIndicator && end === start && end === token.end) {
|
|
40557
|
+
result[result.length - 1].class = selectionIndicatorClass;
|
|
40545
40558
|
}
|
|
40546
|
-
} while (!current.done && usedCharacters);
|
|
40547
|
-
if (current.value) {
|
|
40548
|
-
return { node: current.value, offset: usedCharacters };
|
|
40549
40559
|
}
|
|
40550
|
-
return
|
|
40560
|
+
return result;
|
|
40551
40561
|
}
|
|
40552
40562
|
/**
|
|
40553
|
-
*
|
|
40554
|
-
*
|
|
40555
|
-
*
|
|
40556
|
-
* The function will apply the diff between the current content and the new content to avoid the systematic
|
|
40557
|
-
* destruction of DOM elements which interferes with IME[1]
|
|
40558
|
-
*
|
|
40559
|
-
* Each line of text will be encapsulated in a paragraph element.
|
|
40560
|
-
* Each span will have its own fontcolor and specific class if provided in the HtmlContent object.
|
|
40561
|
-
*
|
|
40562
|
-
* [1] https://developer.mozilla.org/en-US/docs/Glossary/Input_method_editor
|
|
40563
|
+
* Split an array of HTMLContents into lines. Each NEWLINE character encountered will create a new
|
|
40564
|
+
* line. Contents can be split into multiple parts if they contain multiple NEWLINE characters.
|
|
40563
40565
|
*/
|
|
40564
|
-
|
|
40565
|
-
|
|
40566
|
-
|
|
40567
|
-
|
|
40568
|
-
|
|
40569
|
-
|
|
40570
|
-
|
|
40571
|
-
|
|
40572
|
-
|
|
40573
|
-
|
|
40574
|
-
|
|
40575
|
-
let p;
|
|
40576
|
-
if (childElement && childElement.nodeName === "P") {
|
|
40577
|
-
p = childElement;
|
|
40578
|
-
}
|
|
40579
|
-
else {
|
|
40580
|
-
newChild = true;
|
|
40581
|
-
p = document.createElement("p");
|
|
40582
|
-
}
|
|
40583
|
-
const lineLength = line.length;
|
|
40584
|
-
const existingChildren = Array.from(p.childNodes);
|
|
40585
|
-
for (let j = 0; j < lineLength; j++) {
|
|
40586
|
-
const content = line[j];
|
|
40587
|
-
const child = existingChildren[j];
|
|
40588
|
-
// child nodes can be multiple types of nodes: Span, Text, Div, etc...
|
|
40589
|
-
// We can only modify a node in place if it has the same type as the content
|
|
40590
|
-
// that we would insert, which are spans.
|
|
40591
|
-
// Otherwise, it means that the node has been input by the user, through the keyboard or a copy/paste
|
|
40592
|
-
// @ts-ignore (somehow required because jest does not like child.tagName despite the prior check)
|
|
40593
|
-
const childIsSpan = child && "tagName" in child && child.tagName === "SPAN";
|
|
40594
|
-
if (childIsSpan && compareContentToSpanElement(content, child)) {
|
|
40595
|
-
continue;
|
|
40596
|
-
}
|
|
40597
|
-
// this is an empty line in the content
|
|
40598
|
-
if (!content.value && !content.class) {
|
|
40599
|
-
if (child)
|
|
40600
|
-
p.removeChild(child);
|
|
40601
|
-
continue;
|
|
40602
|
-
}
|
|
40603
|
-
const span = document.createElement("span");
|
|
40604
|
-
span.innerText = content.value;
|
|
40605
|
-
span.style.color = content.color || "";
|
|
40606
|
-
if (content.class) {
|
|
40607
|
-
span.classList.add(content.class);
|
|
40608
|
-
}
|
|
40609
|
-
if (child) {
|
|
40610
|
-
p.replaceChild(span, child);
|
|
40611
|
-
}
|
|
40612
|
-
else {
|
|
40613
|
-
p.appendChild(span);
|
|
40566
|
+
splitHtmlContentIntoLines(contents) {
|
|
40567
|
+
const contentSplitInLines = [];
|
|
40568
|
+
let currentLine = [];
|
|
40569
|
+
for (const content of contents) {
|
|
40570
|
+
if (content.value.includes(NEWLINE)) {
|
|
40571
|
+
const lines = content.value.split(NEWLINE);
|
|
40572
|
+
const lastLine = lines.pop();
|
|
40573
|
+
for (const line of lines) {
|
|
40574
|
+
currentLine.push({ color: content.color, value: line }); // don't copy class, only last line should keep it
|
|
40575
|
+
contentSplitInLines.push(currentLine);
|
|
40576
|
+
currentLine = [];
|
|
40614
40577
|
}
|
|
40578
|
+
currentLine.push({ ...content, value: lastLine });
|
|
40615
40579
|
}
|
|
40616
|
-
|
|
40617
|
-
|
|
40618
|
-
p.removeChild(existingChildren[i]);
|
|
40619
|
-
}
|
|
40580
|
+
else {
|
|
40581
|
+
currentLine.push(content);
|
|
40620
40582
|
}
|
|
40621
|
-
|
|
40622
|
-
|
|
40623
|
-
|
|
40624
|
-
|
|
40625
|
-
|
|
40583
|
+
}
|
|
40584
|
+
if (currentLine.length) {
|
|
40585
|
+
contentSplitInLines.push(currentLine);
|
|
40586
|
+
}
|
|
40587
|
+
// Remove useless empty contents
|
|
40588
|
+
const filteredLines = [];
|
|
40589
|
+
for (const line of contentSplitInLines) {
|
|
40590
|
+
if (line.every(this.isContentEmpty)) {
|
|
40591
|
+
filteredLines.push([line[0]]);
|
|
40626
40592
|
}
|
|
40627
|
-
|
|
40628
|
-
|
|
40629
|
-
if (childElement) {
|
|
40630
|
-
this.el.replaceChild(p, childElement);
|
|
40631
|
-
}
|
|
40632
|
-
else {
|
|
40633
|
-
this.el.appendChild(p);
|
|
40634
|
-
}
|
|
40593
|
+
else {
|
|
40594
|
+
filteredLines.push(line.filter((content) => !this.isContentEmpty(content)));
|
|
40635
40595
|
}
|
|
40636
40596
|
}
|
|
40637
|
-
|
|
40638
|
-
|
|
40639
|
-
|
|
40597
|
+
return filteredLines;
|
|
40598
|
+
}
|
|
40599
|
+
isContentEmpty(content) {
|
|
40600
|
+
return !(content.value || content.class);
|
|
40601
|
+
}
|
|
40602
|
+
/**
|
|
40603
|
+
* Compute the state of the composer from the tokenAtCursor.
|
|
40604
|
+
* If the token is a function or symbol (that isn't a cell/range reference) we have to initialize
|
|
40605
|
+
* the autocomplete engine otherwise we initialize the formula assistant.
|
|
40606
|
+
*/
|
|
40607
|
+
processTokenAtCursor() {
|
|
40608
|
+
let content = this.props.composerStore.currentContent;
|
|
40609
|
+
if (this.autoCompleteState.provider) {
|
|
40610
|
+
this.autoCompleteState.hide();
|
|
40611
|
+
}
|
|
40612
|
+
this.functionDescriptionState.showDescription = false;
|
|
40613
|
+
const autoCompleteProvider = this.props.composerStore.autocompleteProvider;
|
|
40614
|
+
if (autoCompleteProvider) {
|
|
40615
|
+
this.autoCompleteState.useProvider(autoCompleteProvider);
|
|
40616
|
+
}
|
|
40617
|
+
const token = this.props.composerStore.tokenAtCursor;
|
|
40618
|
+
if (content.startsWith("=") && token && token.type !== "SYMBOL") {
|
|
40619
|
+
const tokenContext = token.functionContext;
|
|
40620
|
+
const parentFunction = tokenContext?.parent.toUpperCase();
|
|
40621
|
+
if (tokenContext &&
|
|
40622
|
+
parentFunction &&
|
|
40623
|
+
parentFunction in functions &&
|
|
40624
|
+
token.type !== "UNKNOWN") {
|
|
40625
|
+
// initialize Formula Assistant
|
|
40626
|
+
const description = functions[parentFunction];
|
|
40627
|
+
const argPosition = tokenContext.argPosition;
|
|
40628
|
+
this.functionDescriptionState.functionName = parentFunction;
|
|
40629
|
+
this.functionDescriptionState.functionDescription = description;
|
|
40630
|
+
this.functionDescriptionState.argToFocus = description.getArgToFocus(argPosition + 1) - 1;
|
|
40631
|
+
this.functionDescriptionState.showDescription = true;
|
|
40640
40632
|
}
|
|
40641
40633
|
}
|
|
40642
40634
|
}
|
|
40643
|
-
|
|
40644
|
-
|
|
40645
|
-
if (!focusedNode || !this.el.contains(focusedNode))
|
|
40635
|
+
autoComplete(value) {
|
|
40636
|
+
if (!value || this.assistant.forcedClosed) {
|
|
40646
40637
|
return;
|
|
40647
|
-
|
|
40648
|
-
|
|
40638
|
+
}
|
|
40639
|
+
this.autoCompleteState.provider?.selectProposal(value);
|
|
40640
|
+
this.processTokenAtCursor();
|
|
40649
40641
|
}
|
|
40650
|
-
|
|
40651
|
-
|
|
40652
|
-
|
|
40653
|
-
|
|
40654
|
-
|
|
40655
|
-
|
|
40642
|
+
}
|
|
40643
|
+
|
|
40644
|
+
class StandaloneComposerStore extends AbstractComposerStore {
|
|
40645
|
+
args;
|
|
40646
|
+
constructor(get, args) {
|
|
40647
|
+
super(get);
|
|
40648
|
+
this.args = args;
|
|
40649
|
+
this._currentContent = this.getComposerContent();
|
|
40656
40650
|
}
|
|
40657
|
-
|
|
40658
|
-
|
|
40659
|
-
|
|
40660
|
-
|
|
40661
|
-
|
|
40651
|
+
getAutoCompleteProviders() {
|
|
40652
|
+
const providersDefinitions = super.getAutoCompleteProviders();
|
|
40653
|
+
const contextualAutocomplete = this.args().contextualAutocomplete;
|
|
40654
|
+
if (contextualAutocomplete) {
|
|
40655
|
+
providersDefinitions.push(contextualAutocomplete);
|
|
40662
40656
|
}
|
|
40657
|
+
return providersDefinitions;
|
|
40663
40658
|
}
|
|
40664
40659
|
/**
|
|
40665
|
-
*
|
|
40660
|
+
* Replace the current reference selected by the new one.
|
|
40666
40661
|
* */
|
|
40667
|
-
|
|
40668
|
-
|
|
40662
|
+
getZoneReference(zone) {
|
|
40663
|
+
const res = super.getZoneReference(zone);
|
|
40664
|
+
if (this.args().defaultStatic) {
|
|
40665
|
+
return setXcToFixedReferenceType(res, "colrow");
|
|
40666
|
+
}
|
|
40667
|
+
return res;
|
|
40669
40668
|
}
|
|
40670
|
-
|
|
40671
|
-
|
|
40672
|
-
|
|
40673
|
-
|
|
40674
|
-
|
|
40675
|
-
|
|
40676
|
-
|
|
40677
|
-
|
|
40678
|
-
|
|
40679
|
-
|
|
40680
|
-
|
|
40681
|
-
) {
|
|
40682
|
-
if (isFirstParagraph) {
|
|
40683
|
-
isFirstParagraph = false;
|
|
40684
|
-
}
|
|
40685
|
-
else {
|
|
40686
|
-
text += NEWLINE;
|
|
40669
|
+
getComposerContent() {
|
|
40670
|
+
if (this.editionMode === "inactive") {
|
|
40671
|
+
// References in the content might not be linked to the current active sheet
|
|
40672
|
+
// We here force the sheet name prefix for all references that are not in
|
|
40673
|
+
// the current active sheet
|
|
40674
|
+
const defaultRangeSheetId = this.args().defaultRangeSheetId;
|
|
40675
|
+
return rangeTokenize(this.args().content)
|
|
40676
|
+
.map((token) => {
|
|
40677
|
+
if (token.type === "REFERENCE") {
|
|
40678
|
+
const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
|
|
40679
|
+
return this.getters.getRangeString(range, this.getters.getActiveSheetId());
|
|
40687
40680
|
}
|
|
40681
|
+
return token.value;
|
|
40682
|
+
})
|
|
40683
|
+
.join("");
|
|
40684
|
+
}
|
|
40685
|
+
return this._currentContent;
|
|
40686
|
+
}
|
|
40687
|
+
stopEdition() {
|
|
40688
|
+
this._stopEdition();
|
|
40689
|
+
}
|
|
40690
|
+
confirmEdition(content) {
|
|
40691
|
+
this.args().onConfirm(content);
|
|
40692
|
+
}
|
|
40693
|
+
getTokenColor(token) {
|
|
40694
|
+
if (token.type === "SYMBOL") {
|
|
40695
|
+
const matchedColor = this.args().getContextualColoredSymbolToken?.(token);
|
|
40696
|
+
if (matchedColor) {
|
|
40697
|
+
return matchedColor;
|
|
40688
40698
|
}
|
|
40689
|
-
current = it.next();
|
|
40690
40699
|
}
|
|
40691
|
-
return
|
|
40700
|
+
return super.getTokenColor(token);
|
|
40692
40701
|
}
|
|
40693
40702
|
}
|
|
40694
|
-
function compareContentToSpanElement(content, node) {
|
|
40695
|
-
const contentColor = content.color ? toHex(content.color) : "";
|
|
40696
|
-
const nodeColor = node.style?.color ? toHex(node.style.color) : "";
|
|
40697
|
-
const sameColor = contentColor === nodeColor;
|
|
40698
|
-
const sameClass = deepEquals([content.class], [...node.classList]);
|
|
40699
|
-
const sameContent = node.innerText === content.value;
|
|
40700
|
-
return sameColor && sameClass && sameContent;
|
|
40701
|
-
}
|
|
40702
40703
|
|
|
40703
|
-
// -----------------------------------------------------------------------------
|
|
40704
|
-
// Formula Assistant component
|
|
40705
|
-
// -----------------------------------------------------------------------------
|
|
40706
40704
|
css /* scss */ `
|
|
40707
|
-
.o-
|
|
40708
|
-
|
|
40709
|
-
|
|
40710
|
-
|
|
40711
|
-
|
|
40712
|
-
|
|
40713
|
-
|
|
40714
|
-
|
|
40715
|
-
|
|
40716
|
-
|
|
40717
|
-
border-bottom: 1px solid gray;
|
|
40718
|
-
}
|
|
40719
|
-
.o-formula-assistant-arg-description {
|
|
40720
|
-
font-size: 85%;
|
|
40721
|
-
}
|
|
40722
|
-
.o-formula-assistant-focus {
|
|
40723
|
-
div:first-child,
|
|
40724
|
-
span {
|
|
40725
|
-
color: ${COMPOSER_ASSISTANT_COLOR};
|
|
40726
|
-
text-shadow: 0px 0px 1px ${COMPOSER_ASSISTANT_COLOR};
|
|
40705
|
+
.o-spreadsheet {
|
|
40706
|
+
.o-standalone-composer {
|
|
40707
|
+
min-height: 24px;
|
|
40708
|
+
box-sizing: border-box;
|
|
40709
|
+
|
|
40710
|
+
border-bottom: 1px solid;
|
|
40711
|
+
border-color: ${GRAY_300};
|
|
40712
|
+
|
|
40713
|
+
&.active {
|
|
40714
|
+
border-color: ${ACTION_COLOR};
|
|
40727
40715
|
}
|
|
40728
|
-
|
|
40729
|
-
|
|
40716
|
+
|
|
40717
|
+
&.o-invalid {
|
|
40718
|
+
border-bottom: 2px solid red;
|
|
40719
|
+
}
|
|
40720
|
+
|
|
40721
|
+
/* As the standalone composer is potentially very small (eg. in a side panel), we remove the scrollbar display */
|
|
40722
|
+
scrollbar-width: none; /* Firefox */
|
|
40723
|
+
&::-webkit-scrollbar {
|
|
40724
|
+
display: none;
|
|
40730
40725
|
}
|
|
40731
|
-
}
|
|
40732
|
-
.o-formula-assistant-gray {
|
|
40733
|
-
color: gray;
|
|
40734
40726
|
}
|
|
40735
40727
|
}
|
|
40736
40728
|
`;
|
|
40737
|
-
class
|
|
40738
|
-
static template = "o-spreadsheet-
|
|
40729
|
+
class StandaloneComposer extends Component {
|
|
40730
|
+
static template = "o-spreadsheet-StandaloneComposer";
|
|
40739
40731
|
static props = {
|
|
40740
|
-
|
|
40741
|
-
|
|
40742
|
-
|
|
40732
|
+
composerContent: { type: String, optional: true },
|
|
40733
|
+
defaultRangeSheetId: { type: String, optional: true },
|
|
40734
|
+
defaultStatic: { type: Boolean, optional: true },
|
|
40735
|
+
onConfirm: Function,
|
|
40736
|
+
contextualAutocomplete: { type: Object, optional: true },
|
|
40737
|
+
placeholder: { type: String, optional: true },
|
|
40738
|
+
title: { type: String, optional: true },
|
|
40739
|
+
class: { type: String, optional: true },
|
|
40740
|
+
invalid: { type: Boolean, optional: true },
|
|
40741
|
+
getContextualColoredSymbolToken: { type: Function, optional: true },
|
|
40743
40742
|
};
|
|
40744
|
-
|
|
40745
|
-
|
|
40743
|
+
static components = { Composer };
|
|
40744
|
+
static defaultProps = {
|
|
40745
|
+
composerContent: "",
|
|
40746
|
+
defaultStatic: false,
|
|
40747
|
+
};
|
|
40748
|
+
composerFocusStore;
|
|
40749
|
+
standaloneComposerStore;
|
|
40750
|
+
composerInterface;
|
|
40751
|
+
spreadsheetRect = useSpreadsheetRect();
|
|
40752
|
+
setup() {
|
|
40753
|
+
this.composerFocusStore = useStore(ComposerFocusStore);
|
|
40754
|
+
const standaloneComposerStore = useLocalStore(StandaloneComposerStore, () => ({
|
|
40755
|
+
onConfirm: this.props.onConfirm,
|
|
40756
|
+
content: this.props.composerContent,
|
|
40757
|
+
defaultStatic: this.props.defaultStatic ?? false,
|
|
40758
|
+
contextualAutocomplete: this.props.contextualAutocomplete,
|
|
40759
|
+
defaultRangeSheetId: this.props.defaultRangeSheetId,
|
|
40760
|
+
getContextualColoredSymbolToken: this.props.getContextualColoredSymbolToken,
|
|
40761
|
+
}));
|
|
40762
|
+
this.standaloneComposerStore = standaloneComposerStore;
|
|
40763
|
+
this.composerInterface = {
|
|
40764
|
+
id: "standaloneComposer",
|
|
40765
|
+
get editionMode() {
|
|
40766
|
+
return standaloneComposerStore.editionMode;
|
|
40767
|
+
},
|
|
40768
|
+
startEdition: this.standaloneComposerStore.startEdition,
|
|
40769
|
+
setCurrentContent: this.standaloneComposerStore.setCurrentContent,
|
|
40770
|
+
stopEdition: this.standaloneComposerStore.stopEdition,
|
|
40771
|
+
};
|
|
40746
40772
|
}
|
|
40747
|
-
get
|
|
40748
|
-
return this.
|
|
40773
|
+
get focus() {
|
|
40774
|
+
return this.composerFocusStore.activeComposer === this.composerInterface
|
|
40775
|
+
? this.composerFocusStore.focusMode
|
|
40776
|
+
: "inactive";
|
|
40777
|
+
}
|
|
40778
|
+
get composerStyle() {
|
|
40779
|
+
return this.props.invalid
|
|
40780
|
+
? cssPropertiesToCss({ padding: "1px 0px 0px 0px" })
|
|
40781
|
+
: cssPropertiesToCss({ padding: "1px 0px" });
|
|
40782
|
+
}
|
|
40783
|
+
get containerClass() {
|
|
40784
|
+
const classes = [
|
|
40785
|
+
this.focus === "inactive" ? "" : "active",
|
|
40786
|
+
this.props.invalid ? "o-invalid" : "",
|
|
40787
|
+
this.props.class || "",
|
|
40788
|
+
];
|
|
40789
|
+
return classes.join(" ");
|
|
40790
|
+
}
|
|
40791
|
+
onFocus(selection) {
|
|
40792
|
+
this.composerFocusStore.focusComposer(this.composerInterface, { selection });
|
|
40749
40793
|
}
|
|
40750
40794
|
}
|
|
40751
40795
|
|
|
40752
|
-
const functions = functionRegistry.content;
|
|
40753
|
-
const ASSISTANT_WIDTH = 300;
|
|
40754
|
-
const CLOSE_ICON_RADIUS = 9;
|
|
40755
|
-
const selectionIndicatorClass = "selector-flag";
|
|
40756
|
-
const backgroundClass = "background-flag";
|
|
40757
|
-
const selectionIndicatorColor = "#a9a9a9";
|
|
40758
|
-
const selectionIndicator = "␣";
|
|
40759
40796
|
css /* scss */ `
|
|
40760
|
-
.o-
|
|
40761
|
-
|
|
40762
|
-
|
|
40763
|
-
|
|
40764
|
-
|
|
40765
|
-
|
|
40797
|
+
.o-gauge-color-set {
|
|
40798
|
+
table {
|
|
40799
|
+
table-layout: fixed;
|
|
40800
|
+
margin-top: 2%;
|
|
40801
|
+
display: table;
|
|
40802
|
+
text-align: left;
|
|
40803
|
+
font-size: 12px;
|
|
40804
|
+
line-height: 18px;
|
|
40805
|
+
width: 100%;
|
|
40806
|
+
font-size: 12px;
|
|
40807
|
+
}
|
|
40766
40808
|
|
|
40809
|
+
td {
|
|
40767
40810
|
box-sizing: border-box;
|
|
40768
|
-
|
|
40769
|
-
|
|
40770
|
-
padding-left: 3px;
|
|
40771
|
-
padding-right: 3px;
|
|
40772
|
-
outline: none;
|
|
40773
|
-
|
|
40774
|
-
p {
|
|
40775
|
-
margin-bottom: 0px;
|
|
40776
|
-
|
|
40777
|
-
span {
|
|
40778
|
-
white-space: pre-wrap;
|
|
40779
|
-
|
|
40780
|
-
&.${selectionIndicatorClass}:after {
|
|
40781
|
-
content: "${selectionIndicator}";
|
|
40782
|
-
color: ${selectionIndicatorColor};
|
|
40783
|
-
}
|
|
40784
|
-
|
|
40785
|
-
&.${backgroundClass} {
|
|
40786
|
-
border-radius: 5px;
|
|
40787
|
-
background-color: lightgray;
|
|
40788
|
-
padding: 0px 1.5px 1.5px 1.5px;
|
|
40789
|
-
}
|
|
40790
|
-
}
|
|
40791
|
-
}
|
|
40811
|
+
height: 30px;
|
|
40812
|
+
padding: 6px 0;
|
|
40792
40813
|
}
|
|
40793
|
-
.o-
|
|
40794
|
-
|
|
40795
|
-
color: #bdbdbd;
|
|
40796
|
-
position: relative;
|
|
40797
|
-
top: 0%;
|
|
40798
|
-
pointer-events: none;
|
|
40814
|
+
th.o-gauge-color-set-colorPicker {
|
|
40815
|
+
width: 8%;
|
|
40799
40816
|
}
|
|
40800
|
-
|
|
40801
|
-
|
|
40802
|
-
/* reset stack size which is doubled by default */
|
|
40803
|
-
width: ${CLOSE_ICON_RADIUS * 2}px;
|
|
40804
|
-
height: ${CLOSE_ICON_RADIUS * 2}px;
|
|
40805
|
-
line-height: ${CLOSE_ICON_RADIUS * 2}px;
|
|
40817
|
+
th.o-gauge-color-set-text {
|
|
40818
|
+
width: 25%;
|
|
40806
40819
|
}
|
|
40807
|
-
|
|
40808
|
-
|
|
40809
|
-
left: -1px;
|
|
40810
|
-
top: -1px;
|
|
40811
|
-
|
|
40812
|
-
.fa-question-circle {
|
|
40813
|
-
color: ${PRIMARY_BUTTON_BG};
|
|
40814
|
-
}
|
|
40820
|
+
th.o-gauge-color-set-operator {
|
|
40821
|
+
width: 10%;
|
|
40815
40822
|
}
|
|
40816
|
-
|
|
40817
|
-
|
|
40818
|
-
|
|
40819
|
-
|
|
40820
|
-
|
|
40821
|
-
|
|
40822
|
-
|
|
40823
|
-
|
|
40824
|
-
|
|
40825
|
-
|
|
40826
|
-
|
|
40823
|
+
th.o-gauge-color-set-value {
|
|
40824
|
+
width: 22%;
|
|
40825
|
+
}
|
|
40826
|
+
th.o-gauge-color-set-type {
|
|
40827
|
+
width: 30%;
|
|
40828
|
+
}
|
|
40829
|
+
input,
|
|
40830
|
+
select {
|
|
40831
|
+
width: 100%;
|
|
40832
|
+
height: 100%;
|
|
40833
|
+
box-sizing: border-box;
|
|
40827
40834
|
}
|
|
40828
40835
|
}
|
|
40829
40836
|
`;
|
|
40830
|
-
class
|
|
40831
|
-
static template = "o-spreadsheet-
|
|
40837
|
+
class GaugeChartDesignPanel extends Component {
|
|
40838
|
+
static template = "o-spreadsheet-GaugeChartDesignPanel";
|
|
40839
|
+
static components = {
|
|
40840
|
+
SidePanelCollapsible,
|
|
40841
|
+
Section,
|
|
40842
|
+
RoundColorPicker,
|
|
40843
|
+
GeneralDesignEditor,
|
|
40844
|
+
ChartErrorSection,
|
|
40845
|
+
StandaloneComposer,
|
|
40846
|
+
};
|
|
40832
40847
|
static props = {
|
|
40833
|
-
|
|
40834
|
-
|
|
40835
|
-
|
|
40836
|
-
|
|
40837
|
-
rect: { type: Object, optional: true },
|
|
40838
|
-
delimitation: { type: Object, optional: true },
|
|
40839
|
-
onComposerCellFocused: { type: Function, optional: true },
|
|
40840
|
-
onComposerContentFocused: Function,
|
|
40841
|
-
isDefaultFocus: { type: Boolean, optional: true },
|
|
40842
|
-
onInputContextMenu: { type: Function, optional: true },
|
|
40843
|
-
composerStore: Object,
|
|
40844
|
-
placeholder: { type: String, optional: true },
|
|
40848
|
+
figureId: String,
|
|
40849
|
+
definition: Object,
|
|
40850
|
+
updateChart: Function,
|
|
40851
|
+
canUpdateChart: { type: Function, optional: true },
|
|
40845
40852
|
};
|
|
40846
|
-
|
|
40847
|
-
|
|
40848
|
-
|
|
40849
|
-
|
|
40853
|
+
state;
|
|
40854
|
+
setup() {
|
|
40855
|
+
this.state = useState({
|
|
40856
|
+
sectionRuleCancelledReasons: this.checkSectionRuleFormulasAreValid(this.props.definition.sectionRule),
|
|
40857
|
+
sectionRule: deepCopy(this.props.definition.sectionRule),
|
|
40858
|
+
});
|
|
40859
|
+
}
|
|
40860
|
+
get designErrorMessages() {
|
|
40861
|
+
const cancelledReasons = [...(this.state.sectionRuleCancelledReasons || [])];
|
|
40862
|
+
return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
|
|
40863
|
+
}
|
|
40864
|
+
get isRangeMinInvalid() {
|
|
40865
|
+
return !!(this.state.sectionRuleCancelledReasons?.includes("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
|
|
40866
|
+
this.state.sectionRuleCancelledReasons?.includes("GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */));
|
|
40867
|
+
}
|
|
40868
|
+
get isRangeMaxInvalid() {
|
|
40869
|
+
return !!(this.state.sectionRuleCancelledReasons?.includes("EmptyGaugeRangeMax" /* CommandResult.EmptyGaugeRangeMax */) ||
|
|
40870
|
+
this.state.sectionRuleCancelledReasons?.includes("GaugeRangeMaxNaN" /* CommandResult.GaugeRangeMaxNaN */));
|
|
40871
|
+
}
|
|
40872
|
+
// ---------------------------------------------------------------------------
|
|
40873
|
+
// COLOR_SECTION_TEMPLATE
|
|
40874
|
+
// ---------------------------------------------------------------------------
|
|
40875
|
+
get isLowerInflectionPointInvalid() {
|
|
40876
|
+
return !!this.state.sectionRuleCancelledReasons?.includes("GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */);
|
|
40877
|
+
}
|
|
40878
|
+
get isUpperInflectionPointInvalid() {
|
|
40879
|
+
return !!this.state.sectionRuleCancelledReasons?.includes("GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */);
|
|
40880
|
+
}
|
|
40881
|
+
updateSectionColor(target, color) {
|
|
40882
|
+
const sectionRule = deepCopy(this.state.sectionRule);
|
|
40883
|
+
sectionRule.colors[target] = color;
|
|
40884
|
+
this.updateSectionRule(sectionRule);
|
|
40885
|
+
}
|
|
40886
|
+
updateSectionRule(sectionRule) {
|
|
40887
|
+
this.state.sectionRuleCancelledReasons = [];
|
|
40888
|
+
this.state.sectionRuleCancelledReasons.push(...this.checkSectionRuleFormulasAreValid(this.state.sectionRule));
|
|
40889
|
+
const dispatchResult = this.props.updateChart(this.props.figureId, {
|
|
40890
|
+
sectionRule,
|
|
40891
|
+
});
|
|
40892
|
+
if (dispatchResult.isSuccessful) {
|
|
40893
|
+
this.state.sectionRule = deepCopy(sectionRule);
|
|
40894
|
+
}
|
|
40895
|
+
else {
|
|
40896
|
+
this.state.sectionRuleCancelledReasons.push(...dispatchResult.reasons);
|
|
40897
|
+
}
|
|
40898
|
+
}
|
|
40899
|
+
onConfirmGaugeRange(editedRange, content) {
|
|
40900
|
+
this.state.sectionRule = { ...this.state.sectionRule, [editedRange]: content };
|
|
40901
|
+
this.updateSectionRule(this.state.sectionRule);
|
|
40902
|
+
}
|
|
40903
|
+
getGaugeInflectionComposerProps(sectionType) {
|
|
40904
|
+
const inflectionPointName = sectionType === "lowerColor" ? "lowerInflectionPoint" : "upperInflectionPoint";
|
|
40905
|
+
const inflectionPoint = this.state.sectionRule[inflectionPointName];
|
|
40906
|
+
return {
|
|
40907
|
+
onConfirm: (str) => {
|
|
40908
|
+
this.state.sectionRule = {
|
|
40909
|
+
...this.state.sectionRule,
|
|
40910
|
+
[inflectionPointName]: { ...inflectionPoint, value: str },
|
|
40911
|
+
};
|
|
40912
|
+
this.updateSectionRule(this.state.sectionRule);
|
|
40913
|
+
},
|
|
40914
|
+
composerContent: inflectionPoint.value,
|
|
40915
|
+
invalid: sectionType === "lowerColor"
|
|
40916
|
+
? this.isLowerInflectionPointInvalid
|
|
40917
|
+
: this.isUpperInflectionPointInvalid,
|
|
40918
|
+
defaultRangeSheetId: this.sheetId,
|
|
40919
|
+
class: inflectionPointName,
|
|
40920
|
+
placeholder: _t("Value"),
|
|
40921
|
+
title: _t("Value or formula"),
|
|
40922
|
+
};
|
|
40923
|
+
}
|
|
40924
|
+
checkSectionRuleFormulasAreValid(sectionRule) {
|
|
40925
|
+
const reasons = [];
|
|
40926
|
+
if (!this.valueIsValidNumber(sectionRule.rangeMin)) {
|
|
40927
|
+
reasons.push("GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */);
|
|
40928
|
+
}
|
|
40929
|
+
if (!this.valueIsValidNumber(sectionRule.rangeMax)) {
|
|
40930
|
+
reasons.push("GaugeRangeMaxNaN" /* CommandResult.GaugeRangeMaxNaN */);
|
|
40931
|
+
}
|
|
40932
|
+
if (!this.valueIsValidNumber(sectionRule.lowerInflectionPoint.value)) {
|
|
40933
|
+
reasons.push("GaugeLowerInflectionPointNaN" /* CommandResult.GaugeLowerInflectionPointNaN */);
|
|
40934
|
+
}
|
|
40935
|
+
if (!this.valueIsValidNumber(sectionRule.upperInflectionPoint.value)) {
|
|
40936
|
+
reasons.push("GaugeUpperInflectionPointNaN" /* CommandResult.GaugeUpperInflectionPointNaN */);
|
|
40937
|
+
}
|
|
40938
|
+
return reasons;
|
|
40939
|
+
}
|
|
40940
|
+
valueIsValidNumber(value) {
|
|
40941
|
+
const locale = this.env.model.getters.getLocale();
|
|
40942
|
+
if (!value.startsWith("=")) {
|
|
40943
|
+
return tryToNumber(value, locale) !== undefined;
|
|
40944
|
+
}
|
|
40945
|
+
const evaluatedValue = this.env.model.getters.evaluateFormula(this.sheetId, value);
|
|
40946
|
+
if (isMatrix(evaluatedValue)) {
|
|
40947
|
+
return false;
|
|
40948
|
+
}
|
|
40949
|
+
return tryToNumber(evaluatedValue, locale) !== undefined;
|
|
40950
|
+
}
|
|
40951
|
+
get sheetId() {
|
|
40952
|
+
const chart = this.env.model.getters.getChart(this.props.figureId);
|
|
40953
|
+
if (!chart) {
|
|
40954
|
+
throw new Error("Chart not found with id " + this.props.figureId);
|
|
40955
|
+
}
|
|
40956
|
+
return chart.sheetId;
|
|
40957
|
+
}
|
|
40958
|
+
}
|
|
40959
|
+
|
|
40960
|
+
class GeoChartRegionSelectSection extends Component {
|
|
40961
|
+
static template = "o-spreadsheet-GeoChartRegionSelectSection";
|
|
40962
|
+
static components = { Section };
|
|
40963
|
+
static props = {
|
|
40964
|
+
figureId: String,
|
|
40965
|
+
definition: Object,
|
|
40966
|
+
updateChart: Function,
|
|
40850
40967
|
};
|
|
40851
|
-
|
|
40852
|
-
|
|
40853
|
-
|
|
40854
|
-
|
|
40855
|
-
|
|
40856
|
-
|
|
40857
|
-
}
|
|
40858
|
-
|
|
40859
|
-
|
|
40860
|
-
|
|
40861
|
-
|
|
40862
|
-
|
|
40863
|
-
|
|
40864
|
-
|
|
40865
|
-
|
|
40866
|
-
|
|
40867
|
-
|
|
40868
|
-
|
|
40869
|
-
|
|
40870
|
-
|
|
40871
|
-
|
|
40872
|
-
|
|
40873
|
-
|
|
40874
|
-
|
|
40875
|
-
|
|
40876
|
-
|
|
40877
|
-
|
|
40968
|
+
updateSelectedRegion(ev) {
|
|
40969
|
+
const value = ev.target.value;
|
|
40970
|
+
this.props.updateChart(this.props.figureId, { region: value });
|
|
40971
|
+
}
|
|
40972
|
+
get availableRegions() {
|
|
40973
|
+
return this.env.model.getters.getGeoChartAvailableRegions();
|
|
40974
|
+
}
|
|
40975
|
+
get selectedRegion() {
|
|
40976
|
+
return this.props.definition.region || this.availableRegions[0]?.id;
|
|
40977
|
+
}
|
|
40978
|
+
}
|
|
40979
|
+
|
|
40980
|
+
class GeoChartConfigPanel extends GenericChartConfigPanel {
|
|
40981
|
+
static template = "o-spreadsheet-GeoChartConfigPanel";
|
|
40982
|
+
static components = { ...GenericChartConfigPanel.components, GeoChartRegionSelectSection };
|
|
40983
|
+
get dataRanges() {
|
|
40984
|
+
return this.getDataSeriesRanges().slice(0, 1);
|
|
40985
|
+
}
|
|
40986
|
+
onDataSeriesConfirmed() {
|
|
40987
|
+
this.dataSets = spreadRange(this.env.model.getters, this.dataSets).slice(0, 1);
|
|
40988
|
+
this.state.datasetDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
40989
|
+
dataSets: this.dataSets,
|
|
40990
|
+
});
|
|
40991
|
+
}
|
|
40992
|
+
getLabelRangeOptions() {
|
|
40993
|
+
return [
|
|
40994
|
+
{
|
|
40995
|
+
name: "dataSetsHaveTitle",
|
|
40996
|
+
label: this.dataSetsHaveTitleLabel,
|
|
40997
|
+
value: this.props.definition.dataSetsHaveTitle,
|
|
40998
|
+
onChange: this.onUpdateDataSetsHaveTitle.bind(this),
|
|
40999
|
+
},
|
|
41000
|
+
];
|
|
41001
|
+
}
|
|
41002
|
+
}
|
|
41003
|
+
|
|
41004
|
+
const DEFAULT_CUSTOM_COLOR_SCALE = {
|
|
41005
|
+
minColor: "#FFF5EB",
|
|
41006
|
+
midColor: "#FD8D3C",
|
|
41007
|
+
maxColor: "#7F2704",
|
|
41008
|
+
};
|
|
41009
|
+
class GeoChartDesignPanel extends ChartWithAxisDesignPanel {
|
|
41010
|
+
static template = "o-spreadsheet-GeoChartDesignPanel";
|
|
41011
|
+
static components = { ...ChartWithAxisDesignPanel.components, RoundColorPicker };
|
|
41012
|
+
colorScalesChoices = ChartTerms.GeoChart.ColorScales;
|
|
41013
|
+
updateColorScaleType(ev) {
|
|
41014
|
+
const value = ev.target.value;
|
|
41015
|
+
value === "custom"
|
|
41016
|
+
? this.updateColorScale(DEFAULT_CUSTOM_COLOR_SCALE)
|
|
41017
|
+
: this.updateColorScale(value);
|
|
41018
|
+
}
|
|
41019
|
+
updateColorScale(colorScale) {
|
|
41020
|
+
this.props.updateChart(this.props.figureId, { colorScale });
|
|
41021
|
+
}
|
|
41022
|
+
updateMissingValueColor(color) {
|
|
41023
|
+
this.props.updateChart(this.props.figureId, { missingValueColor: color });
|
|
41024
|
+
}
|
|
41025
|
+
updateLegendPosition(ev) {
|
|
41026
|
+
const value = ev.target.value;
|
|
41027
|
+
this.props.updateChart(this.props.figureId, { legendPosition: value });
|
|
41028
|
+
}
|
|
41029
|
+
get selectedColorScale() {
|
|
41030
|
+
return typeof this.props.definition.colorScale === "object"
|
|
41031
|
+
? "custom"
|
|
41032
|
+
: this.props.definition.colorScale || "oranges";
|
|
41033
|
+
}
|
|
41034
|
+
get selectedMissingValueColor() {
|
|
41035
|
+
return this.props.definition.missingValueColor || "#ffffff";
|
|
41036
|
+
}
|
|
41037
|
+
get customColorScale() {
|
|
41038
|
+
if (typeof this.props.definition.colorScale === "object") {
|
|
41039
|
+
return this.props.definition.colorScale;
|
|
40878
41040
|
}
|
|
40879
|
-
|
|
40880
|
-
|
|
40881
|
-
|
|
40882
|
-
|
|
40883
|
-
|
|
40884
|
-
|
|
40885
|
-
|
|
40886
|
-
|
|
40887
|
-
|
|
40888
|
-
|
|
40889
|
-
|
|
40890
|
-
|
|
40891
|
-
|
|
40892
|
-
|
|
40893
|
-
|
|
40894
|
-
|
|
41041
|
+
return undefined;
|
|
41042
|
+
}
|
|
41043
|
+
getCustomColorScaleColor(color) {
|
|
41044
|
+
return this.customColorScale?.[color] ?? "";
|
|
41045
|
+
}
|
|
41046
|
+
setCustomColorScaleColor(colorType, color) {
|
|
41047
|
+
if (!color && colorType !== "midColor") {
|
|
41048
|
+
color = "#fff";
|
|
41049
|
+
}
|
|
41050
|
+
const customColorScale = this.customColorScale;
|
|
41051
|
+
if (!customColorScale) {
|
|
41052
|
+
return;
|
|
41053
|
+
}
|
|
41054
|
+
this.updateColorScale({ ...customColorScale, [colorType]: color });
|
|
41055
|
+
}
|
|
41056
|
+
}
|
|
41057
|
+
|
|
41058
|
+
class LineConfigPanel extends GenericChartConfigPanel {
|
|
41059
|
+
static template = "o-spreadsheet-LineConfigPanel";
|
|
41060
|
+
get canTreatLabelsAsText() {
|
|
41061
|
+
const chart = this.env.model.getters.getChart(this.props.figureId);
|
|
41062
|
+
if (chart && chart instanceof LineChart) {
|
|
41063
|
+
return canChartParseLabels(chart.labelRange, this.env.model.getters);
|
|
40895
41064
|
}
|
|
40896
|
-
|
|
40897
|
-
|
|
40898
|
-
|
|
40899
|
-
|
|
40900
|
-
|
|
40901
|
-
|
|
41065
|
+
return false;
|
|
41066
|
+
}
|
|
41067
|
+
get stackedLabel() {
|
|
41068
|
+
const definition = this.props.definition;
|
|
41069
|
+
return definition.fillArea
|
|
41070
|
+
? this.chartTerms.StackedAreaChart
|
|
41071
|
+
: this.chartTerms.StackedLineChart;
|
|
41072
|
+
}
|
|
41073
|
+
getLabelRangeOptions() {
|
|
41074
|
+
const options = super.getLabelRangeOptions();
|
|
41075
|
+
if (this.canTreatLabelsAsText) {
|
|
41076
|
+
options.push({
|
|
41077
|
+
name: "labelsAsText",
|
|
41078
|
+
value: this.props.definition.labelsAsText,
|
|
41079
|
+
label: this.chartTerms.TreatLabelsAsText,
|
|
41080
|
+
onChange: this.onUpdateLabelsAsText.bind(this),
|
|
41081
|
+
});
|
|
40902
41082
|
}
|
|
40903
|
-
return
|
|
41083
|
+
return options;
|
|
40904
41084
|
}
|
|
40905
|
-
|
|
40906
|
-
|
|
40907
|
-
|
|
40908
|
-
keyMapping = {
|
|
40909
|
-
Enter: (ev) => this.processEnterKey(ev, "down"),
|
|
40910
|
-
"Shift+Enter": (ev) => this.processEnterKey(ev, "up"),
|
|
40911
|
-
"Alt+Enter": this.processNewLineEvent,
|
|
40912
|
-
"Ctrl+Enter": this.processNewLineEvent,
|
|
40913
|
-
Escape: this.processEscapeKey,
|
|
40914
|
-
F2: (ev) => this.toggleEditionMode(ev),
|
|
40915
|
-
F4: (ev) => this.processF4Key(ev),
|
|
40916
|
-
Tab: (ev) => this.processTabKey(ev, "right"),
|
|
40917
|
-
"Shift+Tab": (ev) => this.processTabKey(ev, "left"),
|
|
40918
|
-
};
|
|
40919
|
-
keyCodeMapping = {
|
|
40920
|
-
NumpadDecimal: this.processNumpadDecimal,
|
|
40921
|
-
};
|
|
40922
|
-
setup() {
|
|
40923
|
-
this.DOMFocusableElementStore = useStore(DOMFocusableElementStore);
|
|
40924
|
-
this.autoCompleteState = useLocalStore(AutoCompleteStore);
|
|
40925
|
-
onMounted(() => {
|
|
40926
|
-
const el = this.composerRef.el;
|
|
40927
|
-
if (this.props.isDefaultFocus) {
|
|
40928
|
-
this.DOMFocusableElementStore.setFocusableElement(el);
|
|
40929
|
-
}
|
|
40930
|
-
this.contentHelper.updateEl(el);
|
|
40931
|
-
});
|
|
40932
|
-
this.env.model.selection.observe(this, {
|
|
40933
|
-
handleEvent: () => this.autoCompleteState.hide(),
|
|
41085
|
+
onUpdateLabelsAsText(labelsAsText) {
|
|
41086
|
+
this.props.updateChart(this.props.figureId, {
|
|
41087
|
+
labelsAsText,
|
|
40934
41088
|
});
|
|
40935
|
-
|
|
40936
|
-
|
|
41089
|
+
}
|
|
41090
|
+
onUpdateStacked(stacked) {
|
|
41091
|
+
this.props.updateChart(this.props.figureId, {
|
|
41092
|
+
stacked,
|
|
40937
41093
|
});
|
|
40938
|
-
|
|
40939
|
-
|
|
40940
|
-
|
|
40941
|
-
|
|
40942
|
-
!this.props.isDefaultFocus) {
|
|
40943
|
-
this.DOMFocusableElementStore.focusableElement?.focus();
|
|
40944
|
-
}
|
|
41094
|
+
}
|
|
41095
|
+
onUpdateCumulative(cumulative) {
|
|
41096
|
+
this.props.updateChart(this.props.figureId, {
|
|
41097
|
+
cumulative,
|
|
40945
41098
|
});
|
|
40946
|
-
useEffect(() => {
|
|
40947
|
-
this.processTokenAtCursor();
|
|
40948
|
-
}, () => [this.props.composerStore.editionMode !== "inactive"]);
|
|
40949
41099
|
}
|
|
40950
|
-
|
|
40951
|
-
|
|
40952
|
-
|
|
40953
|
-
|
|
40954
|
-
|
|
40955
|
-
|
|
40956
|
-
|
|
40957
|
-
|
|
40958
|
-
|
|
40959
|
-
|
|
40960
|
-
|
|
40961
|
-
|
|
40962
|
-
|
|
40963
|
-
|
|
40964
|
-
|
|
40965
|
-
|
|
40966
|
-
|
|
40967
|
-
|
|
40968
|
-
|
|
40969
|
-
|
|
40970
|
-
|
|
40971
|
-
|
|
40972
|
-
|
|
40973
|
-
|
|
41100
|
+
}
|
|
41101
|
+
|
|
41102
|
+
class PieChartDesignPanel extends Component {
|
|
41103
|
+
static template = "o-spreadsheet-PieChartDesignPanel";
|
|
41104
|
+
static components = {
|
|
41105
|
+
GeneralDesignEditor,
|
|
41106
|
+
Section,
|
|
41107
|
+
Checkbox,
|
|
41108
|
+
ChartLegend,
|
|
41109
|
+
};
|
|
41110
|
+
static props = {
|
|
41111
|
+
figureId: String,
|
|
41112
|
+
definition: Object,
|
|
41113
|
+
updateChart: Function,
|
|
41114
|
+
canUpdateChart: { type: Function, optional: true },
|
|
41115
|
+
};
|
|
41116
|
+
}
|
|
41117
|
+
|
|
41118
|
+
class RadarChartDesignPanel extends Component {
|
|
41119
|
+
static template = "o-spreadsheet-RadarChartDesignPanel";
|
|
41120
|
+
static components = {
|
|
41121
|
+
GeneralDesignEditor,
|
|
41122
|
+
SeriesDesignEditor,
|
|
41123
|
+
Section,
|
|
41124
|
+
Checkbox,
|
|
41125
|
+
ChartLegend,
|
|
41126
|
+
};
|
|
41127
|
+
static props = {
|
|
41128
|
+
figureId: String,
|
|
41129
|
+
definition: Object,
|
|
41130
|
+
canUpdateChart: Function,
|
|
41131
|
+
updateChart: Function,
|
|
41132
|
+
};
|
|
41133
|
+
}
|
|
41134
|
+
|
|
41135
|
+
class ScatterConfigPanel extends GenericChartConfigPanel {
|
|
41136
|
+
static template = "o-spreadsheet-ScatterConfigPanel";
|
|
41137
|
+
get canTreatLabelsAsText() {
|
|
41138
|
+
const chart = this.env.model.getters.getChart(this.props.figureId);
|
|
41139
|
+
if (chart && chart instanceof ScatterChart) {
|
|
41140
|
+
return canChartParseLabels(chart.labelRange, this.env.model.getters);
|
|
40974
41141
|
}
|
|
40975
|
-
|
|
40976
|
-
// and right should move the cursor.
|
|
40977
|
-
ev.stopPropagation();
|
|
40978
|
-
this.handleArrowKeysForAutocomplete(ev);
|
|
41142
|
+
return false;
|
|
40979
41143
|
}
|
|
40980
|
-
|
|
40981
|
-
|
|
40982
|
-
|
|
40983
|
-
|
|
40984
|
-
this.autoCompleteState.moveSelection(ev.key === "ArrowDown" ? "next" : "previous");
|
|
40985
|
-
}
|
|
41144
|
+
onUpdateLabelsAsText(labelsAsText) {
|
|
41145
|
+
this.props.updateChart(this.props.figureId, {
|
|
41146
|
+
labelsAsText,
|
|
41147
|
+
});
|
|
40986
41148
|
}
|
|
40987
|
-
|
|
40988
|
-
|
|
40989
|
-
|
|
40990
|
-
|
|
40991
|
-
|
|
40992
|
-
|
|
40993
|
-
|
|
40994
|
-
|
|
40995
|
-
|
|
40996
|
-
return;
|
|
40997
|
-
}
|
|
40998
|
-
}
|
|
40999
|
-
this.props.composerStore.stopEdition(direction);
|
|
41149
|
+
getLabelRangeOptions() {
|
|
41150
|
+
const options = super.getLabelRangeOptions();
|
|
41151
|
+
if (this.canTreatLabelsAsText) {
|
|
41152
|
+
options.push({
|
|
41153
|
+
name: "labelsAsText",
|
|
41154
|
+
value: this.props.definition.labelsAsText,
|
|
41155
|
+
label: this.chartTerms.TreatLabelsAsText,
|
|
41156
|
+
onChange: this.onUpdateLabelsAsText.bind(this),
|
|
41157
|
+
});
|
|
41000
41158
|
}
|
|
41159
|
+
return options;
|
|
41001
41160
|
}
|
|
41002
|
-
|
|
41003
|
-
|
|
41004
|
-
|
|
41005
|
-
|
|
41006
|
-
|
|
41007
|
-
|
|
41008
|
-
|
|
41009
|
-
|
|
41010
|
-
|
|
41011
|
-
|
|
41012
|
-
|
|
41013
|
-
|
|
41161
|
+
}
|
|
41162
|
+
|
|
41163
|
+
class ScorecardChartConfigPanel extends Component {
|
|
41164
|
+
static template = "o-spreadsheet-ScorecardChartConfigPanel";
|
|
41165
|
+
static components = { SelectionInput, ChartErrorSection, Section };
|
|
41166
|
+
static props = {
|
|
41167
|
+
figureId: String,
|
|
41168
|
+
definition: Object,
|
|
41169
|
+
updateChart: Function,
|
|
41170
|
+
canUpdateChart: Function,
|
|
41171
|
+
};
|
|
41172
|
+
state = useState({
|
|
41173
|
+
keyValueDispatchResult: undefined,
|
|
41174
|
+
baselineDispatchResult: undefined,
|
|
41175
|
+
});
|
|
41176
|
+
keyValue = this.props.definition.keyValue;
|
|
41177
|
+
baseline = this.props.definition.baseline;
|
|
41178
|
+
get errorMessages() {
|
|
41179
|
+
const cancelledReasons = [
|
|
41180
|
+
...(this.state.keyValueDispatchResult?.reasons || []),
|
|
41181
|
+
...(this.state.baselineDispatchResult?.reasons || []),
|
|
41182
|
+
];
|
|
41183
|
+
return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
|
|
41014
41184
|
}
|
|
41015
|
-
|
|
41016
|
-
|
|
41017
|
-
|
|
41018
|
-
|
|
41019
|
-
|
|
41020
|
-
|
|
41021
|
-
|
|
41022
|
-
this.
|
|
41023
|
-
this.
|
|
41024
|
-
|
|
41025
|
-
end: start + 1,
|
|
41185
|
+
get isKeyValueInvalid() {
|
|
41186
|
+
return !!this.state.keyValueDispatchResult?.isCancelledBecause("InvalidScorecardKeyValue" /* CommandResult.InvalidScorecardKeyValue */);
|
|
41187
|
+
}
|
|
41188
|
+
get isBaselineInvalid() {
|
|
41189
|
+
return !!this.state.keyValueDispatchResult?.isCancelledBecause("InvalidScorecardBaseline" /* CommandResult.InvalidScorecardBaseline */);
|
|
41190
|
+
}
|
|
41191
|
+
onKeyValueRangeChanged(ranges) {
|
|
41192
|
+
this.keyValue = ranges[0];
|
|
41193
|
+
this.state.keyValueDispatchResult = this.props.canUpdateChart(this.props.figureId, {
|
|
41194
|
+
keyValue: this.keyValue,
|
|
41026
41195
|
});
|
|
41027
|
-
this.processContent();
|
|
41028
41196
|
}
|
|
41029
|
-
|
|
41030
|
-
this.props.
|
|
41031
|
-
|
|
41032
|
-
|
|
41197
|
+
updateKeyValueRange() {
|
|
41198
|
+
this.state.keyValueDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
41199
|
+
keyValue: this.keyValue,
|
|
41200
|
+
});
|
|
41033
41201
|
}
|
|
41034
|
-
|
|
41035
|
-
|
|
41036
|
-
this.props.composerStore.cycleReferences();
|
|
41037
|
-
this.processContent();
|
|
41202
|
+
getKeyValueRange() {
|
|
41203
|
+
return this.keyValue || "";
|
|
41038
41204
|
}
|
|
41039
|
-
|
|
41040
|
-
|
|
41041
|
-
this.props.
|
|
41042
|
-
|
|
41205
|
+
onBaselineRangeChanged(ranges) {
|
|
41206
|
+
this.baseline = ranges[0];
|
|
41207
|
+
this.state.baselineDispatchResult = this.props.canUpdateChart(this.props.figureId, {
|
|
41208
|
+
baseline: this.baseline,
|
|
41209
|
+
});
|
|
41043
41210
|
}
|
|
41044
|
-
|
|
41045
|
-
|
|
41046
|
-
|
|
41047
|
-
const locale = this.env.model.getters.getLocale();
|
|
41048
|
-
const selection = this.contentHelper.getCurrentSelection();
|
|
41049
|
-
const currentContent = this.props.composerStore.currentContent;
|
|
41050
|
-
const content = currentContent.slice(0, selection.start) +
|
|
41051
|
-
locale.decimalSeparator +
|
|
41052
|
-
currentContent.slice(selection.end);
|
|
41053
|
-
// Update composer even by hand rather than dispatching an InputEvent because untrusted inputs
|
|
41054
|
-
// events aren't handled natively by contentEditable
|
|
41055
|
-
this.props.composerStore.setCurrentContent(content, {
|
|
41056
|
-
start: selection.start + 1,
|
|
41057
|
-
end: selection.start + 1,
|
|
41211
|
+
updateBaselineRange() {
|
|
41212
|
+
this.state.baselineDispatchResult = this.props.updateChart(this.props.figureId, {
|
|
41213
|
+
baseline: this.baseline,
|
|
41058
41214
|
});
|
|
41059
|
-
// We need to do the process content here in case there is no render between the keyDown and the
|
|
41060
|
-
// keyUp event
|
|
41061
|
-
this.processContent();
|
|
41062
41215
|
}
|
|
41063
|
-
|
|
41064
|
-
this.
|
|
41216
|
+
getBaselineRange() {
|
|
41217
|
+
return this.baseline || "";
|
|
41065
41218
|
}
|
|
41066
|
-
|
|
41067
|
-
this.
|
|
41219
|
+
updateBaselineMode(ev) {
|
|
41220
|
+
this.props.updateChart(this.props.figureId, { baselineMode: ev.target.value });
|
|
41068
41221
|
}
|
|
41069
|
-
|
|
41070
|
-
|
|
41071
|
-
|
|
41072
|
-
|
|
41073
|
-
|
|
41074
|
-
|
|
41075
|
-
|
|
41076
|
-
|
|
41077
|
-
|
|
41078
|
-
|
|
41079
|
-
|
|
41080
|
-
|
|
41081
|
-
|
|
41082
|
-
|
|
41083
|
-
|
|
41084
|
-
}
|
|
41222
|
+
}
|
|
41223
|
+
|
|
41224
|
+
class ScorecardChartDesignPanel extends Component {
|
|
41225
|
+
static template = "o-spreadsheet-ScorecardChartDesignPanel";
|
|
41226
|
+
static components = {
|
|
41227
|
+
GeneralDesignEditor,
|
|
41228
|
+
RoundColorPicker,
|
|
41229
|
+
SidePanelCollapsible,
|
|
41230
|
+
Section,
|
|
41231
|
+
Checkbox,
|
|
41232
|
+
};
|
|
41233
|
+
static props = {
|
|
41234
|
+
figureId: String,
|
|
41235
|
+
definition: Object,
|
|
41236
|
+
updateChart: Function,
|
|
41237
|
+
canUpdateChart: { type: Function, optional: true },
|
|
41238
|
+
};
|
|
41239
|
+
get colorsSectionTitle() {
|
|
41240
|
+
return this.props.definition.baselineMode === "progress"
|
|
41241
|
+
? _t("Progress bar colors")
|
|
41242
|
+
: _t("Baseline colors");
|
|
41085
41243
|
}
|
|
41086
|
-
|
|
41087
|
-
|
|
41088
|
-
// let the browser clipboard work
|
|
41089
|
-
ev.stopPropagation();
|
|
41090
|
-
}
|
|
41091
|
-
else {
|
|
41092
|
-
// the user meant to paste in the sheet, not open the composer with the pasted content
|
|
41093
|
-
// While we're not editing, we still have the focus and should therefore prevent
|
|
41094
|
-
// the native "paste" to occur.
|
|
41095
|
-
ev.preventDefault();
|
|
41096
|
-
}
|
|
41244
|
+
get humanizeNumbersLabel() {
|
|
41245
|
+
return _t("Humanize numbers");
|
|
41097
41246
|
}
|
|
41098
|
-
|
|
41099
|
-
|
|
41100
|
-
* */
|
|
41101
|
-
onInput(ev) {
|
|
41102
|
-
if (!this.shouldProcessInputEvents) {
|
|
41103
|
-
return;
|
|
41104
|
-
}
|
|
41105
|
-
ev.stopPropagation();
|
|
41106
|
-
let content;
|
|
41107
|
-
if (this.props.composerStore.editionMode === "inactive") {
|
|
41108
|
-
content = ev.data || "";
|
|
41109
|
-
}
|
|
41110
|
-
else {
|
|
41111
|
-
content = this.contentHelper.getText();
|
|
41112
|
-
}
|
|
41113
|
-
if (this.props.focus === "inactive") {
|
|
41114
|
-
return this.props.onComposerCellFocused?.(content);
|
|
41115
|
-
}
|
|
41116
|
-
let selection = this.contentHelper.getCurrentSelection();
|
|
41117
|
-
this.props.composerStore.stopComposerRangeSelection();
|
|
41118
|
-
this.props.composerStore.setCurrentContent(content, selection);
|
|
41119
|
-
this.processTokenAtCursor();
|
|
41247
|
+
get defaultScorecardTitleFontSize() {
|
|
41248
|
+
return SCORECARD_CHART_TITLE_FONT_SIZE;
|
|
41120
41249
|
}
|
|
41121
|
-
|
|
41122
|
-
|
|
41123
|
-
if (this.autoCompleteState.provider && ["ArrowUp", "ArrowDown"].includes(ev.key)) {
|
|
41124
|
-
return;
|
|
41125
|
-
}
|
|
41126
|
-
if (this.props.composerStore.isSelectingRange && ev.key?.startsWith("Arrow")) {
|
|
41127
|
-
return;
|
|
41128
|
-
}
|
|
41129
|
-
const { start: oldStart, end: oldEnd } = this.props.composerStore.composerSelection;
|
|
41130
|
-
const { start, end } = this.contentHelper.getCurrentSelection();
|
|
41131
|
-
if (start !== oldStart || end !== oldEnd) {
|
|
41132
|
-
this.props.composerStore.changeComposerCursorSelection(start, end);
|
|
41133
|
-
}
|
|
41134
|
-
this.processTokenAtCursor();
|
|
41135
|
-
}
|
|
41250
|
+
updateHumanizeNumbers(humanize) {
|
|
41251
|
+
this.props.updateChart(this.props.figureId, { humanize });
|
|
41136
41252
|
}
|
|
41137
|
-
|
|
41138
|
-
|
|
41139
|
-
return;
|
|
41140
|
-
}
|
|
41141
|
-
const target = ev.relatedTarget;
|
|
41142
|
-
if (!target || !(target instanceof HTMLElement)) {
|
|
41143
|
-
this.props.composerStore.stopEdition();
|
|
41144
|
-
return;
|
|
41145
|
-
}
|
|
41146
|
-
if (target.attributes.getNamedItem("composerFocusableElement")) {
|
|
41147
|
-
this.contentHelper.el.focus();
|
|
41148
|
-
return;
|
|
41149
|
-
}
|
|
41150
|
-
if (target.classList.contains("o-composer")) {
|
|
41151
|
-
return;
|
|
41152
|
-
}
|
|
41153
|
-
this.props.composerStore.stopEdition();
|
|
41253
|
+
translate(term) {
|
|
41254
|
+
return _t(term);
|
|
41154
41255
|
}
|
|
41155
|
-
|
|
41156
|
-
this.
|
|
41256
|
+
updateBaselineDescr(ev) {
|
|
41257
|
+
this.props.updateChart(this.props.figureId, { baselineDescr: ev.target.value });
|
|
41157
41258
|
}
|
|
41158
|
-
|
|
41159
|
-
|
|
41160
|
-
|
|
41161
|
-
|
|
41162
|
-
|
|
41163
|
-
|
|
41164
|
-
|
|
41165
|
-
|
|
41166
|
-
|
|
41167
|
-
|
|
41168
|
-
|
|
41169
|
-
return;
|
|
41259
|
+
setColor(color, colorPickerId) {
|
|
41260
|
+
switch (colorPickerId) {
|
|
41261
|
+
case "backgroundColor":
|
|
41262
|
+
this.props.updateChart(this.props.figureId, { background: color });
|
|
41263
|
+
break;
|
|
41264
|
+
case "baselineColorDown":
|
|
41265
|
+
this.props.updateChart(this.props.figureId, { baselineColorDown: color });
|
|
41266
|
+
break;
|
|
41267
|
+
case "baselineColorUp":
|
|
41268
|
+
this.props.updateChart(this.props.figureId, { baselineColorUp: color });
|
|
41269
|
+
break;
|
|
41170
41270
|
}
|
|
41171
|
-
this.contentHelper.removeSelection();
|
|
41172
41271
|
}
|
|
41173
|
-
|
|
41174
|
-
|
|
41175
|
-
|
|
41176
|
-
|
|
41177
|
-
|
|
41178
|
-
|
|
41179
|
-
|
|
41180
|
-
|
|
41181
|
-
|
|
41272
|
+
}
|
|
41273
|
+
|
|
41274
|
+
class WaterfallChartDesignPanel extends Component {
|
|
41275
|
+
static template = "o-spreadsheet-WaterfallChartDesignPanel";
|
|
41276
|
+
static components = {
|
|
41277
|
+
GeneralDesignEditor,
|
|
41278
|
+
Checkbox,
|
|
41279
|
+
SidePanelCollapsible,
|
|
41280
|
+
Section,
|
|
41281
|
+
RoundColorPicker,
|
|
41282
|
+
AxisDesignEditor,
|
|
41283
|
+
RadioSelection,
|
|
41284
|
+
ChartLegend,
|
|
41285
|
+
};
|
|
41286
|
+
static props = {
|
|
41287
|
+
figureId: String,
|
|
41288
|
+
definition: Object,
|
|
41289
|
+
updateChart: Function,
|
|
41290
|
+
canUpdateChart: { type: Function, optional: true },
|
|
41291
|
+
};
|
|
41292
|
+
axisChoices = CHART_AXIS_CHOICES;
|
|
41293
|
+
onUpdateShowSubTotals(showSubTotals) {
|
|
41294
|
+
this.props.updateChart(this.props.figureId, { showSubTotals });
|
|
41182
41295
|
}
|
|
41183
|
-
|
|
41184
|
-
|
|
41185
|
-
return;
|
|
41186
|
-
}
|
|
41187
|
-
const composerContent = this.props.composerStore.currentContent;
|
|
41188
|
-
const isValidFormula = composerContent.startsWith("=");
|
|
41189
|
-
if (isValidFormula) {
|
|
41190
|
-
const tokens = this.props.composerStore.currentTokens;
|
|
41191
|
-
const currentSelection = this.contentHelper.getCurrentSelection();
|
|
41192
|
-
if (currentSelection.start === currentSelection.end)
|
|
41193
|
-
return;
|
|
41194
|
-
const currentSelectedText = composerContent.substring(currentSelection.start, currentSelection.end);
|
|
41195
|
-
const token = tokens.filter((token) => token.value.includes(currentSelectedText) &&
|
|
41196
|
-
token.start <= currentSelection.start &&
|
|
41197
|
-
token.end >= currentSelection.end)[0];
|
|
41198
|
-
if (!token) {
|
|
41199
|
-
return;
|
|
41200
|
-
}
|
|
41201
|
-
if (token.type === "REFERENCE") {
|
|
41202
|
-
this.props.composerStore.changeComposerCursorSelection(token.start, token.end);
|
|
41203
|
-
}
|
|
41204
|
-
}
|
|
41296
|
+
onUpdateShowConnectorLines(showConnectorLines) {
|
|
41297
|
+
this.props.updateChart(this.props.figureId, { showConnectorLines });
|
|
41205
41298
|
}
|
|
41206
|
-
|
|
41207
|
-
|
|
41208
|
-
this.props.onInputContextMenu?.(ev);
|
|
41209
|
-
}
|
|
41299
|
+
onUpdateFirstValueAsSubtotal(firstValueAsSubtotal) {
|
|
41300
|
+
this.props.updateChart(this.props.figureId, { firstValueAsSubtotal });
|
|
41210
41301
|
}
|
|
41211
|
-
|
|
41212
|
-
this.
|
|
41302
|
+
updateColor(colorName, color) {
|
|
41303
|
+
this.props.updateChart(this.props.figureId, { [colorName]: color });
|
|
41213
41304
|
}
|
|
41214
|
-
|
|
41215
|
-
|
|
41305
|
+
get axesList() {
|
|
41306
|
+
return [
|
|
41307
|
+
{ id: "x", name: _t("Horizontal axis") },
|
|
41308
|
+
{ id: "y", name: _t("Vertical axis") },
|
|
41309
|
+
];
|
|
41310
|
+
}
|
|
41311
|
+
get positiveValuesColor() {
|
|
41312
|
+
return (this.props.definition.positiveValuesColor ||
|
|
41313
|
+
CHART_WATERFALL_POSITIVE_COLOR);
|
|
41314
|
+
}
|
|
41315
|
+
get negativeValuesColor() {
|
|
41316
|
+
return (this.props.definition.negativeValuesColor ||
|
|
41317
|
+
CHART_WATERFALL_NEGATIVE_COLOR);
|
|
41318
|
+
}
|
|
41319
|
+
get subTotalValuesColor() {
|
|
41320
|
+
return (this.props.definition.subTotalValuesColor ||
|
|
41321
|
+
CHART_WATERFALL_SUBTOTAL_COLOR);
|
|
41216
41322
|
}
|
|
41217
|
-
|
|
41218
|
-
|
|
41219
|
-
|
|
41220
|
-
|
|
41221
|
-
if (this.compositionActive) {
|
|
41222
|
-
return;
|
|
41223
|
-
}
|
|
41224
|
-
this.shouldProcessInputEvents = false;
|
|
41225
|
-
if (this.props.focus !== "inactive" && document.activeElement !== this.contentHelper.el) {
|
|
41226
|
-
this.contentHelper.el.focus();
|
|
41227
|
-
}
|
|
41228
|
-
const content = this.getContentLines();
|
|
41229
|
-
this.contentHelper.setText(content);
|
|
41230
|
-
if (content.length !== 0 && content.length[0] !== 0) {
|
|
41231
|
-
if (this.props.focus !== "inactive") {
|
|
41232
|
-
// Put the cursor back where it was before the rendering
|
|
41233
|
-
const { start, end } = this.props.composerStore.composerSelection;
|
|
41234
|
-
this.contentHelper.selectRange(start, end);
|
|
41235
|
-
}
|
|
41236
|
-
this.contentHelper.scrollSelectionIntoView();
|
|
41237
|
-
}
|
|
41238
|
-
this.shouldProcessInputEvents = true;
|
|
41323
|
+
updateVerticalAxisPosition(value) {
|
|
41324
|
+
this.props.updateChart(this.props.figureId, {
|
|
41325
|
+
verticalAxisPosition: value,
|
|
41326
|
+
});
|
|
41239
41327
|
}
|
|
41240
|
-
|
|
41241
|
-
|
|
41242
|
-
|
|
41243
|
-
|
|
41244
|
-
|
|
41245
|
-
|
|
41246
|
-
|
|
41247
|
-
|
|
41248
|
-
|
|
41249
|
-
|
|
41250
|
-
|
|
41251
|
-
|
|
41252
|
-
|
|
41328
|
+
}
|
|
41329
|
+
|
|
41330
|
+
const chartSidePanelComponentRegistry = new Registry();
|
|
41331
|
+
chartSidePanelComponentRegistry
|
|
41332
|
+
.add("line", {
|
|
41333
|
+
configuration: LineConfigPanel,
|
|
41334
|
+
design: ChartWithAxisDesignPanel,
|
|
41335
|
+
})
|
|
41336
|
+
.add("scatter", {
|
|
41337
|
+
configuration: ScatterConfigPanel,
|
|
41338
|
+
design: ChartWithAxisDesignPanel,
|
|
41339
|
+
})
|
|
41340
|
+
.add("bar", {
|
|
41341
|
+
configuration: BarConfigPanel,
|
|
41342
|
+
design: ChartWithAxisDesignPanel,
|
|
41343
|
+
})
|
|
41344
|
+
.add("combo", {
|
|
41345
|
+
configuration: GenericChartConfigPanel,
|
|
41346
|
+
design: ComboChartDesignPanel,
|
|
41347
|
+
})
|
|
41348
|
+
.add("pie", {
|
|
41349
|
+
configuration: GenericChartConfigPanel,
|
|
41350
|
+
design: PieChartDesignPanel,
|
|
41351
|
+
})
|
|
41352
|
+
.add("gauge", {
|
|
41353
|
+
configuration: GaugeChartConfigPanel,
|
|
41354
|
+
design: GaugeChartDesignPanel,
|
|
41355
|
+
})
|
|
41356
|
+
.add("scorecard", {
|
|
41357
|
+
configuration: ScorecardChartConfigPanel,
|
|
41358
|
+
design: ScorecardChartDesignPanel,
|
|
41359
|
+
})
|
|
41360
|
+
.add("waterfall", {
|
|
41361
|
+
configuration: GenericChartConfigPanel,
|
|
41362
|
+
design: WaterfallChartDesignPanel,
|
|
41363
|
+
})
|
|
41364
|
+
.add("pyramid", {
|
|
41365
|
+
configuration: GenericChartConfigPanel,
|
|
41366
|
+
design: ChartWithAxisDesignPanel,
|
|
41367
|
+
})
|
|
41368
|
+
.add("radar", {
|
|
41369
|
+
configuration: GenericChartConfigPanel,
|
|
41370
|
+
design: RadarChartDesignPanel,
|
|
41371
|
+
})
|
|
41372
|
+
.add("geo", {
|
|
41373
|
+
configuration: GeoChartConfigPanel,
|
|
41374
|
+
design: GeoChartDesignPanel,
|
|
41375
|
+
});
|
|
41376
|
+
|
|
41377
|
+
css /* scss */ `
|
|
41378
|
+
.o-section .o-input.o-type-selector {
|
|
41379
|
+
height: 30px;
|
|
41380
|
+
padding-left: 35px;
|
|
41381
|
+
padding-top: 5px;
|
|
41382
|
+
}
|
|
41383
|
+
.o-type-selector-preview {
|
|
41384
|
+
left: 5px;
|
|
41385
|
+
top: 3px;
|
|
41386
|
+
.o-chart-preview {
|
|
41387
|
+
width: 24px;
|
|
41388
|
+
height: 24px;
|
|
41253
41389
|
}
|
|
41254
|
-
|
|
41255
|
-
|
|
41256
|
-
|
|
41257
|
-
|
|
41258
|
-
|
|
41259
|
-
|
|
41260
|
-
|
|
41261
|
-
|
|
41262
|
-
|
|
41263
|
-
|
|
41264
|
-
|
|
41265
|
-
|
|
41266
|
-
|
|
41267
|
-
|
|
41268
|
-
|
|
41269
|
-
|
|
41270
|
-
|
|
41271
|
-
|
|
41272
|
-
|
|
41273
|
-
result[result.length - 1].class = selectionIndicatorClass;
|
|
41274
|
-
}
|
|
41275
|
-
}
|
|
41276
|
-
return result;
|
|
41390
|
+
}
|
|
41391
|
+
|
|
41392
|
+
.o-popover .o-chart-select-popover {
|
|
41393
|
+
box-sizing: border-box;
|
|
41394
|
+
background: #fff;
|
|
41395
|
+
.o-chart-type-item {
|
|
41396
|
+
cursor: pointer;
|
|
41397
|
+
padding: 3px 6px;
|
|
41398
|
+
margin: 1px 2px;
|
|
41399
|
+
&.selected,
|
|
41400
|
+
&:hover {
|
|
41401
|
+
border: 1px solid ${ACTION_COLOR};
|
|
41402
|
+
background: ${BADGE_SELECTED_COLOR};
|
|
41403
|
+
padding: 2px 5px;
|
|
41404
|
+
}
|
|
41405
|
+
.o-chart-preview {
|
|
41406
|
+
width: 48px;
|
|
41407
|
+
height: 48px;
|
|
41408
|
+
}
|
|
41277
41409
|
}
|
|
41278
|
-
|
|
41279
|
-
|
|
41280
|
-
|
|
41281
|
-
|
|
41282
|
-
|
|
41283
|
-
|
|
41284
|
-
|
|
41285
|
-
|
|
41286
|
-
|
|
41287
|
-
|
|
41288
|
-
|
|
41289
|
-
|
|
41290
|
-
|
|
41291
|
-
|
|
41292
|
-
|
|
41293
|
-
|
|
41294
|
-
currentLine.push({ ...content, value: lastLine });
|
|
41410
|
+
}
|
|
41411
|
+
`;
|
|
41412
|
+
class ChartTypePicker extends Component {
|
|
41413
|
+
static template = "o-spreadsheet-ChartTypePicker";
|
|
41414
|
+
static components = { Section, Popover };
|
|
41415
|
+
static props = { figureId: String, chartPanelStore: Object };
|
|
41416
|
+
categories = chartCategories;
|
|
41417
|
+
chartTypeByCategories = {};
|
|
41418
|
+
popoverRef = useRef("popoverRef");
|
|
41419
|
+
selectRef = useRef("selectRef");
|
|
41420
|
+
state = useState({ popoverProps: undefined, popoverStyle: "" });
|
|
41421
|
+
setup() {
|
|
41422
|
+
useExternalListener(window, "pointerdown", this.onExternalClick, { capture: true });
|
|
41423
|
+
for (const subtypeProperties of chartSubtypeRegistry.getAll()) {
|
|
41424
|
+
if (this.chartTypeByCategories[subtypeProperties.category]) {
|
|
41425
|
+
this.chartTypeByCategories[subtypeProperties.category].push(subtypeProperties);
|
|
41295
41426
|
}
|
|
41296
41427
|
else {
|
|
41297
|
-
|
|
41428
|
+
this.chartTypeByCategories[subtypeProperties.category] = [subtypeProperties];
|
|
41298
41429
|
}
|
|
41299
41430
|
}
|
|
41300
|
-
|
|
41301
|
-
|
|
41302
|
-
|
|
41303
|
-
|
|
41304
|
-
|
|
41305
|
-
for (const line of contentSplitInLines) {
|
|
41306
|
-
if (line.every(this.isContentEmpty)) {
|
|
41307
|
-
filteredLines.push([line[0]]);
|
|
41308
|
-
}
|
|
41309
|
-
else {
|
|
41310
|
-
filteredLines.push(line.filter((content) => !this.isContentEmpty(content)));
|
|
41311
|
-
}
|
|
41431
|
+
}
|
|
41432
|
+
onExternalClick(ev) {
|
|
41433
|
+
if (isChildEvent(this.popoverRef.el?.parentElement, ev) ||
|
|
41434
|
+
isChildEvent(this.selectRef.el, ev)) {
|
|
41435
|
+
return;
|
|
41312
41436
|
}
|
|
41313
|
-
|
|
41437
|
+
this.closePopover();
|
|
41314
41438
|
}
|
|
41315
|
-
|
|
41316
|
-
|
|
41439
|
+
onTypeChange(type) {
|
|
41440
|
+
this.props.chartPanelStore.changeChartType(this.props.figureId, type);
|
|
41441
|
+
this.closePopover();
|
|
41317
41442
|
}
|
|
41318
|
-
|
|
41319
|
-
|
|
41320
|
-
* If the token is a function or symbol (that isn't a cell/range reference) we have to initialize
|
|
41321
|
-
* the autocomplete engine otherwise we initialize the formula assistant.
|
|
41322
|
-
*/
|
|
41323
|
-
processTokenAtCursor() {
|
|
41324
|
-
let content = this.props.composerStore.currentContent;
|
|
41325
|
-
if (this.autoCompleteState.provider) {
|
|
41326
|
-
this.autoCompleteState.hide();
|
|
41327
|
-
}
|
|
41328
|
-
this.functionDescriptionState.showDescription = false;
|
|
41329
|
-
const autoCompleteProvider = this.props.composerStore.autocompleteProvider;
|
|
41330
|
-
if (autoCompleteProvider) {
|
|
41331
|
-
this.autoCompleteState.useProvider(autoCompleteProvider);
|
|
41332
|
-
}
|
|
41333
|
-
const token = this.props.composerStore.tokenAtCursor;
|
|
41334
|
-
if (content.startsWith("=") && token && token.type !== "SYMBOL") {
|
|
41335
|
-
const tokenContext = token.functionContext;
|
|
41336
|
-
const parentFunction = tokenContext?.parent.toUpperCase();
|
|
41337
|
-
if (tokenContext &&
|
|
41338
|
-
parentFunction &&
|
|
41339
|
-
parentFunction in functions &&
|
|
41340
|
-
token.type !== "UNKNOWN") {
|
|
41341
|
-
// initialize Formula Assistant
|
|
41342
|
-
const description = functions[parentFunction];
|
|
41343
|
-
const argPosition = tokenContext.argPosition;
|
|
41344
|
-
this.functionDescriptionState.functionName = parentFunction;
|
|
41345
|
-
this.functionDescriptionState.functionDescription = description;
|
|
41346
|
-
this.functionDescriptionState.argToFocus = description.getArgToFocus(argPosition + 1) - 1;
|
|
41347
|
-
this.functionDescriptionState.showDescription = true;
|
|
41348
|
-
}
|
|
41349
|
-
}
|
|
41443
|
+
getChartDefinition(figureId) {
|
|
41444
|
+
return this.env.model.getters.getChartDefinition(figureId);
|
|
41350
41445
|
}
|
|
41351
|
-
|
|
41352
|
-
|
|
41446
|
+
getSelectedChartSubtypeProperties() {
|
|
41447
|
+
const definition = this.getChartDefinition(this.props.figureId);
|
|
41448
|
+
const matchedChart = chartSubtypeRegistry
|
|
41449
|
+
.getAll()
|
|
41450
|
+
.find((c) => c.matcher?.(definition) || false);
|
|
41451
|
+
return matchedChart || chartSubtypeRegistry.get(definition.type);
|
|
41452
|
+
}
|
|
41453
|
+
onPointerDown(ev) {
|
|
41454
|
+
if (this.state.popoverProps) {
|
|
41455
|
+
this.closePopover();
|
|
41353
41456
|
return;
|
|
41354
41457
|
}
|
|
41355
|
-
|
|
41356
|
-
|
|
41458
|
+
const target = ev.currentTarget;
|
|
41459
|
+
const { bottom, right, width } = target.getBoundingClientRect();
|
|
41460
|
+
this.state.popoverProps = {
|
|
41461
|
+
anchorRect: { x: right, y: bottom, width: 0, height: 0 },
|
|
41462
|
+
positioning: "TopRight",
|
|
41463
|
+
verticalOffset: 0,
|
|
41464
|
+
};
|
|
41465
|
+
this.state.popoverStyle = cssPropertiesToCss({ width: `${width}px` });
|
|
41466
|
+
}
|
|
41467
|
+
closePopover() {
|
|
41468
|
+
this.state.popoverProps = undefined;
|
|
41357
41469
|
}
|
|
41358
41470
|
}
|
|
41359
41471
|
|
|
41360
|
-
class
|
|
41361
|
-
|
|
41362
|
-
|
|
41363
|
-
|
|
41364
|
-
|
|
41365
|
-
this.
|
|
41366
|
-
}
|
|
41367
|
-
getAutoCompleteProviders() {
|
|
41368
|
-
const providersDefinitions = super.getAutoCompleteProviders();
|
|
41369
|
-
const contextualAutocomplete = this.args().contextualAutocomplete;
|
|
41370
|
-
if (contextualAutocomplete) {
|
|
41371
|
-
providersDefinitions.push(contextualAutocomplete);
|
|
41372
|
-
}
|
|
41373
|
-
return providersDefinitions;
|
|
41472
|
+
class MainChartPanelStore extends SpreadsheetStore {
|
|
41473
|
+
mutators = ["activatePanel", "changeChartType"];
|
|
41474
|
+
panel = "configuration";
|
|
41475
|
+
creationContexts = {};
|
|
41476
|
+
activatePanel(panel) {
|
|
41477
|
+
this.panel = panel;
|
|
41374
41478
|
}
|
|
41375
|
-
|
|
41376
|
-
|
|
41377
|
-
|
|
41378
|
-
|
|
41379
|
-
|
|
41380
|
-
|
|
41381
|
-
return setXcToFixedReferenceType(res, "colrow");
|
|
41479
|
+
changeChartType(figureId, newDisplayType) {
|
|
41480
|
+
const currentCreationContext = this.getters.getContextCreationChart(figureId);
|
|
41481
|
+
const savedCreationContext = this.creationContexts[figureId] || {};
|
|
41482
|
+
let newRanges = currentCreationContext?.range;
|
|
41483
|
+
if (newRanges?.every((range, i) => deepEquals(range, savedCreationContext.range?.[i]))) {
|
|
41484
|
+
newRanges = Object.assign([], savedCreationContext.range, currentCreationContext?.range);
|
|
41382
41485
|
}
|
|
41383
|
-
|
|
41384
|
-
|
|
41385
|
-
|
|
41386
|
-
|
|
41387
|
-
|
|
41388
|
-
|
|
41389
|
-
|
|
41390
|
-
|
|
41391
|
-
return rangeTokenize(this.args().content)
|
|
41392
|
-
.map((token) => {
|
|
41393
|
-
if (token.type === "REFERENCE") {
|
|
41394
|
-
const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
|
|
41395
|
-
return this.getters.getRangeString(range, this.getters.getActiveSheetId());
|
|
41396
|
-
}
|
|
41397
|
-
return token.value;
|
|
41398
|
-
})
|
|
41399
|
-
.join("");
|
|
41486
|
+
this.creationContexts[figureId] = {
|
|
41487
|
+
...savedCreationContext,
|
|
41488
|
+
...currentCreationContext,
|
|
41489
|
+
range: newRanges,
|
|
41490
|
+
};
|
|
41491
|
+
const sheetId = this.getters.getFigureSheetId(figureId);
|
|
41492
|
+
if (!sheetId) {
|
|
41493
|
+
return;
|
|
41400
41494
|
}
|
|
41401
|
-
|
|
41402
|
-
|
|
41403
|
-
|
|
41404
|
-
|
|
41405
|
-
|
|
41406
|
-
|
|
41407
|
-
this.args().onConfirm(content);
|
|
41495
|
+
const definition = this.getChartDefinitionFromContextCreation(figureId, newDisplayType);
|
|
41496
|
+
this.model.dispatch("UPDATE_CHART", {
|
|
41497
|
+
definition,
|
|
41498
|
+
id: figureId,
|
|
41499
|
+
sheetId,
|
|
41500
|
+
});
|
|
41408
41501
|
}
|
|
41409
|
-
|
|
41410
|
-
|
|
41411
|
-
|
|
41412
|
-
|
|
41413
|
-
|
|
41414
|
-
|
|
41415
|
-
}
|
|
41416
|
-
return super.getTokenColor(token);
|
|
41502
|
+
getChartDefinitionFromContextCreation(figureId, newDisplayType) {
|
|
41503
|
+
const newChartInfo = chartSubtypeRegistry.get(newDisplayType);
|
|
41504
|
+
const ChartClass = chartRegistry.get(newChartInfo.chartType);
|
|
41505
|
+
return {
|
|
41506
|
+
...ChartClass.getChartDefinitionFromContextCreation(this.creationContexts[figureId]),
|
|
41507
|
+
...newChartInfo.subtypeDefinition,
|
|
41508
|
+
};
|
|
41417
41509
|
}
|
|
41418
41510
|
}
|
|
41419
41511
|
|
|
41420
41512
|
css /* scss */ `
|
|
41421
|
-
.o-
|
|
41422
|
-
.o-
|
|
41423
|
-
|
|
41424
|
-
|
|
41513
|
+
.o-chart {
|
|
41514
|
+
.o-panel {
|
|
41515
|
+
display: flex;
|
|
41516
|
+
.o-panel-element {
|
|
41517
|
+
flex: 1 0 auto;
|
|
41518
|
+
padding: 8px 0px;
|
|
41519
|
+
text-align: center;
|
|
41520
|
+
cursor: pointer;
|
|
41521
|
+
border-right: 1px solid ${GRAY_300};
|
|
41425
41522
|
|
|
41426
|
-
|
|
41427
|
-
|
|
41523
|
+
&.inactive {
|
|
41524
|
+
color: ${TEXT_BODY};
|
|
41525
|
+
background-color: ${GRAY_100};
|
|
41526
|
+
border-bottom: 1px solid ${GRAY_300};
|
|
41527
|
+
}
|
|
41428
41528
|
|
|
41429
|
-
|
|
41430
|
-
|
|
41431
|
-
|
|
41529
|
+
&:not(.inactive) {
|
|
41530
|
+
color: ${TEXT_HEADING};
|
|
41531
|
+
border-bottom: 1px solid #fff;
|
|
41532
|
+
}
|
|
41432
41533
|
|
|
41433
|
-
|
|
41434
|
-
|
|
41534
|
+
.fa {
|
|
41535
|
+
margin-right: 4px;
|
|
41536
|
+
}
|
|
41435
41537
|
}
|
|
41436
|
-
|
|
41437
|
-
|
|
41438
|
-
scrollbar-width: none; /* Firefox */
|
|
41439
|
-
&::-webkit-scrollbar {
|
|
41440
|
-
display: none;
|
|
41538
|
+
.o-panel-element:last-child {
|
|
41539
|
+
border-right: none;
|
|
41441
41540
|
}
|
|
41442
41541
|
}
|
|
41443
41542
|
}
|
|
41444
41543
|
`;
|
|
41445
|
-
class
|
|
41446
|
-
static template = "o-spreadsheet-
|
|
41447
|
-
static
|
|
41448
|
-
|
|
41449
|
-
|
|
41450
|
-
|
|
41451
|
-
|
|
41452
|
-
|
|
41453
|
-
placeholder: { type: String, optional: true },
|
|
41454
|
-
class: { type: String, optional: true },
|
|
41455
|
-
invalid: { type: Boolean, optional: true },
|
|
41456
|
-
getContextualColoredSymbolToken: { type: Function, optional: true },
|
|
41457
|
-
};
|
|
41458
|
-
static components = { Composer };
|
|
41459
|
-
static defaultProps = {
|
|
41460
|
-
composerContent: "",
|
|
41461
|
-
defaultStatic: false,
|
|
41462
|
-
};
|
|
41463
|
-
composerFocusStore;
|
|
41464
|
-
standaloneComposerStore;
|
|
41465
|
-
composerInterface;
|
|
41466
|
-
spreadsheetRect = useSpreadsheetRect();
|
|
41544
|
+
class ChartPanel extends Component {
|
|
41545
|
+
static template = "o-spreadsheet-ChartPanel";
|
|
41546
|
+
static components = { Section, ChartTypePicker };
|
|
41547
|
+
static props = { onCloseSidePanel: Function, figureId: String };
|
|
41548
|
+
store;
|
|
41549
|
+
get figureId() {
|
|
41550
|
+
return this.props.figureId;
|
|
41551
|
+
}
|
|
41467
41552
|
setup() {
|
|
41468
|
-
this.
|
|
41469
|
-
|
|
41470
|
-
|
|
41471
|
-
|
|
41472
|
-
|
|
41473
|
-
|
|
41474
|
-
|
|
41475
|
-
|
|
41476
|
-
|
|
41477
|
-
this.standaloneComposerStore = standaloneComposerStore;
|
|
41478
|
-
this.composerInterface = {
|
|
41479
|
-
id: "standaloneComposer",
|
|
41480
|
-
get editionMode() {
|
|
41481
|
-
return standaloneComposerStore.editionMode;
|
|
41482
|
-
},
|
|
41483
|
-
startEdition: this.standaloneComposerStore.startEdition,
|
|
41484
|
-
setCurrentContent: this.standaloneComposerStore.setCurrentContent,
|
|
41485
|
-
stopEdition: this.standaloneComposerStore.stopEdition,
|
|
41553
|
+
this.store = useLocalStore(MainChartPanelStore);
|
|
41554
|
+
}
|
|
41555
|
+
updateChart(figureId, updateDefinition) {
|
|
41556
|
+
if (figureId !== this.figureId) {
|
|
41557
|
+
return;
|
|
41558
|
+
}
|
|
41559
|
+
const definition = {
|
|
41560
|
+
...this.getChartDefinition(this.figureId),
|
|
41561
|
+
...updateDefinition,
|
|
41486
41562
|
};
|
|
41563
|
+
return this.env.model.dispatch("UPDATE_CHART", {
|
|
41564
|
+
definition,
|
|
41565
|
+
id: figureId,
|
|
41566
|
+
sheetId: this.env.model.getters.getFigureSheetId(figureId),
|
|
41567
|
+
});
|
|
41487
41568
|
}
|
|
41488
|
-
|
|
41489
|
-
|
|
41490
|
-
|
|
41491
|
-
|
|
41569
|
+
canUpdateChart(figureId, updateDefinition) {
|
|
41570
|
+
if (figureId !== this.figureId || !this.env.model.getters.isChartDefined(figureId)) {
|
|
41571
|
+
return;
|
|
41572
|
+
}
|
|
41573
|
+
const definition = {
|
|
41574
|
+
...this.getChartDefinition(this.figureId),
|
|
41575
|
+
...updateDefinition,
|
|
41576
|
+
};
|
|
41577
|
+
return this.env.model.canDispatch("UPDATE_CHART", {
|
|
41578
|
+
definition,
|
|
41579
|
+
id: figureId,
|
|
41580
|
+
sheetId: this.env.model.getters.getFigureSheetId(figureId),
|
|
41581
|
+
});
|
|
41492
41582
|
}
|
|
41493
|
-
|
|
41494
|
-
|
|
41495
|
-
|
|
41496
|
-
|
|
41583
|
+
onTypeChange(type) {
|
|
41584
|
+
if (!this.figureId) {
|
|
41585
|
+
return;
|
|
41586
|
+
}
|
|
41587
|
+
this.store.changeChartType(this.figureId, type);
|
|
41497
41588
|
}
|
|
41498
|
-
get
|
|
41499
|
-
|
|
41500
|
-
|
|
41501
|
-
|
|
41502
|
-
|
|
41503
|
-
|
|
41504
|
-
|
|
41589
|
+
get chartPanel() {
|
|
41590
|
+
if (!this.figureId) {
|
|
41591
|
+
throw new Error("Chart not defined.");
|
|
41592
|
+
}
|
|
41593
|
+
const type = this.env.model.getters.getChartType(this.figureId);
|
|
41594
|
+
if (!type) {
|
|
41595
|
+
throw new Error("Chart not defined.");
|
|
41596
|
+
}
|
|
41597
|
+
const chartPanel = chartSidePanelComponentRegistry.get(type);
|
|
41598
|
+
if (!chartPanel) {
|
|
41599
|
+
throw new Error(`Component is not defined for type ${type}`);
|
|
41600
|
+
}
|
|
41601
|
+
return chartPanel;
|
|
41505
41602
|
}
|
|
41506
|
-
|
|
41507
|
-
this.
|
|
41603
|
+
getChartDefinition(figureId) {
|
|
41604
|
+
return this.env.model.getters.getChartDefinition(figureId);
|
|
41508
41605
|
}
|
|
41509
41606
|
}
|
|
41510
41607
|
|
|
@@ -41764,7 +41861,7 @@ class ConditionalFormatPreviewList extends Component {
|
|
|
41764
41861
|
draggedItemId: cf.id,
|
|
41765
41862
|
initialMousePosition: event.clientY,
|
|
41766
41863
|
items: items,
|
|
41767
|
-
|
|
41864
|
+
scrollableContainerEl: this.cfListRef.el,
|
|
41768
41865
|
onDragEnd: (cfId, finalIndex) => this.onDragEnd(cfId, finalIndex),
|
|
41769
41866
|
});
|
|
41770
41867
|
}
|
|
@@ -44949,6 +45046,7 @@ class PivotLayoutConfigurator extends Component {
|
|
|
44949
45046
|
unusedGranularities: Object,
|
|
44950
45047
|
dateGranularities: Array,
|
|
44951
45048
|
datetimeGranularities: Array,
|
|
45049
|
+
getScrollableContainerEl: { type: Function, optional: true },
|
|
44952
45050
|
pivotId: String,
|
|
44953
45051
|
};
|
|
44954
45052
|
dimensionsRef = useRef("pivot-dimensions");
|
|
@@ -44982,7 +45080,7 @@ class PivotLayoutConfigurator extends Component {
|
|
|
44982
45080
|
draggedItemId: dimension.nameWithGranularity,
|
|
44983
45081
|
initialMousePosition: event.clientY,
|
|
44984
45082
|
items: draggableItems,
|
|
44985
|
-
|
|
45083
|
+
scrollableContainerEl: this.props.getScrollableContainerEl?.() || this.dimensionsRef.el,
|
|
44986
45084
|
onDragEnd: (dimensionName, finalIndex) => {
|
|
44987
45085
|
const originalIndex = draggableIds.findIndex((id) => id === dimensionName);
|
|
44988
45086
|
if (originalIndex === finalIndex) {
|
|
@@ -45031,7 +45129,7 @@ class PivotLayoutConfigurator extends Component {
|
|
|
45031
45129
|
draggedItemId: measure.id,
|
|
45032
45130
|
initialMousePosition: event.clientY,
|
|
45033
45131
|
items: draggableItems,
|
|
45034
|
-
|
|
45132
|
+
scrollableContainerEl: this.props.getScrollableContainerEl?.() || this.dimensionsRef.el,
|
|
45035
45133
|
onDragEnd: (measureName, finalIndex) => {
|
|
45036
45134
|
const originalIndex = draggableIds.findIndex((id) => id === measureName);
|
|
45037
45135
|
if (originalIndex === finalIndex) {
|
|
@@ -45664,7 +45762,7 @@ class SpreadsheetPivotTable {
|
|
|
45664
45762
|
rowTreeToRows(tree, parentRow) {
|
|
45665
45763
|
return tree.flatMap((node) => {
|
|
45666
45764
|
const row = {
|
|
45667
|
-
indent: parentRow ? parentRow.indent + 1 :
|
|
45765
|
+
indent: parentRow ? parentRow.indent + 1 : 1,
|
|
45668
45766
|
fields: [...(parentRow?.fields || []), node.field],
|
|
45669
45767
|
values: [...(parentRow?.values || []), node.value],
|
|
45670
45768
|
};
|
|
@@ -45720,7 +45818,7 @@ function dataEntriesToRows(dataEntries, index, rows, fields, values) {
|
|
|
45720
45818
|
pivotTableRows.push({
|
|
45721
45819
|
fields: _fields,
|
|
45722
45820
|
values: _values,
|
|
45723
|
-
indent: index,
|
|
45821
|
+
indent: index + 1,
|
|
45724
45822
|
});
|
|
45725
45823
|
const record = groups[value];
|
|
45726
45824
|
if (record) {
|
|
@@ -46716,6 +46814,7 @@ class PivotSpreadsheetSidePanel extends Component {
|
|
|
46716
46814
|
};
|
|
46717
46815
|
store;
|
|
46718
46816
|
state;
|
|
46817
|
+
pivotSidePanelRef = useRef("pivotSidePanel");
|
|
46719
46818
|
setup() {
|
|
46720
46819
|
this.store = useLocalStore(PivotSidePanelStore, this.props.pivotId);
|
|
46721
46820
|
this.state = useState({
|
|
@@ -46744,6 +46843,9 @@ class PivotSpreadsheetSidePanel extends Component {
|
|
|
46744
46843
|
get definition() {
|
|
46745
46844
|
return this.store.definition;
|
|
46746
46845
|
}
|
|
46846
|
+
getScrollableContainerEl() {
|
|
46847
|
+
return this.pivotSidePanelRef.el;
|
|
46848
|
+
}
|
|
46747
46849
|
onSelectionChanged(ranges) {
|
|
46748
46850
|
this.state.rangeHasChanged = true;
|
|
46749
46851
|
this.state.range = ranges[0];
|
|
@@ -55922,6 +56024,8 @@ class RangeAdapter {
|
|
|
55922
56024
|
this.getters = getters;
|
|
55923
56025
|
}
|
|
55924
56026
|
static getters = [
|
|
56027
|
+
"adaptFormulaStringDependencies",
|
|
56028
|
+
"copyFormulaStringForSheet",
|
|
55925
56029
|
"extendRange",
|
|
55926
56030
|
"getRangeString",
|
|
55927
56031
|
"getRangeFromSheetXC",
|
|
@@ -56314,6 +56418,38 @@ class RangeAdapter {
|
|
|
56314
56418
|
const unionOfZones = unionUnboundedZones(...zones);
|
|
56315
56419
|
return this.getRangeFromZone(ranges[0].sheetId, unionOfZones);
|
|
56316
56420
|
}
|
|
56421
|
+
adaptFormulaStringDependencies(sheetId, formula, applyChange) {
|
|
56422
|
+
if (!formula.startsWith("=")) {
|
|
56423
|
+
return formula;
|
|
56424
|
+
}
|
|
56425
|
+
const compiledFormula = compile(formula);
|
|
56426
|
+
const updatedDependencies = compiledFormula.dependencies.map((dep) => {
|
|
56427
|
+
const range = this.getters.getRangeFromSheetXC(sheetId, dep);
|
|
56428
|
+
const changedRange = applyChange(range);
|
|
56429
|
+
return changedRange.changeType === "NONE" ? range : changedRange.range;
|
|
56430
|
+
});
|
|
56431
|
+
return this.getters.getFormulaString(sheetId, compiledFormula.tokens, updatedDependencies);
|
|
56432
|
+
}
|
|
56433
|
+
/**
|
|
56434
|
+
* Copy a formula string to another sheet.
|
|
56435
|
+
*
|
|
56436
|
+
* @param mode
|
|
56437
|
+
* `keepSameReference` will make the formula reference the exact same ranges,
|
|
56438
|
+
* `moveReference` will change all the references to `sheetIdFrom` into references to `sheetIdTo`.
|
|
56439
|
+
*/
|
|
56440
|
+
copyFormulaStringForSheet(sheetIdFrom, sheetIdTo, formula, mode) {
|
|
56441
|
+
if (!formula.startsWith("=")) {
|
|
56442
|
+
return formula;
|
|
56443
|
+
}
|
|
56444
|
+
const compiledFormula = compile(formula);
|
|
56445
|
+
const updatedDependencies = compiledFormula.dependencies.map((dep) => {
|
|
56446
|
+
const range = this.getters.getRangeFromSheetXC(sheetIdFrom, dep);
|
|
56447
|
+
return mode === "keepSameReference"
|
|
56448
|
+
? range
|
|
56449
|
+
: duplicateRangeInDuplicatedSheet(sheetIdFrom, sheetIdTo, range);
|
|
56450
|
+
});
|
|
56451
|
+
return this.getters.getFormulaString(sheetIdTo, compiledFormula.tokens, updatedDependencies);
|
|
56452
|
+
}
|
|
56317
56453
|
// ---------------------------------------------------------------------------
|
|
56318
56454
|
// Private
|
|
56319
56455
|
// ---------------------------------------------------------------------------
|
|
@@ -69211,7 +69347,7 @@ class BottomBar extends Component {
|
|
|
69211
69347
|
draggedItemId: sheetId,
|
|
69212
69348
|
initialMousePosition: event.clientX,
|
|
69213
69349
|
items: sheets,
|
|
69214
|
-
|
|
69350
|
+
scrollableContainerEl: this.sheetListRef.el,
|
|
69215
69351
|
onDragEnd: (sheetId, finalIndex) => this.onDragEnd(sheetId, finalIndex),
|
|
69216
69352
|
});
|
|
69217
69353
|
}
|
|
@@ -69266,7 +69402,7 @@ class ClickableCellsStore extends SpreadsheetStore {
|
|
|
69266
69402
|
this._registryItems = markRaw(clickableCellRegistry.getAll().sort((a, b) => a.sequence - b.sequence));
|
|
69267
69403
|
}
|
|
69268
69404
|
}
|
|
69269
|
-
|
|
69405
|
+
getClickableItem(position) {
|
|
69270
69406
|
const { sheetId, col, row } = position;
|
|
69271
69407
|
const clickableCells = this._clickableCells;
|
|
69272
69408
|
const xc = toXC(col, row);
|
|
@@ -69274,33 +69410,37 @@ class ClickableCellsStore extends SpreadsheetStore {
|
|
|
69274
69410
|
clickableCells[sheetId] = {};
|
|
69275
69411
|
}
|
|
69276
69412
|
if (!(xc in clickableCells[sheetId])) {
|
|
69277
|
-
|
|
69413
|
+
const clickableCell = this.findClickableItem(position);
|
|
69414
|
+
if (clickableCell) {
|
|
69415
|
+
clickableCells[sheetId][xc] = clickableCell;
|
|
69416
|
+
}
|
|
69278
69417
|
}
|
|
69279
69418
|
return clickableCells[sheetId][xc];
|
|
69280
69419
|
}
|
|
69281
|
-
|
|
69420
|
+
findClickableItem(position) {
|
|
69282
69421
|
const getters = this.getters;
|
|
69283
69422
|
for (const item of this._registryItems) {
|
|
69284
69423
|
if (item.condition(position, getters)) {
|
|
69285
|
-
return item
|
|
69424
|
+
return item;
|
|
69286
69425
|
}
|
|
69287
69426
|
}
|
|
69288
|
-
return
|
|
69427
|
+
return undefined;
|
|
69289
69428
|
}
|
|
69290
69429
|
get clickableCells() {
|
|
69291
69430
|
const cells = [];
|
|
69292
69431
|
const getters = this.getters;
|
|
69293
69432
|
const sheetId = getters.getActiveSheetId();
|
|
69294
69433
|
for (const position of this.getters.getVisibleCellPositions()) {
|
|
69295
|
-
const
|
|
69296
|
-
if (!
|
|
69434
|
+
const item = this.getClickableItem(position);
|
|
69435
|
+
if (!item) {
|
|
69297
69436
|
continue;
|
|
69298
69437
|
}
|
|
69299
69438
|
const zone = getters.expandZone(sheetId, positionToZone(position));
|
|
69300
69439
|
cells.push({
|
|
69301
69440
|
coordinates: getters.getVisibleRect(zone),
|
|
69302
69441
|
position,
|
|
69303
|
-
action,
|
|
69442
|
+
action: item.execute,
|
|
69443
|
+
title: item.title || "",
|
|
69304
69444
|
});
|
|
69305
69445
|
}
|
|
69306
69446
|
return cells;
|
|
@@ -74676,6 +74816,9 @@ class Model extends EventBus {
|
|
|
74676
74816
|
this.coreGetters.extendRange = this.range.extendRange.bind(this.range);
|
|
74677
74817
|
this.coreGetters.getRangesUnion = this.range.getRangesUnion.bind(this.range);
|
|
74678
74818
|
this.coreGetters.removeRangesSheetPrefix = this.range.removeRangesSheetPrefix.bind(this.range);
|
|
74819
|
+
this.coreGetters.adaptFormulaStringDependencies =
|
|
74820
|
+
this.range.adaptFormulaStringDependencies.bind(this.range);
|
|
74821
|
+
this.coreGetters.copyFormulaStringForSheet = this.range.copyFormulaStringForSheet.bind(this.range);
|
|
74679
74822
|
this.getters = {
|
|
74680
74823
|
isReadonly: () => this.config.mode === "readonly" || this.config.mode === "dashboard",
|
|
74681
74824
|
isDashboard: () => this.config.mode === "dashboard",
|
|
@@ -75332,6 +75475,6 @@ const chartHelpers = { ...CHART_HELPERS, ...CHART_RUNTIME_HELPERS };
|
|
|
75332
75475
|
export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, CoreViewPlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, chartHelpers, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
|
|
75333
75476
|
|
|
75334
75477
|
|
|
75335
|
-
__info__.version = "18.2.0-alpha.
|
|
75336
|
-
__info__.date = "2025-02-
|
|
75337
|
-
__info__.hash = "
|
|
75478
|
+
__info__.version = "18.2.0-alpha.7";
|
|
75479
|
+
__info__.date = "2025-02-10T09:01:19.353Z";
|
|
75480
|
+
__info__.hash = "0432f17";
|