Skip to content

Commit 8c118c0

Browse files
BSmick6sarahboyce
authored andcommitted
Fixed #35940 -- Disabled SelectFilter add/remove buttons when appropriate.
1 parent a9c79b4 commit 8c118c0

File tree

7 files changed

+103
-52
lines changed

7 files changed

+103
-52
lines changed

django/contrib/admin/static/admin/css/responsive.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,15 +631,15 @@ input[type="submit"], button {
631631
background-position: 0 0;
632632
}
633633

634-
.active.selector-remove:focus, .active.selector-remove:hover {
634+
:enabled.selector-remove:focus, :enabled.selector-remove:hover {
635635
background-position: 0 -24px;
636636
}
637637

638638
.selector-add {
639639
background-position: 0 -48px;
640640
}
641641

642-
.active.selector-add:focus, .active.selector-add:hover {
642+
:enabled.selector-add:focus, :enabled.selector-add:hover {
643643
background-position: 0 -72px;
644644
}
645645

django/contrib/admin/static/admin/css/responsive_rtl.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,15 @@
7575
background-position: 0 0;
7676
}
7777

78-
[dir="rtl"] .active.selector-remove:focus, .active.selector-remove:hover {
78+
[dir="rtl"] :enabled.selector-remove:focus, :enabled.selector-remove:hover {
7979
background-position: 0 -24px;
8080
}
8181

8282
[dir="rtl"] .selector-add {
8383
background-position: 0 -48px;
8484
}
8585

86-
[dir="rtl"] .active.selector-add:focus, .active.selector-add:hover {
86+
[dir="rtl"] :enabled.selector-add:focus, :enabled.selector-add:hover {
8787
background-position: 0 -72px;
8888
}
8989
}

django/contrib/admin/static/admin/css/rtl.css

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ fieldset .fieldBox {
224224
background-size: 24px auto;
225225
}
226226

227-
.active.selector-add:focus, .active.selector-add:hover {
227+
:enabled.selector-add:focus, :enabled.selector-add:hover {
228228
background-position: 0 -120px;
229229
}
230230

@@ -233,23 +233,23 @@ fieldset .fieldBox {
233233
background-size: 24px auto;
234234
}
235235

236-
.active.selector-remove:focus, .active.selector-remove:hover {
236+
:enabled.selector-remove:focus, :enabled.selector-remove:hover {
237237
background-position: 0 -168px;
238238
}
239239

240240
.selector-chooseall {
241241
background: url(../img/selector-icons.svg) right -128px no-repeat;
242242
}
243243

244-
.active.selector-chooseall:focus, .active.selector-chooseall:hover {
244+
:enabled.selector-chooseall:focus, :enabled.selector-chooseall:hover {
245245
background-position: 100% -144px;
246246
}
247247

248248
.selector-clearall {
249249
background: url(../img/selector-icons.svg) 0 -160px no-repeat;
250250
}
251251

252-
.active.selector-clearall:focus, .active.selector-clearall:hover {
252+
:enabled.selector-clearall:focus, :enabled.selector-clearall:hover {
253253
background-position: 0 -176px;
254254
}
255255

django/contrib/admin/static/admin/css/widgets.css

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,11 @@
129129
border: none;
130130
}
131131

132-
.active.selector-add, .active.selector-remove {
132+
:enabled.selector-add, :enabled.selector-remove {
133133
opacity: 1;
134134
}
135135

136-
.active.selector-add:hover, .active.selector-remove:hover {
136+
:enabled.selector-add:hover, :enabled.selector-remove:hover {
137137
cursor: pointer;
138138
}
139139

@@ -142,7 +142,7 @@
142142
background-size: 24px auto;
143143
}
144144

145-
.active.selector-add:focus, .active.selector-add:hover {
145+
:enabled.selector-add:focus, :enabled.selector-add:hover {
146146
background-position: 0 -168px;
147147
}
148148

@@ -151,7 +151,7 @@
151151
background-size: 24px auto;
152152
}
153153

154-
.active.selector-remove:focus, .active.selector-remove:hover {
154+
:enabled.selector-remove:focus, :enabled.selector-remove:hover {
155155
background-position: 0 -120px;
156156
}
157157

@@ -169,16 +169,16 @@
169169
border: none;
170170
}
171171

172-
.active.selector-chooseall:focus, .active.selector-clearall:focus,
173-
.active.selector-chooseall:hover, .active.selector-clearall:hover {
172+
:enabled.selector-chooseall:focus, :enabled.selector-clearall:focus,
173+
:enabled.selector-chooseall:hover, :enabled.selector-clearall:hover {
174174
color: var(--link-fg);
175175
}
176176

177-
.active.selector-chooseall, .active.selector-clearall {
177+
:enabled.selector-chooseall, :enabled.selector-clearall {
178178
opacity: 1;
179179
}
180180

181-
.active.selector-chooseall:hover, .active.selector-clearall:hover {
181+
:enabled.selector-chooseall:hover, :enabled.selector-clearall:hover {
182182
cursor: pointer;
183183
}
184184

@@ -188,7 +188,7 @@
188188
cursor: default;
189189
}
190190

191-
.active.selector-chooseall:focus, .active.selector-chooseall:hover {
191+
:enabled.selector-chooseall:focus, :enabled.selector-chooseall:hover {
192192
background-position: 100% -176px;
193193
}
194194

@@ -198,7 +198,7 @@
198198
cursor: default;
199199
}
200200

201-
.active.selector-clearall:focus, .active.selector-clearall:hover {
201+
:enabled.selector-clearall:focus, :enabled.selector-clearall:hover {
202202
background-position: 0 -144px;
203203
}
204204

@@ -252,12 +252,12 @@
252252
cursor: default;
253253
}
254254

255-
.stacked .active.selector-add {
255+
.stacked :enabled.selector-add {
256256
background-position: 0 -48px;
257257
cursor: pointer;
258258
}
259259

260-
.stacked .active.selector-add:focus, .stacked .active.selector-add:hover {
260+
.stacked :enabled.selector-add:focus, .stacked :enabled.selector-add:hover {
261261
background-position: 0 -72px;
262262
cursor: pointer;
263263
}
@@ -268,12 +268,12 @@
268268
cursor: default;
269269
}
270270

271-
.stacked .active.selector-remove {
271+
.stacked :enabled.selector-remove {
272272
background-position: 0 0px;
273273
cursor: pointer;
274274
}
275275

276-
.stacked .active.selector-remove:focus, .stacked .active.selector-remove:hover {
276+
.stacked :enabled.selector-remove:focus, .stacked :enabled.selector-remove:hover {
277277
background-position: 0 -24px;
278278
cursor: pointer;
279279
}

django/contrib/admin/static/admin/js/SelectFilter2.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ Requires core.js and SelectBox.js.
149149

150150
// Set up the JavaScript event handlers for the select box filter interface
151151
const move_selection = function(e, elem, move_func, from, to) {
152-
if (elem.classList.contains('active')) {
152+
if (!elem.hasAttribute('disabled')) {
153153
move_func(from, to);
154154
SelectFilter.refresh_icons(field_id);
155155
SelectFilter.refresh_filtered_selects(field_id);
@@ -248,13 +248,12 @@ Requires core.js and SelectBox.js.
248248
refresh_icons: function(field_id) {
249249
const from = document.getElementById(field_id + '_from');
250250
const to = document.getElementById(field_id + '_to');
251-
// Active if at least one item is selected
252-
document.getElementById(field_id + '_add').classList.toggle('active', SelectFilter.any_selected(from));
253-
document.getElementById(field_id + '_remove').classList.toggle('active', SelectFilter.any_selected(to));
254-
// Active if the corresponding box isn't empty
255-
document.getElementById(field_id + '_add_all').classList.toggle('active', from.querySelector('option'));
256-
document.getElementById(field_id + '_remove_all').classList.toggle('active', to.querySelector('option'));
257-
SelectFilter.refresh_filtered_warning(field_id);
251+
// Disabled if no items are selected.
252+
document.getElementById(field_id + '_add').disabled = !SelectFilter.any_selected(from);
253+
document.getElementById(field_id + '_remove').disabled = !SelectFilter.any_selected(to);
254+
// Disabled if the corresponding box is empty.
255+
document.getElementById(field_id + '_add_all').disabled = !from.querySelector('option');
256+
document.getElementById(field_id + '_remove_all').disabled = !to.querySelector('option');
258257
},
259258
filter_key_press: function(event, field_id, source, target) {
260259
const source_box = document.getElementById(field_id + source);

django/contrib/admin/tests.py

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -218,19 +218,16 @@ def assertSelectedOptions(self, selector, values):
218218
"""
219219
self._assertOptionsValues("%s > option:checked" % selector, values)
220220

221-
def has_css_class(self, selector, klass):
221+
def is_disabled(self, selector):
222222
"""
223-
Return True if the element identified by `selector` has the CSS class
224-
`klass`.
223+
Return True if the element identified by `selector` has the `disabled`
224+
attribute.
225225
"""
226226
from selenium.webdriver.common.by import By
227227

228228
return (
229-
self.selenium.find_element(
230-
By.CSS_SELECTOR,
231-
selector,
229+
self.selenium.find_element(By.CSS_SELECTOR, selector).get_attribute(
230+
"disabled"
232231
)
233-
.get_attribute("class")
234-
.find(klass)
235-
!= -1
232+
== "true"
236233
)

tests/admin_widgets/tests.py

Lines changed: 68 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,21 +1254,27 @@ def setUp(self):
12541254
self.arthur = Student.objects.create(name="Arthur")
12551255
self.school = School.objects.create(name="School of Awesome")
12561256

1257-
def assertActiveButtons(
1258-
self, mode, field_name, choose, remove, choose_all=None, remove_all=None
1257+
def assertButtonsDisabled(
1258+
self,
1259+
mode,
1260+
field_name,
1261+
choose_btn_disabled=False,
1262+
remove_btn_disabled=False,
1263+
choose_all_btn_disabled=False,
1264+
remove_all_btn_disabled=False,
12591265
):
12601266
choose_button = "#id_%s_add" % field_name
12611267
choose_all_button = "#id_%s_add_all" % field_name
12621268
remove_button = "#id_%s_remove" % field_name
12631269
remove_all_button = "#id_%s_remove_all" % field_name
1264-
self.assertEqual(self.has_css_class(choose_button, "active"), choose)
1265-
self.assertEqual(self.has_css_class(remove_button, "active"), remove)
1270+
self.assertEqual(self.is_disabled(choose_button), choose_btn_disabled)
1271+
self.assertEqual(self.is_disabled(remove_button), remove_btn_disabled)
12661272
if mode == "horizontal":
12671273
self.assertEqual(
1268-
self.has_css_class(choose_all_button, "active"), choose_all
1274+
self.is_disabled(choose_all_button), choose_all_btn_disabled
12691275
)
12701276
self.assertEqual(
1271-
self.has_css_class(remove_all_button, "active"), remove_all
1277+
self.is_disabled(remove_all_button), remove_all_btn_disabled
12721278
)
12731279

12741280
def execute_basic_operations(self, mode, field_name):
@@ -1296,7 +1302,14 @@ def execute_basic_operations(self, mode, field_name):
12961302
],
12971303
)
12981304
self.assertSelectOptions(to_box, [str(self.lisa.id), str(self.peter.id)])
1299-
self.assertActiveButtons(mode, field_name, False, False, True, True)
1305+
self.assertButtonsDisabled(
1306+
mode,
1307+
field_name,
1308+
choose_btn_disabled=True,
1309+
remove_btn_disabled=True,
1310+
choose_all_btn_disabled=False,
1311+
remove_all_btn_disabled=False,
1312+
)
13001313

13011314
# Click 'Choose all' --------------------------------------------------
13021315
if mode == "horizontal":
@@ -1323,7 +1336,14 @@ def execute_basic_operations(self, mode, field_name):
13231336
str(self.john.id),
13241337
],
13251338
)
1326-
self.assertActiveButtons(mode, field_name, False, False, False, True)
1339+
self.assertButtonsDisabled(
1340+
mode,
1341+
field_name,
1342+
choose_btn_disabled=True,
1343+
remove_btn_disabled=True,
1344+
choose_all_btn_disabled=True,
1345+
remove_all_btn_disabled=False,
1346+
)
13271347

13281348
# Click 'Remove all' --------------------------------------------------
13291349
if mode == "horizontal":
@@ -1350,7 +1370,14 @@ def execute_basic_operations(self, mode, field_name):
13501370
],
13511371
)
13521372
self.assertSelectOptions(to_box, [])
1353-
self.assertActiveButtons(mode, field_name, False, False, True, False)
1373+
self.assertButtonsDisabled(
1374+
mode,
1375+
field_name,
1376+
choose_btn_disabled=True,
1377+
remove_btn_disabled=True,
1378+
choose_all_btn_disabled=False,
1379+
remove_all_btn_disabled=True,
1380+
)
13541381

13551382
# Choose some options ------------------------------------------------
13561383
from_lisa_select_option = self.selenium.find_element(
@@ -1367,9 +1394,23 @@ def execute_basic_operations(self, mode, field_name):
13671394
self.select_option(from_box, str(self.jason.id))
13681395
self.select_option(from_box, str(self.bob.id))
13691396
self.select_option(from_box, str(self.john.id))
1370-
self.assertActiveButtons(mode, field_name, True, False, True, False)
1397+
self.assertButtonsDisabled(
1398+
mode,
1399+
field_name,
1400+
choose_btn_disabled=False,
1401+
remove_btn_disabled=True,
1402+
choose_all_btn_disabled=False,
1403+
remove_all_btn_disabled=True,
1404+
)
13711405
self.selenium.find_element(By.ID, choose_button).click()
1372-
self.assertActiveButtons(mode, field_name, False, False, True, True)
1406+
self.assertButtonsDisabled(
1407+
mode,
1408+
field_name,
1409+
choose_btn_disabled=True,
1410+
remove_btn_disabled=True,
1411+
choose_all_btn_disabled=False,
1412+
remove_all_btn_disabled=False,
1413+
)
13731414

13741415
self.assertSelectOptions(
13751416
from_box,
@@ -1402,9 +1443,23 @@ def execute_basic_operations(self, mode, field_name):
14021443
# Remove some options -------------------------------------------------
14031444
self.select_option(to_box, str(self.lisa.id))
14041445
self.select_option(to_box, str(self.bob.id))
1405-
self.assertActiveButtons(mode, field_name, False, True, True, True)
1446+
self.assertButtonsDisabled(
1447+
mode,
1448+
field_name,
1449+
choose_btn_disabled=True,
1450+
remove_btn_disabled=False,
1451+
choose_all_btn_disabled=False,
1452+
remove_all_btn_disabled=False,
1453+
)
14061454
self.selenium.find_element(By.ID, remove_button).click()
1407-
self.assertActiveButtons(mode, field_name, False, False, True, True)
1455+
self.assertButtonsDisabled(
1456+
mode,
1457+
field_name,
1458+
choose_btn_disabled=True,
1459+
remove_btn_disabled=True,
1460+
choose_all_btn_disabled=False,
1461+
remove_all_btn_disabled=False,
1462+
)
14081463

14091464
self.assertSelectOptions(
14101465
from_box,

0 commit comments

Comments
 (0)