').addClass('selector-chosen')
+ .append($('
').text('Chosen ' + settings.verbose_name))
+ .append(
+ $('
').addClass('selector-filter')
+ .text(gettext('Select your choice(s) and click '))
+ .append(
+ $('').attr({
+ 'src': settings.admin_media_prefix + 'img/admin/selector-add.gif',
+ 'alt': gettext('Add')
+ })
+ )
+ ).append(selected)
+ .append(
+ $('').addClass('selector-clearall')
+ .text(gettext('Clear all'))
+ .attr('href', '#')
+ ).appendTo(selector);
+
+ SelectBox.init(choices.attr('id'));
+ SelectBox.init(selected.attr('id'));
+
+ // If this is a saved instance, move the already selected options across
+ // to the selected list.
+ settings.select(choices.children().filter(':selected'), choices, selected);
+
+ // Hook up selection events.
+ $(search).keyup(function(event) {
+ if ((event.which && event.which == 13) || (event.keyCode && event.keyCode == 13)) {
+ settings.select(choices.children().filter(':selected'), choices, selected);
+ return false;
+ }
+ SelectBox.filter(choices.attr('id'), $(this).val());
+ return true;
+ });
+ $('.selector-chooseall').click(function() {
+ settings.select(choices.children(), choices, selected);
+ return false;
+ });
+
+ $('.selector-clearall').click(function() {
+ settings.deselect(selected.children(), selected, choices);
+ return false;
+ });
+
+ $('.selector-add').click(function() {
+ settings.select(choices.children().filter(':selected'), choices, selected);
+ return false;
+ });
+
+ $('.selector-remove').click(function() {
+ settings.deselect(selected.children().filter(':selected'), selected, choices);
+ return false;
+ });
+
+ choices.dblclick(function() {
+ settings.select(choices.children().filter(':selected'), choices, selected);
+ });
+
+ selected.dblclick(function() {
+ settings.deselect(selected.children().filter(':selected'), selected, choices);
+ });
+
+ choices.keydown(function(event) {
+ event.which = event.which ? event.which : event.keyCode;
+ switch(event.which) {
+ case 13:
+ // Enter pressed - don't submit the form but move the current selection.
+ settings.select(choices.children().filter(':selected'), choices, selected);
+ this.selectedIndex = (this.selectedIndex == this.length) ? this.length - 1 : this.selectedIndex;
+ return false;
+ case 39:
+ // Right arrow - move across (only when horizontal)
+ if (!settings.is_stacked) {
+ settings.select(choices.children().filter(':selected'), choices, selected);
+ this.selectedIndex = (this.selectedIndex == this.length) ? this.length - 1 : this.selectedIndex;
+ return false;
+ }
+ }
+ return true;
+ });
+
+ selected.keydown(function(event) {
+ event.which = event.which ? event.which : event.keyCode;
+ switch(event.which) {
+ case 13:
+ // Enter pressed - don't submit the form but move the current selection.
+ settings.select(selected.children().filter(':selected'), selected, choices);
+ this.selectedIndex = (this.selectedIndex == this.length) ? this.length - 1 : this.selectedIndex;
+ return false;
+ case 37:
+ // Left arrow - move across (only when horizontal)
+ if (!settings.is_stacked) {
+ settings.select(selected.children().filter(':selected'), selected, choices);
+ this.selectedIndex = (this.selectedIndex == this.length) ? this.length - 1 : this.selectedIndex;
+ return false;
+ }
+ }
+ return true;
+ });
+
+ $('form').submit(function() {
+ selected.children().each(function(i, option) {
+ $(option).attr('selected', 'selected');
+ });
+ return true;
+ });
+ }
+ };
+
+ $.fn.selectFilter = function(method) {
+ if (methods[method]) {
+ return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+ } else if (typeof method === 'object' || !method ) {
+ return methods.init.apply(this, arguments);
+ } else {
+ $.error('Method ' + method + ' does not exist on jQuery.selectFilter');
+ }
+ };
+})(django.jQuery);
Index: django/contrib/admin/options.py
===================================================================
--- django/contrib/admin/options.py (revision 16355)
+++ django/contrib/admin/options.py (working copy)
@@ -1321,7 +1321,7 @@
js.append('js/urlify.js')
js.append('js/prepopulate.min.js')
if self.filter_vertical or self.filter_horizontal:
- js.extend(['js/SelectBox.js' , 'js/SelectFilter2.js'])
+ js.extend(['js/SelectBox.js' , 'js/selectfilter.js'])
return forms.Media(js=['%s%s' % (settings.ADMIN_MEDIA_PREFIX, url) for url in js])
media = property(_media)
Index: django/contrib/admin/widgets.py
===================================================================
--- django/contrib/admin/widgets.py (revision 16355)
+++ django/contrib/admin/widgets.py (working copy)
@@ -22,9 +22,8 @@
catalog has been loaded in the page
"""
class Media:
- js = (settings.ADMIN_MEDIA_PREFIX + "js/core.js",
- settings.ADMIN_MEDIA_PREFIX + "js/SelectBox.js",
- settings.ADMIN_MEDIA_PREFIX + "js/SelectFilter2.js")
+ js = (settings.ADMIN_MEDIA_PREFIX + 'js/SelectBox.js',
+ settings.ADMIN_MEDIA_PREFIX + "js/selectfilter.js",)
def __init__(self, verbose_name, is_stacked, attrs=None, choices=()):
self.verbose_name = verbose_name
@@ -35,12 +34,27 @@
if attrs is None: attrs = {}
attrs['class'] = 'selectfilter'
if self.is_stacked: attrs['class'] += 'stacked'
+ id_ = attrs.get('id', 'id_%s' % name)
output = [super(FilteredSelectMultiple, self).render(name, value, attrs, choices)]
- output.append(u'\n' % \
- (name, self.verbose_name.replace('"', '\\"'), int(self.is_stacked), settings.ADMIN_MEDIA_PREFIX))
+ output.append(u'''
+''' % {
+ 'id': id_,
+ 'name': name,
+ 'verbose_name': self.verbose_name.replace('"', '\\"'),
+ 'is_stacked': int(self.is_stacked),
+ 'admin_media_prefix': settings.ADMIN_MEDIA_PREFIX
+ })
return mark_safe(u''.join(output))
class AdminDateWidget(forms.DateInput):
@@ -131,11 +145,10 @@
url = u''
if "class" not in attrs:
attrs['class'] = 'vForeignKeyRawIdAdminField' # The JavaScript looks for this hook.
+ id_ = attrs.get('id', 'id_%s' % name)
output = [super(ForeignKeyRawIdWidget, self).render(name, value, attrs)]
- # TODO: "id_" is hard-coded here. This should instead use the correct
- # API to determine the ID dynamically.
- output.append(u' ' % \
- (related_url, url, name))
+ output.append(u' ' % \
+ (related_url, url, id_))
output.append(u'' % (settings.ADMIN_MEDIA_PREFIX, _('Lookup')))
if value:
output.append(self.label_for_value(value))
@@ -238,10 +251,9 @@
self.widget.choices = self.choices
output = [self.widget.render(name, value, *args, **kwargs)]
if self.can_add_related:
- # TODO: "id_" is hard-coded here. This should instead use the correct
- # API to determine the ID dynamically.
- output.append(u' ' % \
- (related_url, name))
+ id_ = self.attrs.get('id', 'id_%s' % name)
+ output.append(u' ' % \
+ (related_url, id_))
output.append(u'' % (settings.ADMIN_MEDIA_PREFIX, _('Add Another')))
return mark_safe(u''.join(output))