fix: ticket preview popup wrong position and persists after interactions

- position:fixed popup was adding window.scrollX/scrollY to viewport coords
  from getBoundingClientRect(), making it appear far below link when scrolled
- Off-screen check compared against innerHeight + scrollY instead of innerHeight
- Added clamp to prevent negative coords (popup clipped off top/left edge)
- Hide preview on scroll, modal open, and pagination clicks (capture phase)
  so stale popup doesn't linger after user navigates away

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-04 22:51:39 -04:00
parent b7b6884bb0
commit d588590989
+23 -5
View File
@@ -1332,21 +1332,25 @@ function showTicketPreview(event) {
<div class="preview-footer">Created by ${lt.escHtml(createdBy)}</div>
`;
// Position the preview
// Position the preview — element is position:fixed so coords are
// viewport-relative; getBoundingClientRect() already returns viewport coords,
// do NOT add scrollX/scrollY
const rect = link.getBoundingClientRect();
const previewWidth = 320;
const previewHeight = 200;
let left = rect.left + window.scrollX;
let top = rect.bottom + window.scrollY + 5;
let left = rect.left;
let top = rect.bottom + 5;
// Adjust if going off-screen
if (left + previewWidth > window.innerWidth) {
left = window.innerWidth - previewWidth - 20;
}
if (top + previewHeight > window.innerHeight + window.scrollY) {
top = rect.top + window.scrollY - previewHeight - 5;
if (top + previewHeight > window.innerHeight) {
top = rect.top - previewHeight - 5;
}
if (left < 0) left = 4;
if (top < 0) top = 4;
currentPreview.style.left = left + 'px';
currentPreview.style.top = top + 'px';
@@ -1374,6 +1378,20 @@ document.addEventListener('DOMContentLoaded', function() {
}
});
// Hide preview when a modal opens, user scrolls, or page is about to navigate
document.addEventListener('click', function(e) {
if (e.target.closest('[data-modal-open], [data-action="open-advanced-search"], .lt-pagination a, .lt-pagination button')) {
hideTicketPreview();
if (currentPreview) currentPreview.classList.add('is-hidden');
}
}, true);
document.addEventListener('scroll', function() {
if (currentPreview && !currentPreview.classList.contains('is-hidden')) {
currentPreview.classList.add('is-hidden');
if (previewTimeout) { clearTimeout(previewTimeout); previewTimeout = null; }
}
}, { passive: true });
/**
* Toggle export dropdown menu
*/