Ticket #4592: 4592-1.diff

File 4592-1.diff, 9.7 KB (added by Matt McClanahan <cardinal@…>, 8 years ago)
  • django/newforms/widgets.py

     
    215215            return data.getlist(name)
    216216        return data.get(name, None)
    217217
    218 class RadioInput(StrAndUnicode):
    219     "An object used by RadioFieldRenderer that represents a single <input type='radio'>."
     218class ChoiceInput(StrAndUnicode):
     219    "An object used by ChoiceFieldRenderer that represents a single radio or checkbox input."
    220220    def __init__(self, name, value, attrs, choice, index):
    221221        self.name, self.value = name, value
    222222        self.attrs = attrs
    223223        self.choice_value = smart_unicode(choice[0])
    224224        self.choice_label = smart_unicode(choice[1])
    225225        self.index = index
     226        self.type = ''
    226227
    227228    def __unicode__(self):
    228229        return u'<label>%s %s</label>' % (self.tag(), self.choice_label)
     
    233234    def tag(self):
    234235        if 'id' in self.attrs:
    235236            self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index)
    236         final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value)
     237        final_attrs = dict(self.attrs, type=self.type, name=self.name, value=self.choice_value)
    237238        if self.is_checked():
    238239            final_attrs['checked'] = 'checked'
    239240        return u'<input%s />' % flatatt(final_attrs)
    240241
    241 class RadioFieldRenderer(StrAndUnicode):
    242     "An object used by RadioSelect to enable customization of radio widgets."
    243     def __init__(self, name, value, attrs, choices):
     242class RadioChoiceInput(ChoiceInput):
     243    def __init__(self, name, value, attrs, choice, index):
     244        super(RadioChoiceInput, self).__init__(name, value, attrs, choice, index)
     245        self.type = 'radio'
     246
     247class CheckboxChoiceInput(ChoiceInput):
     248    def __init__(self, name, value, attrs, choice, index):
     249        super(CheckboxChoiceInput, self).__init__(name, value, attrs, choice, index)
     250        self.type = 'checkbox'
     251
     252    def is_checked(self):
     253        return self.choice_value in self.value
     254
     255class ChoiceFieldRenderer(StrAndUnicode):
     256    "An object used to enable customization of radio and checkbox widgets."
     257    def __init__(self, name, value, attrs, choices, choice_widget=ChoiceInput):
    244258        self.name, self.value, self.attrs = name, value, attrs
    245259        self.choices = choices
     260        self.type = ''
     261        self.choice_widget = choice_widget
    246262
    247263    def __iter__(self):
    248264        for i, choice in enumerate(self.choices):
    249             yield RadioInput(self.name, self.value, self.attrs.copy(), choice, i)
     265            yield self.choice_widget(self.name, self.value, self.attrs.copy(), choice, i)
    250266
    251267    def __getitem__(self, idx):
    252268        choice = self.choices[idx] # Let the IndexError propogate
    253         return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
     269        return self.choice_widget(self.name, self.value, self.attrs.copy(), choice, idx)
    254270
    255271    def __unicode__(self):
    256         "Outputs a <ul> for this set of radio fields."
     272        "Outputs a <ul> for this set of choice fields."
    257273        return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % w for w in self])
    258274
    259275class RadioSelect(Select):
    260276    def render(self, name, value, attrs=None, choices=()):
    261         "Returns a RadioFieldRenderer instance rather than a Unicode string."
     277        "Returns a ChoiceFieldRenderer instance rather than a Unicode string."
    262278        if value is None: value = ''
    263279        str_value = smart_unicode(value) # Normalize to string.
    264280        final_attrs = self.build_attrs(attrs)
    265         return RadioFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)))
     281        return ChoiceFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)), choice_widget=RadioChoiceInput)
    266282
    267283    def id_for_label(self, id_):
    268284        # RadioSelect is represented by multiple <input type="radio"> fields,
     
    276292
    277293class CheckboxSelectMultiple(SelectMultiple):
    278294    def render(self, name, value, attrs=None, choices=()):
    279         if value is None: value = []
    280         has_id = attrs and 'id' in attrs
     295        "Returns a ChoiceFieldRenderer instance rather than a Unicode string."
     296        if value is None: value = ''
     297        str_values = set([smart_unicode(v) for v in value]) # Normalize to strings.
    281298        final_attrs = self.build_attrs(attrs, name=name)
    282         output = [u'<ul>']
    283         str_values = set([smart_unicode(v) for v in value]) # Normalize to strings.
    284         for i, (option_value, option_label) in enumerate(chain(self.choices, choices)):
    285             # If an ID attribute was given, add a numeric index as a suffix,
    286             # so that the checkboxes don't all have the same ID attribute.
    287             if has_id:
    288                 final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i))
    289             cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values)
    290             option_value = smart_unicode(option_value)
    291             rendered_cb = cb.render(name, option_value)
    292             output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(smart_unicode(option_label))))
    293         output.append(u'</ul>')
    294         return u'\n'.join(output)
     299        return ChoiceFieldRenderer(name, str_values, final_attrs, list(chain(self.choices, choices)), choice_widget=CheckboxChoiceInput)
    295300
    296301    def id_for_label(self, id_):
    297302        # See the comment for RadioSelect.id_for_label()
  • tests/regressiontests/forms/tests.py

     
    614614<li><label><input type="radio" name="num" value="5" /> 5</label></li>
    615615</ul>
    616616
    617 The render() method returns a RadioFieldRenderer object, whose str() is a <ul>.
     617The render() method returns a ChoiceFieldRenderer object, whose str() is a <ul>.
    618618You can manipulate that object directly to customize the way the RadioSelect
    619619is rendered.
    620620>>> w = RadioSelect()
     
    644644beatle J G George False
    645645beatle J R Ringo False
    646646
    647 A RadioFieldRenderer object also allows index access to individual RadioInput
     647A ChoiceFieldRenderer object also allows index access to individual RadioInput
    648648objects.
    649649>>> w = RadioSelect()
    650650>>> r = w.render('beatle', 'J', choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
     
    792792<li><label><input type="checkbox" name="nums" value="5" /> 5</label></li>
    793793</ul>
    794794
    795 >>> w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')])
     795The render() method returns a ChoiceFieldRenderer object, whose str() is a <ul>.
     796You can manipulate that object directly to customize the way the RadioSelect
     797is rendered.
     798>>> w2 = CheckboxSelectMultiple()
     799>>> r = w2.render('beatle', ['J', 'G'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
     800>>> for inp in r:
     801...     print inp
     802<label><input checked="checked" type="checkbox" name="beatle" value="J" /> John</label>
     803<label><input type="checkbox" name="beatle" value="P" /> Paul</label>
     804<label><input checked="checked" type="checkbox" name="beatle" value="G" /> George</label>
     805<label><input type="checkbox" name="beatle" value="R" /> Ringo</label>
     806>>> for inp in r:
     807...     print '%s<br />' % inp
     808<label><input checked="checked" type="checkbox" name="beatle" value="J" /> John</label><br />
     809<label><input type="checkbox" name="beatle" value="P" /> Paul</label><br />
     810<label><input checked="checked" type="checkbox" name="beatle" value="G" /> George</label><br />
     811<label><input type="checkbox" name="beatle" value="R" /> Ringo</label><br />
     812>>> for inp in r:
     813...     print '<p>%s %s</p>' % (inp.tag(), inp.choice_label)
     814<p><input checked="checked" type="checkbox" name="beatle" value="J" /> John</p>
     815<p><input type="checkbox" name="beatle" value="P" /> Paul</p>
     816<p><input checked="checked" type="checkbox" name="beatle" value="G" /> George</p>
     817<p><input type="checkbox" name="beatle" value="R" /> Ringo</p>
     818>>> for inp in r:
     819...     print '%s %s %s %s %s' % (inp.name, inp.value, inp.choice_value, inp.choice_label, inp.is_checked())
     820beatle set([u'J', u'G']) J John True
     821beatle set([u'J', u'G']) P Paul False
     822beatle set([u'J', u'G']) G George True
     823beatle set([u'J', u'G']) R Ringo False
     824
     825A ChoiceFieldRenderer object also allows index access to individual RadioInput
     826objects.
     827>>> w2 = CheckboxSelectMultiple()
     828>>> r = w2.render('beatle', ['J'], choices=(('J', 'John'), ('P', 'Paul'), ('G', 'George'), ('R', 'Ringo')))
     829>>> print r[1]
     830<label><input type="checkbox" name="beatle" value="P" /> Paul</label>
     831>>> print r[0]
     832<label><input checked="checked" type="checkbox" name="beatle" value="J" /> John</label>
     833>>> r[0].is_checked()
     834True
     835>>> r[1].is_checked()
     836False
     837>>> r[1].name, r[1].value, r[1].choice_value, r[1].choice_label
     838('beatle', set([u'J']), u'P', u'Paul')
     839>>> r[10]
     840Traceback (most recent call last):
     841...
     842IndexError: list index out of range
     843
     844>>> unicode(w.render('nums', ['ŠĐĆŽćžšđ'], choices=[('ŠĐĆŽćžšđ', 'ŠĐabcĆŽćžšđ'), ('ćžšđ', 'abcćžšđ')]))
    796845u'<ul>\n<li><label><input type="checkbox" name="nums" value="1" /> 1</label></li>\n<li><label><input type="checkbox" name="nums" value="2" /> 2</label></li>\n<li><label><input type="checkbox" name="nums" value="3" /> 3</label></li>\n<li><label><input checked="checked" type="checkbox" name="nums" value="\u0160\u0110\u0106\u017d\u0107\u017e\u0161\u0111" /> \u0160\u0110abc\u0106\u017d\u0107\u017e\u0161\u0111</label></li>\n<li><label><input type="checkbox" name="nums" value="\u0107\u017e\u0161\u0111" /> abc\u0107\u017e\u0161\u0111</label></li>\n</ul>'
    797846
    798847# MultiWidget #################################################################
Back to Top