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