Skip to content

Commit 4963285

Browse files
Switch docker folder row centering to height-sync strategy
1 parent 9d1cd6b commit 4963285

4 files changed

Lines changed: 116 additions & 31 deletions

File tree

209 KB
Binary file not shown.

folderview.plus.plg

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,19 @@
66
<!ENTITY launch "Settings/FolderViewPlus">
77
<!ENTITY plugdir "/usr/local/emhttp/plugins/&name;">
88
<!ENTITY pluginURL "https://raw.githubusercontent.com/&github;/main/folderview.plus.plg">
9-
<!ENTITY version "2026.03.07.9">
10-
<!ENTITY md5 "58513ecfa1d0ea947e4f9b76afef07af">
9+
<!ENTITY version "2026.03.08.1">
10+
<!ENTITY md5 "76df551e15cc106d3888dde47b74fdbc">
1111
]>
1212

1313
<PLUGIN name="&name;" author="&author;" version="&version;" launch="&launch;" pluginURL="&pluginURL;" icon="folder-open-o" support="https://github.com/alexphillips-dev/FolderView-Plus/issues" min="7.0.0">
1414
<CHANGES>
1515

16+
###2026.03.08.1
17+
- Replace Docker folder left-column centering strategy with height-sync + flex alignment:
18+
- remove absolute-position centering for folder name block,
19+
- compute/sync row height across folder row clones and apply that height to folder cells,
20+
- keep observer-driven re-apply for late fixed-column/table clone renders.
21+
1622
###2026.03.07.9
1723
- Harden Docker folder vertical centering for fixed-column render paths:
1824
- center all folder name cells (`td.ct-name.folder-name`) regardless of table clone/source,

src/folderview.plus/usr/local/emhttp/plugins/folderview.plus/scripts/docker.js

Lines changed: 99 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,52 @@ const escapeClassToken = (value) => {
6464
return input.replace(/[^a-zA-Z0-9_-]/g, '\\$&');
6565
};
6666

67-
const applyFolderCellCentering = (cell) => {
67+
const getFolderIdFromRow = (row) => {
68+
if (!row || !row.classList) {
69+
return '';
70+
}
71+
for (const cls of row.classList) {
72+
if (typeof cls === 'string' && cls.startsWith('folder-id-')) {
73+
return cls.substring('folder-id-'.length);
74+
}
75+
}
76+
return '';
77+
};
78+
79+
const getRenderedRowHeight = (row) => {
80+
if (!row) {
81+
return 0;
82+
}
83+
const rect = row.getBoundingClientRect ? row.getBoundingClientRect() : null;
84+
const rectHeight = rect && Number.isFinite(rect.height) ? rect.height : 0;
85+
const offsetHeight = Number.isFinite(row.offsetHeight) ? row.offsetHeight : 0;
86+
return Math.max(Math.round(rectHeight), Math.round(offsetHeight), 0);
87+
};
88+
89+
const syncFolderRowsHeight = (rows) => {
90+
if (!rows || !rows.length) {
91+
return 0;
92+
}
93+
let maxHeight = 0;
94+
rows.forEach((row) => {
95+
maxHeight = Math.max(maxHeight, getRenderedRowHeight(row));
96+
});
97+
if (maxHeight <= 0) {
98+
return 0;
99+
}
100+
rows.forEach((row) => {
101+
row.style.setProperty('height', `${maxHeight}px`, 'important');
102+
Array.from(row.children || []).forEach((td) => {
103+
if (td && td.tagName === 'TD') {
104+
td.style.setProperty('height', `${maxHeight}px`, 'important');
105+
td.style.setProperty('vertical-align', 'middle', 'important');
106+
}
107+
});
108+
});
109+
return maxHeight;
110+
};
111+
112+
const applyFolderCellCentering = (cell, rowHeight = 0) => {
68113
if (!cell) {
69114
return false;
70115
}
@@ -82,46 +127,78 @@ const applyFolderCellCentering = (cell) => {
82127
return false;
83128
}
84129

85-
const row = cell.parentElement;
86-
if (row && row.tagName === 'TR') {
87-
Array.from(row.children).forEach((td) => {
88-
if (td && td.tagName === 'TD') {
89-
td.style.setProperty('vertical-align', 'middle', 'important');
90-
}
91-
});
92-
}
93-
130+
const height = Number.isFinite(rowHeight) && rowHeight > 0 ? Math.round(rowHeight) : getRenderedRowHeight(cell.parentElement);
94131
cell.style.setProperty('vertical-align', 'middle', 'important');
95-
cell.style.setProperty('position', 'relative', 'important');
132+
cell.style.setProperty('position', 'static', 'important');
133+
cell.style.setProperty('display', 'table-cell', 'important');
96134
cell.style.setProperty('padding-top', '0px', 'important');
97135
cell.style.setProperty('padding-bottom', '0px', 'important');
136+
if (height > 0) {
137+
cell.style.setProperty('height', `${height}px`, 'important');
138+
}
98139

99-
sub.style.setProperty('position', 'absolute', 'important');
100-
sub.style.setProperty('top', '50%', 'important');
101-
sub.style.setProperty('left', '8px', 'important');
102-
sub.style.setProperty('right', '8px', 'important');
103-
sub.style.setProperty('transform', 'translateY(-50%)', 'important');
140+
sub.style.setProperty('position', 'relative', 'important');
141+
sub.style.setProperty('top', 'auto', 'important');
142+
sub.style.setProperty('left', 'auto', 'important');
143+
sub.style.setProperty('right', 'auto', 'important');
144+
sub.style.setProperty('transform', 'none', 'important');
104145
sub.style.setProperty('display', 'flex', 'important');
105146
sub.style.setProperty('align-items', 'center', 'important');
147+
sub.style.setProperty('min-height', '48px', 'important');
148+
sub.style.setProperty('width', '100%', 'important');
149+
if (height > 0) {
150+
sub.style.setProperty('height', `${Math.max(0, height - 2)}px`, 'important');
151+
}
106152

107153
return true;
108154
};
109155

110156
const forceAllFolderRowsVerticalCenter = () => {
157+
const rowsByFolderId = new Map();
158+
const handledRows = new Set();
159+
160+
document.querySelectorAll('tr[class*="folder-id-"]').forEach((row) => {
161+
const id = getFolderIdFromRow(row);
162+
if (!id) {
163+
return;
164+
}
165+
if (!rowsByFolderId.has(id)) {
166+
rowsByFolderId.set(id, []);
167+
}
168+
rowsByFolderId.get(id).push(row);
169+
});
170+
171+
rowsByFolderId.forEach((rows) => {
172+
const syncedHeight = syncFolderRowsHeight(rows);
173+
rows.forEach((row) => {
174+
handledRows.add(row);
175+
row.querySelectorAll('td.ct-name.folder-name').forEach((cell) => {
176+
applyFolderCellCentering(cell, syncedHeight);
177+
});
178+
});
179+
});
180+
111181
document.querySelectorAll('td.ct-name.folder-name').forEach((cell) => {
112-
applyFolderCellCentering(cell);
182+
const parentRow = cell.parentElement;
183+
if (!handledRows.has(parentRow)) {
184+
applyFolderCellCentering(cell, getRenderedRowHeight(parentRow));
185+
}
113186
});
114187
};
115188

116189
const forceFolderRowVerticalCenter = (id) => {
117190
const escapedId = escapeClassToken(id);
118-
let centered = false;
119-
document.querySelectorAll(`tr.folder-id-${escapedId} td.ct-name.folder-name`).forEach((cell) => {
120-
centered = applyFolderCellCentering(cell) || centered;
121-
});
122-
if (!centered) {
191+
const rows = Array.from(document.querySelectorAll(`tr.folder-id-${escapedId}`));
192+
if (!rows.length) {
123193
forceAllFolderRowsVerticalCenter();
194+
return;
124195
}
196+
const syncedHeight = syncFolderRowsHeight(rows);
197+
rows.forEach((row) => {
198+
row.querySelectorAll('td.ct-name.folder-name').forEach((cell) => {
199+
applyFolderCellCentering(cell, syncedHeight);
200+
});
201+
});
125202
};
126203

127204
let folderRowCenterObserver = null;

src/folderview.plus/usr/local/emhttp/plugins/folderview.plus/styles/docker.css

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,19 +36,21 @@ tr[class*="folder-id-"] > td {
3636
/* Unraid table styles can force top visual placement.
3737
Center the left folder block explicitly within the row height. */
3838
td.ct-name.folder-name {
39-
position: relative;
39+
position: static;
40+
display: table-cell;
4041
padding-top: 0 !important;
4142
padding-bottom: 0 !important;
4243
vertical-align: middle !important;
4344
}
4445

4546
td.ct-name.folder-name > .folder-name-sub {
46-
position: absolute;
47-
top: 50%;
48-
left: 8px;
49-
right: 8px;
50-
transform: translateY(-50%);
51-
min-height: 0;
47+
position: relative;
48+
top: auto;
49+
left: auto;
50+
right: auto;
51+
transform: none;
52+
min-height: 48px;
53+
width: 100%;
5254
}
5355

5456
.folder-outer {

0 commit comments

Comments
 (0)