Fixed #10615 - Added selection counter to admin change list. Thanks to Martin Mahner for the idea and initial patch.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@12107 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Jannis Leidel 2010-01-05 18:24:27 +00:00
parent 33afa13af5
commit afa4c5ac60
9 changed files with 61 additions and 3 deletions

View File

@ -228,6 +228,12 @@
border-right: 1px solid #ddd; border-right: 1px solid #ddd;
} }
.action_counter{
font-size: 11px;
margin: 0 0.5em;
display: none;
}
#changelist table input { #changelist table input {
margin: 0; margin: 0;
} }

View File

@ -1,10 +1,22 @@
var Actions = { var Actions = {
init: function() { init: function() {
var selectAll = document.getElementById('action-toggle'); counterSpans = document.getElementsBySelector('span._acnt');
counterContainer = document.getElementsBySelector('span.action_counter');
actionCheckboxes = document.getElementsBySelector('tr input.action-select');
selectAll = document.getElementById('action-toggle');
for(var i = 0; i < counterContainer.length; i++) {
counterContainer[i].style.display = 'inline';
}
if (selectAll) { if (selectAll) {
selectAll.style.display = 'inline'; selectAll.style.display = 'inline';
addEvent(selectAll, 'click', function() { addEvent(selectAll, 'click', function() {
Actions.checker(selectAll.checked); Actions.checker(selectAll.checked);
Actions.counter();
});
}
for(var i = 0; i < actionCheckboxes.length; i++) {
addEvent(actionCheckboxes[i], 'click', function() {
Actions.counter();
}); });
} }
var changelistTable = document.getElementsBySelector('#changelist table')[0]; var changelistTable = document.getElementsBySelector('#changelist table')[0];
@ -16,6 +28,7 @@ var Actions = {
if (target.className == 'action-select') { if (target.className == 'action-select') {
var tr = target.parentNode.parentNode; var tr = target.parentNode.parentNode;
Actions.toggleRow(tr, target.checked); Actions.toggleRow(tr, target.checked);
Actions.checked();
} }
}); });
} }
@ -27,13 +40,26 @@ var Actions = {
tr.className = tr.className.replace(' selected', ''); tr.className = tr.className.replace(' selected', '');
} }
}, },
checked: function() {
selectAll.checked = false;
},
checker: function(checked) { checker: function(checked) {
var actionCheckboxes = document.getElementsBySelector('tr input.action-select');
for(var i = 0; i < actionCheckboxes.length; i++) { for(var i = 0; i < actionCheckboxes.length; i++) {
actionCheckboxes[i].checked = checked; actionCheckboxes[i].checked = checked;
Actions.toggleRow(actionCheckboxes[i].parentNode.parentNode, checked); Actions.toggleRow(actionCheckboxes[i].parentNode.parentNode, checked);
} }
},
counter: function() {
counter = 0;
for(var i = 0; i < actionCheckboxes.length; i++) {
if(actionCheckboxes[i].checked){
counter++;
}
}
for(var i = 0; i < counterSpans.length; i++) {
counterSpans[i].innerHTML = counter;
}
} }
}; };
addEvent(window, 'load', Actions.init); addEvent(window, 'load', Actions.init);

View File

@ -210,6 +210,7 @@ class ModelAdmin(BaseModelAdmin):
action_form = helpers.ActionForm action_form = helpers.ActionForm
actions_on_top = True actions_on_top = True
actions_on_bottom = False actions_on_bottom = False
actions_selection_counter = True
def __init__(self, model, admin_site): def __init__(self, model, admin_site):
self.model = model self.model = model
@ -1024,7 +1025,13 @@ class ModelAdmin(BaseModelAdmin):
else: else:
action_form = None action_form = None
if cl.result_count == 1:
module_name = force_unicode(opts.verbose_name)
else:
module_name = force_unicode(opts.verbose_name_plural)
context = { context = {
'module_name': module_name,
'title': cl.title, 'title': cl.title,
'is_popup': cl.is_popup, 'is_popup': cl.is_popup,
'cl': cl, 'cl': cl,
@ -1035,6 +1042,7 @@ class ModelAdmin(BaseModelAdmin):
'action_form': action_form, 'action_form': action_form,
'actions_on_top': self.actions_on_top, 'actions_on_top': self.actions_on_top,
'actions_on_bottom': self.actions_on_bottom, 'actions_on_bottom': self.actions_on_bottom,
'actions_selection_counter': self.actions_selection_counter,
} }
context.update(extra_context or {}) context.update(extra_context or {})
context_instance = template.RequestContext(request, current_app=self.admin_site.name) context_instance = template.RequestContext(request, current_app=self.admin_site.name)

View File

@ -2,4 +2,9 @@
<div class="actions"> <div class="actions">
{% for field in action_form %}<label>{{ field.label }} {{ field }}</label>{% endfor %} {% for field in action_form %}<label>{{ field.label }} {{ field }}</label>{% endfor %}
<button type="submit" class="button" title="{% trans "Run the selected action" %}" name="index" value="{{ action_index|default:0 }}">{% trans "Go" %}</button> <button type="submit" class="button" title="{% trans "Run the selected action" %}" name="index" value="{{ action_index|default:0 }}">{% trans "Go" %}</button>
{% if actions_selection_counter %}
<span class="action_counter">
{% blocktrans with cl.result_count as total_count %}<span class="_acnt">0</span> of {{ total_count }} {{ module_name }} selected{% endblocktrans %}
</span>
{% endif %}
</div> </div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

@ -697,6 +697,12 @@ Controls where on the page the actions bar appears. By default, the admin
changelist displays actions at the top of the page (``actions_on_top = True; changelist displays actions at the top of the page (``actions_on_top = True;
actions_on_bottom = False``). actions_on_bottom = False``).
.. attribute:: ModelAdmin.actions_selection_counter
Controls whether a selection counter is display next to the action dropdown.
By default, the admin changelist will display it
(``actions_selection_counter = True``).
.. attribute:: ModelAdmin.change_list_template .. attribute:: ModelAdmin.change_list_template
Path to a custom template that will be used by the model objects "change list" Path to a custom template that will be used by the model objects "change list"

View File

@ -1209,6 +1209,13 @@ class AdminActionsTest(TestCase):
self.assertContains(response, msg) self.assertContains(response, msg)
self.failUnlessEqual(Subscriber.objects.count(), 2) self.failUnlessEqual(Subscriber.objects.count(), 2)
def test_selection_counter(self):
"""
Check if the selection counter is there.
"""
response = self.client.get('/test_admin/admin/admin_views/subscriber/')
self.assertContains(response, '<span class="_acnt">0</span> of 2 subscribers selected')
class TestCustomChangeList(TestCase): class TestCustomChangeList(TestCase):
fixtures = ['admin-views-users.xml'] fixtures = ['admin-views-users.xml']