mirror of
https://github.com/django/django.git
synced 2025-06-13 15:39:13 +00:00
[5.2.x] Fixed #36423 -- Prevented filter_horizontal buttons from intercepting form submission.
In the admin's filter_horizontal widget, optional action buttons like "Choose all", "Remove all", etc. were changed from `<a>` to `<button>` elements in #34619, but without specifying `type="button"`. As a result, when pressing Enter while focused on a form input, these buttons could be triggered and intercept form submission. Explicitly set `type="button"` on these control buttons to prevent them from acting as submit buttons. Thanks Antoliny Lee for the quick triage and review. Regression in 857b1048d53ebf5fc5581c110e85c212b81ca83a. Backport of 90429625a85f1f77dfea200c91bd2dabab57974f from main.
This commit is contained in:
parent
e107b8a9d3
commit
37e5cc6d89
1
AUTHORS
1
AUTHORS
@ -163,6 +163,7 @@ answer newbie questions, and generally made Django that much better:
|
||||
Bhuvnesh Sharma <bhuvnesh875@gmail.com>
|
||||
Bill Fenner <fenner@gmail.com>
|
||||
Bjørn Stabell <bjorn@exoweb.net>
|
||||
Blayze Wilhelm <https://github.com/blayzen-w>
|
||||
Bo Marchman <bo.marchman@gmail.com>
|
||||
Bogdan Mateescu
|
||||
Bojan Mihelac <bmihelac@mihelac.org>
|
||||
|
@ -72,7 +72,8 @@ Requires core.js and SelectBox.js.
|
||||
selector_available,
|
||||
interpolate(gettext('Choose all %s'), [field_name]),
|
||||
'id', field_id + '_add_all',
|
||||
'class', 'selector-chooseall'
|
||||
'class', 'selector-chooseall',
|
||||
'type', 'button'
|
||||
);
|
||||
|
||||
// <ul class="selector-chooser">
|
||||
@ -83,14 +84,16 @@ Requires core.js and SelectBox.js.
|
||||
quickElement('li', selector_chooser),
|
||||
interpolate(gettext('Choose selected %s'), [field_name]),
|
||||
'id', field_id + '_add',
|
||||
'class', 'selector-add'
|
||||
'class', 'selector-add',
|
||||
'type', 'button'
|
||||
);
|
||||
const remove_button = quickElement(
|
||||
'button',
|
||||
quickElement('li', selector_chooser),
|
||||
interpolate(gettext('Remove selected %s'), [field_name]),
|
||||
'id', field_id + '_remove',
|
||||
'class', 'selector-remove'
|
||||
'class', 'selector-remove',
|
||||
'type', 'button'
|
||||
);
|
||||
|
||||
// <div class="selector-chosen">
|
||||
@ -142,7 +145,8 @@ Requires core.js and SelectBox.js.
|
||||
selector_chosen,
|
||||
interpolate(gettext('Remove all %s'), [field_name]),
|
||||
'id', field_id + '_remove_all',
|
||||
'class', 'selector-clearall'
|
||||
'class', 'selector-clearall',
|
||||
'type', 'button'
|
||||
);
|
||||
|
||||
from_box.name = from_box.name + '_old';
|
||||
|
@ -30,3 +30,7 @@ Bugfixes
|
||||
* Fixed a regression in Django 5.2 that caused a crash when using ``OuterRef``
|
||||
in PostgreSQL aggregate functions ``ArrayAgg``, ``StringAgg``, and
|
||||
``JSONBAgg`` (:ticket:`36405`).
|
||||
|
||||
* Fixed a regression in Django 5.2 where admin's ``filter_horizontal`` buttons
|
||||
lacked ``type="button"``, causing them to intercept form submission when
|
||||
pressing the Enter key (:ticket:`36423`).
|
||||
|
@ -31,6 +31,7 @@ QUnit.test('init', function(assert) {
|
||||
assert.equal($('.selector-chosen .selector-chosen-title .helptext').text(), 'Remove things by selecting them and then select the "Remove" arrow button.');
|
||||
assert.equal($('.selector-filter label .help-tooltip')[0].getAttribute("aria-label"), "Type into this box to filter down the list of available things.");
|
||||
assert.equal($('.selector-filter label .help-tooltip')[1].getAttribute("aria-label"), "Type into this box to filter down the list of selected things.");
|
||||
assert.equal($('#test button:not([type="button"])').length, 0);
|
||||
});
|
||||
|
||||
QUnit.test('filtering available options', function(assert) {
|
||||
|
@ -1740,6 +1740,48 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
|
||||
|
||||
self.assertCountSeleniumElements("#id_students_to > option", 2)
|
||||
|
||||
def test_form_submission_via_enter_key_with_filter_horizontal(self):
|
||||
"""
|
||||
The main form can be submitted correctly by pressing the enter key.
|
||||
There is no shadowing from other buttons inside the form.
|
||||
"""
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
|
||||
self.school.students.set([self.peter])
|
||||
self.school.alumni.set([self.lisa])
|
||||
|
||||
self.admin_login(username="super", password="secret", login_url="/")
|
||||
self.selenium.get(
|
||||
self.live_server_url
|
||||
+ reverse("admin:admin_widgets_school_change", args=(self.school.id,))
|
||||
)
|
||||
|
||||
self.wait_page_ready()
|
||||
self.select_option("#id_students_from", str(self.lisa.id))
|
||||
self.selenium.find_element(By.ID, "id_students_add").click()
|
||||
self.select_option("#id_alumni_from", str(self.peter.id))
|
||||
self.selenium.find_element(By.ID, "id_alumni_add").click()
|
||||
|
||||
# Trigger form submission via Enter key on a text input field.
|
||||
name_input = self.selenium.find_element(By.ID, "id_name")
|
||||
name_input.click()
|
||||
name_input.send_keys(Keys.ENTER)
|
||||
|
||||
# Form was submitted, success message should be shown.
|
||||
self.wait_for_text(
|
||||
"li.success", "The school “School of Awesome” was changed successfully."
|
||||
)
|
||||
|
||||
# Changes should be stored properly in the database.
|
||||
school = School.objects.get(id=self.school.id)
|
||||
self.assertSequenceEqual(
|
||||
school.students.all().order_by("name"), [self.lisa, self.peter]
|
||||
)
|
||||
self.assertSequenceEqual(
|
||||
school.alumni.all().order_by("name"), [self.lisa, self.peter]
|
||||
)
|
||||
|
||||
|
||||
@ignore_warnings(category=RemovedInDjango60Warning)
|
||||
class AdminRawIdWidgetSeleniumTests(AdminWidgetSeleniumTestCase):
|
||||
|
Loading…
x
Reference in New Issue
Block a user