@odoo/o-spreadsheet 18.4.0-alpha.8 → 18.4.0-alpha.9
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 +758 -514
- package/dist/o-spreadsheet.d.ts +25 -3
- package/dist/o-spreadsheet.esm.js +758 -514
- package/dist/o-spreadsheet.iife.js +758 -514
- package/dist/o-spreadsheet.iife.min.js +394 -394
- package/dist/o_spreadsheet.xml +25 -6
- package/package.json +1 -1
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* This file is generated by o-spreadsheet build tools. Do not edit it.
|
|
4
4
|
* @see https://github.com/odoo/o-spreadsheet
|
|
5
|
-
* @version 18.4.0-alpha.
|
|
6
|
-
* @date 2025-06-
|
|
7
|
-
* @hash
|
|
5
|
+
* @version 18.4.0-alpha.9
|
|
6
|
+
* @date 2025-06-19T18:23:22.025Z
|
|
7
|
+
* @hash 6d4d685
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
'use strict';
|
|
@@ -22,13 +22,21 @@ function createAction(item) {
|
|
|
22
22
|
const icon = item.icon;
|
|
23
23
|
const secondaryIcon = item.secondaryIcon;
|
|
24
24
|
const itemId = item.id || nextItemId++;
|
|
25
|
+
const isEnabled = item.isEnabled ? item.isEnabled : () => true;
|
|
25
26
|
return {
|
|
26
27
|
id: itemId.toString(),
|
|
27
28
|
name: typeof name === "function" ? name : () => name,
|
|
28
29
|
isVisible: item.isVisible ? item.isVisible : () => true,
|
|
29
|
-
isEnabled:
|
|
30
|
+
isEnabled: isEnabled,
|
|
30
31
|
isActive: item.isActive,
|
|
31
|
-
execute: item.execute
|
|
32
|
+
execute: item.execute
|
|
33
|
+
? (env, isMiddleClick) => {
|
|
34
|
+
if (isEnabled(env)) {
|
|
35
|
+
return item.execute(env, isMiddleClick);
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
: undefined,
|
|
32
40
|
children: children
|
|
33
41
|
? (env) => {
|
|
34
42
|
return children
|
|
@@ -299,6 +307,7 @@ const GROUP_LAYER_WIDTH = 21;
|
|
|
299
307
|
const GRID_ICON_MARGIN = 2;
|
|
300
308
|
const GRID_ICON_EDGE_LENGTH = 17;
|
|
301
309
|
const FOOTER_HEIGHT = 2 * DEFAULT_CELL_HEIGHT;
|
|
310
|
+
const DATA_VALIDATION_CHIP_MARGIN = 5;
|
|
302
311
|
// 768px is a common breakpoint for small screens
|
|
303
312
|
// Typically inside Odoo, it is the threshold for switching to mobile view
|
|
304
313
|
const MOBILE_WIDTH_BREAKPOINT = 768;
|
|
@@ -644,9 +653,6 @@ function parseSheetUrl(sheetLink) {
|
|
|
644
653
|
function isDefined(argument) {
|
|
645
654
|
return argument !== undefined;
|
|
646
655
|
}
|
|
647
|
-
function isNotNull(argument) {
|
|
648
|
-
return argument !== null;
|
|
649
|
-
}
|
|
650
656
|
/**
|
|
651
657
|
* Check if all the values of an object, and all the values of the objects inside of it, are undefined.
|
|
652
658
|
*/
|
|
@@ -1357,9 +1363,16 @@ function darkenColor(color, percentage) {
|
|
|
1357
1363
|
if (percentage === 1) {
|
|
1358
1364
|
return "#000";
|
|
1359
1365
|
}
|
|
1366
|
+
// increase saturation to compensate and make it more vivid
|
|
1367
|
+
hsla.s = Math.min(100, percentage * hsla.s + hsla.s);
|
|
1360
1368
|
hsla.l = hsla.l - percentage * hsla.l;
|
|
1361
1369
|
return hslaToHex(hsla);
|
|
1362
1370
|
}
|
|
1371
|
+
function chipTextColor(chipBackgroundColor) {
|
|
1372
|
+
return relativeLuminance(chipBackgroundColor) < 0.6
|
|
1373
|
+
? lightenColor(chipBackgroundColor, 0.9)
|
|
1374
|
+
: darkenColor(chipBackgroundColor, 0.75);
|
|
1375
|
+
}
|
|
1363
1376
|
const COLORS_SM = [
|
|
1364
1377
|
"#4EA7F2", // Blue
|
|
1365
1378
|
"#EA6175", // Red
|
|
@@ -21688,6 +21701,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
21688
21701
|
if (isTrendLineAxis(dataset.xAxisID) || dataset.hidden) {
|
|
21689
21702
|
continue;
|
|
21690
21703
|
}
|
|
21704
|
+
const yAxisScale = chart.scales[dataset.yAxisID];
|
|
21691
21705
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
21692
21706
|
const parsedValue = dataset._parsed[i];
|
|
21693
21707
|
const value = Number(chart.config.type === "radar" ? parsedValue.r : parsedValue.y);
|
|
@@ -21698,10 +21712,18 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
21698
21712
|
const xPosition = point.x;
|
|
21699
21713
|
let yPosition = 0;
|
|
21700
21714
|
if (chart.config.type === "line" || chart.config.type === "radar") {
|
|
21701
|
-
yPosition = point.y - 10;
|
|
21715
|
+
yPosition = value < 0 ? point.y + 10 : point.y - 10;
|
|
21702
21716
|
}
|
|
21703
21717
|
else {
|
|
21704
|
-
|
|
21718
|
+
const yZeroLine = yAxisScale.getPixelForValue(0);
|
|
21719
|
+
const distanceFromAxisOrigin = Math.abs(yZeroLine - point.y);
|
|
21720
|
+
const textHeight = 12; // ChartJS default text height
|
|
21721
|
+
if (distanceFromAxisOrigin < textHeight) {
|
|
21722
|
+
yPosition = value < 0 ? yZeroLine + textHeight / 2 : yZeroLine - textHeight / 2;
|
|
21723
|
+
}
|
|
21724
|
+
else {
|
|
21725
|
+
yPosition = value < 0 ? point.y - point.height / 2 : point.y + point.height / 2;
|
|
21726
|
+
}
|
|
21705
21727
|
}
|
|
21706
21728
|
yPosition = Math.min(yPosition, yMax);
|
|
21707
21729
|
yPosition = Math.max(yPosition, yMin);
|
|
@@ -21711,7 +21733,7 @@ function drawLineOrBarOrRadarChartValues(chart, options, ctx) {
|
|
|
21711
21733
|
}
|
|
21712
21734
|
for (const otherPosition of textsPositions[xPosition] || []) {
|
|
21713
21735
|
if (Math.abs(otherPosition - yPosition) < 13) {
|
|
21714
|
-
yPosition = otherPosition - 13;
|
|
21736
|
+
yPosition = value < 0 ? otherPosition + 13 : otherPosition - 13;
|
|
21715
21737
|
}
|
|
21716
21738
|
}
|
|
21717
21739
|
textsPositions[xPosition].push(yPosition);
|
|
@@ -21730,6 +21752,8 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
21730
21752
|
if (isTrendLineAxis(dataset.xAxisID)) {
|
|
21731
21753
|
return; // ignore trend lines
|
|
21732
21754
|
}
|
|
21755
|
+
const xAxisScale = chart.scales[dataset.xAxisID];
|
|
21756
|
+
const xZeroLine = xAxisScale.getPixelForValue(0);
|
|
21733
21757
|
for (let i = 0; i < dataset._parsed.length; i++) {
|
|
21734
21758
|
const value = Number(dataset._parsed[i].x);
|
|
21735
21759
|
if (isNaN(value)) {
|
|
@@ -21738,17 +21762,27 @@ function drawHorizontalBarChartValues(chart, options, ctx) {
|
|
|
21738
21762
|
const displayValue = options.callback(value, dataset, i);
|
|
21739
21763
|
const point = dataset.data[i];
|
|
21740
21764
|
const yPosition = point.y;
|
|
21741
|
-
|
|
21742
|
-
|
|
21743
|
-
|
|
21765
|
+
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
21766
|
+
const distanceFromAxisOrigin = Math.abs(point.x - xZeroLine);
|
|
21767
|
+
const PADDING = 3;
|
|
21768
|
+
let xPosition;
|
|
21769
|
+
if (distanceFromAxisOrigin < textWidth) {
|
|
21770
|
+
xPosition =
|
|
21771
|
+
value < 0 ? xZeroLine - textWidth / 2 - PADDING : xZeroLine + textWidth / 2 + PADDING;
|
|
21772
|
+
}
|
|
21773
|
+
else {
|
|
21774
|
+
xPosition = value < 0 ? point.x + point.width / 2 : point.x - point.width / 2;
|
|
21775
|
+
xPosition = Math.min(xPosition, xMax);
|
|
21776
|
+
xPosition = Math.max(xPosition, xMin);
|
|
21777
|
+
}
|
|
21744
21778
|
// Avoid overlapping texts with same Y
|
|
21745
21779
|
if (!textsPositions[yPosition]) {
|
|
21746
21780
|
textsPositions[yPosition] = [];
|
|
21747
21781
|
}
|
|
21748
|
-
const textWidth = computeTextWidth(ctx, displayValue, { fontSize: 12 }, "px");
|
|
21749
21782
|
for (const otherPosition of textsPositions[yPosition]) {
|
|
21750
21783
|
if (Math.abs(otherPosition - xPosition) < textWidth) {
|
|
21751
|
-
xPosition =
|
|
21784
|
+
xPosition =
|
|
21785
|
+
value < 0 ? otherPosition - textWidth - PADDING : otherPosition + textWidth + PADDING;
|
|
21752
21786
|
}
|
|
21753
21787
|
}
|
|
21754
21788
|
textsPositions[yPosition].push(xPosition);
|
|
@@ -25682,7 +25716,9 @@ function getPyramidChartShowValues(definition, args) {
|
|
|
25682
25716
|
background: definition.background,
|
|
25683
25717
|
callback: (value, dataset) => {
|
|
25684
25718
|
value = Math.abs(Number(value));
|
|
25685
|
-
return
|
|
25719
|
+
return value === 0
|
|
25720
|
+
? ""
|
|
25721
|
+
: formatChartDatasetValue(axisFormats, locale)(value, dataset.xAxisID || "x");
|
|
25686
25722
|
},
|
|
25687
25723
|
};
|
|
25688
25724
|
}
|
|
@@ -29343,6 +29379,12 @@ class Menu extends owl.Component {
|
|
|
29343
29379
|
menu.onStopHover?.(this.env);
|
|
29344
29380
|
this.props.onMouseLeave?.(menu, ev);
|
|
29345
29381
|
}
|
|
29382
|
+
onClickMenu(menu, ev) {
|
|
29383
|
+
if (!this.isEnabled(menu)) {
|
|
29384
|
+
return;
|
|
29385
|
+
}
|
|
29386
|
+
this.props.onClickMenu?.(menu, ev);
|
|
29387
|
+
}
|
|
29346
29388
|
}
|
|
29347
29389
|
|
|
29348
29390
|
/**
|
|
@@ -29841,9 +29883,6 @@ class MenuPopover extends owl.Component {
|
|
|
29841
29883
|
this.subMenu.parentMenu = undefined;
|
|
29842
29884
|
}
|
|
29843
29885
|
onClickMenu(menu, ev) {
|
|
29844
|
-
if (!this.isEnabled(menu)) {
|
|
29845
|
-
return;
|
|
29846
|
-
}
|
|
29847
29886
|
if (this.isRoot(menu)) {
|
|
29848
29887
|
this.openSubMenu(menu, ev.currentTarget);
|
|
29849
29888
|
}
|
|
@@ -31094,11 +31133,9 @@ criterionEvaluatorRegistry.add("isValueInRange", {
|
|
|
31094
31133
|
if (!value) {
|
|
31095
31134
|
return false;
|
|
31096
31135
|
}
|
|
31097
|
-
const
|
|
31098
|
-
const criterionValues = getters.getRangeValues(range);
|
|
31136
|
+
const criterionValues = getters.getDataValidationRangeValues(sheetId, criterion);
|
|
31099
31137
|
return criterionValues
|
|
31100
|
-
.
|
|
31101
|
-
.map((value) => value.toString().toLowerCase())
|
|
31138
|
+
.map((value) => value.toLowerCase())
|
|
31102
31139
|
.includes(value.toString().toLowerCase());
|
|
31103
31140
|
},
|
|
31104
31141
|
getErrorString: (criterion) => _t("The value must be a value in the range %s", String(criterion.values[0])),
|
|
@@ -31270,6 +31307,12 @@ class TextValueProvider extends owl.Component {
|
|
|
31270
31307
|
selectedElement?.scrollIntoView?.({ block: "nearest" });
|
|
31271
31308
|
}, () => [this.props.selectedIndex, this.autoCompleteListRef.el]);
|
|
31272
31309
|
}
|
|
31310
|
+
getCss(html) {
|
|
31311
|
+
return cssPropertiesToCss({
|
|
31312
|
+
color: html.color || "#000000",
|
|
31313
|
+
background: html.backgroundColor,
|
|
31314
|
+
});
|
|
31315
|
+
}
|
|
31273
31316
|
}
|
|
31274
31317
|
|
|
31275
31318
|
class ContentEditableHelper {
|
|
@@ -31408,7 +31451,6 @@ class ContentEditableHelper {
|
|
|
31408
31451
|
// We can only modify a node in place if it has the same type as the content
|
|
31409
31452
|
// that we would insert, which are spans.
|
|
31410
31453
|
// Otherwise, it means that the node has been input by the user, through the keyboard or a copy/paste
|
|
31411
|
-
// @ts-ignore (somehow required because jest does not like child.tagName despite the prior check)
|
|
31412
31454
|
const childIsSpan = child && "tagName" in child && child.tagName === "SPAN";
|
|
31413
31455
|
if (childIsSpan && compareContentToSpanElement(content, child)) {
|
|
31414
31456
|
continue;
|
|
@@ -31443,9 +31485,7 @@ class ContentEditableHelper {
|
|
|
31443
31485
|
}
|
|
31444
31486
|
// Empty line
|
|
31445
31487
|
if (!p.hasChildNodes()) {
|
|
31446
|
-
|
|
31447
|
-
span.appendChild(document.createElement("br"));
|
|
31448
|
-
p.appendChild(span);
|
|
31488
|
+
p.appendChild(document.createElement("span"));
|
|
31449
31489
|
}
|
|
31450
31490
|
// replace p if necessary
|
|
31451
31491
|
if (newChild) {
|
|
@@ -31492,13 +31532,10 @@ class ContentEditableHelper {
|
|
|
31492
31532
|
}
|
|
31493
31533
|
getText() {
|
|
31494
31534
|
let text = "";
|
|
31495
|
-
const it = iterateChildren(this.el);
|
|
31496
|
-
let current = it.next();
|
|
31497
31535
|
let isFirstParagraph = true;
|
|
31498
|
-
|
|
31499
|
-
|
|
31500
|
-
|
|
31501
|
-
}
|
|
31536
|
+
let emptyParagraph = false;
|
|
31537
|
+
const it = iterateChildren(this.el);
|
|
31538
|
+
for (let current = it.next(); !current.done; current = it.next()) {
|
|
31502
31539
|
if (current.value.nodeName === "P" ||
|
|
31503
31540
|
(current.value.nodeName === "DIV" && current.value !== this.el) // On paste, the HTML may contain <div> instead of <p>
|
|
31504
31541
|
) {
|
|
@@ -31508,8 +31545,15 @@ class ContentEditableHelper {
|
|
|
31508
31545
|
else {
|
|
31509
31546
|
text += NEWLINE;
|
|
31510
31547
|
}
|
|
31548
|
+
emptyParagraph = ["<br>", "<span><br></span>"].includes(current.value.innerHTML);
|
|
31549
|
+
continue;
|
|
31550
|
+
}
|
|
31551
|
+
if (!current.value.hasChildNodes()) {
|
|
31552
|
+
if (current.value.nodeName === "BR" && !emptyParagraph) {
|
|
31553
|
+
text += NEWLINE;
|
|
31554
|
+
}
|
|
31555
|
+
text += current.value.textContent;
|
|
31511
31556
|
}
|
|
31512
|
-
current = it.next();
|
|
31513
31557
|
}
|
|
31514
31558
|
return text;
|
|
31515
31559
|
}
|
|
@@ -32859,6 +32903,12 @@ class Composer extends owl.Component {
|
|
|
32859
32903
|
owl.useEffect(() => {
|
|
32860
32904
|
this.processTokenAtCursor();
|
|
32861
32905
|
}, () => [this.props.composerStore.editionMode !== "inactive"]);
|
|
32906
|
+
owl.useEffect(() => {
|
|
32907
|
+
this.contentHelper.scrollSelectionIntoView();
|
|
32908
|
+
}, () => [
|
|
32909
|
+
this.props.composerStore.composerSelection.start,
|
|
32910
|
+
this.props.composerStore.composerSelection.end,
|
|
32911
|
+
]);
|
|
32862
32912
|
}
|
|
32863
32913
|
// ---------------------------------------------------------------------------
|
|
32864
32914
|
// Handlers
|
|
@@ -33069,6 +33119,7 @@ class Composer extends owl.Component {
|
|
|
33069
33119
|
if (this.env.isMobile() && !isIOS()) {
|
|
33070
33120
|
return;
|
|
33071
33121
|
}
|
|
33122
|
+
this.debouncedHover.stopDebounce();
|
|
33072
33123
|
this.contentHelper.removeSelection();
|
|
33073
33124
|
}
|
|
33074
33125
|
onMouseup() {
|
|
@@ -33147,7 +33198,6 @@ class Composer extends owl.Component {
|
|
|
33147
33198
|
const { start, end } = this.props.composerStore.composerSelection;
|
|
33148
33199
|
this.contentHelper.selectRange(start, end);
|
|
33149
33200
|
}
|
|
33150
|
-
this.contentHelper.scrollSelectionIntoView();
|
|
33151
33201
|
}
|
|
33152
33202
|
this.shouldProcessInputEvents = true;
|
|
33153
33203
|
}
|
|
@@ -33623,6 +33673,414 @@ class SingleInputCriterionForm extends CriterionForm {
|
|
|
33623
33673
|
}
|
|
33624
33674
|
}
|
|
33625
33675
|
|
|
33676
|
+
/**
|
|
33677
|
+
* Start listening to pointer events and apply the given callbacks.
|
|
33678
|
+
*
|
|
33679
|
+
* @returns A function to remove the listeners.
|
|
33680
|
+
*/
|
|
33681
|
+
function startDnd(onPointerMove, onPointerUp) {
|
|
33682
|
+
const removeListeners = () => {
|
|
33683
|
+
window.removeEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33684
|
+
window.removeEventListener("dragstart", _onDragStart);
|
|
33685
|
+
window.removeEventListener("pointermove", onPointerMove);
|
|
33686
|
+
window.removeEventListener("wheel", onPointerMove);
|
|
33687
|
+
};
|
|
33688
|
+
const _onPointerUp = (ev) => {
|
|
33689
|
+
onPointerUp(ev);
|
|
33690
|
+
removeListeners();
|
|
33691
|
+
};
|
|
33692
|
+
function _onDragStart(ev) {
|
|
33693
|
+
ev.preventDefault();
|
|
33694
|
+
}
|
|
33695
|
+
window.addEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33696
|
+
window.addEventListener("dragstart", _onDragStart);
|
|
33697
|
+
window.addEventListener("pointermove", onPointerMove);
|
|
33698
|
+
// mouse wheel on window is by default a passive event.
|
|
33699
|
+
// preventDefault() is not allowed in passive event handler.
|
|
33700
|
+
// https://chromestatus.com/feature/6662647093133312
|
|
33701
|
+
window.addEventListener("wheel", onPointerMove, { passive: false });
|
|
33702
|
+
return removeListeners;
|
|
33703
|
+
}
|
|
33704
|
+
|
|
33705
|
+
const LINE_VERTICAL_PADDING = 1;
|
|
33706
|
+
const PICKER_PADDING = 8;
|
|
33707
|
+
const ITEM_BORDER_WIDTH = 1;
|
|
33708
|
+
const ITEM_EDGE_LENGTH = 18;
|
|
33709
|
+
const ITEMS_PER_LINE = 10;
|
|
33710
|
+
const MAGNIFIER_EDGE = 16;
|
|
33711
|
+
const ITEM_GAP = 2;
|
|
33712
|
+
const CONTENT_WIDTH = ITEMS_PER_LINE * (ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH) + (ITEMS_PER_LINE - 1) * ITEM_GAP;
|
|
33713
|
+
const INNER_GRADIENT_WIDTH = CONTENT_WIDTH - 2 * ITEM_BORDER_WIDTH;
|
|
33714
|
+
const INNER_GRADIENT_HEIGHT = CONTENT_WIDTH - 30 - 2 * ITEM_BORDER_WIDTH;
|
|
33715
|
+
const CONTAINER_WIDTH = CONTENT_WIDTH + 2 * PICKER_PADDING;
|
|
33716
|
+
css /* scss */ `
|
|
33717
|
+
.o-color-picker {
|
|
33718
|
+
padding: ${PICKER_PADDING}px 0;
|
|
33719
|
+
/* FIXME: this is useless, overiden by the popover container */
|
|
33720
|
+
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
|
|
33721
|
+
background-color: white;
|
|
33722
|
+
line-height: 1.2;
|
|
33723
|
+
overflow-y: auto;
|
|
33724
|
+
overflow-x: hidden;
|
|
33725
|
+
width: ${CONTAINER_WIDTH}px;
|
|
33726
|
+
|
|
33727
|
+
.o-color-picker-section-name {
|
|
33728
|
+
margin: 0px ${ITEM_BORDER_WIDTH}px;
|
|
33729
|
+
padding: 4px ${PICKER_PADDING}px;
|
|
33730
|
+
}
|
|
33731
|
+
.colors-grid {
|
|
33732
|
+
display: grid;
|
|
33733
|
+
padding: ${LINE_VERTICAL_PADDING}px ${PICKER_PADDING}px;
|
|
33734
|
+
grid-template-columns: repeat(${ITEMS_PER_LINE}, 1fr);
|
|
33735
|
+
grid-gap: ${ITEM_GAP}px;
|
|
33736
|
+
}
|
|
33737
|
+
.o-color-picker-toggler-button {
|
|
33738
|
+
display: flex;
|
|
33739
|
+
.o-color-picker-toggler-sign {
|
|
33740
|
+
display: flex;
|
|
33741
|
+
margin: auto auto;
|
|
33742
|
+
width: 55%;
|
|
33743
|
+
height: 55%;
|
|
33744
|
+
.o-icon {
|
|
33745
|
+
width: 100%;
|
|
33746
|
+
height: 100%;
|
|
33747
|
+
}
|
|
33748
|
+
}
|
|
33749
|
+
}
|
|
33750
|
+
.o-color-picker-line-item {
|
|
33751
|
+
width: ${ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
33752
|
+
height: ${ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
33753
|
+
margin: 0px;
|
|
33754
|
+
border-radius: 50px;
|
|
33755
|
+
border: ${ITEM_BORDER_WIDTH}px solid #666666;
|
|
33756
|
+
padding: 0px;
|
|
33757
|
+
font-size: 16px;
|
|
33758
|
+
background: white;
|
|
33759
|
+
&:hover {
|
|
33760
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
33761
|
+
outline: 1px solid gray;
|
|
33762
|
+
cursor: pointer;
|
|
33763
|
+
}
|
|
33764
|
+
}
|
|
33765
|
+
.o-buttons {
|
|
33766
|
+
padding: ${PICKER_PADDING}px;
|
|
33767
|
+
display: flex;
|
|
33768
|
+
.o-cancel {
|
|
33769
|
+
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
33770
|
+
width: 100%;
|
|
33771
|
+
padding: 5px;
|
|
33772
|
+
font-size: 14px;
|
|
33773
|
+
background: white;
|
|
33774
|
+
border-radius: 4px;
|
|
33775
|
+
&:hover:enabled {
|
|
33776
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
33777
|
+
}
|
|
33778
|
+
}
|
|
33779
|
+
}
|
|
33780
|
+
.o-add-button {
|
|
33781
|
+
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
33782
|
+
padding: 4px;
|
|
33783
|
+
background: white;
|
|
33784
|
+
border-radius: 4px;
|
|
33785
|
+
&:hover:enabled {
|
|
33786
|
+
background-color: rgba(0, 0, 0, 0.08);
|
|
33787
|
+
}
|
|
33788
|
+
}
|
|
33789
|
+
.o-separator {
|
|
33790
|
+
border-bottom: ${MENU_SEPARATOR_BORDER_WIDTH}px solid ${SEPARATOR_COLOR};
|
|
33791
|
+
margin-top: ${MENU_SEPARATOR_PADDING}px;
|
|
33792
|
+
margin-bottom: ${MENU_SEPARATOR_PADDING}px;
|
|
33793
|
+
}
|
|
33794
|
+
|
|
33795
|
+
.o-custom-selector {
|
|
33796
|
+
padding: ${PICKER_PADDING + 2}px ${PICKER_PADDING}px;
|
|
33797
|
+
position: relative;
|
|
33798
|
+
.o-gradient {
|
|
33799
|
+
margin-bottom: ${MAGNIFIER_EDGE / 2}px;
|
|
33800
|
+
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
33801
|
+
width: ${INNER_GRADIENT_WIDTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
33802
|
+
height: ${INNER_GRADIENT_HEIGHT + 2 * ITEM_BORDER_WIDTH}px;
|
|
33803
|
+
position: relative;
|
|
33804
|
+
}
|
|
33805
|
+
|
|
33806
|
+
.magnifier {
|
|
33807
|
+
height: ${MAGNIFIER_EDGE}px;
|
|
33808
|
+
width: ${MAGNIFIER_EDGE}px;
|
|
33809
|
+
border-radius: 50%;
|
|
33810
|
+
border: 2px solid #fff;
|
|
33811
|
+
box-shadow: 0px 0px 3px #c0c0c0;
|
|
33812
|
+
position: absolute;
|
|
33813
|
+
z-index: 2;
|
|
33814
|
+
}
|
|
33815
|
+
.saturation {
|
|
33816
|
+
background: linear-gradient(to right, #fff 0%, transparent 100%);
|
|
33817
|
+
}
|
|
33818
|
+
.lightness {
|
|
33819
|
+
background: linear-gradient(to top, #000 0%, transparent 100%);
|
|
33820
|
+
}
|
|
33821
|
+
.o-hue-picker {
|
|
33822
|
+
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
33823
|
+
width: 100%;
|
|
33824
|
+
height: 12px;
|
|
33825
|
+
border-radius: 4px;
|
|
33826
|
+
background: linear-gradient(
|
|
33827
|
+
to right,
|
|
33828
|
+
hsl(0 100% 50%) 0%,
|
|
33829
|
+
hsl(0.2turn 100% 50%) 20%,
|
|
33830
|
+
hsl(0.3turn 100% 50%) 30%,
|
|
33831
|
+
hsl(0.4turn 100% 50%) 40%,
|
|
33832
|
+
hsl(0.5turn 100% 50%) 50%,
|
|
33833
|
+
hsl(0.6turn 100% 50%) 60%,
|
|
33834
|
+
hsl(0.7turn 100% 50%) 70%,
|
|
33835
|
+
hsl(0.8turn 100% 50%) 80%,
|
|
33836
|
+
hsl(0.9turn 100% 50%) 90%,
|
|
33837
|
+
hsl(1turn 100% 50%) 100%
|
|
33838
|
+
);
|
|
33839
|
+
position: relative;
|
|
33840
|
+
cursor: crosshair;
|
|
33841
|
+
}
|
|
33842
|
+
.o-hue-slider {
|
|
33843
|
+
margin-top: -3px;
|
|
33844
|
+
}
|
|
33845
|
+
.o-custom-input-preview {
|
|
33846
|
+
padding: 2px 0px;
|
|
33847
|
+
display: flex;
|
|
33848
|
+
input {
|
|
33849
|
+
width: 50%;
|
|
33850
|
+
border-radius: 4px;
|
|
33851
|
+
padding: 4px 23px 4px 10px;
|
|
33852
|
+
height: 24px;
|
|
33853
|
+
border: 1px solid #c0c0c0;
|
|
33854
|
+
margin-right: 2px;
|
|
33855
|
+
}
|
|
33856
|
+
.o-wrong-color {
|
|
33857
|
+
/* FIXME bootstrap class instead? */
|
|
33858
|
+
outline-color: red;
|
|
33859
|
+
border-color: red;
|
|
33860
|
+
&:focus {
|
|
33861
|
+
outline-style: solid;
|
|
33862
|
+
outline-width: 1px;
|
|
33863
|
+
}
|
|
33864
|
+
}
|
|
33865
|
+
}
|
|
33866
|
+
.o-custom-input-buttons {
|
|
33867
|
+
padding: 2px 0px;
|
|
33868
|
+
display: flex;
|
|
33869
|
+
justify-content: end;
|
|
33870
|
+
}
|
|
33871
|
+
.o-color-preview {
|
|
33872
|
+
border: 1px solid #c0c0c0;
|
|
33873
|
+
border-radius: 4px;
|
|
33874
|
+
width: 50%;
|
|
33875
|
+
}
|
|
33876
|
+
}
|
|
33877
|
+
}
|
|
33878
|
+
`;
|
|
33879
|
+
class ColorPicker extends owl.Component {
|
|
33880
|
+
static template = "o-spreadsheet-ColorPicker";
|
|
33881
|
+
static props = {
|
|
33882
|
+
onColorPicked: Function,
|
|
33883
|
+
currentColor: { type: String, optional: true },
|
|
33884
|
+
maxHeight: { type: Number, optional: true },
|
|
33885
|
+
anchorRect: Object,
|
|
33886
|
+
disableNoColor: { type: Boolean, optional: true },
|
|
33887
|
+
};
|
|
33888
|
+
static defaultProps = { currentColor: "" };
|
|
33889
|
+
static components = { Popover };
|
|
33890
|
+
COLORS = COLOR_PICKER_DEFAULTS;
|
|
33891
|
+
state = owl.useState({
|
|
33892
|
+
showGradient: false,
|
|
33893
|
+
currentHslaColor: isColorValid(this.props.currentColor)
|
|
33894
|
+
? { ...hexToHSLA(this.props.currentColor), a: 1 }
|
|
33895
|
+
: { h: 0, s: 100, l: 100, a: 1 },
|
|
33896
|
+
customHexColor: isColorValid(this.props.currentColor) ? toHex(this.props.currentColor) : "",
|
|
33897
|
+
});
|
|
33898
|
+
get colorPickerStyle() {
|
|
33899
|
+
if (this.props.maxHeight !== undefined && this.props.maxHeight <= 0) {
|
|
33900
|
+
return cssPropertiesToCss({ display: "none" });
|
|
33901
|
+
}
|
|
33902
|
+
return "";
|
|
33903
|
+
}
|
|
33904
|
+
get popoverProps() {
|
|
33905
|
+
return {
|
|
33906
|
+
anchorRect: this.props.anchorRect,
|
|
33907
|
+
maxHeight: this.props.maxHeight,
|
|
33908
|
+
positioning: "bottom-left",
|
|
33909
|
+
verticalOffset: 0,
|
|
33910
|
+
};
|
|
33911
|
+
}
|
|
33912
|
+
get gradientHueStyle() {
|
|
33913
|
+
const hue = this.state.currentHslaColor?.h || 0;
|
|
33914
|
+
return cssPropertiesToCss({
|
|
33915
|
+
background: `hsl(${hue} 100% 50%)`,
|
|
33916
|
+
});
|
|
33917
|
+
}
|
|
33918
|
+
get sliderStyle() {
|
|
33919
|
+
const hue = this.state.currentHslaColor?.h || 0;
|
|
33920
|
+
const delta = Math.round((hue / 360) * INNER_GRADIENT_WIDTH);
|
|
33921
|
+
const left = clip(delta, 1, INNER_GRADIENT_WIDTH) - ICON_EDGE_LENGTH / 2;
|
|
33922
|
+
return cssPropertiesToCss({
|
|
33923
|
+
"margin-left": `${left}px`,
|
|
33924
|
+
});
|
|
33925
|
+
}
|
|
33926
|
+
get pointerStyle() {
|
|
33927
|
+
const { s, l } = this.state.currentHslaColor || { s: 0, l: 0 };
|
|
33928
|
+
const left = Math.round(INNER_GRADIENT_WIDTH * clip(s / 100, 0, 1));
|
|
33929
|
+
const top = Math.round(INNER_GRADIENT_HEIGHT * clip(1 - (2 * l) / (200 - s), 0, 1));
|
|
33930
|
+
return cssPropertiesToCss({
|
|
33931
|
+
left: `${-MAGNIFIER_EDGE / 2 + left}px`,
|
|
33932
|
+
top: `${-MAGNIFIER_EDGE / 2 + top}px`,
|
|
33933
|
+
background: hslaToHex(this.state.currentHslaColor),
|
|
33934
|
+
});
|
|
33935
|
+
}
|
|
33936
|
+
get colorPreviewStyle() {
|
|
33937
|
+
return cssPropertiesToCss({
|
|
33938
|
+
"background-color": hslaToHex(this.state.currentHslaColor),
|
|
33939
|
+
});
|
|
33940
|
+
}
|
|
33941
|
+
get checkmarkColor() {
|
|
33942
|
+
return chartFontColor(this.props.currentColor);
|
|
33943
|
+
}
|
|
33944
|
+
get isHexColorInputValid() {
|
|
33945
|
+
return !this.state.customHexColor || isColorValid(this.state.customHexColor);
|
|
33946
|
+
}
|
|
33947
|
+
setCustomGradient({ x, y }) {
|
|
33948
|
+
const offsetX = clip(x, 0, INNER_GRADIENT_WIDTH);
|
|
33949
|
+
const offsetY = clip(y, 0, INNER_GRADIENT_HEIGHT);
|
|
33950
|
+
const deltaX = offsetX / INNER_GRADIENT_WIDTH;
|
|
33951
|
+
const deltaY = offsetY / INNER_GRADIENT_HEIGHT;
|
|
33952
|
+
const s = 100 * deltaX;
|
|
33953
|
+
const l = 100 * (1 - deltaY) * (1 - 0.5 * deltaX);
|
|
33954
|
+
this.updateColor({ s, l });
|
|
33955
|
+
}
|
|
33956
|
+
setCustomHue(x) {
|
|
33957
|
+
// needs to be capped such that h is in [0°, 359°]
|
|
33958
|
+
const h = Math.round(clip((360 * x) / INNER_GRADIENT_WIDTH, 0, 359));
|
|
33959
|
+
this.updateColor({ h });
|
|
33960
|
+
}
|
|
33961
|
+
updateColor(newHsl) {
|
|
33962
|
+
this.state.currentHslaColor = { ...this.state.currentHslaColor, ...newHsl };
|
|
33963
|
+
this.state.customHexColor = hslaToHex(this.state.currentHslaColor);
|
|
33964
|
+
}
|
|
33965
|
+
onColorClick(color) {
|
|
33966
|
+
if (color) {
|
|
33967
|
+
this.props.onColorPicked(toHex(color));
|
|
33968
|
+
}
|
|
33969
|
+
}
|
|
33970
|
+
resetColor() {
|
|
33971
|
+
this.props.onColorPicked("");
|
|
33972
|
+
}
|
|
33973
|
+
toggleColorPicker() {
|
|
33974
|
+
this.state.showGradient = !this.state.showGradient;
|
|
33975
|
+
}
|
|
33976
|
+
dragGradientPointer(ev) {
|
|
33977
|
+
const initialGradientCoordinates = { x: ev.offsetX, y: ev.offsetY };
|
|
33978
|
+
this.setCustomGradient(initialGradientCoordinates);
|
|
33979
|
+
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
33980
|
+
const onMouseMove = (ev) => {
|
|
33981
|
+
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
33982
|
+
const deltaX = currentMousePosition.x - initialMousePosition.x;
|
|
33983
|
+
const deltaY = currentMousePosition.y - initialMousePosition.y;
|
|
33984
|
+
const currentGradientCoordinates = {
|
|
33985
|
+
x: initialGradientCoordinates.x + deltaX,
|
|
33986
|
+
y: initialGradientCoordinates.y + deltaY,
|
|
33987
|
+
};
|
|
33988
|
+
this.setCustomGradient(currentGradientCoordinates);
|
|
33989
|
+
};
|
|
33990
|
+
startDnd(onMouseMove, () => { });
|
|
33991
|
+
}
|
|
33992
|
+
dragHuePointer(ev) {
|
|
33993
|
+
const initialX = ev.offsetX;
|
|
33994
|
+
const initialMouseX = ev.clientX;
|
|
33995
|
+
this.setCustomHue(initialX);
|
|
33996
|
+
const onMouseMove = (ev) => {
|
|
33997
|
+
const currentMouseX = ev.clientX;
|
|
33998
|
+
const deltaX = currentMouseX - initialMouseX;
|
|
33999
|
+
const x = initialX + deltaX;
|
|
34000
|
+
this.setCustomHue(x);
|
|
34001
|
+
};
|
|
34002
|
+
startDnd(onMouseMove, () => { });
|
|
34003
|
+
}
|
|
34004
|
+
setHexColor(ev) {
|
|
34005
|
+
// only support HEX code input
|
|
34006
|
+
const val = ev.target.value.replace("##", "#").slice(0, 7);
|
|
34007
|
+
this.state.customHexColor = val;
|
|
34008
|
+
if (!isColorValid(val)) ;
|
|
34009
|
+
else {
|
|
34010
|
+
this.state.currentHslaColor = { ...hexToHSLA(val), a: 1 };
|
|
34011
|
+
}
|
|
34012
|
+
}
|
|
34013
|
+
addCustomColor(ev) {
|
|
34014
|
+
if (!isHSLAValid(this.state.currentHslaColor) || !isColorValid(this.state.customHexColor)) {
|
|
34015
|
+
return;
|
|
34016
|
+
}
|
|
34017
|
+
this.props.onColorPicked(toHex(this.state.customHexColor));
|
|
34018
|
+
}
|
|
34019
|
+
isSameColor(color1, color2) {
|
|
34020
|
+
return isSameColor(color1, color2);
|
|
34021
|
+
}
|
|
34022
|
+
}
|
|
34023
|
+
|
|
34024
|
+
class Section extends owl.Component {
|
|
34025
|
+
static template = "o_spreadsheet.Section";
|
|
34026
|
+
static props = {
|
|
34027
|
+
class: { type: String, optional: true },
|
|
34028
|
+
title: { type: String, optional: true },
|
|
34029
|
+
slots: Object,
|
|
34030
|
+
};
|
|
34031
|
+
}
|
|
34032
|
+
|
|
34033
|
+
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
34034
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
34035
|
+
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
34036
|
+
</svg>
|
|
34037
|
+
`;
|
|
34038
|
+
css /* scss */ `
|
|
34039
|
+
.o-round-color-picker-button {
|
|
34040
|
+
width: 20px;
|
|
34041
|
+
height: 20px;
|
|
34042
|
+
cursor: pointer;
|
|
34043
|
+
border: 1px solid ${GRAY_300};
|
|
34044
|
+
background-position: 1px 1px;
|
|
34045
|
+
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
34046
|
+
}
|
|
34047
|
+
`;
|
|
34048
|
+
class RoundColorPicker extends owl.Component {
|
|
34049
|
+
static template = "o-spreadsheet.RoundColorPicker";
|
|
34050
|
+
static components = { Section, ColorPicker };
|
|
34051
|
+
static props = {
|
|
34052
|
+
currentColor: { type: String, optional: true },
|
|
34053
|
+
title: { type: String, optional: true },
|
|
34054
|
+
onColorPicked: Function,
|
|
34055
|
+
disableNoColor: { type: Boolean, optional: true },
|
|
34056
|
+
};
|
|
34057
|
+
colorPickerButtonRef = owl.useRef("colorPickerButton");
|
|
34058
|
+
state;
|
|
34059
|
+
setup() {
|
|
34060
|
+
this.state = owl.useState({ pickerOpened: false });
|
|
34061
|
+
owl.useExternalListener(window, "click", this.closePicker);
|
|
34062
|
+
}
|
|
34063
|
+
closePicker() {
|
|
34064
|
+
this.state.pickerOpened = false;
|
|
34065
|
+
}
|
|
34066
|
+
togglePicker() {
|
|
34067
|
+
this.state.pickerOpened = !this.state.pickerOpened;
|
|
34068
|
+
}
|
|
34069
|
+
onColorPicked(color) {
|
|
34070
|
+
this.props.onColorPicked(color);
|
|
34071
|
+
this.state.pickerOpened = false;
|
|
34072
|
+
}
|
|
34073
|
+
get colorPickerAnchorRect() {
|
|
34074
|
+
const button = this.colorPickerButtonRef.el;
|
|
34075
|
+
return getBoundingRectAsPOJO(button);
|
|
34076
|
+
}
|
|
34077
|
+
get buttonStyle() {
|
|
34078
|
+
return cssPropertiesToCss({
|
|
34079
|
+
background: this.props.currentColor,
|
|
34080
|
+
});
|
|
34081
|
+
}
|
|
34082
|
+
}
|
|
34083
|
+
|
|
33626
34084
|
css /* scss */ `
|
|
33627
34085
|
.o-dv-list-item-delete {
|
|
33628
34086
|
color: #666666;
|
|
@@ -33631,7 +34089,7 @@ css /* scss */ `
|
|
|
33631
34089
|
`;
|
|
33632
34090
|
class ListCriterionForm extends CriterionForm {
|
|
33633
34091
|
static template = "o-spreadsheet-ListCriterionForm";
|
|
33634
|
-
static components = { CriterionInput };
|
|
34092
|
+
static components = { CriterionInput, RoundColorPicker };
|
|
33635
34093
|
state = owl.useState({
|
|
33636
34094
|
numberOfValues: Math.max(this.props.criterion.values.length, 2),
|
|
33637
34095
|
});
|
|
@@ -33639,7 +34097,7 @@ class ListCriterionForm extends CriterionForm {
|
|
|
33639
34097
|
super.setup();
|
|
33640
34098
|
const setupDefault = (props) => {
|
|
33641
34099
|
if (props.criterion.displayStyle === undefined) {
|
|
33642
|
-
this.updateCriterion({ displayStyle: "
|
|
34100
|
+
this.updateCriterion({ displayStyle: "chip" });
|
|
33643
34101
|
}
|
|
33644
34102
|
};
|
|
33645
34103
|
owl.onWillUpdateProps(setupDefault);
|
|
@@ -33650,6 +34108,11 @@ class ListCriterionForm extends CriterionForm {
|
|
|
33650
34108
|
values[index] = value;
|
|
33651
34109
|
this.updateCriterion({ values });
|
|
33652
34110
|
}
|
|
34111
|
+
onColorChanged(color, value) {
|
|
34112
|
+
const colors = { ...this.props.criterion.colors };
|
|
34113
|
+
colors[value] = color || undefined;
|
|
34114
|
+
this.updateCriterion({ colors });
|
|
34115
|
+
}
|
|
33653
34116
|
onAddAnotherValue() {
|
|
33654
34117
|
this.state.numberOfValues++;
|
|
33655
34118
|
}
|
|
@@ -33685,35 +34148,6 @@ class ListCriterionForm extends CriterionForm {
|
|
|
33685
34148
|
}
|
|
33686
34149
|
}
|
|
33687
34150
|
|
|
33688
|
-
/**
|
|
33689
|
-
* Start listening to pointer events and apply the given callbacks.
|
|
33690
|
-
*
|
|
33691
|
-
* @returns A function to remove the listeners.
|
|
33692
|
-
*/
|
|
33693
|
-
function startDnd(onPointerMove, onPointerUp) {
|
|
33694
|
-
const removeListeners = () => {
|
|
33695
|
-
window.removeEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33696
|
-
window.removeEventListener("dragstart", _onDragStart);
|
|
33697
|
-
window.removeEventListener("pointermove", onPointerMove);
|
|
33698
|
-
window.removeEventListener("wheel", onPointerMove);
|
|
33699
|
-
};
|
|
33700
|
-
const _onPointerUp = (ev) => {
|
|
33701
|
-
onPointerUp(ev);
|
|
33702
|
-
removeListeners();
|
|
33703
|
-
};
|
|
33704
|
-
function _onDragStart(ev) {
|
|
33705
|
-
ev.preventDefault();
|
|
33706
|
-
}
|
|
33707
|
-
window.addEventListener("pointerup", _onPointerUp, { capture: true });
|
|
33708
|
-
window.addEventListener("dragstart", _onDragStart);
|
|
33709
|
-
window.addEventListener("pointermove", onPointerMove);
|
|
33710
|
-
// mouse wheel on window is by default a passive event.
|
|
33711
|
-
// preventDefault() is not allowed in passive event handler.
|
|
33712
|
-
// https://chromestatus.com/feature/6662647093133312
|
|
33713
|
-
window.addEventListener("wheel", onPointerMove, { passive: false });
|
|
33714
|
-
return removeListeners;
|
|
33715
|
-
}
|
|
33716
|
-
|
|
33717
34151
|
function useDragAndDropListItems() {
|
|
33718
34152
|
let dndHelper;
|
|
33719
34153
|
const previousCursor = document.body.style.cursor;
|
|
@@ -34573,12 +35007,12 @@ class SelectionInput extends owl.Component {
|
|
|
34573
35007
|
|
|
34574
35008
|
class ValueInRangeCriterionForm extends CriterionForm {
|
|
34575
35009
|
static template = "o-spreadsheet-ValueInRangeCriterionForm";
|
|
34576
|
-
static components = { SelectionInput };
|
|
35010
|
+
static components = { RoundColorPicker, SelectionInput };
|
|
34577
35011
|
setup() {
|
|
34578
35012
|
super.setup();
|
|
34579
35013
|
const setupDefault = (props) => {
|
|
34580
35014
|
if (props.criterion.displayStyle === undefined) {
|
|
34581
|
-
this.updateCriterion({ displayStyle: "
|
|
35015
|
+
this.updateCriterion({ displayStyle: "chip" });
|
|
34582
35016
|
}
|
|
34583
35017
|
};
|
|
34584
35018
|
owl.onWillUpdateProps(setupDefault);
|
|
@@ -34591,6 +35025,16 @@ class ValueInRangeCriterionForm extends CriterionForm {
|
|
|
34591
35025
|
const displayStyle = ev.target.value;
|
|
34592
35026
|
this.updateCriterion({ displayStyle });
|
|
34593
35027
|
}
|
|
35028
|
+
onColorChanged(color, value) {
|
|
35029
|
+
const colors = { ...this.props.criterion.colors };
|
|
35030
|
+
colors[value] = color || undefined;
|
|
35031
|
+
this.updateCriterion({ colors });
|
|
35032
|
+
}
|
|
35033
|
+
get values() {
|
|
35034
|
+
const sheetId = this.env.model.getters.getActiveSheetId();
|
|
35035
|
+
const values = this.env.model.getters.getDataValidationRangeValues(sheetId, this.props.criterion);
|
|
35036
|
+
return new Set(values);
|
|
35037
|
+
}
|
|
34594
35038
|
}
|
|
34595
35039
|
|
|
34596
35040
|
const criterionCategoriesSequences = {
|
|
@@ -36169,19 +36613,44 @@ const RED_DOT = {
|
|
|
36169
36613
|
height: 512,
|
|
36170
36614
|
paths: [{ fillColor: "#E06666", path: DOT_PATH }],
|
|
36171
36615
|
};
|
|
36172
|
-
|
|
36173
|
-
|
|
36174
|
-
|
|
36175
|
-
|
|
36176
|
-
}
|
|
36177
|
-
|
|
36178
|
-
|
|
36179
|
-
|
|
36180
|
-
|
|
36181
|
-
|
|
36182
|
-
|
|
36183
|
-
|
|
36184
|
-
}
|
|
36616
|
+
function getCaretDownSvg(color) {
|
|
36617
|
+
return {
|
|
36618
|
+
width: 512,
|
|
36619
|
+
height: 512,
|
|
36620
|
+
paths: [{ fillColor: color.textColor || TEXT_BODY_MUTED, path: "M120 195 h270 l-135 130" }],
|
|
36621
|
+
};
|
|
36622
|
+
}
|
|
36623
|
+
function getHoveredCaretDownSvg(color) {
|
|
36624
|
+
return {
|
|
36625
|
+
width: 512,
|
|
36626
|
+
height: 512,
|
|
36627
|
+
paths: [
|
|
36628
|
+
{ fillColor: color.textColor || TEXT_BODY_MUTED, path: "M15 15 h482 v482 h-482" },
|
|
36629
|
+
{ fillColor: color.fillColor || "#fff", path: "M120 195 h270 l-135 130" },
|
|
36630
|
+
],
|
|
36631
|
+
};
|
|
36632
|
+
}
|
|
36633
|
+
const CHIP_CARET_DOWN_PATH = "M40 185 h270 l-135 128";
|
|
36634
|
+
function getChipSvg(chipStyle) {
|
|
36635
|
+
return {
|
|
36636
|
+
width: 512,
|
|
36637
|
+
height: 512,
|
|
36638
|
+
paths: [{ fillColor: chipStyle.textColor || TEXT_BODY_MUTED, path: CHIP_CARET_DOWN_PATH }],
|
|
36639
|
+
};
|
|
36640
|
+
}
|
|
36641
|
+
function getHoveredChipSvg(chipStyle) {
|
|
36642
|
+
return {
|
|
36643
|
+
width: 512,
|
|
36644
|
+
height: 512,
|
|
36645
|
+
paths: [
|
|
36646
|
+
{
|
|
36647
|
+
fillColor: chipStyle.textColor || TEXT_BODY_MUTED,
|
|
36648
|
+
path: "M0,225 A175,175 0 1,0 350,225 A175,175 0 1,0 0,225",
|
|
36649
|
+
},
|
|
36650
|
+
{ fillColor: chipStyle.fillColor || TEXT_BODY_MUTED, path: CHIP_CARET_DOWN_PATH },
|
|
36651
|
+
],
|
|
36652
|
+
};
|
|
36653
|
+
}
|
|
36185
36654
|
const CHECKBOX_UNCHECKED = {
|
|
36186
36655
|
width: 512,
|
|
36187
36656
|
height: 512,
|
|
@@ -41089,6 +41558,10 @@ const REMOVE_ROWS_ACTION = (env) => {
|
|
|
41089
41558
|
});
|
|
41090
41559
|
};
|
|
41091
41560
|
const CAN_REMOVE_COLUMNS_ROWS = (dimension, env) => {
|
|
41561
|
+
if ((dimension === "COL" && env.model.getters.getActiveRows().size > 0) ||
|
|
41562
|
+
(dimension === "ROW" && env.model.getters.getActiveCols().size > 0)) {
|
|
41563
|
+
return false;
|
|
41564
|
+
}
|
|
41092
41565
|
const sheetId = env.model.getters.getActiveSheetId();
|
|
41093
41566
|
const selectedElements = env.model.getters.getElementsFromSelection(dimension);
|
|
41094
41567
|
const includesAllVisibleHeaders = env.model.getters.checkElementsIncludeAllVisibleHeaders(sheetId, dimension, selectedElements);
|
|
@@ -42643,7 +43116,7 @@ const insertDropdown = {
|
|
|
42643
43116
|
criterion: {
|
|
42644
43117
|
type: "isValueInList",
|
|
42645
43118
|
values: [],
|
|
42646
|
-
displayStyle: "
|
|
43119
|
+
displayStyle: "chip",
|
|
42647
43120
|
},
|
|
42648
43121
|
},
|
|
42649
43122
|
});
|
|
@@ -44558,6 +45031,11 @@ class GridComposer extends owl.Component {
|
|
|
44558
45031
|
rect = this.defaultRect;
|
|
44559
45032
|
isEditing = false;
|
|
44560
45033
|
isCellReferenceVisible = false;
|
|
45034
|
+
currentEditedCell = {
|
|
45035
|
+
col: 0,
|
|
45036
|
+
row: 0,
|
|
45037
|
+
sheetId: this.env.model.getters.getActiveSheetId(),
|
|
45038
|
+
};
|
|
44561
45039
|
composerStore;
|
|
44562
45040
|
composerFocusStore;
|
|
44563
45041
|
composerInterface;
|
|
@@ -44682,12 +45160,17 @@ class GridComposer extends owl.Component {
|
|
|
44682
45160
|
if (!isEditing && this.composerFocusStore.activeComposer !== this.composerInterface) {
|
|
44683
45161
|
this.composerFocusStore.focusComposer(this.composerInterface, { focusMode: "inactive" });
|
|
44684
45162
|
}
|
|
45163
|
+
let shouldRecomputeRect = !deepEquals(this.currentEditedCell, this.composerStore.currentEditedCell);
|
|
44685
45164
|
if (this.isEditing !== isEditing) {
|
|
44686
45165
|
this.isEditing = isEditing;
|
|
44687
45166
|
if (!isEditing) {
|
|
44688
45167
|
this.rect = this.defaultRect;
|
|
44689
45168
|
return;
|
|
44690
45169
|
}
|
|
45170
|
+
this.currentEditedCell = this.composerStore.currentEditedCell;
|
|
45171
|
+
shouldRecomputeRect = true;
|
|
45172
|
+
}
|
|
45173
|
+
if (shouldRecomputeRect) {
|
|
44691
45174
|
const position = this.env.model.getters.getActivePosition();
|
|
44692
45175
|
const zone = this.env.model.getters.expandZone(position.sheetId, positionToZone(position));
|
|
44693
45176
|
this.rect = this.env.model.getters.getVisibleRect(zone);
|
|
@@ -45793,11 +46276,14 @@ class GridOverlay extends owl.Component {
|
|
|
45793
46276
|
onCellClicked(ev) {
|
|
45794
46277
|
const openedPopover = this.cellPopovers.persistentCellPopover;
|
|
45795
46278
|
const [col, row] = this.getCartesianCoordinates(ev);
|
|
46279
|
+
const clickedIcon = this.getInteractiveIconAtEvent(ev);
|
|
46280
|
+
if (clickedIcon) {
|
|
46281
|
+
this.env.model.selection.getBackToDefault();
|
|
46282
|
+
}
|
|
45796
46283
|
this.props.onCellClicked(col, row, {
|
|
45797
46284
|
expandZone: ev.shiftKey,
|
|
45798
46285
|
addZone: isCtrlKey(ev),
|
|
45799
46286
|
}, ev);
|
|
45800
|
-
const clickedIcon = this.getInteractiveIconAtEvent(ev);
|
|
45801
46287
|
if (clickedIcon?.onClick) {
|
|
45802
46288
|
clickedIcon.onClick(clickedIcon.position, this.env);
|
|
45803
46289
|
}
|
|
@@ -46662,6 +47148,19 @@ class GridRenderer {
|
|
|
46662
47148
|
const width = box.width * (percentage / 100);
|
|
46663
47149
|
ctx.fillRect(box.x, box.y, width, box.height);
|
|
46664
47150
|
}
|
|
47151
|
+
if (box?.chip) {
|
|
47152
|
+
ctx.save();
|
|
47153
|
+
ctx.beginPath();
|
|
47154
|
+
ctx.rect(box.x, box.y, box.width, box.height);
|
|
47155
|
+
ctx.clip();
|
|
47156
|
+
const chip = box.chip;
|
|
47157
|
+
ctx.fillStyle = chip.color;
|
|
47158
|
+
const radius = 10;
|
|
47159
|
+
ctx.beginPath();
|
|
47160
|
+
ctx.roundRect(chip.x, chip.y, chip.width, chip.height, radius);
|
|
47161
|
+
ctx.fill();
|
|
47162
|
+
ctx.restore();
|
|
47163
|
+
}
|
|
46665
47164
|
if (box.overlayColor) {
|
|
46666
47165
|
ctx.fillStyle = box.overlayColor;
|
|
46667
47166
|
ctx.fillRect(box.x, box.y, box.width, box.height);
|
|
@@ -46801,19 +47300,6 @@ class GridRenderer {
|
|
|
46801
47300
|
ctx.font = font;
|
|
46802
47301
|
}
|
|
46803
47302
|
ctx.fillStyle = style.textColor || "#000";
|
|
46804
|
-
// compute horizontal align start point parameter
|
|
46805
|
-
let x = box.x;
|
|
46806
|
-
if (align === "left") {
|
|
46807
|
-
const leftIconSize = box.icons.left ? box.icons.left.size + box.icons.left.margin : 0;
|
|
46808
|
-
x += MIN_CELL_TEXT_MARGIN + leftIconSize;
|
|
46809
|
-
}
|
|
46810
|
-
else if (align === "right") {
|
|
46811
|
-
const rightIconSize = box.icons.right ? box.icons.right.size + box.icons.right.margin : 0;
|
|
46812
|
-
x += box.width - MIN_CELL_TEXT_MARGIN - rightIconSize;
|
|
46813
|
-
}
|
|
46814
|
-
else {
|
|
46815
|
-
x += box.width / 2;
|
|
46816
|
-
}
|
|
46817
47303
|
// horizontal align text direction
|
|
46818
47304
|
ctx.textAlign = align;
|
|
46819
47305
|
// clip rect if needed
|
|
@@ -46824,15 +47310,13 @@ class GridRenderer {
|
|
|
46824
47310
|
ctx.rect(x, y, width, height);
|
|
46825
47311
|
ctx.clip();
|
|
46826
47312
|
}
|
|
46827
|
-
|
|
46828
|
-
|
|
46829
|
-
const numberOfLines = box.content.textLines.length;
|
|
46830
|
-
let y = this.getters.computeTextYCoordinate(box, textLineHeight, style.verticalAlign, numberOfLines);
|
|
47313
|
+
const x = box.content.x;
|
|
47314
|
+
let y = box.content.y;
|
|
46831
47315
|
// use the horizontal and the vertical start points to:
|
|
46832
47316
|
// fill text / fill strikethrough / fill underline
|
|
46833
47317
|
for (const brokenLine of box.content.textLines) {
|
|
46834
|
-
drawDecoratedText(ctx, brokenLine, { x
|
|
46835
|
-
y += MIN_CELL_TEXT_MARGIN +
|
|
47318
|
+
drawDecoratedText(ctx, brokenLine, { x, y }, style.underline, style.strikethrough);
|
|
47319
|
+
y += MIN_CELL_TEXT_MARGIN + box.content.fontSizePx;
|
|
46836
47320
|
}
|
|
46837
47321
|
if (box.clipRect) {
|
|
46838
47322
|
ctx.restore();
|
|
@@ -47067,11 +47551,15 @@ class GridRenderer {
|
|
|
47067
47551
|
const showFormula = this.getters.shouldShowFormulas();
|
|
47068
47552
|
const { x, y, width, height } = this.getters.getRect(zone);
|
|
47069
47553
|
const { verticalAlign } = this.getters.getCellStyle(position);
|
|
47554
|
+
const chipStyle = this.getters.getDataValidationChipStyle(position);
|
|
47070
47555
|
let style = this.getters.getCellComputedStyle(position);
|
|
47071
47556
|
if (this.fingerprints.isEnabled) {
|
|
47072
47557
|
const fingerprintColor = this.fingerprints.colors.get(position);
|
|
47073
47558
|
style = { ...style, fillColor: fingerprintColor };
|
|
47074
47559
|
}
|
|
47560
|
+
if (chipStyle?.textColor) {
|
|
47561
|
+
style = { ...style, textColor: chipStyle.textColor };
|
|
47562
|
+
}
|
|
47075
47563
|
const dataBarFill = this.fingerprints.isEnabled
|
|
47076
47564
|
? undefined
|
|
47077
47565
|
: this.getters.getConditionalDataBar(position);
|
|
@@ -47105,22 +47593,55 @@ class GridRenderer {
|
|
|
47105
47593
|
const maxWidth = width - 2 * MIN_CELL_TEXT_MARGIN;
|
|
47106
47594
|
const multiLineText = this.getters.getCellMultiLineText(position, { maxWidth, wrapText });
|
|
47107
47595
|
const textWidth = Math.max(...multiLineText.map((line) => this.getters.getTextWidth(line, style) + MIN_CELL_TEXT_MARGIN));
|
|
47596
|
+
const chipMargin = chipStyle ? DATA_VALIDATION_CHIP_MARGIN : 0;
|
|
47108
47597
|
const leftIconWidth = box.icons.left ? box.icons.left.size + box.icons.left.margin : 0;
|
|
47598
|
+
const leftMargin = leftIconWidth + chipMargin;
|
|
47109
47599
|
const rightIconWidth = box.icons.right ? box.icons.right.size + box.icons.right.margin : 0;
|
|
47110
|
-
const
|
|
47600
|
+
const rightMargin = rightIconWidth + chipMargin;
|
|
47601
|
+
const contentWidth = leftMargin + textWidth + rightMargin;
|
|
47111
47602
|
const align = this.computeCellAlignment(position, contentWidth > width);
|
|
47603
|
+
// compute vertical align start point parameter:
|
|
47604
|
+
const numberOfLines = multiLineText.length;
|
|
47605
|
+
const contentY = Math.round(this.getters.computeTextYCoordinate(box, fontSizePX, style.verticalAlign, numberOfLines));
|
|
47606
|
+
// compute horizontal align start point parameter
|
|
47607
|
+
let contentX = box.x;
|
|
47608
|
+
if (align === "left") {
|
|
47609
|
+
contentX += MIN_CELL_TEXT_MARGIN + leftMargin;
|
|
47610
|
+
}
|
|
47611
|
+
else if (align === "right") {
|
|
47612
|
+
contentX += box.width - MIN_CELL_TEXT_MARGIN - rightMargin;
|
|
47613
|
+
}
|
|
47614
|
+
else {
|
|
47615
|
+
contentX += box.width / 2;
|
|
47616
|
+
}
|
|
47617
|
+
contentX = Math.round(contentX);
|
|
47618
|
+
const textHeight = computeTextLinesHeight(fontSizePX, numberOfLines);
|
|
47112
47619
|
box.content = {
|
|
47113
47620
|
textLines: multiLineText,
|
|
47114
47621
|
width: wrapping === "overflow" ? textWidth : width,
|
|
47115
47622
|
align,
|
|
47623
|
+
x: contentX,
|
|
47624
|
+
y: contentY,
|
|
47625
|
+
fontSizePx: fontSizePX,
|
|
47116
47626
|
};
|
|
47627
|
+
if (chipStyle?.fillColor) {
|
|
47628
|
+
const chipMarginLeft = leftMargin;
|
|
47629
|
+
const chipMarginRight = DATA_VALIDATION_CHIP_MARGIN;
|
|
47630
|
+
box.chip = {
|
|
47631
|
+
color: chipStyle.fillColor,
|
|
47632
|
+
width: box.width - chipMarginLeft - chipMarginRight,
|
|
47633
|
+
height: textHeight + 2,
|
|
47634
|
+
x: box.x + chipMarginLeft,
|
|
47635
|
+
y: contentY - 2,
|
|
47636
|
+
};
|
|
47637
|
+
}
|
|
47117
47638
|
/** ClipRect */
|
|
47118
47639
|
const isOverflowing = contentWidth > width || fontSizePX > height;
|
|
47119
|
-
if (box.icons.left || box.icons.right) {
|
|
47640
|
+
if (box.icons.left || box.icons.right || box.chip) {
|
|
47120
47641
|
box.clipRect = {
|
|
47121
|
-
x: box.x +
|
|
47642
|
+
x: box.x + leftMargin,
|
|
47122
47643
|
y: box.y,
|
|
47123
|
-
width: Math.max(0, width -
|
|
47644
|
+
width: Math.max(0, width - leftMargin - rightMargin),
|
|
47124
47645
|
height,
|
|
47125
47646
|
};
|
|
47126
47647
|
}
|
|
@@ -47820,15 +48341,6 @@ class Selection extends owl.Component {
|
|
|
47820
48341
|
}
|
|
47821
48342
|
}
|
|
47822
48343
|
|
|
47823
|
-
class Section extends owl.Component {
|
|
47824
|
-
static template = "o_spreadsheet.Section";
|
|
47825
|
-
static props = {
|
|
47826
|
-
class: { type: String, optional: true },
|
|
47827
|
-
title: { type: String, optional: true },
|
|
47828
|
-
slots: Object,
|
|
47829
|
-
};
|
|
47830
|
-
}
|
|
47831
|
-
|
|
47832
48344
|
class ChartDataSeries extends owl.Component {
|
|
47833
48345
|
static template = "o-spreadsheet.ChartDataSeries";
|
|
47834
48346
|
static components = { SelectionInput, Section };
|
|
@@ -48377,325 +48889,6 @@ class ActionButton extends owl.Component {
|
|
|
48377
48889
|
}
|
|
48378
48890
|
}
|
|
48379
48891
|
|
|
48380
|
-
const LINE_VERTICAL_PADDING = 1;
|
|
48381
|
-
const PICKER_PADDING = 8;
|
|
48382
|
-
const ITEM_BORDER_WIDTH = 1;
|
|
48383
|
-
const ITEM_EDGE_LENGTH = 18;
|
|
48384
|
-
const ITEMS_PER_LINE = 10;
|
|
48385
|
-
const MAGNIFIER_EDGE = 16;
|
|
48386
|
-
const ITEM_GAP = 2;
|
|
48387
|
-
const CONTENT_WIDTH = ITEMS_PER_LINE * (ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH) + (ITEMS_PER_LINE - 1) * ITEM_GAP;
|
|
48388
|
-
const INNER_GRADIENT_WIDTH = CONTENT_WIDTH - 2 * ITEM_BORDER_WIDTH;
|
|
48389
|
-
const INNER_GRADIENT_HEIGHT = CONTENT_WIDTH - 30 - 2 * ITEM_BORDER_WIDTH;
|
|
48390
|
-
const CONTAINER_WIDTH = CONTENT_WIDTH + 2 * PICKER_PADDING;
|
|
48391
|
-
css /* scss */ `
|
|
48392
|
-
.o-color-picker {
|
|
48393
|
-
padding: ${PICKER_PADDING}px 0;
|
|
48394
|
-
/* FIXME: this is useless, overiden by the popover container */
|
|
48395
|
-
box-shadow: 1px 2px 5px 2px rgba(51, 51, 51, 0.15);
|
|
48396
|
-
background-color: white;
|
|
48397
|
-
line-height: 1.2;
|
|
48398
|
-
overflow-y: auto;
|
|
48399
|
-
overflow-x: hidden;
|
|
48400
|
-
width: ${CONTAINER_WIDTH}px;
|
|
48401
|
-
|
|
48402
|
-
.o-color-picker-section-name {
|
|
48403
|
-
margin: 0px ${ITEM_BORDER_WIDTH}px;
|
|
48404
|
-
padding: 4px ${PICKER_PADDING}px;
|
|
48405
|
-
}
|
|
48406
|
-
.colors-grid {
|
|
48407
|
-
display: grid;
|
|
48408
|
-
padding: ${LINE_VERTICAL_PADDING}px ${PICKER_PADDING}px;
|
|
48409
|
-
grid-template-columns: repeat(${ITEMS_PER_LINE}, 1fr);
|
|
48410
|
-
grid-gap: ${ITEM_GAP}px;
|
|
48411
|
-
}
|
|
48412
|
-
.o-color-picker-toggler-button {
|
|
48413
|
-
display: flex;
|
|
48414
|
-
.o-color-picker-toggler-sign {
|
|
48415
|
-
display: flex;
|
|
48416
|
-
margin: auto auto;
|
|
48417
|
-
width: 55%;
|
|
48418
|
-
height: 55%;
|
|
48419
|
-
.o-icon {
|
|
48420
|
-
width: 100%;
|
|
48421
|
-
height: 100%;
|
|
48422
|
-
}
|
|
48423
|
-
}
|
|
48424
|
-
}
|
|
48425
|
-
.o-color-picker-line-item {
|
|
48426
|
-
width: ${ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
48427
|
-
height: ${ITEM_EDGE_LENGTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
48428
|
-
margin: 0px;
|
|
48429
|
-
border-radius: 50px;
|
|
48430
|
-
border: ${ITEM_BORDER_WIDTH}px solid #666666;
|
|
48431
|
-
padding: 0px;
|
|
48432
|
-
font-size: 16px;
|
|
48433
|
-
background: white;
|
|
48434
|
-
&:hover {
|
|
48435
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
48436
|
-
outline: 1px solid gray;
|
|
48437
|
-
cursor: pointer;
|
|
48438
|
-
}
|
|
48439
|
-
}
|
|
48440
|
-
.o-buttons {
|
|
48441
|
-
padding: ${PICKER_PADDING}px;
|
|
48442
|
-
display: flex;
|
|
48443
|
-
.o-cancel {
|
|
48444
|
-
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
48445
|
-
width: 100%;
|
|
48446
|
-
padding: 5px;
|
|
48447
|
-
font-size: 14px;
|
|
48448
|
-
background: white;
|
|
48449
|
-
border-radius: 4px;
|
|
48450
|
-
&:hover:enabled {
|
|
48451
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
48452
|
-
}
|
|
48453
|
-
}
|
|
48454
|
-
}
|
|
48455
|
-
.o-add-button {
|
|
48456
|
-
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
48457
|
-
padding: 4px;
|
|
48458
|
-
background: white;
|
|
48459
|
-
border-radius: 4px;
|
|
48460
|
-
&:hover:enabled {
|
|
48461
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
48462
|
-
}
|
|
48463
|
-
}
|
|
48464
|
-
.o-separator {
|
|
48465
|
-
border-bottom: ${MENU_SEPARATOR_BORDER_WIDTH}px solid ${SEPARATOR_COLOR};
|
|
48466
|
-
margin-top: ${MENU_SEPARATOR_PADDING}px;
|
|
48467
|
-
margin-bottom: ${MENU_SEPARATOR_PADDING}px;
|
|
48468
|
-
}
|
|
48469
|
-
|
|
48470
|
-
.o-custom-selector {
|
|
48471
|
-
padding: ${PICKER_PADDING + 2}px ${PICKER_PADDING}px;
|
|
48472
|
-
position: relative;
|
|
48473
|
-
.o-gradient {
|
|
48474
|
-
margin-bottom: ${MAGNIFIER_EDGE / 2}px;
|
|
48475
|
-
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
48476
|
-
width: ${INNER_GRADIENT_WIDTH + 2 * ITEM_BORDER_WIDTH}px;
|
|
48477
|
-
height: ${INNER_GRADIENT_HEIGHT + 2 * ITEM_BORDER_WIDTH}px;
|
|
48478
|
-
position: relative;
|
|
48479
|
-
}
|
|
48480
|
-
|
|
48481
|
-
.magnifier {
|
|
48482
|
-
height: ${MAGNIFIER_EDGE}px;
|
|
48483
|
-
width: ${MAGNIFIER_EDGE}px;
|
|
48484
|
-
border-radius: 50%;
|
|
48485
|
-
border: 2px solid #fff;
|
|
48486
|
-
box-shadow: 0px 0px 3px #c0c0c0;
|
|
48487
|
-
position: absolute;
|
|
48488
|
-
z-index: 2;
|
|
48489
|
-
}
|
|
48490
|
-
.saturation {
|
|
48491
|
-
background: linear-gradient(to right, #fff 0%, transparent 100%);
|
|
48492
|
-
}
|
|
48493
|
-
.lightness {
|
|
48494
|
-
background: linear-gradient(to top, #000 0%, transparent 100%);
|
|
48495
|
-
}
|
|
48496
|
-
.o-hue-picker {
|
|
48497
|
-
border: ${ITEM_BORDER_WIDTH}px solid #c0c0c0;
|
|
48498
|
-
width: 100%;
|
|
48499
|
-
height: 12px;
|
|
48500
|
-
border-radius: 4px;
|
|
48501
|
-
background: linear-gradient(
|
|
48502
|
-
to right,
|
|
48503
|
-
hsl(0 100% 50%) 0%,
|
|
48504
|
-
hsl(0.2turn 100% 50%) 20%,
|
|
48505
|
-
hsl(0.3turn 100% 50%) 30%,
|
|
48506
|
-
hsl(0.4turn 100% 50%) 40%,
|
|
48507
|
-
hsl(0.5turn 100% 50%) 50%,
|
|
48508
|
-
hsl(0.6turn 100% 50%) 60%,
|
|
48509
|
-
hsl(0.7turn 100% 50%) 70%,
|
|
48510
|
-
hsl(0.8turn 100% 50%) 80%,
|
|
48511
|
-
hsl(0.9turn 100% 50%) 90%,
|
|
48512
|
-
hsl(1turn 100% 50%) 100%
|
|
48513
|
-
);
|
|
48514
|
-
position: relative;
|
|
48515
|
-
cursor: crosshair;
|
|
48516
|
-
}
|
|
48517
|
-
.o-hue-slider {
|
|
48518
|
-
margin-top: -3px;
|
|
48519
|
-
}
|
|
48520
|
-
.o-custom-input-preview {
|
|
48521
|
-
padding: 2px 0px;
|
|
48522
|
-
display: flex;
|
|
48523
|
-
input {
|
|
48524
|
-
width: 50%;
|
|
48525
|
-
border-radius: 4px;
|
|
48526
|
-
padding: 4px 23px 4px 10px;
|
|
48527
|
-
height: 24px;
|
|
48528
|
-
border: 1px solid #c0c0c0;
|
|
48529
|
-
margin-right: 2px;
|
|
48530
|
-
}
|
|
48531
|
-
.o-wrong-color {
|
|
48532
|
-
/* FIXME bootstrap class instead? */
|
|
48533
|
-
outline-color: red;
|
|
48534
|
-
border-color: red;
|
|
48535
|
-
&:focus {
|
|
48536
|
-
outline-style: solid;
|
|
48537
|
-
outline-width: 1px;
|
|
48538
|
-
}
|
|
48539
|
-
}
|
|
48540
|
-
}
|
|
48541
|
-
.o-custom-input-buttons {
|
|
48542
|
-
padding: 2px 0px;
|
|
48543
|
-
display: flex;
|
|
48544
|
-
justify-content: end;
|
|
48545
|
-
}
|
|
48546
|
-
.o-color-preview {
|
|
48547
|
-
border: 1px solid #c0c0c0;
|
|
48548
|
-
border-radius: 4px;
|
|
48549
|
-
width: 50%;
|
|
48550
|
-
}
|
|
48551
|
-
}
|
|
48552
|
-
}
|
|
48553
|
-
`;
|
|
48554
|
-
class ColorPicker extends owl.Component {
|
|
48555
|
-
static template = "o-spreadsheet-ColorPicker";
|
|
48556
|
-
static props = {
|
|
48557
|
-
onColorPicked: Function,
|
|
48558
|
-
currentColor: { type: String, optional: true },
|
|
48559
|
-
maxHeight: { type: Number, optional: true },
|
|
48560
|
-
anchorRect: Object,
|
|
48561
|
-
disableNoColor: { type: Boolean, optional: true },
|
|
48562
|
-
};
|
|
48563
|
-
static defaultProps = { currentColor: "" };
|
|
48564
|
-
static components = { Popover };
|
|
48565
|
-
COLORS = COLOR_PICKER_DEFAULTS;
|
|
48566
|
-
state = owl.useState({
|
|
48567
|
-
showGradient: false,
|
|
48568
|
-
currentHslaColor: isColorValid(this.props.currentColor)
|
|
48569
|
-
? { ...hexToHSLA(this.props.currentColor), a: 1 }
|
|
48570
|
-
: { h: 0, s: 100, l: 100, a: 1 },
|
|
48571
|
-
customHexColor: isColorValid(this.props.currentColor) ? toHex(this.props.currentColor) : "",
|
|
48572
|
-
});
|
|
48573
|
-
get colorPickerStyle() {
|
|
48574
|
-
if (this.props.maxHeight !== undefined && this.props.maxHeight <= 0) {
|
|
48575
|
-
return cssPropertiesToCss({ display: "none" });
|
|
48576
|
-
}
|
|
48577
|
-
return "";
|
|
48578
|
-
}
|
|
48579
|
-
get popoverProps() {
|
|
48580
|
-
return {
|
|
48581
|
-
anchorRect: this.props.anchorRect,
|
|
48582
|
-
maxHeight: this.props.maxHeight,
|
|
48583
|
-
positioning: "bottom-left",
|
|
48584
|
-
verticalOffset: 0,
|
|
48585
|
-
};
|
|
48586
|
-
}
|
|
48587
|
-
get gradientHueStyle() {
|
|
48588
|
-
const hue = this.state.currentHslaColor?.h || 0;
|
|
48589
|
-
return cssPropertiesToCss({
|
|
48590
|
-
background: `hsl(${hue} 100% 50%)`,
|
|
48591
|
-
});
|
|
48592
|
-
}
|
|
48593
|
-
get sliderStyle() {
|
|
48594
|
-
const hue = this.state.currentHslaColor?.h || 0;
|
|
48595
|
-
const delta = Math.round((hue / 360) * INNER_GRADIENT_WIDTH);
|
|
48596
|
-
const left = clip(delta, 1, INNER_GRADIENT_WIDTH) - ICON_EDGE_LENGTH / 2;
|
|
48597
|
-
return cssPropertiesToCss({
|
|
48598
|
-
"margin-left": `${left}px`,
|
|
48599
|
-
});
|
|
48600
|
-
}
|
|
48601
|
-
get pointerStyle() {
|
|
48602
|
-
const { s, l } = this.state.currentHslaColor || { s: 0, l: 0 };
|
|
48603
|
-
const left = Math.round(INNER_GRADIENT_WIDTH * clip(s / 100, 0, 1));
|
|
48604
|
-
const top = Math.round(INNER_GRADIENT_HEIGHT * clip(1 - (2 * l) / (200 - s), 0, 1));
|
|
48605
|
-
return cssPropertiesToCss({
|
|
48606
|
-
left: `${-MAGNIFIER_EDGE / 2 + left}px`,
|
|
48607
|
-
top: `${-MAGNIFIER_EDGE / 2 + top}px`,
|
|
48608
|
-
background: hslaToHex(this.state.currentHslaColor),
|
|
48609
|
-
});
|
|
48610
|
-
}
|
|
48611
|
-
get colorPreviewStyle() {
|
|
48612
|
-
return cssPropertiesToCss({
|
|
48613
|
-
"background-color": hslaToHex(this.state.currentHslaColor),
|
|
48614
|
-
});
|
|
48615
|
-
}
|
|
48616
|
-
get checkmarkColor() {
|
|
48617
|
-
return chartFontColor(this.props.currentColor);
|
|
48618
|
-
}
|
|
48619
|
-
get isHexColorInputValid() {
|
|
48620
|
-
return !this.state.customHexColor || isColorValid(this.state.customHexColor);
|
|
48621
|
-
}
|
|
48622
|
-
setCustomGradient({ x, y }) {
|
|
48623
|
-
const offsetX = clip(x, 0, INNER_GRADIENT_WIDTH);
|
|
48624
|
-
const offsetY = clip(y, 0, INNER_GRADIENT_HEIGHT);
|
|
48625
|
-
const deltaX = offsetX / INNER_GRADIENT_WIDTH;
|
|
48626
|
-
const deltaY = offsetY / INNER_GRADIENT_HEIGHT;
|
|
48627
|
-
const s = 100 * deltaX;
|
|
48628
|
-
const l = 100 * (1 - deltaY) * (1 - 0.5 * deltaX);
|
|
48629
|
-
this.updateColor({ s, l });
|
|
48630
|
-
}
|
|
48631
|
-
setCustomHue(x) {
|
|
48632
|
-
// needs to be capped such that h is in [0°, 359°]
|
|
48633
|
-
const h = Math.round(clip((360 * x) / INNER_GRADIENT_WIDTH, 0, 359));
|
|
48634
|
-
this.updateColor({ h });
|
|
48635
|
-
}
|
|
48636
|
-
updateColor(newHsl) {
|
|
48637
|
-
this.state.currentHslaColor = { ...this.state.currentHslaColor, ...newHsl };
|
|
48638
|
-
this.state.customHexColor = hslaToHex(this.state.currentHslaColor);
|
|
48639
|
-
}
|
|
48640
|
-
onColorClick(color) {
|
|
48641
|
-
if (color) {
|
|
48642
|
-
this.props.onColorPicked(toHex(color));
|
|
48643
|
-
}
|
|
48644
|
-
}
|
|
48645
|
-
resetColor() {
|
|
48646
|
-
this.props.onColorPicked("");
|
|
48647
|
-
}
|
|
48648
|
-
toggleColorPicker() {
|
|
48649
|
-
this.state.showGradient = !this.state.showGradient;
|
|
48650
|
-
}
|
|
48651
|
-
dragGradientPointer(ev) {
|
|
48652
|
-
const initialGradientCoordinates = { x: ev.offsetX, y: ev.offsetY };
|
|
48653
|
-
this.setCustomGradient(initialGradientCoordinates);
|
|
48654
|
-
const initialMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
48655
|
-
const onMouseMove = (ev) => {
|
|
48656
|
-
const currentMousePosition = { x: ev.clientX, y: ev.clientY };
|
|
48657
|
-
const deltaX = currentMousePosition.x - initialMousePosition.x;
|
|
48658
|
-
const deltaY = currentMousePosition.y - initialMousePosition.y;
|
|
48659
|
-
const currentGradientCoordinates = {
|
|
48660
|
-
x: initialGradientCoordinates.x + deltaX,
|
|
48661
|
-
y: initialGradientCoordinates.y + deltaY,
|
|
48662
|
-
};
|
|
48663
|
-
this.setCustomGradient(currentGradientCoordinates);
|
|
48664
|
-
};
|
|
48665
|
-
startDnd(onMouseMove, () => { });
|
|
48666
|
-
}
|
|
48667
|
-
dragHuePointer(ev) {
|
|
48668
|
-
const initialX = ev.offsetX;
|
|
48669
|
-
const initialMouseX = ev.clientX;
|
|
48670
|
-
this.setCustomHue(initialX);
|
|
48671
|
-
const onMouseMove = (ev) => {
|
|
48672
|
-
const currentMouseX = ev.clientX;
|
|
48673
|
-
const deltaX = currentMouseX - initialMouseX;
|
|
48674
|
-
const x = initialX + deltaX;
|
|
48675
|
-
this.setCustomHue(x);
|
|
48676
|
-
};
|
|
48677
|
-
startDnd(onMouseMove, () => { });
|
|
48678
|
-
}
|
|
48679
|
-
setHexColor(ev) {
|
|
48680
|
-
// only support HEX code input
|
|
48681
|
-
const val = ev.target.value.replace("##", "#").slice(0, 7);
|
|
48682
|
-
this.state.customHexColor = val;
|
|
48683
|
-
if (!isColorValid(val)) ;
|
|
48684
|
-
else {
|
|
48685
|
-
this.state.currentHslaColor = { ...hexToHSLA(val), a: 1 };
|
|
48686
|
-
}
|
|
48687
|
-
}
|
|
48688
|
-
addCustomColor(ev) {
|
|
48689
|
-
if (!isHSLAValid(this.state.currentHslaColor) || !isColorValid(this.state.customHexColor)) {
|
|
48690
|
-
return;
|
|
48691
|
-
}
|
|
48692
|
-
this.props.onColorPicked(toHex(this.state.customHexColor));
|
|
48693
|
-
}
|
|
48694
|
-
isSameColor(color1, color2) {
|
|
48695
|
-
return isSameColor(color1, color2);
|
|
48696
|
-
}
|
|
48697
|
-
}
|
|
48698
|
-
|
|
48699
48892
|
css /* scss */ `
|
|
48700
48893
|
.o-color-picker-widget {
|
|
48701
48894
|
display: flex;
|
|
@@ -49163,57 +49356,6 @@ class RadioSelection extends owl.Component {
|
|
|
49163
49356
|
};
|
|
49164
49357
|
}
|
|
49165
49358
|
|
|
49166
|
-
const TRANSPARENT_BACKGROUND_SVG = /*xml*/ `
|
|
49167
|
-
<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10">
|
|
49168
|
-
<path fill="#d9d9d9" d="M5 5h5v5H5zH0V0h5"/>
|
|
49169
|
-
</svg>
|
|
49170
|
-
`;
|
|
49171
|
-
css /* scss */ `
|
|
49172
|
-
.o-round-color-picker-button {
|
|
49173
|
-
width: 20px;
|
|
49174
|
-
height: 20px;
|
|
49175
|
-
cursor: pointer;
|
|
49176
|
-
border: 1px solid ${GRAY_300};
|
|
49177
|
-
background-position: 1px 1px;
|
|
49178
|
-
background-image: url("data:image/svg+xml,${encodeURIComponent(TRANSPARENT_BACKGROUND_SVG)}");
|
|
49179
|
-
}
|
|
49180
|
-
`;
|
|
49181
|
-
class RoundColorPicker extends owl.Component {
|
|
49182
|
-
static template = "o-spreadsheet.RoundColorPicker";
|
|
49183
|
-
static components = { Section, ColorPicker };
|
|
49184
|
-
static props = {
|
|
49185
|
-
currentColor: { type: String, optional: true },
|
|
49186
|
-
title: { type: String, optional: true },
|
|
49187
|
-
onColorPicked: Function,
|
|
49188
|
-
disableNoColor: { type: Boolean, optional: true },
|
|
49189
|
-
};
|
|
49190
|
-
colorPickerButtonRef = owl.useRef("colorPickerButton");
|
|
49191
|
-
state;
|
|
49192
|
-
setup() {
|
|
49193
|
-
this.state = owl.useState({ pickerOpened: false });
|
|
49194
|
-
owl.useExternalListener(window, "click", this.closePicker);
|
|
49195
|
-
}
|
|
49196
|
-
closePicker() {
|
|
49197
|
-
this.state.pickerOpened = false;
|
|
49198
|
-
}
|
|
49199
|
-
togglePicker() {
|
|
49200
|
-
this.state.pickerOpened = !this.state.pickerOpened;
|
|
49201
|
-
}
|
|
49202
|
-
onColorPicked(color) {
|
|
49203
|
-
this.props.onColorPicked(color);
|
|
49204
|
-
this.state.pickerOpened = false;
|
|
49205
|
-
}
|
|
49206
|
-
get colorPickerAnchorRect() {
|
|
49207
|
-
const button = this.colorPickerButtonRef.el;
|
|
49208
|
-
return getBoundingRectAsPOJO(button);
|
|
49209
|
-
}
|
|
49210
|
-
get buttonStyle() {
|
|
49211
|
-
return cssPropertiesToCss({
|
|
49212
|
-
background: this.props.currentColor,
|
|
49213
|
-
});
|
|
49214
|
-
}
|
|
49215
|
-
}
|
|
49216
|
-
|
|
49217
49359
|
class GeneralDesignEditor extends owl.Component {
|
|
49218
49360
|
static template = "o-spreadsheet-GeneralDesignEditor";
|
|
49219
49361
|
static components = {
|
|
@@ -59544,7 +59686,7 @@ class DataValidationPlugin extends CorePlugin {
|
|
|
59544
59686
|
if (!rule)
|
|
59545
59687
|
return false;
|
|
59546
59688
|
return ((rule.criterion.type === "isValueInList" || rule.criterion.type === "isValueInRange") &&
|
|
59547
|
-
rule.criterion.displayStyle === "arrow");
|
|
59689
|
+
(rule.criterion.displayStyle === "arrow" || rule.criterion.displayStyle === "chip"));
|
|
59548
59690
|
}
|
|
59549
59691
|
addDataValidationRule(sheetId, newRule) {
|
|
59550
59692
|
const rules = this.rules[sheetId];
|
|
@@ -65910,7 +66052,10 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
65910
66052
|
"getDataValidationInvalidCriterionValueMessage",
|
|
65911
66053
|
"getInvalidDataValidationMessage",
|
|
65912
66054
|
"getValidationResultForCellValue",
|
|
66055
|
+
"getDataValidationRangeValues",
|
|
65913
66056
|
"isCellValidCheckbox",
|
|
66057
|
+
"getDataValidationCellStyle",
|
|
66058
|
+
"getDataValidationChipStyle",
|
|
65914
66059
|
"isDataValidationInvalid",
|
|
65915
66060
|
];
|
|
65916
66061
|
validationResults = {};
|
|
@@ -65931,6 +66076,18 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
65931
66076
|
isDataValidationInvalid(cellPosition) {
|
|
65932
66077
|
return !this.getValidationResultForCell(cellPosition).isValid;
|
|
65933
66078
|
}
|
|
66079
|
+
getDataValidationCellStyle(position) {
|
|
66080
|
+
if (this.hasChip(position)) {
|
|
66081
|
+
return undefined; // The style is not applied on the cell if it's a chip
|
|
66082
|
+
}
|
|
66083
|
+
return this.getDataValidationStyle(position);
|
|
66084
|
+
}
|
|
66085
|
+
getDataValidationChipStyle(position) {
|
|
66086
|
+
if (this.hasChip(position)) {
|
|
66087
|
+
return this.getDataValidationStyle(position) ?? { fillColor: GRAY_200 };
|
|
66088
|
+
}
|
|
66089
|
+
return undefined;
|
|
66090
|
+
}
|
|
65934
66091
|
getInvalidDataValidationMessage(cellPosition) {
|
|
65935
66092
|
const validationResult = this.getValidationResultForCell(cellPosition);
|
|
65936
66093
|
return validationResult.isValid ? undefined : validationResult.error;
|
|
@@ -65953,6 +66110,11 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
65953
66110
|
}
|
|
65954
66111
|
return evaluator.isCriterionValueValid(value) ? undefined : evaluator.criterionValueErrorString;
|
|
65955
66112
|
}
|
|
66113
|
+
getDataValidationRangeValues(sheetId, criterion) {
|
|
66114
|
+
const range = this.getters.getRangeFromSheetXC(sheetId, String(criterion.values[0]));
|
|
66115
|
+
const criterionValues = this.getters.getRangeValues(range);
|
|
66116
|
+
return criterionValues.map((value) => value?.toString()).filter(isDefined);
|
|
66117
|
+
}
|
|
65956
66118
|
isCellValidCheckbox(cellPosition) {
|
|
65957
66119
|
if (!this.getters.isMainCellPosition(cellPosition)) {
|
|
65958
66120
|
return false;
|
|
@@ -65972,6 +66134,38 @@ class EvaluationDataValidationPlugin extends CoreViewPlugin {
|
|
|
65972
66134
|
const error = this.getRuleErrorForCellValue(cellValue, cellPosition, rule);
|
|
65973
66135
|
return error ? { error, rule, isValid: false } : VALID_RESULT;
|
|
65974
66136
|
}
|
|
66137
|
+
hasChip(position) {
|
|
66138
|
+
const rule = this.getters.getValidationRuleForCell(position);
|
|
66139
|
+
return ((rule?.criterion.type === "isValueInList" || rule?.criterion.type === "isValueInRange") &&
|
|
66140
|
+
rule.criterion.displayStyle === "chip");
|
|
66141
|
+
}
|
|
66142
|
+
getDataValidationStyle(position) {
|
|
66143
|
+
const rule = this.getters.getValidationRuleForCell(position);
|
|
66144
|
+
if (!rule || this.isDataValidationInvalid(position)) {
|
|
66145
|
+
return undefined;
|
|
66146
|
+
}
|
|
66147
|
+
const evaluatedCell = this.getters.getEvaluatedCell(position);
|
|
66148
|
+
const color = this.getValueColor(rule, evaluatedCell.value);
|
|
66149
|
+
if (!color) {
|
|
66150
|
+
return undefined;
|
|
66151
|
+
}
|
|
66152
|
+
const style = {
|
|
66153
|
+
fillColor: color,
|
|
66154
|
+
textColor: chipTextColor(color),
|
|
66155
|
+
};
|
|
66156
|
+
return style;
|
|
66157
|
+
}
|
|
66158
|
+
getValueColor(rule, value) {
|
|
66159
|
+
if (rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange") {
|
|
66160
|
+
return undefined;
|
|
66161
|
+
}
|
|
66162
|
+
for (const criterionValue in rule.criterion.colors) {
|
|
66163
|
+
if (criterionValue.toLowerCase() === String(value).toLowerCase()) {
|
|
66164
|
+
return rule.criterion.colors[criterionValue];
|
|
66165
|
+
}
|
|
66166
|
+
}
|
|
66167
|
+
return undefined;
|
|
66168
|
+
}
|
|
65975
66169
|
isValidFormula(value) {
|
|
65976
66170
|
return !compile(value).isBadExpression;
|
|
65977
66171
|
}
|
|
@@ -66068,12 +66262,35 @@ iconsOnCellRegistry.add("data_validation_checkbox", (getters, position) => {
|
|
|
66068
66262
|
}
|
|
66069
66263
|
return undefined;
|
|
66070
66264
|
});
|
|
66265
|
+
iconsOnCellRegistry.add("data_validation_chip_icon", (getters, position) => {
|
|
66266
|
+
const chipStyle = getters.getDataValidationChipStyle(position);
|
|
66267
|
+
if (chipStyle) {
|
|
66268
|
+
const cellStyle = getters.getCellComputedStyle(position);
|
|
66269
|
+
return {
|
|
66270
|
+
svg: getChipSvg(chipStyle),
|
|
66271
|
+
hoverSvg: getHoveredChipSvg(chipStyle),
|
|
66272
|
+
priority: 10,
|
|
66273
|
+
horizontalAlign: "right",
|
|
66274
|
+
size: computeTextFontSizeInPixels(cellStyle),
|
|
66275
|
+
margin: 4,
|
|
66276
|
+
position,
|
|
66277
|
+
onClick: (position, env) => {
|
|
66278
|
+
const { col, row } = position;
|
|
66279
|
+
env.model.selection.selectCell(col, row);
|
|
66280
|
+
env.startCellEdition();
|
|
66281
|
+
},
|
|
66282
|
+
type: "data_validation_chip_icon",
|
|
66283
|
+
};
|
|
66284
|
+
}
|
|
66285
|
+
return undefined;
|
|
66286
|
+
});
|
|
66071
66287
|
iconsOnCellRegistry.add("data_validation_list_icon", (getters, position) => {
|
|
66072
66288
|
const hasIcon = !getters.isReadonly() && getters.cellHasListDataValidationIcon(position);
|
|
66073
66289
|
if (hasIcon) {
|
|
66290
|
+
const cellStyle = getters.getCellComputedStyle(position);
|
|
66074
66291
|
return {
|
|
66075
|
-
svg:
|
|
66076
|
-
hoverSvg:
|
|
66292
|
+
svg: getCaretDownSvg(cellStyle),
|
|
66293
|
+
hoverSvg: getHoveredCaretDownSvg(cellStyle),
|
|
66077
66294
|
priority: 2,
|
|
66078
66295
|
horizontalAlign: "right",
|
|
66079
66296
|
size: GRID_ICON_EDGE_LENGTH,
|
|
@@ -68615,11 +68832,11 @@ class OTRegistry extends Registry {
|
|
|
68615
68832
|
* transformation function given
|
|
68616
68833
|
*/
|
|
68617
68834
|
addTransformation(executed, toTransforms, fn) {
|
|
68835
|
+
if (!this.content[executed]) {
|
|
68836
|
+
this.content[executed] = new Map();
|
|
68837
|
+
}
|
|
68618
68838
|
for (const toTransform of toTransforms) {
|
|
68619
|
-
|
|
68620
|
-
this.content[toTransform] = new Map();
|
|
68621
|
-
}
|
|
68622
|
-
this.content[toTransform].set(executed, fn);
|
|
68839
|
+
this.content[executed].set(toTransform, fn);
|
|
68623
68840
|
}
|
|
68624
68841
|
return this;
|
|
68625
68842
|
}
|
|
@@ -68628,7 +68845,7 @@ class OTRegistry extends Registry {
|
|
|
68628
68845
|
* that the executed command happened.
|
|
68629
68846
|
*/
|
|
68630
68847
|
getTransformation(toTransform, executed) {
|
|
68631
|
-
return this.content[
|
|
68848
|
+
return this.content[executed] && this.content[executed].get(toTransform);
|
|
68632
68849
|
}
|
|
68633
68850
|
}
|
|
68634
68851
|
const otRegistry = new OTRegistry();
|
|
@@ -68958,10 +69175,20 @@ function adaptTransform(toTransform, executed) {
|
|
|
68958
69175
|
*/
|
|
68959
69176
|
function transformAll(toTransform, executed) {
|
|
68960
69177
|
let transformedCommands = [...toTransform];
|
|
69178
|
+
const possibleTransformations = new Set(otRegistry.getKeys());
|
|
68961
69179
|
for (const executedCommand of executed) {
|
|
68962
|
-
|
|
68963
|
-
|
|
68964
|
-
|
|
69180
|
+
// If the executed command is not in the registry, we skip it
|
|
69181
|
+
// because we know there won't be any transformation impacting the
|
|
69182
|
+
// commands to transform.
|
|
69183
|
+
if (possibleTransformations.has(executedCommand.type)) {
|
|
69184
|
+
transformedCommands = transformedCommands.reduce((acc, cmd) => {
|
|
69185
|
+
const transformed = transform(cmd, executedCommand);
|
|
69186
|
+
if (transformed) {
|
|
69187
|
+
acc.push(transformed);
|
|
69188
|
+
}
|
|
69189
|
+
return acc;
|
|
69190
|
+
}, []);
|
|
69191
|
+
}
|
|
68965
69192
|
}
|
|
68966
69193
|
return transformedCommands;
|
|
68967
69194
|
}
|
|
@@ -70518,6 +70745,9 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
70518
70745
|
for (const icon of this.getters.getCellIcons(position)) {
|
|
70519
70746
|
contentWidth += icon.margin + icon.size;
|
|
70520
70747
|
}
|
|
70748
|
+
if (this.getters.getDataValidationChipStyle(position)) {
|
|
70749
|
+
contentWidth += DATA_VALIDATION_CHIP_MARGIN * 2;
|
|
70750
|
+
}
|
|
70521
70751
|
if (contentWidth === 0) {
|
|
70522
70752
|
return 0;
|
|
70523
70753
|
}
|
|
@@ -70675,7 +70905,7 @@ class SheetUIPlugin extends UIPlugin {
|
|
|
70675
70905
|
}
|
|
70676
70906
|
const position = this.getters.getCellPosition(cell.id);
|
|
70677
70907
|
const colSize = this.getters.getColSize(sheetId, position.col);
|
|
70678
|
-
if (cell.isFormula) {
|
|
70908
|
+
if (cell.isFormula || this.getters.getArrayFormulaSpreadingOn(position)) {
|
|
70679
70909
|
const content = this.getters.getEvaluatedCell(position).formattedValue;
|
|
70680
70910
|
const evaluatedSize = getCellContentHeight(this.ctx, content, cell?.style, colSize);
|
|
70681
70911
|
if (evaluatedSize > evaluatedRowSize && evaluatedSize > DEFAULT_CELL_HEIGHT) {
|
|
@@ -70878,6 +71108,8 @@ class CellComputedStylePlugin extends UIPlugin {
|
|
|
70878
71108
|
if (invalidateEvaluationCommands.has(cmd.type) ||
|
|
70879
71109
|
cmd.type === "UPDATE_CELL" ||
|
|
70880
71110
|
cmd.type === "SET_FORMATTING" ||
|
|
71111
|
+
cmd.type === "ADD_DATA_VALIDATION_RULE" ||
|
|
71112
|
+
cmd.type === "REMOVE_DATA_VALIDATION_RULE" ||
|
|
70881
71113
|
cmd.type === "EVALUATE_CELLS") {
|
|
70882
71114
|
this.styles = {};
|
|
70883
71115
|
this.borders = {};
|
|
@@ -70949,8 +71181,10 @@ class CellComputedStylePlugin extends UIPlugin {
|
|
|
70949
71181
|
const cell = this.getters.getCell(position);
|
|
70950
71182
|
const cfStyle = this.getters.getCellConditionalFormatStyle(position);
|
|
70951
71183
|
const tableStyle = this.getters.getCellTableStyle(position);
|
|
71184
|
+
const dataValidationStyle = this.getters.getDataValidationCellStyle(position);
|
|
70952
71185
|
const computedStyle = {
|
|
70953
71186
|
...removeFalsyAttributes(tableStyle),
|
|
71187
|
+
...removeFalsyAttributes(dataValidationStyle),
|
|
70954
71188
|
...removeFalsyAttributes(cell?.style),
|
|
70955
71189
|
...removeFalsyAttributes(cfStyle),
|
|
70956
71190
|
};
|
|
@@ -74512,19 +74746,29 @@ autoCompleteProviders.add("dataValidation", {
|
|
|
74512
74746
|
(rule.criterion.type !== "isValueInList" && rule.criterion.type !== "isValueInRange")) {
|
|
74513
74747
|
return [];
|
|
74514
74748
|
}
|
|
74515
|
-
|
|
74516
|
-
|
|
74517
|
-
|
|
74518
|
-
|
|
74519
|
-
|
|
74520
|
-
|
|
74521
|
-
values
|
|
74522
|
-
|
|
74523
|
-
|
|
74524
|
-
|
|
74525
|
-
|
|
74526
|
-
|
|
74527
|
-
|
|
74749
|
+
const sheetId = this.composer.currentEditedCell.sheetId;
|
|
74750
|
+
const values = rule.criterion.type === "isValueInRange"
|
|
74751
|
+
? Array.from(new Set(this.getters.getDataValidationRangeValues(sheetId, rule.criterion)))
|
|
74752
|
+
: rule.criterion.values;
|
|
74753
|
+
const isChip = rule.criterion.displayStyle === "chip";
|
|
74754
|
+
if (!isChip) {
|
|
74755
|
+
return values.map((value) => ({ text: value }));
|
|
74756
|
+
}
|
|
74757
|
+
const colors = rule.criterion.colors;
|
|
74758
|
+
return values.map((value) => {
|
|
74759
|
+
const color = colors?.[value];
|
|
74760
|
+
return {
|
|
74761
|
+
text: value,
|
|
74762
|
+
htmlContent: [
|
|
74763
|
+
{
|
|
74764
|
+
value,
|
|
74765
|
+
color: color ? chipTextColor(color) : undefined,
|
|
74766
|
+
backgroundColor: color || GRAY_200,
|
|
74767
|
+
classes: ["badge rounded-pill fs-6 fw-normal w-100 mt-1 text-start"],
|
|
74768
|
+
},
|
|
74769
|
+
],
|
|
74770
|
+
};
|
|
74771
|
+
});
|
|
74528
74772
|
},
|
|
74529
74773
|
selectProposal(tokenAtCursor, value) {
|
|
74530
74774
|
this.composer.setCurrentContent(value);
|
|
@@ -83392,6 +83636,6 @@ exports.tokenColors = tokenColors;
|
|
|
83392
83636
|
exports.tokenize = tokenize;
|
|
83393
83637
|
|
|
83394
83638
|
|
|
83395
|
-
__info__.version = "18.4.0-alpha.
|
|
83396
|
-
__info__.date = "2025-06-
|
|
83397
|
-
__info__.hash = "
|
|
83639
|
+
__info__.version = "18.4.0-alpha.9";
|
|
83640
|
+
__info__.date = "2025-06-19T18:23:22.025Z";
|
|
83641
|
+
__info__.hash = "6d4d685";
|