This commit is contained in:
Sean Helvey 2025-11-17 13:45:10 +01:00 committed by GitHub
commit d247f4954e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 134 additions and 63 deletions

View file

@ -952,6 +952,7 @@ answer newbie questions, and generally made Django that much better:
Scott Pashley <github@scottpashley.co.uk> Scott Pashley <github@scottpashley.co.uk>
scott@staplefish.com scott@staplefish.com
Sean Brant Sean Brant
Sean Helvey <me@seanhelvey.com>
Sebastian Hillig <sebastian.hillig@gmail.com> Sebastian Hillig <sebastian.hillig@gmail.com>
Sebastian Spiegel <https://www.tivix.com/> Sebastian Spiegel <https://www.tivix.com/>
Segyo Myung <myungsekyo@gmail.com> Segyo Myung <myungsekyo@gmail.com>

View file

@ -8,6 +8,7 @@ from urllib.parse import quote as urlquote
from urllib.parse import urlsplit from urllib.parse import urlsplit
from django import forms from django import forms
from django.apps import apps
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.admin import helpers, widgets from django.contrib.admin import helpers, widgets
@ -71,6 +72,7 @@ from django.views.decorators.csrf import csrf_protect
from django.views.generic import RedirectView from django.views.generic import RedirectView
IS_POPUP_VAR = "_popup" IS_POPUP_VAR = "_popup"
SOURCE_MODEL_VAR = "_source_model"
TO_FIELD_VAR = "_to_field" TO_FIELD_VAR = "_to_field"
IS_FACETS_VAR = "_facets" IS_FACETS_VAR = "_facets"
@ -1342,6 +1344,7 @@ class ModelAdmin(BaseModelAdmin):
"save_on_top": self.save_on_top, "save_on_top": self.save_on_top,
"to_field_var": TO_FIELD_VAR, "to_field_var": TO_FIELD_VAR,
"is_popup_var": IS_POPUP_VAR, "is_popup_var": IS_POPUP_VAR,
"source_model_var": SOURCE_MODEL_VAR,
"app_label": app_label, "app_label": app_label,
} }
) )
@ -1398,12 +1401,39 @@ class ModelAdmin(BaseModelAdmin):
else: else:
attr = obj._meta.pk.attname attr = obj._meta.pk.attname
value = obj.serializable_value(attr) value = obj.serializable_value(attr)
popup_response_data = json.dumps( popup_response = {
{ "value": str(value),
"value": str(value), "obj": str(obj),
"obj": str(obj), }
}
) # Find the optgroup for the new item, if available
source_model_name = request.POST.get(SOURCE_MODEL_VAR)
if source_model_name:
if "." not in source_model_name:
raise ValueError(f"Invalid model format: {source_model_name}")
app_label, model_name = source_model_name.split(".", 1)
try:
source_model = apps.get_model(app_label, model_name)
except LookupError:
raise LookupError(f"No installed app/model: {source_model_name}")
form_class = self.admin_site._registry[source_model].form
if (
hasattr(form_class, "_meta")
and hasattr(form_class._meta, "fields")
and form_class._meta.fields is not None
and self.opts.verbose_name_plural in form_class._meta.fields
):
field_choices = (
form_class().fields[self.opts.verbose_name_plural].choices
)
for optgroup_label, optgroup_choices in field_choices:
for choice_value, choice_display in optgroup_choices:
if choice_display == str(obj):
popup_response["optgroup"] = optgroup_label
popup_response_data = json.dumps(popup_response)
return TemplateResponse( return TemplateResponse(
request, request,
self.popup_response_template self.popup_response_template
@ -1913,6 +1943,7 @@ class ModelAdmin(BaseModelAdmin):
"object_id": object_id, "object_id": object_id,
"original": obj, "original": obj,
"is_popup": IS_POPUP_VAR in request.POST or IS_POPUP_VAR in request.GET, "is_popup": IS_POPUP_VAR in request.POST or IS_POPUP_VAR in request.GET,
"source_model": request.GET.get(SOURCE_MODEL_VAR),
"to_field": to_field, "to_field": to_field,
"media": media, "media": media,
"inline_admin_formsets": inline_formsets, "inline_admin_formsets": inline_formsets,

View file

@ -1,5 +1,6 @@
'use strict'; 'use strict';
{ {
const getOptionGroupName = (option) => option.parentElement.label;
const SelectBox = { const SelectBox = {
cache: {}, cache: {},
init: function(id) { init: function(id) {
@ -7,20 +8,29 @@
SelectBox.cache[id] = []; SelectBox.cache[id] = [];
const cache = SelectBox.cache[id]; const cache = SelectBox.cache[id];
for (const node of box.options) { for (const node of box.options) {
cache.push({value: node.value, text: node.text, displayed: 1}); const group = getOptionGroupName(node);
cache.push({group, value: node.value, text: node.text, displayed: 1});
} }
SelectBox.sort(id);
}, },
redisplay: function(id) { redisplay: function(id) {
// Repopulate HTML select box from cache // Repopulate HTML select box from cache
const box = document.getElementById(id); const box = document.getElementById(id);
const scroll_value_from_top = box.scrollTop; const scroll_value_from_top = box.scrollTop;
box.innerHTML = ''; box.innerHTML = '';
for (const node of SelectBox.cache[id]) { let node = box;
if (node.displayed) { let group = null;
const new_option = new Option(node.text, node.value, false, false); for (const option of SelectBox.cache[id]) {
// Shows a tooltip when hovering over the option if (option.group && option.group !== group && option.displayed) {
new_option.title = node.text; group = option.group;
box.appendChild(new_option); node = document.createElement('optgroup');
node.setAttribute('label', option.group);
box.appendChild(node);
}
if (option.displayed) {
const new_option = new Option(option.text, option.value, false, false);
new_option.title = option.text;
node.appendChild(new_option);
} }
} }
box.scrollTop = scroll_value_from_top; box.scrollTop = scroll_value_from_top;
@ -57,7 +67,8 @@
cache.splice(delete_index, 1); cache.splice(delete_index, 1);
}, },
add_to_cache: function(id, option) { add_to_cache: function(id, option) {
SelectBox.cache[id].push({value: option.value, text: option.text, displayed: 1}); SelectBox.cache[id].push({group: option.group, value: option.value, text: option.text, displayed: 1});
SelectBox.sort(id);
}, },
cache_contains: function(id, value) { cache_contains: function(id, value) {
// Check if an item is contained in the cache // Check if an item is contained in the cache
@ -73,7 +84,8 @@
for (const option of from_box.options) { for (const option of from_box.options) {
const option_value = option.value; const option_value = option.value;
if (option.selected && SelectBox.cache_contains(from, option_value)) { if (option.selected && SelectBox.cache_contains(from, option_value)) {
SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); const group = getOptionGroupName(option);
SelectBox.add_to_cache(to, {group, value: option_value, text: option.text, displayed: 1});
SelectBox.delete_from_cache(from, option_value); SelectBox.delete_from_cache(from, option_value);
} }
} }
@ -85,7 +97,8 @@
for (const option of from_box.options) { for (const option of from_box.options) {
const option_value = option.value; const option_value = option.value;
if (SelectBox.cache_contains(from, option_value)) { if (SelectBox.cache_contains(from, option_value)) {
SelectBox.add_to_cache(to, {value: option_value, text: option.text, displayed: 1}); const group = getOptionGroupName(option);
SelectBox.add_to_cache(to, {group, value: option_value, text: option.text, displayed: 1});
SelectBox.delete_from_cache(from, option_value); SelectBox.delete_from_cache(from, option_value);
} }
} }
@ -94,8 +107,8 @@
}, },
sort: function(id) { sort: function(id) {
SelectBox.cache[id].sort(function(a, b) { SelectBox.cache[id].sort(function(a, b) {
a = a.text.toLowerCase(); a = (a.group && a.group.toLowerCase() || '') + a.text.toLowerCase();
b = b.text.toLowerCase(); b = (b.group && b.group.toLowerCase() || '') + b.text.toLowerCase();
if (a > b) { if (a > b) {
return 1; return 1;
} }

View file

@ -123,7 +123,7 @@
}); });
} }
function dismissAddRelatedObjectPopup(win, newId, newRepr) { function dismissAddRelatedObjectPopup(win, newId, newRepr, optgroup) {
const name = removePopupIndex(win.name); const name = removePopupIndex(win.name);
const elem = document.getElementById(name); const elem = document.getElementById(name);
if (elem) { if (elem) {
@ -143,8 +143,9 @@
} else { } else {
const toId = name + "_to"; const toId = name + "_to";
const toElem = document.getElementById(toId); const toElem = document.getElementById(toId);
const o = new Option(newRepr, newId); const newOption = new Option(newRepr, newId);
SelectBox.add_to_cache(toId, o); newOption.group = optgroup;
SelectBox.add_to_cache(toId, newOption);
SelectBox.redisplay(toId); SelectBox.redisplay(toId);
if (toElem && toElem.nodeName.toUpperCase() === 'SELECT') { if (toElem && toElem.nodeName.toUpperCase() === 'SELECT') {
const skipIds = [name + "_from"]; const skipIds = [name + "_from"];

View file

@ -9,7 +9,7 @@
opener.dismissDeleteRelatedObjectPopup(window, initData.value); opener.dismissDeleteRelatedObjectPopup(window, initData.value);
break; break;
default: default:
opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj); opener.dismissAddRelatedObjectPopup(window, initData.value, initData.obj, initData.optgroup);
break; break;
} }
} }

View file

@ -38,6 +38,7 @@
<div> <div>
{% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1">{% endif %} {% if is_popup %}<input type="hidden" name="{{ is_popup_var }}" value="1">{% endif %}
{% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">{% endif %} {% if to_field %}<input type="hidden" name="{{ to_field_var }}" value="{{ to_field }}">{% endif %}
{% if source_model %}<input type="hidden" name="{{ source_model_var }}" value="{{ source_model }}">{% endif %}
{% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %} {% if save_on_top %}{% block submit_buttons_top %}{% submit_row %}{% endblock %}{% endif %}
{% if errors %} {% if errors %}
<p class="errornote"> <p class="errornote">

View file

@ -11,6 +11,7 @@ from django.contrib.admin.exceptions import (
from django.contrib.admin.options import ( from django.contrib.admin.options import (
IS_FACETS_VAR, IS_FACETS_VAR,
IS_POPUP_VAR, IS_POPUP_VAR,
SOURCE_MODEL_VAR,
TO_FIELD_VAR, TO_FIELD_VAR,
IncorrectLookupParameters, IncorrectLookupParameters,
ShowFacets, ShowFacets,
@ -49,6 +50,7 @@ IGNORED_PARAMS = (
SEARCH_VAR, SEARCH_VAR,
IS_FACETS_VAR, IS_FACETS_VAR,
IS_POPUP_VAR, IS_POPUP_VAR,
SOURCE_MODEL_VAR,
TO_FIELD_VAR, TO_FIELD_VAR,
) )

View file

@ -332,16 +332,24 @@ class RelatedFieldWidgetWrapper(forms.Widget):
) )
def get_context(self, name, value, attrs): def get_context(self, name, value, attrs):
from django.contrib.admin.views.main import IS_POPUP_VAR, TO_FIELD_VAR from django.contrib.admin.views.main import (
IS_POPUP_VAR,
SOURCE_MODEL_VAR,
TO_FIELD_VAR,
)
rel_opts = self.rel.model._meta rel_opts = self.rel.model._meta
info = (rel_opts.app_label, rel_opts.model_name) info = (rel_opts.app_label, rel_opts.model_name)
related_field_name = self.rel.get_related_field().name related_field_name = self.rel.get_related_field().name
app_label = self.rel.field.model._meta.app_label
model_name = self.rel.field.model._meta.model_name
url_params = "&".join( url_params = "&".join(
"%s=%s" % param "%s=%s" % param
for param in [ for param in [
(TO_FIELD_VAR, related_field_name), (TO_FIELD_VAR, related_field_name),
(IS_POPUP_VAR, 1), (IS_POPUP_VAR, 1),
(SOURCE_MODEL_VAR, f"{app_label}.{model_name}"),
] ]
) )
context = { context = {

View file

@ -45,3 +45,16 @@ QUnit.test('preserve scroll position', function(assert) {
assert.equal(toSelectBox.options.length, selectedOptions.length); assert.equal(toSelectBox.options.length, selectedOptions.length);
assert.notEqual(fromSelectBox.scrollTop, 0); assert.notEqual(fromSelectBox.scrollTop, 0);
}); });
QUnit.test('retain optgroups', function(assert) {
const $ = django.jQuery;
$('<select id="id"></select>').appendTo('#qunit-fixture');
const grp = $('<optgroup label="group one">').appendTo('#id');
$('<option value="0">A</option>').appendTo(grp);
$('</optgroup>').appendTo('#id');
$('<option value="1">B</option>').appendTo('#id');
SelectBox.init('id');
SelectBox.redisplay('id');
assert.equal($('#id option').length, 2);
assert.equal($('#id optgroup').length, 1);
});

View file

@ -44,9 +44,9 @@ QUnit.test('init', function(assert) {
QUnit.test('filtering available options', function(assert) { QUnit.test('filtering available options', function(assert) {
const $ = django.jQuery; const $ = django.jQuery;
$('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture');
$('<option value="1" title="Red">Red</option>').appendTo('#select'); $('<option value="1" title="Blue">Blue</option>').appendTo('#select');
$('<option value="2" title="Blue">Blue</option>').appendTo('#select'); $('<option value="2" title="Green">Green</option>').appendTo('#select');
$('<option value="3" title="Green">Green</option>').appendTo('#select'); $('<option value="3" title="Red">Red</option>').appendTo('#select');
SelectFilter.init('select', 'items', 0); SelectFilter.init('select', 'items', 0);
assert.equal($('#select_from option').length, 3); assert.equal($('#select_from option').length, 3);
assert.equal($('#select_to option').length, 0); assert.equal($('#select_to option').length, 0);
@ -58,7 +58,7 @@ QUnit.test('filtering available options', function(assert) {
setTimeout(() => { setTimeout(() => {
assert.equal($('#select_from option').length, 2); assert.equal($('#select_from option').length, 2);
assert.equal($('#select_to option').length, 0); assert.equal($('#select_to option').length, 0);
assert.equal($('#select_from option')[0].value, '1'); assert.equal($('#select_from option')[0].value, '2');
assert.equal($('#select_from option')[1].value, '3'); assert.equal($('#select_from option')[1].value, '3');
done(); done();
}); });
@ -67,9 +67,9 @@ QUnit.test('filtering available options', function(assert) {
QUnit.test('filtering selected options', function(assert) { QUnit.test('filtering selected options', function(assert) {
const $ = django.jQuery; const $ = django.jQuery;
$('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture');
$('<option selected value="1" title="Red">Red</option>').appendTo('#select'); $('<option selected value="1" title="Blue">Blue</option>').appendTo('#select');
$('<option selected value="2" title="Blue">Blue</option>').appendTo('#select'); $('<option selected value="2" title="Green">Green</option>').appendTo('#select');
$('<option selected value="3" title="Green">Green</option>').appendTo('#select'); $('<option selected value="3" title="Red">Red</option>').appendTo('#select');
SelectFilter.init('select', 'items', 0); SelectFilter.init('select', 'items', 0);
assert.equal($('#select_from option').length, 0); assert.equal($('#select_from option').length, 0);
assert.equal($('#select_to option').length, 3); assert.equal($('#select_to option').length, 3);
@ -81,7 +81,7 @@ QUnit.test('filtering selected options', function(assert) {
setTimeout(() => { setTimeout(() => {
assert.equal($('#select_from option').length, 0); assert.equal($('#select_from option').length, 0);
assert.equal($('#select_to option').length, 2); assert.equal($('#select_to option').length, 2);
assert.equal($('#select_to option')[0].value, '1'); assert.equal($('#select_to option')[0].value, '2');
assert.equal($('#select_to option')[1].value, '3'); assert.equal($('#select_to option')[1].value, '3');
done(); done();
}); });
@ -90,9 +90,9 @@ QUnit.test('filtering selected options', function(assert) {
QUnit.test('filtering available options to nothing', function(assert) { QUnit.test('filtering available options to nothing', function(assert) {
const $ = django.jQuery; const $ = django.jQuery;
$('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture');
$('<option value="1" title="Red">Red</option>').appendTo('#select'); $('<option value="1" title="Blue">Blue</option>').appendTo('#select');
$('<option value="2" title="Blue">Blue</option>').appendTo('#select'); $('<option value="2" title="Green">Green</option>').appendTo('#select');
$('<option value="3" title="Green">Green</option>').appendTo('#select'); $('<option value="3" title="Red">Red</option>').appendTo('#select');
SelectFilter.init('select', 'items', 0); SelectFilter.init('select', 'items', 0);
assert.equal($('#select_from option').length, 3); assert.equal($('#select_from option').length, 3);
assert.equal($('#select_to option').length, 0); assert.equal($('#select_to option').length, 0);
@ -111,9 +111,9 @@ QUnit.test('filtering available options to nothing', function(assert) {
QUnit.test('filtering selected options to nothing', function(assert) { QUnit.test('filtering selected options to nothing', function(assert) {
const $ = django.jQuery; const $ = django.jQuery;
$('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture');
$('<option selected value="1" title="Red">Red</option>').appendTo('#select'); $('<option selected value="1" title="Blue">Blue</option>').appendTo('#select');
$('<option selected value="2" title="Blue">Blue</option>').appendTo('#select'); $('<option selected value="2" title="Green">Green</option>').appendTo('#select');
$('<option selected value="3" title="Green">Green</option>').appendTo('#select'); $('<option selected value="3" title="Red">Red</option>').appendTo('#select');
SelectFilter.init('select', 'items', 0); SelectFilter.init('select', 'items', 0);
assert.equal($('#select_from option').length, 0); assert.equal($('#select_from option').length, 0);
assert.equal($('#select_to option').length, 3); assert.equal($('#select_to option').length, 3);
@ -132,9 +132,9 @@ QUnit.test('filtering selected options to nothing', function(assert) {
QUnit.test('selecting option', function(assert) { QUnit.test('selecting option', function(assert) {
const $ = django.jQuery; const $ = django.jQuery;
$('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture');
$('<option value="1" title="Red">Red</option>').appendTo('#select'); $('<option value="1" title="Blue">Blue</option>').appendTo('#select');
$('<option value="2" title="Blue">Blue</option>').appendTo('#select'); $('<option value="2" title="Green">Green</option>').appendTo('#select');
$('<option value="3" title="Green">Green</option>').appendTo('#select'); $('<option value="3" title="Red">Red</option>').appendTo('#select');
SelectFilter.init('select', 'items', 0); SelectFilter.init('select', 'items', 0);
assert.equal($('#select_from option').length, 3); assert.equal($('#select_from option').length, 3);
assert.equal($('#select_to option').length, 0); assert.equal($('#select_to option').length, 0);
@ -154,13 +154,13 @@ QUnit.test('selecting option', function(assert) {
QUnit.test('deselecting option', function(assert) { QUnit.test('deselecting option', function(assert) {
const $ = django.jQuery; const $ = django.jQuery;
$('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture'); $('<form><select multiple id="select"></select></form>').appendTo('#qunit-fixture');
$('<option selected value="1" title="Red">Red</option>').appendTo('#select'); $('<option value="1" title="Blue">Blue</option>').appendTo('#select');
$('<option value="2" title="Blue">Blue</option>').appendTo('#select'); $('<option value="2" title="Green">Green</option>').appendTo('#select');
$('<option value="3" title="Green">Green</option>').appendTo('#select'); $('<option selected value="3" title="Red">Red</option>').appendTo('#select');
SelectFilter.init('select', 'items', 0); SelectFilter.init('select', 'items', 0);
assert.equal($('#select_from option').length, 2); assert.equal($('#select_from option').length, 2);
assert.equal($('#select_to option').length, 1); assert.equal($('#select_to option').length, 1);
assert.equal($('#select_to option')[0].value, '1'); assert.equal($('#select_to option')[0].value, '3');
// move back to the left // move back to the left
const done_left = assert.async(); const done_left = assert.async();
$('#select_to')[0].selectedIndex = 0; $('#select_to')[0].selectedIndex = 0;

View file

@ -957,6 +957,7 @@ class RelatedFieldWidgetWrapperTests(SimpleTestCase):
self.assertIn("<a ", output) self.assertIn("<a ", output)
def test_data_model_ref_when_model_name_is_camel_case(self): def test_data_model_ref_when_model_name_is_camel_case(self):
self.maxDiff = None
rel = VideoStream._meta.get_field("release_event").remote_field rel = VideoStream._meta.get_field("release_event").remote_field
widget = forms.Select() widget = forms.Select()
wrapper = widgets.RelatedFieldWidgetWrapper(widget, rel, widget_admin_site) wrapper = widgets.RelatedFieldWidgetWrapper(widget, rel, widget_admin_site)
@ -971,7 +972,7 @@ class RelatedFieldWidgetWrapperTests(SimpleTestCase):
</select> </select>
<a class="related-widget-wrapper-link add-related" id="add_id_stream" <a class="related-widget-wrapper-link add-related" id="add_id_stream"
data-popup="yes" title="Add another release event" data-popup="yes" title="Add another release event"
href="/admin_widgets/releaseevent/add/?_to_field=album&amp;_popup=1"> href="/admin_widgets/releaseevent/add/?_to_field=album&amp;_popup=1&_source_model=admin_widgets.videostream">
<img src="/static/admin/img/icon-addlink.svg" alt="" width="24" height="24"> <img src="/static/admin/img/icon-addlink.svg" alt="" width="24" height="24">
</a> </a>
</div> </div>
@ -1354,14 +1355,14 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
self.assertSelectOptions( self.assertSelectOptions(
to_box, to_box,
[ [
str(self.lisa.id),
str(self.peter.id),
str(self.arthur.id), str(self.arthur.id),
str(self.bob.id), str(self.bob.id),
str(self.cliff.id), str(self.cliff.id),
str(self.jason.id), str(self.jason.id),
str(self.jenny.id), str(self.jenny.id),
str(self.john.id), str(self.john.id),
str(self.lisa.id),
str(self.peter.id),
], ],
) )
self.assertButtonsDisabled( self.assertButtonsDisabled(
@ -1387,14 +1388,14 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
self.assertSelectOptions( self.assertSelectOptions(
from_box, from_box,
[ [
str(self.lisa.id),
str(self.peter.id),
str(self.arthur.id), str(self.arthur.id),
str(self.bob.id), str(self.bob.id),
str(self.cliff.id), str(self.cliff.id),
str(self.jason.id), str(self.jason.id),
str(self.jenny.id), str(self.jenny.id),
str(self.john.id), str(self.john.id),
str(self.lisa.id),
str(self.peter.id),
], ],
) )
self.assertSelectOptions(to_box, []) self.assertSelectOptions(to_box, [])
@ -1443,19 +1444,19 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
self.assertSelectOptions( self.assertSelectOptions(
from_box, from_box,
[ [
str(self.peter.id),
str(self.arthur.id), str(self.arthur.id),
str(self.cliff.id), str(self.cliff.id),
str(self.jenny.id), str(self.jenny.id),
str(self.peter.id),
], ],
) )
self.assertSelectOptions( self.assertSelectOptions(
to_box, to_box,
[ [
str(self.lisa.id),
str(self.bob.id), str(self.bob.id),
str(self.jason.id), str(self.jason.id),
str(self.john.id), str(self.john.id),
str(self.lisa.id),
], ],
) )
@ -1492,12 +1493,12 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
self.assertSelectOptions( self.assertSelectOptions(
from_box, from_box,
[ [
str(self.peter.id),
str(self.arthur.id), str(self.arthur.id),
str(self.bob.id),
str(self.cliff.id), str(self.cliff.id),
str(self.jenny.id), str(self.jenny.id),
str(self.lisa.id), str(self.lisa.id),
str(self.bob.id), str(self.peter.id),
], ],
) )
self.assertSelectOptions(to_box, [str(self.jason.id), str(self.john.id)]) self.assertSelectOptions(to_box, [str(self.jason.id), str(self.john.id)])
@ -1510,19 +1511,19 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
self.assertSelectOptions( self.assertSelectOptions(
from_box, from_box,
[ [
str(self.peter.id), str(self.bob.id),
str(self.jenny.id), str(self.jenny.id),
str(self.lisa.id), str(self.lisa.id),
str(self.bob.id), str(self.peter.id),
], ],
) )
self.assertSelectOptions( self.assertSelectOptions(
to_box, to_box,
[ [
str(self.jason.id),
str(self.john.id),
str(self.arthur.id), str(self.arthur.id),
str(self.cliff.id), str(self.cliff.id),
str(self.jason.id),
str(self.john.id),
], ],
) )
@ -1532,9 +1533,9 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
# Confirm they're selected after clicking inactive buttons: ticket # Confirm they're selected after clicking inactive buttons: ticket
# #26575 # #26575
self.assertSelectedOptions(from_box, [str(self.peter.id), str(self.lisa.id)]) self.assertSelectedOptions(from_box, [str(self.lisa.id), str(self.peter.id)])
self.selenium.find_element(By.ID, remove_button).click() self.selenium.find_element(By.ID, remove_button).click()
self.assertSelectedOptions(from_box, [str(self.peter.id), str(self.lisa.id)]) self.assertSelectedOptions(from_box, [str(self.lisa.id), str(self.peter.id)])
# Unselect the options ------------------------------------------------ # Unselect the options ------------------------------------------------
self.deselect_option(from_box, str(self.peter.id)) self.deselect_option(from_box, str(self.peter.id))
@ -1661,9 +1662,9 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
self.assertSelectOptions( self.assertSelectOptions(
to_box, to_box,
[ [
str(self.jason.id),
str(self.lisa.id), str(self.lisa.id),
str(self.peter.id), str(self.peter.id),
str(self.jason.id),
], ],
) )
@ -1673,7 +1674,7 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
from_box, [str(self.arthur.id), str(self.lisa.id)] from_box, [str(self.arthur.id), str(self.lisa.id)]
) )
self.assertSelectOptions( self.assertSelectOptions(
to_box, [str(self.peter.id), str(self.jason.id)] to_box, [str(self.jason.id), str(self.peter.id)]
) )
input.send_keys([Keys.BACK_SPACE]) # Clear text box input.send_keys([Keys.BACK_SPACE]) # Clear text box
@ -1689,7 +1690,7 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
], ],
) )
self.assertSelectOptions( self.assertSelectOptions(
to_box, [str(self.peter.id), str(self.jason.id)] to_box, [str(self.jason.id), str(self.peter.id)]
) )
# Pressing enter on a filtered option sends it properly to # Pressing enter on a filtered option sends it properly to
@ -1700,7 +1701,7 @@ class HorizontalVerticalFilterSeleniumTests(AdminWidgetSeleniumTestCase):
self.assertSelectOptions(from_box, [str(self.jason.id)]) self.assertSelectOptions(from_box, [str(self.jason.id)])
input.send_keys([Keys.ENTER]) input.send_keys([Keys.ENTER])
self.assertSelectOptions( self.assertSelectOptions(
to_box, [str(self.peter.id), str(self.jason.id)] to_box, [str(self.jason.id), str(self.peter.id)]
) )
input.send_keys([Keys.BACK_SPACE, Keys.BACK_SPACE]) input.send_keys([Keys.BACK_SPACE, Keys.BACK_SPACE])