Compare commits

..

No commits in common. "8e6fb4b66d52af5b345de7e44ceb35b47f65e504" and "7c0c7d8c3e8c4232a5d455c8b1375cb86052bf32" have entirely different histories.

4 changed files with 35 additions and 75 deletions

View File

@ -1 +1 @@
v20260101-07-run-checks-shift-multiselect-delegation-fix v20260101-06-run-checks-shift-multiselect-fix

View File

@ -286,9 +286,6 @@
var btnMarkAllReviewed = document.getElementById('rcm_mark_all_reviewed'); var btnMarkAllReviewed = document.getElementById('rcm_mark_all_reviewed');
// Shift-click range selection for checkbox rows
var lastCheckedCb = null;
function statusClass(status) { function statusClass(status) {
var s = (status || "").toString().toLowerCase(); var s = (status || "").toString().toLowerCase();
@ -351,18 +348,9 @@
if (btnMark) btnMark.disabled = ids.length === 0; if (btnMark) btnMark.disabled = ids.length === 0;
if (btnUnmark) btnUnmark.disabled = ids.length === 0; if (btnUnmark) btnUnmark.disabled = ids.length === 0;
if (statusEl) statusEl.textContent = ids.length ? (ids.length + ' selected') : ''; if (statusEl) statusEl.textContent = ids.length ? (ids.length + ' selected') : '';
refreshSelectAll();
} }
function refreshSelectAll() { var lastRowCheckbox = null;
if (!selectAll) return;
var cbs = table.querySelectorAll('tbody .rc_row_cb');
var total = cbs.length;
var checked = 0;
cbs.forEach(function (cb) { if (cb.checked) checked++; });
selectAll.indeterminate = checked > 0 && checked < total;
selectAll.checked = total > 0 && checked === total;
}
if (selectAll) { if (selectAll) {
selectAll.addEventListener('change', function () { selectAll.addEventListener('change', function () {
@ -372,67 +360,47 @@
}); });
} }
// Prevent browser text selection when using Shift with checkbox selection // Shift-click multi select for row checkboxes (continuous range)
table.addEventListener('mousedown', function (e) { table.addEventListener('click', function (e) {
var t = e.target; if (!(e.target && e.target.classList && e.target.classList.contains('rc_row_cb'))) return;
if (!t) return;
if (t.classList && t.classList.contains('rc_row_cb') && e.shiftKey) {
e.preventDefault();
if (window.getSelection) {
try { window.getSelection().removeAllRanges(); } catch (err) {}
}
}
}, true);
// Handle Shift-click range selection on the checkbox inputs (delegated) // Prevent row click handlers and stop the browser from doing text-range selection.
table.addEventListener('click', function (e) { e.stopPropagation();
var t = e.target;
if (!t || !(t.classList && t.classList.contains('rc_row_cb'))) return;
// Custom handling so we can reliably read shiftKey and control the toggle + range // If shift is held, apply the checkbox state to the whole range.
if (e.shiftKey && lastCheckedCb && lastCheckedCb !== t) { if (e.shiftKey && lastRowCheckbox && lastRowCheckbox !== e.target) {
e.preventDefault(); var cbs = Array.prototype.slice.call(table.querySelectorAll('tbody .rc_row_cb'));
e.stopPropagation(); var start = cbs.indexOf(lastRowCheckbox);
var end = cbs.indexOf(e.target);
// The default action would toggle the checkbox; do it manually if (start !== -1 && end !== -1) {
var targetChecked = !t.checked; var min = Math.min(start, end);
t.checked = targetChecked; var max = Math.max(start, end);
var state = e.target.checked;
var cbs = Array.prototype.slice.call(table.querySelectorAll('tbody .rc_row_cb')); for (var i = min; i <= max; i++) {
var start = cbs.indexOf(lastCheckedCb); cbs[i].checked = state;
var end = cbs.indexOf(t); }
}
if (start !== -1 && end !== -1) {
var lo = Math.min(start, end);
var hi = Math.max(start, end);
for (var i = lo; i <= hi; i++) {
cbs[i].checked = targetChecked;
} }
}
if (window.getSelection) { lastRowCheckbox = e.target;
try { window.getSelection().removeAllRanges(); } catch (err) {}
}
updateButtons(); // Clear any accidental text selection caused by Shift-click.
lastCheckedCb = t; try {
return; var sel = window.getSelection ? window.getSelection() : null;
} if (sel && sel.removeAllRanges) sel.removeAllRanges();
} catch (err) {}
// Normal click: let default toggle happen, but remember the last checkbox updateButtons();
lastCheckedCb = t; });
// Defer update until after the checkbox state changes // Fallback: any checkbox change should still update the buttons.
setTimeout(updateButtons, 0); table.addEventListener('change', function (e) {
}, true); if (e.target && e.target.classList && e.target.classList.contains('rc_row_cb')) {
updateButtons();
// Fallback for keyboard toggles (space) and other state changes }
table.addEventListener('change', function (e) { });
if (e.target && e.target.classList && e.target.classList.contains('rc_row_cb')) {
lastCheckedCb = e.target;
updateButtons();
}
});
function postJson(url, body) { function postJson(url, body) {
return fetch(url, { return fetch(url, {

View File

@ -142,15 +142,6 @@
- Implemented tracking of the last selected checkbox to enable continuous range selection. - Implemented tracking of the last selected checkbox to enable continuous range selection.
- Ensured multiselect only applies to checkbox interactions and not table row text. - Ensured multiselect only applies to checkbox interactions and not table row text.
---
## v20260101-07-run-checks-shift-multiselect-delegation-fix
- Reworked Shift-click multiselect on the Run Checks page using event delegation.
- Ensured checkbox range selection works correctly with dynamically rendered table rows.
- Disabled default browser text selection when using Shift during checkbox interaction.
- Applied Gmail-style range selection logic for consistent multi-row selection behavior.
================================================================================================================================================ ================================================================================================================================================
## v0.1.14 ## v0.1.14

1
temp.md Normal file
View File

@ -0,0 +1 @@
left empty