You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by hn...@apache.org on 2025/04/25 08:10:31 UTC
(myfaces-tobago) 01/02: fix(sheet): column width FR-values
This is an automated email from the ASF dual-hosted git repository.
hnoeth pushed a commit to branch tobago-5.x
in repository https://gitbox.apache.org/repos/asf/myfaces-tobago.git
commit 002a794bd9c7645b9e0a6c74f0f7d3ebefc1e175
Author: Henning Noeth <hn...@apache.org>
AuthorDate: Thu Apr 24 13:50:27 2025 +0200
fix(sheet): column width FR-values
* add tests
* fix column width in TS
Issue: TOBAGO-2407
---
.../Sheet_Column_Width.test.js | 24 +++++++
.../20-sheet-column-width/Sheet_Column_Width.xhtml | 40 ++++++++++++
.../src/main/ts/tobago-sheet.ts | 73 ++++++++++++++++++++++
3 files changed, 137 insertions(+)
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/20-sheet-column-width/Sheet_Column_Width.test.js b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/20-sheet-column-width/Sheet_Column_Width.test.js
index 756a13ab74..ab34c2a546 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/20-sheet-column-width/Sheet_Column_Width.test.js
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/20-sheet-column-width/Sheet_Column_Width.test.js
@@ -93,6 +93,30 @@ it("Only auto value set for a 900px-sheet", function (done) {
test.start();
});
+it("'100px 20% 4fr 1fr auto' for a 1000px-sheet", function (done) {
+ const columnHeads = querySelectorAllFn("#page\\:mainForm\\:fixFr100px20p4fr1frAuto header table thead tr th");
+
+ const test = new JasmineTestTool(done);
+ test.do(() => expect(getComputedStyle(columnHeads()[0]).width).toBe("100px"));
+ test.do(() => expect(getComputedStyle(columnHeads()[1]).width).toBe("200px"));
+ test.do(() => expect(getComputedStyle(columnHeads()[2]).width).toBe("400px"));
+ test.do(() => expect(getComputedStyle(columnHeads()[3]).width).toBe("100px"));
+ test.do(() => expect(getComputedStyle(columnHeads()[4]).width).toBe("200px"));
+ test.start();
+});
+
+it("'150px 20% 4fr 1fr' for a 1000px-sheet", function (done) {
+ const columnHeads = querySelectorAllFn("#page\\:mainForm\\:fixFr150px20p4fr1fr header table thead tr th");
+
+ const test = new JasmineTestTool(done);
+ test.do(() => expect(getComputedStyle(columnHeads()[0]).width).toBe("150px"));
+ test.do(() => expect(getComputedStyle(columnHeads()[1]).width).toBe("200px"));
+ test.do(() => expect(getComputedStyle(columnHeads()[2]).width).toBe("400px"));
+ test.do(() => expect(getComputedStyle(columnHeads()[3]).width).toBe("100px"));
+ test.do(() => expect(getComputedStyle(columnHeads()[4]).width).toBe("150px"));
+ test.start();
+});
+
it("There must be no horizontal scrollbar", function (done) {
const sheetBody = querySelectorFn("#page\\:mainForm\\:testSheetColumnWidth .tobago-body");
diff --git a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/20-sheet-column-width/Sheet_Column_Width.xhtml b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/20-sheet-column-width/Sheet_Column_Width.xhtml
index 3a06b118a5..d63c8873cc 100644
--- a/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/20-sheet-column-width/Sheet_Column_Width.xhtml
+++ b/tobago-example/tobago-example-demo/src/main/webapp/content/900-test/3000-sheet/20-sheet-column-width/Sheet_Column_Width.xhtml
@@ -80,6 +80,46 @@
</tc:column>
</tc:sheet>
+ <tc:sheet id="fixFr100px20p4fr1frAuto" value="#{columnWidthController.solarList}" var="object" rows="2"
+ columns="100px 20% 4fr 1fr auto">
+ <tc:style width="1000px"/>
+ <tc:column label="Name">
+ <tc:out value="#{object.name}"/>
+ </tc:column>
+ <tc:column label="Orbit">
+ <tc:out value="#{object.orbit}"/>
+ </tc:column>
+ <tc:column label="Period (Days)">
+ <tc:out value="#{object.period}"/>
+ </tc:column>
+ <tc:column id="discoverer" label="Discoverer">
+ <tc:out value="#{object.discoverer}"/>
+ </tc:column>
+ <tc:column id="year" label="Year">
+ <tc:out value="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt."/>
+ </tc:column>
+ </tc:sheet>
+
+ <tc:sheet id="fixFr150px20p4fr1fr" value="#{columnWidthController.solarList}" var="object" rows="2"
+ columns="150px 20% 4fr 1fr">
+ <tc:style width="1000px"/>
+ <tc:column label="Name">
+ <tc:out value="#{object.name}"/>
+ </tc:column>
+ <tc:column label="Orbit">
+ <tc:out value="#{object.orbit}"/>
+ </tc:column>
+ <tc:column label="Period (Days)">
+ <tc:out value="#{object.period}"/>
+ </tc:column>
+ <tc:column id="discoverer" label="Discoverer">
+ <tc:out value="#{object.discoverer}"/>
+ </tc:column>
+ <tc:column id="year" label="Year">
+ <tc:out value="Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt."/>
+ </tc:column>
+ </tc:sheet>
+
<tc:sheet id="testSheetColumnWidth" value="#{columnWidthController.solarList}" var="luminary"
columns="200px 1fr 1fr" rows="5" markup="bordered">
<tc:style customClass="vertical-border-big"/>
diff --git a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts
index 64e06b33a7..700d88972f 100644
--- a/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts
+++ b/tobago-theme/tobago-theme-standard/src/main/ts/tobago-sheet.ts
@@ -92,6 +92,8 @@ export class Sheet extends HTMLElement {
}
this.initScrollbarFiller();
+ const resizeObserver = new ResizeObserver((entries) => this.fixColumnWidth());
+ resizeObserver.observe(this);
// resize column: mouse events -------------------------------------------------------------------------------- //
@@ -402,6 +404,46 @@ Type: ${data.type}`);
}
}
+ /**
+ * Fix column width for columns with fr-value if the layout contains both fr-values and px-values.
+ * The CSS function calc(100% - [number]px) doesn't work in table.
+ */
+ private fixColumnWidth(): void {
+ const renderedColumnWidth: string[] = this.renderedColumnWidth;
+
+ const hasPxAndFrValues = renderedColumnWidth.some(value => value.endsWith("px") || value.endsWith("fr"));
+ if (hasPxAndFrValues) {
+ const percent100InPx = parseFloat(getComputedStyle(this).width);
+ if (percent100InPx > 0) {
+ let frBaseInPx = percent100InPx;
+ renderedColumnWidth.forEach((value) => {
+ if (value.endsWith("px")) {
+ frBaseInPx -= parseFloat(value);
+ } else if (value.endsWith("%")) {
+ frBaseInPx -= (percent100InPx * parseFloat(value) / 100);
+ } else if (value === "auto") {
+ const autoInPercent = 100 / (this.headerCols.length - 2);
+ frBaseInPx -= (percent100InPx * autoInPercent / 100);
+ }
+ });
+
+ const sumOfFr = renderedColumnWidth
+ .filter(value => value.endsWith("fr"))
+ .map(value => parseFloat(value))
+ .reduce((previousValue, currentValue) => previousValue + currentValue, 0);
+
+ renderedColumnWidth.forEach((value, index) => {
+ if (value.endsWith("fr")) {
+ // Use percent value instead of px value to prioritize the sheet width over column (percentage) width.
+ const widthPercent = 100 * frBaseInPx / percent100InPx / sumOfFr * parseFloat(value) + "%";
+ this.headerCols.item(index).style.width = widthPercent;
+ this.bodyCols.item(index).style.width = widthPercent;
+ }
+ });
+ }
+ }
+ }
+
mousedown(event: MouseEvent): void {
Page.page(this).dataset.SheetMousedownData = this.id;
@@ -757,6 +799,37 @@ Type: ${data.type}`);
return rootNode.getElementById(this.id + "::rendered") as HTMLInputElement;
}
+ /**
+ * Return the width of all rendered col tags as a string array. If the user has set the width manually, the exact
+ * pixel value is used, otherwise the layout value.
+ */
+ private get renderedColumnWidth(): string[] {
+ const renderedColumnWidth: string[] = [];
+ const layoutValues: any[] = JSON.parse(this.dataset.tobagoLayout).columns;
+ this.hiddenInputRenderedValue.forEach((rendered, i) => {
+ if (rendered) {
+ let pxValue = -1;
+ if (this.hiddenInputWidthValue.length > i) {
+ pxValue = this.hiddenInputWidthValue[i];
+ }
+
+ if (pxValue > -1) {
+ renderedColumnWidth.push(pxValue + "px");
+ } else {
+ const layoutValue = layoutValues[i % layoutValues.length];
+ if (typeof layoutValue === "number") {
+ renderedColumnWidth.push(layoutValue + "fr");
+ } else if (typeof layoutValue === "object" && layoutValue.measure !== undefined) {
+ renderedColumnWidth.push(layoutValue.measure);
+ } else {
+ renderedColumnWidth.push(layoutValue); //auto
+ }
+ }
+ }
+ });
+ return renderedColumnWidth;
+ }
+
get scrollPosition(): number[] {
return JSON.parse(this.hiddenInputScrollPosition.value);
}