diff --git a/django/contrib/admin/helpers.py b/django/contrib/admin/helpers.py index d047d89..29b777f 100644 --- a/django/contrib/admin/helpers.py +++ b/django/contrib/admin/helpers.py @@ -17,6 +17,8 @@ ACTION_CHECKBOX_NAME = '_selected_action' class ActionForm(forms.Form): action = forms.ChoiceField(label=_('Action:')) + select_across = forms.BooleanField(label='', required=False, initial=0, + widget=forms.HiddenInput({'class': 'select-across'})) checkbox = forms.CheckboxInput({'class': 'action-select'}, lambda value: False) diff --git a/django/contrib/admin/media/css/changelists.css b/django/contrib/admin/media/css/changelists.css index a9d7543..99ff8bc 100644 --- a/django/contrib/admin/media/css/changelists.css +++ b/django/contrib/admin/media/css/changelists.css @@ -228,12 +228,6 @@ border-right: 1px solid #ddd; } -.action_counter{ - font-size: 11px; - margin: 0 0.5em; - display: none; -} - #changelist table input { margin: 0; } @@ -250,6 +244,21 @@ background: white url(../img/admin/nav-bg-reverse.gif) 0 -10px repeat-x; } +#changelist .actions.selected { + background: #fffccf; + border-top: 1px solid #fffee8; + border-bottom: 1px solid #edecd6; +} + +#changelist .actions span.all, +#changelist .actions span.action-counter, +#changelist .actions span.clear, +#changelist .actions span.question { + font-size: 11px; + margin: 0 0.5em; + display: none; +} + #changelist .actions:last-child { border-bottom: none; } diff --git a/django/contrib/admin/media/js/actions.js b/django/contrib/admin/media/js/actions.js index 658f015..c50bdf5 100644 --- a/django/contrib/admin/media/js/actions.js +++ b/django/contrib/admin/media/js/actions.js @@ -1,20 +1,42 @@ var Actions = { init: function() { counterSpans = document.getElementsBySelector('span._acnt'); - counterContainer = document.getElementsBySelector('span.action_counter'); + counterContainer = document.getElementsBySelector('span.action-counter'); + allContainer = document.getElementsBySelector('div.actions span.all'); + actionContainer = document.getElementsBySelector('div.actions'); actionCheckboxes = document.getElementsBySelector('tr input.action-select'); + acrossInputs = document.getElementsBySelector('div.actions input.select-across'); + acrossQuestions = document.getElementsBySelector('div.actions span.question'); + acrossClears = document.getElementsBySelector('div.actions span.clear'); + acrossQuestionLinks = document.getElementsBySelector('div.actions span.question a'); + acrossClearsLinks = document.getElementsBySelector('div.actions span.clear a'); + + Actions.setDisplay(counterContainer, 'inline'); selectAll = document.getElementById('action-toggle'); - lastChecked = null; - for(var i = 0; i < counterContainer.length; i++) { - counterContainer[i].style.display = 'inline'; - } if (selectAll) { - selectAll.style.display = 'inline'; + Actions.setDisplay([selectAll], 'inline'); addEvent(selectAll, 'click', function() { Actions.checker(selectAll.checked); Actions.counter(); }); + for(var i = 0; i < acrossQuestionLinks.length; i++) { + addEvent(acrossQuestionLinks[i], 'click', function() { + Actions.setAcrossInputs(1); + Actions.showClear() + return false; + }); + } + for(var i = 0; i < acrossClearsLinks.length; i++) { + addEvent(acrossClearsLinks[i], 'click', function() { + selectAll.checked = false; + Actions.clearAcross(); + Actions.checker(0); + Actions.counter(); + return false; + }); + } } + lastChecked = null; for(var i = 0; i < actionCheckboxes.length; i++) { addEvent(actionCheckboxes[i], 'click', function(e) { if (!e) { var e = window.event; } @@ -57,15 +79,54 @@ var Actions = { tr.className = tr.className.replace(' selected', ''); } }, - checked: function() { - selectAll.checked = false; + setAcrossInputs: function(checked) { + for(var i = 0; i < acrossInputs.length; i++) { + acrossInputs[i].value = checked; + } }, checker: function(checked) { + if (checked) { + Actions.showQuestion() + } else { + Actions.reset(); + } for(var i = 0; i < actionCheckboxes.length; i++) { actionCheckboxes[i].checked = checked; Actions.toggleRow(actionCheckboxes[i].parentNode.parentNode, checked); } }, + setDisplay: function(elements, value) { + for(var i = 0; i < elements.length; i++) { + elements[i].style.display = value; + } + }, + showQuestion: function() { + Actions.setDisplay(acrossQuestions, 'inline'); + Actions.setDisplay(acrossClears, 'none'); + Actions.setDisplay(allContainer, 'none'); + }, + showClear: function() { + Actions.setDisplay(acrossQuestions, 'none'); + Actions.setDisplay(acrossClears, 'inline'); + Actions.setDisplay(counterContainer, 'none'); + Actions.setDisplay(allContainer, 'inline'); + for(var i = 0; i < actionContainer.length; i++) { + Actions.toggleRow(actionContainer[i], true) + } + }, + reset: function() { + Actions.setDisplay(allContainer, 'none') + Actions.setDisplay(acrossQuestions, 'none'); + Actions.setDisplay(acrossClears, 'none'); + Actions.setDisplay(counterContainer, 'inline'); + }, + clearAcross: function() { + Actions.reset() + Actions.setAcrossInputs(0); + for(var i = 0; i < actionContainer.length; i++) { + Actions.toggleRow(actionContainer[i], false) + } + }, counter: function() { counter = 0; for(var i = 0; i < actionCheckboxes.length; i++) { @@ -76,7 +137,13 @@ var Actions = { for(var i = 0; i < counterSpans.length; i++) { counterSpans[i].innerHTML = counter; } - selectAll.checked = (counter == actionCheckboxes.length); + if (counter == actionCheckboxes.length) { + selectAll.checked = true; + Actions.showQuestion() + } else { + selectAll.checked = false; + Actions.clearAcross() + } } }; diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index 6dc707e..7c00a39 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -721,16 +721,20 @@ class ModelAdmin(BaseModelAdmin): action = action_form.cleaned_data['action'] func, name, description = self.get_actions(request)[action] - # Get the list of selected PKs. If nothing's selected, we can't - # perform an action on it, so bail. - selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) - if not selected: + selected = None + if not action_form.cleaned_data.get('select_across'): + queryset = queryset.filter(pk__in=selected) + else: + # Get the list of selected PKs. If nothing's selected, we can't + # perform an action on it, so bail. + selected = request.POST.getlist(helpers.ACTION_CHECKBOX_NAME) + if not selected or not queryset: # Reminder that something needs to be selected or nothing will happen msg = _("Items must be selected in order to perform actions on them. No items have been changed.") self.message_user(request, msg) return None - response = func(self, request, queryset.filter(pk__in=selected)) + response = func(self, request, queryset) # Actions may return an HttpResponse, which will be used as the # response from the POST. If not, we'll be a good little HTTP diff --git a/django/contrib/admin/templates/admin/actions.html b/django/contrib/admin/templates/admin/actions.html index 6d96616..41966fb 100644 --- a/django/contrib/admin/templates/admin/actions.html +++ b/django/contrib/admin/templates/admin/actions.html @@ -1,10 +1,28 @@ {% load i18n %}