mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-05-24 22:47:06 -04:00
fix: keep console summary row aligned when toggling event columns
The footer matched cells positionally with `eventCells[index]`, but bootstrap-table omits hidden columns from the rebuilt tfoot, so hiding e.g. Hour shifted every later period's total into the wrong cell. Tag each event header with a unique col<Period>Events class and target the footer cell by that class instead of by index. Bootstrap-table also rebuilds the tfoot on column-switch, which wiped our injected totals until the next ajax refresh. Cache the last footer payload and re-apply it on column-switch / column-switch-all. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -294,7 +294,7 @@ echo $navbar ?>
|
||||
);
|
||||
parseFilter($filter);
|
||||
$eventsLink = canView('Events') ? '?view='.ZM_WEB_EVENTS_VIEW.'&page=1'.$filter['querystring'] : '';
|
||||
echo '<th data-sortable="true" data-field="'.$i.'Events" class="colEvents"'
|
||||
echo '<th data-sortable="true" data-field="'.$i.'Events" class="colEvents col'.$i.'Events"'
|
||||
.'>'
|
||||
.htmlspecialchars($eventCounts[$i]['title'])
|
||||
.'</th>'.PHP_EOL;
|
||||
|
||||
@@ -2,9 +2,11 @@
|
||||
const table = $j('#consoleTable');
|
||||
var ajax = null;
|
||||
var monitors = {}; // Store monitors by ID for function modal
|
||||
var lastFooter = null; // Cached footer payload for re-applying after column toggles
|
||||
|
||||
// Update footer with dynamic totals
|
||||
function updateFooter(footer) {
|
||||
lastFooter = footer;
|
||||
// Target the footer within the bootstrap-table wrapper
|
||||
// Bootstrap-table may transform td to th and wrap content in divs
|
||||
var footerRow = $j('#consoleTable').closest('.bootstrap-table').find('tfoot tr');
|
||||
@@ -32,35 +34,33 @@ function updateFooter(footer) {
|
||||
// Update bandwidth/FPS (in Function column)
|
||||
updateCell('td.colFunction, th.colFunction', footer.bandwidth_fps);
|
||||
|
||||
// Update event totals
|
||||
// Update event totals. Target each period by its unique col<Period>Events
|
||||
// class rather than by positional index: bootstrap-table drops hidden columns
|
||||
// from the tfoot DOM entirely, so an index-based lookup would shift every
|
||||
// period after the hidden one into the wrong cell.
|
||||
var eventPeriods = ['Total', 'Hour', 'Day', 'Week', 'Month', 'Archived'];
|
||||
var eventCells = footerRow.find('td.colEvents, th.colEvents');
|
||||
eventPeriods.forEach(function(period, index) {
|
||||
if (eventCells.length > index) {
|
||||
var cell = $j(eventCells[index]);
|
||||
// Only update the th-inner div if it exists
|
||||
var innerDiv = cell.find('.th-inner');
|
||||
var target = innerDiv.length ? innerDiv : cell;
|
||||
eventPeriods.forEach(function(period) {
|
||||
var sel = 'td.col' + period + 'Events, th.col' + period + 'Events';
|
||||
var cell = footerRow.find(sel);
|
||||
if (!cell.length) return;
|
||||
|
||||
var contentHtml = footer[period + 'Events'] + '<br/><div class="small text-nowrap text-muted">' +
|
||||
footer[period + 'EventDiskSpace'] + '</div>';
|
||||
var innerDiv = cell.find('.th-inner');
|
||||
var target = innerDiv.length ? innerDiv : cell;
|
||||
|
||||
// Create or update link with filter querystring
|
||||
if (canView.Events && footer[period + 'FilterQuery']) {
|
||||
var link = target.find('a');
|
||||
if (link.length) {
|
||||
// Update existing link href and content
|
||||
link.attr('href', '?view=' + ZM_WEB_EVENTS_VIEW + footer[period + 'FilterQuery']);
|
||||
link.html(contentHtml);
|
||||
} else {
|
||||
// Create new link
|
||||
target.html('<a href="?view=' + ZM_WEB_EVENTS_VIEW + footer[period + 'FilterQuery'] + '">' +
|
||||
contentHtml + '</a>');
|
||||
}
|
||||
var contentHtml = footer[period + 'Events'] + '<br/><div class="small text-nowrap text-muted">' +
|
||||
footer[period + 'EventDiskSpace'] + '</div>';
|
||||
|
||||
if (canView.Events && footer[period + 'FilterQuery']) {
|
||||
var link = target.find('a');
|
||||
if (link.length) {
|
||||
link.attr('href', '?view=' + ZM_WEB_EVENTS_VIEW + footer[period + 'FilterQuery']);
|
||||
link.html(contentHtml);
|
||||
} else {
|
||||
// No permission or no filter query, just show text
|
||||
target.html(contentHtml);
|
||||
target.html('<a href="?view=' + ZM_WEB_EVENTS_VIEW + footer[period + 'FilterQuery'] + '">' +
|
||||
contentHtml + '</a>');
|
||||
}
|
||||
} else {
|
||||
target.html(contentHtml);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -566,6 +566,12 @@ function initPage() {
|
||||
$j('.functionLnk').click(manageFunctionModal);
|
||||
});
|
||||
|
||||
// Re-apply cached footer totals when columns are toggled, because
|
||||
// bootstrap-table rebuilds tfoot on column-switch and clears our content.
|
||||
table.on('column-switch.bs.table column-switch-all.bs.table', function() {
|
||||
if (lastFooter) updateFooter(lastFooter);
|
||||
});
|
||||
|
||||
// Makes table sortable - disabled by default, enabled by Sort button
|
||||
// Note: This may need adjustment for bootstrap-table compatibility
|
||||
$j('#consoleTableBody').sortable({
|
||||
|
||||
Reference in New Issue
Block a user