X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;ds=inline;f=tools%2Fwidgets%2Fdropdownmultiple.py;h=10c7a2b98883c86eabf9a1eb6acf965b8c378343;hb=3ad5726e7dd331376eb4268b9dcb1b29cb1f0b7b;hp=37e17e48714cc386bb776093d6dec099becb2051;hpb=053fc78de59d8f55c276d3b1c89ecc7997a64985;p=matthijs%2Fprojects%2Fxerxes.git diff --git a/tools/widgets/dropdownmultiple.py b/tools/widgets/dropdownmultiple.py index 37e17e4..10c7a2b 100644 --- a/tools/widgets/dropdownmultiple.py +++ b/tools/widgets/dropdownmultiple.py @@ -1,26 +1,27 @@ +# Code taken from http://www.djangosnippets.org/snippets/747/ # -*- coding: utf-8 -*- from django.forms import widgets from django.utils.safestring import mark_safe from django.utils.datastructures import MultiValueDict -from django.newforms.util import flatatt +from django.forms.util import flatatt TPL_OPTION = """""" TPL_SELECT = """ - %(opts)s """ TPL_SCRIPT = """ """ TPL_FULL = """ - + """ -class DropDownMultiple(widgets.Widget): - choices = None - +class DropDownMultiple(widgets.SelectMultiple): def __init__(self, attrs=None, choices=()): - self.choices = choices + super(DropDownMultiple, self).__init__(attrs=attrs, choices=choices) + + def render(self, name, value, attrs=None, choices=()): + # Always render both the default SelectMultiple and our + # javascript assisted version. This allows for graceful + # degradation when javascript is not available or enabled + # (together with the javascript code above). + nonjs_output = super(DropDownMultiple, self).render(name, value, attrs=attrs, choices=choices) + js_output = self.render_js(name, value, attrs=attrs, choices=choices) - super(DropDownMultiple, self).__init__(attrs) + return nonjs_output + js_output - def render(self, name, value, attrs=None, choices=()): + def render_js(self, name, value, attrs=None, choices=()): if value is None: value = [] final_attrs = self.build_attrs(attrs, name=name) @@ -59,27 +75,35 @@ class DropDownMultiple(widgets.Widget): id = final_attrs['id'] del final_attrs['id'] - # Insert blank value - choices = [('','---')] + list(self.choices) + # Insert blank value. We insert this in self.choices, because + # render_options merges self.choices with its choices argument + # (in that order) and we want to have the empty option at the + # top. + old_choices = self.choices + self.choices = [('','---')] + list(self.choices) # Build values items = [] for val in value: - opts = "\n".join([TPL_OPTION %{'value': k, 'desc': v, 'selected': val == k and 'selected="selected"' or ''} for k, v in choices]) + opts = self.render_options(choices, [val]) items.append(TPL_SELECT %{'attrs': flatatt(final_attrs), 'opts': opts}) # Build blank value - opts = "\n".join([TPL_OPTION %{'value': k, 'desc': v, 'selected': ''} for k, v in choices]) + opts = self.render_options(choices, ['']) items.append(TPL_SELECT %{'attrs': flatatt(final_attrs), 'opts': opts}) script = TPL_SCRIPT %{'id': id} output = TPL_FULL %{'id': id, 'values': '\n'.join(items), 'script': script} + + # Restore the original choices + self.choices = old_choices return mark_safe(output) - def value_from_datadict(self, data, files, name): - if isinstance(data, MultiValueDict): - return [i for i in data.getlist(name) if i] - - return data.get(name, None) + def value_from_datadict(self, *args, **kwargs): + # Let our parent take care of this, but filter out the empty + # value (which is usually present from the last unused + # dropdown). + values = super(DropDownMultiple, self).value_from_datadict(*args, **kwargs) + return [i for i in values if i]