Fixed #32647 -- Restored multi-row select with shift-modifier in admin changelist.

Regression in 30e59705fc.
This commit is contained in:
Carlton Gibson 2021-04-15 17:15:28 +02:00
parent 54e94640ac
commit 5c73fbb6a9
3 changed files with 52 additions and 1 deletions

View File

@ -88,6 +88,16 @@
window.Actions = function(actionCheckboxes, options) {
options = Object.assign({}, defaults, options);
let list_editable_changed = false;
let lastChecked = null;
let shiftPressed = false;
document.addEventListener('keydown', (event) => {
shiftPressed = event.shiftKey;
});
document.addEventListener('keyup', (event) => {
shiftPressed = event.shiftKey;
});
document.getElementById(options.allToggleId).addEventListener('click', function(event) {
checker(actionCheckboxes, options, this.checked);
@ -113,12 +123,28 @@
});
});
function affectedCheckboxes(target, withModifier) {
const multiSelect = (lastChecked && withModifier && lastChecked !== target);
if (!multiSelect) {
return [target];
}
const checkboxes = Array.from(actionCheckboxes);
const targetIndex = checkboxes.findIndex(el => el === target);
const lastCheckedIndex = checkboxes.findIndex(el => el === lastChecked);
const startIndex = Math.min(targetIndex, lastCheckedIndex);
const endIndex = Math.max(targetIndex, lastCheckedIndex);
const filtered = checkboxes.filter((el, index) => (startIndex <= index) && (index <= endIndex));
return filtered;
};
Array.from(document.getElementById('result_list').tBodies).forEach(function(el) {
el.addEventListener('change', function(event) {
const target = event.target;
if (target.classList.contains('action-select')) {
target.closest('tr').classList.toggle(options.selectedClass, target.checked);
const checkboxes = affectedCheckboxes(target, shiftPressed);
checker(checkboxes, options, target.checked);
updateCounter(actionCheckboxes, options);
lastChecked = target;
} else {
list_editable_changed = true;
}

View File

@ -44,3 +44,6 @@ Bugfixes
* Fixed a regression in Django 3.2 that caused a crash when decoding a cookie
value, used by ``django.contrib.messages.storage.cookie.CookieStorage``, in
the pre-Django 3.2 format (:ticket:`32643`).
* Fixed a regression in Django 3.2 that stopped the shift-key modifier
selecting multiple rows in the admin changelist (:ticket:`32647`).

View File

@ -1381,6 +1381,28 @@ class SeleniumTests(AdminSeleniumTestCase):
self.assertIs(all_selector.get_property('checked'), False)
self.assertEqual(row.get_attribute('class'), '')
def test_modifier_allows_multiple_section(self):
"""
Selecting a row and then selecting another row whilst holding shift
should select all rows in-between.
"""
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
Parent.objects.bulk_create([Parent(name='parent%d' % i) for i in range(5)])
self.admin_login(username='super', password='secret')
self.selenium.get(self.live_server_url + reverse('admin:admin_changelist_parent_changelist'))
checkboxes = self.selenium.find_elements_by_css_selector('tr input.action-select')
self.assertEqual(len(checkboxes), 5)
for c in checkboxes:
self.assertIs(c.get_property('checked'), False)
# Check first row. Hold-shift and check next-to-last row.
checkboxes[0].click()
ActionChains(self.selenium).key_down(Keys.SHIFT).click(checkboxes[-2]).key_up(Keys.SHIFT).perform()
for c in checkboxes[:-2]:
self.assertIs(c.get_property('checked'), True)
self.assertIs(checkboxes[-1].get_property('checked'), False)
def test_select_all_across_pages(self):
Parent.objects.bulk_create([Parent(name='parent%d' % i) for i in range(101)])
self.admin_login(username='super', password='secret')