From b0e252c6f29d4436c85b36846b23bd0d9c2b6631 Mon Sep 17 00:00:00 2001 From: Benjamin Dauvergne Date: Mon, 26 Aug 2013 15:24:37 +0200 Subject: [PATCH] feed_plugin: import widget used in the passerelle_register_plugin and show checkbox widget before their label fixes #3420 --- .../apps/feed_plugin/forms.py | 5 +- .../feed_plugin/select_user_feed.html | 13 ++- .../apps/feed_plugin/widgets.py | 104 ++++++++++++++++++ 3 files changed, 118 insertions(+), 4 deletions(-) create mode 100644 compte_agglo_montpellier/apps/feed_plugin/widgets.py diff --git a/compte_agglo_montpellier/apps/feed_plugin/forms.py b/compte_agglo_montpellier/apps/feed_plugin/forms.py index c7ab439..f16c576 100644 --- a/compte_agglo_montpellier/apps/feed_plugin/forms.py +++ b/compte_agglo_montpellier/apps/feed_plugin/forms.py @@ -1,8 +1,9 @@ from django import forms from django.utils.translation import ugettext as _ -import models +from . import models +from . import widgets class FeedForm(forms.Form): feeds = forms.ModelMultipleChoiceField(queryset=models.Feed.objects.all(), - label=_('Your feeds'), widget=forms.CheckboxSelectMultiple) + label=_('Your feeds'), widget=widgets.CheckboxMultipleSelect) diff --git a/compte_agglo_montpellier/apps/feed_plugin/templates/feed_plugin/select_user_feed.html b/compte_agglo_montpellier/apps/feed_plugin/templates/feed_plugin/select_user_feed.html index cc6de55..41ec1aa 100644 --- a/compte_agglo_montpellier/apps/feed_plugin/templates/feed_plugin/select_user_feed.html +++ b/compte_agglo_montpellier/apps/feed_plugin/templates/feed_plugin/select_user_feed.html @@ -1,6 +1,15 @@ {% load i18n %} -
+ {% csrf_token %} - {{ form.feeds }} +
diff --git a/compte_agglo_montpellier/apps/feed_plugin/widgets.py b/compte_agglo_montpellier/apps/feed_plugin/widgets.py new file mode 100644 index 0000000..30a7262 --- /dev/null +++ b/compte_agglo_montpellier/apps/feed_plugin/widgets.py @@ -0,0 +1,104 @@ +from itertools import chain + +from django.forms.widgets import SubWidget, SelectMultiple +from django.forms.util import flatatt +from django.utils.html import conditional_escape +from django.utils.encoding import StrAndUnicode, force_unicode +from django.utils.safestring import mark_safe + +class CheckboxInput(SubWidget): + """ + An object used by CheckboxRenderer that represents a single + . + """ + def __init__(self, name, value, attrs, choice, index): + self.name, self.value = name, value + self.attrs = attrs + self.choice_value = force_unicode(choice[0]) + self.choice_label = force_unicode(choice[1]) + self.index = index + + def __unicode__(self): + return self.render() + + def render(self, name=None, value=None, attrs=None, choices=()): + name = name or self.name + value = value or self.value + attrs = attrs or self.attrs + + if 'id' in self.attrs: + label_for = ' for="%s_%s"' % (self.attrs['id'], self.index) + else: + label_for = '' + choice_label = conditional_escape(force_unicode(self.choice_label)) + return mark_safe(u'%s %s' % (label_for, self.tag(), choice_label)) + + def is_checked(self): + return self.choice_value in self.value + + def tag(self): + if 'id' in self.attrs: + self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index) + final_attrs = dict(self.attrs, type='checkbox', name=self.name, value=self.choice_value) + if self.is_checked(): + final_attrs['checked'] = 'checked' + return mark_safe(u'' % flatatt(final_attrs)) + +class CheckboxRenderer(StrAndUnicode): + def __init__(self, name, value, attrs, choices): + self.name, self.value, self.attrs = name, value, attrs + self.choices = choices + + def __iter__(self): + for i, choice in enumerate(self.choices): + yield CheckboxInput(self.name, self.value, self.attrs.copy(), choice, i) + + def __getitem__(self, idx): + choice = self.choices[idx] # Let the IndexError propogate + return CheckboxInput(self.name, self.value, self.attrs.copy(), choice, idx) + + def __unicode__(self): + return self.render() + + def render(self): + """Outputs a
    for this set of checkbox fields.""" + return mark_safe(u'
      \n%s\n
    ' % u'\n'.join([u'
  • %s
  • ' + % force_unicode(w) for w in self])) + +class CheckboxMultipleSelect(SelectMultiple): + """ + Checkbox multi select field that enables iteration of each checkbox + Similar to django.forms.widgets.RadioSelect + """ + renderer = CheckboxRenderer + + def __init__(self, *args, **kwargs): + # Override the default renderer if we were passed one. + renderer = kwargs.pop('renderer', None) + if renderer: + self.renderer = renderer + super(CheckboxMultipleSelect, self).__init__(*args, **kwargs) + + def subwidgets(self, name, value, attrs=None, choices=()): + for widget in self.get_renderer(name, value, attrs, choices): + yield widget + + def get_renderer(self, name, value, attrs=None, choices=()): + """Returns an instance of the renderer.""" + if value is None: value = '' + str_values = set([force_unicode(v) for v in value]) # Normalize to string. + if attrs is None: + attrs = {} + if 'id' not in attrs: + attrs['id'] = name + final_attrs = self.build_attrs(attrs) + choices = list(chain(self.choices, choices)) + return self.renderer(name, str_values, final_attrs, choices) + + def render(self, name, value, attrs=None, choices=()): + return self.get_renderer(name, value, attrs, choices).render() + + def id_for_label(self, id_): + if id_: + id_ += '_0' + return id_