1 # Code taken from http://www.djangosnippets.org/snippets/747/
2 # -*- coding: utf-8 -*-
3 from django.forms import widgets
4 from django.utils.safestring import mark_safe
5 from django.utils.datastructures import MultiValueDict
6 from django.forms.util import flatatt
8 TPL_OPTION = """<option value="%(value)s" %(selected)s>%(desc)s</option>"""
11 <select class="dropdown_select" %(attrs)s disabled="disabled">
18 $('span#%(id)s_multiple>select.dropdown_select').change(function(){
19 var pattern = 'span#%(id)s_multiple>select.dropdown_select';
20 var last_item = $(pattern+':last');
22 if (last_item.val()) {
23 last_item.clone(true).appendTo($('span#%(id)s_multiple'));
24 $('span#%(id)s_multiple').append(' ');
29 for (var i=$(pattern).length-1; i>=0; i--) {
30 if (values.indexOf($($(pattern).get(i)).val()) >= 0) {
31 $($(pattern).get(i)).remove();
33 values.push($($(pattern).get(i)).val());
37 $(document).ready(function(){
38 // Since we do graceful fallback, the JScript driven interface
39 // is hidden and disabled by default and the plain HTML
40 // interface is shown. Here we swap them around.
41 $('select#%(id)s').hide();
42 $('select#%(id)s').attr('disabled', true);
43 $('span#%(id)s_multiple').show();
44 $('span#%(id)s_multiple>select.dropdown_select').attr('disabled', false);
50 <span class="dropdown_multiple" id="%(id)s_multiple" style="display:none">
56 class DropDownMultiple(widgets.SelectMultiple):
57 def __init__(self, attrs=None, choices=()):
58 super(DropDownMultiple, self).__init__(attrs=attrs, choices=choices)
60 def render(self, name, value, attrs=None, choices=()):
61 # Always render both the default SelectMultiple and our
62 # javascript assisted version. This allows for graceful
63 # degradation when javascript is not available or enabled
64 # (together with the javascript code above).
65 nonjs_output = super(DropDownMultiple, self).render(name, value, attrs=attrs, choices=choices)
66 js_output = self.render_js(name, value, attrs=attrs, choices=choices)
68 return nonjs_output + js_output
70 def render_js(self, name, value, attrs=None, choices=()):
71 if value is None: value = []
72 final_attrs = self.build_attrs(attrs, name=name)
75 id = final_attrs['id']
79 choices = [('','---')] + list(choices)
84 opts = self.render_options(choices, [val])
86 items.append(TPL_SELECT %{'attrs': flatatt(final_attrs), 'opts': opts})
89 opts = self.render_options(choices, [''])
90 items.append(TPL_SELECT %{'attrs': flatatt(final_attrs), 'opts': opts})
92 script = TPL_SCRIPT %{'id': id}
93 output = TPL_FULL %{'id': id, 'values': '\n'.join(items), 'script': script}
95 return mark_safe(output)
97 def value_from_datadict(self, *args, **kwargs):
98 # Let our parent take care of this, but filter out the empty
99 # value (which is usually present from the last unused
101 values = super(DropDownMultiple, self).value_from_datadict(*args, **kwargs)
102 return [i for i in values if i]