diff --git a/AUTHORS b/AUTHORS index b300a6791d..efa728584b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -163,6 +163,7 @@ answer newbie questions, and generally made Django that much better: Bhuvnesh Sharma Bill Fenner Bjørn Stabell + Blayze Wilhelm Bo Marchman Bogdan Mateescu Bojan Mihelac diff --git a/django/contrib/admin/static/admin/js/SelectFilter2.js b/django/contrib/admin/static/admin/js/SelectFilter2.js index 08d47fc298..970b511b0c 100644 --- a/django/contrib/admin/static/admin/js/SelectFilter2.js +++ b/django/contrib/admin/static/admin/js/SelectFilter2.js @@ -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' ); //
    @@ -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' ); //
    @@ -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'; diff --git a/docs/releases/5.2.2.txt b/docs/releases/5.2.2.txt index 8ed0856352..5647c0cc07 100644 --- a/docs/releases/5.2.2.txt +++ b/docs/releases/5.2.2.txt @@ -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`). diff --git a/js_tests/admin/SelectFilter2.test.js b/js_tests/admin/SelectFilter2.test.js index 8c1480d2a6..1fd46bd0ce 100644 --- a/js_tests/admin/SelectFilter2.test.js +++ b/js_tests/admin/SelectFilter2.test.js @@ -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) { diff --git a/tests/admin_widgets/tests.py b/tests/admin_widgets/tests.py index 74fc30a706..7720ec04c0 100644 --- a/tests/admin_widgets/tests.py +++ b/tests/admin_widgets/tests.py @@ -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):