I can select rows and columns

This commit is contained in:
2026-01-24 19:23:10 +01:00
parent ba2b6e672a
commit 06e81fe72a
2 changed files with 99 additions and 2 deletions

View File

@@ -1477,8 +1477,87 @@ function initDataGrid(gridId) {
updateDatagridSelection(gridId)
}
function initDataGridMouseOver(gridId) {
/**
* Initialize DataGrid hover effects using event delegation.
*
* Optimizations:
* - Event delegation: 1 listener instead of N×2 (where N = number of cells)
* - Row mode: O(1) via class toggle on parent row
* - Column mode: RAF batching + cached cells for efficient class removal
* - Works with HTMX swaps: listener on stable parent, querySelectorAll finds new cells
* - No mouseout: hover selection stays visible when leaving the table
*
* @param {string} gridId - The DataGrid instance ID
*/
function initDataGridMouseOver(gridId) {
const table = document.getElementById(`t_${gridId}`);
if (!table) {
console.error(`Table with id "t_${gridId}" not found.`);
return;
}
const wrapper = document.getElementById(`tw_${gridId}`);
const selectionModeDiv = document.getElementById(`tsm_${gridId}`);
// Track hover state
let currentHoverRow = null;
let currentHoverColId = null;
let currentHoverColCells = null;
table.addEventListener('mouseover', (e) => {
// Skip hover during scrolling
if (wrapper?.hasAttribute('mf-no-hover')) return;
const cell = e.target.closest('.dt2-cell');
if (!cell) return;
const selectionMode = selectionModeDiv?.getAttribute('selection-mode');
if (selectionMode === 'row') {
const rowElement = cell.parentElement;
if (rowElement !== currentHoverRow) {
if (currentHoverRow) {
currentHoverRow.classList.remove('dt2-hover-row');
}
rowElement.classList.add('dt2-hover-row');
currentHoverRow = rowElement;
}
} else if (selectionMode === 'column') {
const colId = cell.dataset.col;
// Skip if same column
if (colId === currentHoverColId) return;
requestAnimationFrame(() => {
// Remove old column highlight
if (currentHoverColCells) {
currentHoverColCells.forEach(c => c.classList.remove('dt2-hover-column'));
}
// Query and add new column highlight
currentHoverColCells = table.querySelectorAll(`.dt2-cell[data-col="${colId}"]`);
currentHoverColCells.forEach(c => c.classList.add('dt2-hover-column'));
currentHoverColId = colId;
});
}
});
// Clean up when leaving the table entirely
table.addEventListener('mouseout', (e) => {
if (!table.contains(e.relatedTarget)) {
if (currentHoverRow) {
currentHoverRow.classList.remove('dt2-hover-row');
currentHoverRow = null;
}
if (currentHoverColCells) {
currentHoverColCells.forEach(c => c.classList.remove('dt2-hover-column'));
currentHoverColCells = null;
currentHoverColId = null;
}
}
});
}
/**
@@ -1638,6 +1717,7 @@ function initDataGridScrollbars(gridId) {
dragStartY = e.clientY;
dragStartScrollTop = cachedBodyScrollTop;
wrapper.setAttribute("mf-no-tooltip", "");
wrapper.setAttribute("mf-no-hover", "");
}, {signal});
// Horizontal scrollbar mousedown
@@ -1646,6 +1726,7 @@ function initDataGridScrollbars(gridId) {
dragStartX = e.clientX;
dragStartScrollLeft = cachedTableScrollLeft;
wrapper.setAttribute("mf-no-tooltip", "");
wrapper.setAttribute("mf-no-hover", "");
}, {signal});
// Consolidated mousemove listener
@@ -1684,9 +1765,11 @@ function initDataGridScrollbars(gridId) {
if (isDraggingVertical) {
isDraggingVertical = false;
wrapper.removeAttribute("mf-no-tooltip");
wrapper.removeAttribute("mf-no-hover");
} else if (isDraggingHorizontal) {
isDraggingHorizontal = false;
wrapper.removeAttribute("mf-no-tooltip");
wrapper.removeAttribute("mf-no-hover");
}
}, {signal});
@@ -1694,8 +1777,20 @@ function initDataGridScrollbars(gridId) {
let rafScheduledWheel = false;
let pendingWheelDeltaX = 0;
let pendingWheelDeltaY = 0;
let wheelEndTimeout = null;
const handleWheelScrolling = (event) => {
// Disable hover and tooltip during wheel scroll
wrapper.setAttribute("mf-no-hover", "");
wrapper.setAttribute("mf-no-tooltip", "");
// Clear previous timeout and re-enable after 150ms of no wheel events
if (wheelEndTimeout) clearTimeout(wheelEndTimeout);
wheelEndTimeout = setTimeout(() => {
wrapper.removeAttribute("mf-no-hover");
wrapper.removeAttribute("mf-no-tooltip");
}, 150);
// Accumulate wheel deltas
pendingWheelDeltaX += event.deltaX;
pendingWheelDeltaY += event.deltaY;

View File

@@ -179,6 +179,7 @@ class DataGrid(MultipleInstance):
df = self._df.copy()
df = self._apply_sort(df) # need to keep the real type to sort
df = self._apply_filter(df)
self._state.ns_total_rows = len(df)
return df
@@ -533,7 +534,8 @@ class DataGrid(MultipleInstance):
return Div(
*[Div(selection_type=s_type, element_id=f"{elt_id}") for s_type, elt_id in selected],
id=f"tsm_{self._id}",
selection_mode=f"{self._state.selection.selection_mode}",
#selection_mode=f"{self._state.selection.selection_mode}",
selection_mode=f"column",
**extra_attr,
)