Ticket #4592: 4592-2.diff

File 4592-2.diff, 9.2 KB (added by Matt McClanahan <cardinal@…>, 17 years ago)

Tweak

  • 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    input_type = None # Subclasses must define this.
     220
     221    "An object used by ChoiceFieldRenderer that represents a single radio or checkbox input."
    220222    def __init__(self, name, value, attrs, choice, index):
    221223        self.name, self.value = name, value
    222224        self.attrs = attrs
     
    233235    def tag(self):
    234236        if 'id' in self.attrs:
    235237            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)
     238        final_attrs = dict(self.attrs, type=self.input_type, name=self.name, value=self.choice_value)
    237239        if self.is_checked():
    238240            final_attrs['checked'] = 'checked'
    239241        return u'<input%s />' % flatatt(final_attrs)
    240242
    241 class RadioFieldRenderer(StrAndUnicode):
    242     "An object used by RadioSelect to enable customization of radio widgets."
    243     def __init__(self, name, value, attrs, choices):
     243class RadioChoiceInput(ChoiceInput):
     244    input_type = 'radio'
     245
     246class CheckboxChoiceInput(ChoiceInput):
     247    input_type = 'checkbox'
     248
     249    def is_checked(self):
     250        return self.choice_value in self.value
     251
     252class ChoiceFieldRenderer(StrAndUnicode):
     253    "An object used to enable customization of radio and checkbox widgets."
     254    def __init__(self, name, value, attrs, choices, choice_widget=ChoiceInput):
    244255        self.name, self.value, self.attrs = name, value, attrs
    245256        self.choices = choices
     257        self.choice_widget = choice_widget
    246258
    247259    def __iter__(self):
    248260        for i, choice in enumerate(self.choices):
    249             yield RadioInput(self.name, self.value, self.attrs.copy(), choice, i)
     261            yield self.choice_widget(self.name, self.value, self.attrs.copy(), choice, i)
    250262
    251263    def __getitem__(self, idx):
    252264        choice = self.choices[idx] # Let the IndexError propogate
    253         return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx)
     265        return self.choice_widget(self.name, self.value, self.attrs.copy(), choice, idx)
    254266
    255267    def __unicode__(self):
    256         "Outputs a <ul> for this set of radio fields."
     268        "Outputs a <ul> for this set of choice fields."
    257269        return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % w for w in self])
    258270
    259271class RadioSelect(Select):
    260272    def render(self, name, value, attrs=None, choices=()):
    261         "Returns a RadioFieldRenderer instance rather than a Unicode string."
     273        "Returns a ChoiceFieldRenderer instance rather than a Unicode string."
    262274        if value is None: value = ''
    263275        str_value = smart_unicode(value) # Normalize to string.
    264276        final_attrs = self.build_attrs(attrs)
    265         return RadioFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)))
     277        return ChoiceFieldRenderer(name, str_value, final_attrs, list(chain(self.choices, choices)), choice_widget=RadioChoiceInput)
    266278
    267279    def id_for_label(self, id_):
    268280        # RadioSelect is represented by multiple <input type="radio"> fields,
     
    276288
    277289class CheckboxSelectMultiple(SelectMultiple):
    278290    def render(self, name, value, attrs=None, choices=()):
    279         if value is None: value = []
    280         has_id = attrs and 'id' in attrs
     291        "Returns a ChoiceFieldRenderer instance rather than a Unicode string."
     292        if value is None: value = ''
     293        str_values = set([smart_unicode(v) for v in value]) # Normalize to strings.
    281294        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)
     295        return ChoiceFieldRenderer(name, str_values, final_attrs, list(chain(self.choices, choices)), choice_widget=CheckboxChoiceInput)
    295296
    296297    def id_for_label(self, id_):
    297298        # 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