Ticket #3568: htmlnewforms.diff
File htmlnewforms.diff, 15.6 KB (added by , 18 years ago) |
---|
-
django/newforms/forms.py
5 5 from django.utils.datastructures import SortedDict, MultiValueDict 6 6 from django.utils.html import escape 7 7 from fields import Field 8 from serializations import * 8 9 from widgets import TextInput, Textarea, HiddenInput, MultipleHiddenInput 9 10 from util import flatatt, StrAndUnicode, ErrorDict, ErrorList, ValidationError 10 11 import copy 11 12 12 __all__ = ('BaseForm', 'Form' )13 __all__ = ('BaseForm', 'Form', 'SERIALIZATION_XHTML', 'SERIALIZATION_HTML401', 'SERIALIZATION_DEFAULT', 'SERIALIZATION_HTML_COMPATIBLE_XHTML1') 13 14 14 15 NON_FIELD_ERRORS = '__all__' 15 16 … … 107 108 """ 108 109 return self.prefix and ('%s-%s' % (self.prefix, field_name)) or field_name 109 110 110 def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row ):111 def _html_output(self, normal_row, error_row, row_ender, help_text_html, errors_on_separate_row, serialization=SERIALIZATION_DEFAULT): 111 112 "Helper function for outputting HTML. Used by as_table(), as_ul(), as_p()." 112 113 top_errors = self.non_field_errors() # Errors that should be displayed above all fields. 113 114 output, hidden_fields = [], [] 114 115 for name, field in self.fields.items(): 115 bf = BoundField(self, field, name )116 bf = BoundField(self, field, name,serialization) 116 117 bf_errors = ErrorList([escape(error) for error in bf.errors]) # Escape and cache in local variable. 117 118 if bf.is_hidden: 118 119 if bf_errors: … … 139 140 output.append(str_hidden) 140 141 return u'\n'.join(output) 141 142 142 def as_table(self ):143 def as_table(self,serialization=SERIALIZATION_DEFAULT): 143 144 "Returns this form rendered as HTML <tr>s -- excluding the <table></table>." 144 return self._html_output(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'<br />%s', False) 145 br = u'<br' + end_empty_element(u'br',serialization) 146 return self._html_output(u'<tr><th>%(label)s</th><td>%(errors)s%(field)s%(help_text)s</td></tr>', u'<tr><td colspan="2">%s</td></tr>', '</td></tr>', u'' + br + '%s', False, serialization) 145 147 146 def as_ul(self ):148 def as_ul(self,serialization=SERIALIZATION_DEFAULT): 147 149 "Returns this form rendered as HTML <li>s -- excluding the <ul></ul>." 148 return self._html_output(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False )150 return self._html_output(u'<li>%(errors)s%(label)s %(field)s%(help_text)s</li>', u'<li>%s</li>', '</li>', u' %s', False, serialization) 149 151 150 def as_p(self ):152 def as_p(self,serialization=SERIALIZATION_DEFAULT): 151 153 "Returns this form rendered as HTML <p>s." 152 return self._html_output(u'<p>%(label)s %(field)s%(help_text)s</p>', u'<p>%s</p>', '</p>', u' %s', True) 154 return self._html_output(u'<p>%(label)s %(field)s%(help_text)s</p>', u'<p>%s</p>', '</p>', u' %s', True, serialization) 155 156 def as_div(self,serialization=SERIALIZATION_DEFAULT): 157 "Returns this form rendered as HTML <div>s." 158 return self._html_output(u'<div>%(label)s %(field)s%(help_text)s</div>', u'<div>%s</div>', '</div>', u' %s', True, serialization) 153 159 154 160 def non_field_errors(self): 155 161 """ … … 209 215 210 216 class BoundField(StrAndUnicode): 211 217 "A Field plus data" 212 def __init__(self, form, field, name ):218 def __init__(self, form, field, name,serialization=SERIALIZATION_DEFAULT): 213 219 self.form = form 214 220 self.field = field 215 221 self.name = name … … 219 225 else: 220 226 self.label = self.field.label 221 227 self.help_text = field.help_text or '' 228 self.serialization=serialization 222 229 223 230 def __unicode__(self): 224 231 "Renders this field as an HTML widget." 225 232 # Use the 'widget' attribute on the field to determine which type 226 233 # of HTML widget to use. 227 value = self.as_widget(self.field.widget) 234 value = self.as_widget(widget=self.field.widget, 235 attrs=None, 236 serialization=self.serialization) 228 237 if not isinstance(value, basestring): 229 238 # Some Widget render() methods -- notably RadioSelect -- return a 230 239 # "special" object rather than a string. Call the __str__() on that … … 240 249 return self.form.errors.get(self.name, ErrorList()) 241 250 errors = property(_errors) 242 251 243 def as_widget(self, widget, attrs=None ):252 def as_widget(self, widget, attrs=None, serialization=SERIALIZATION_DEFAULT): 244 253 attrs = attrs or {} 245 254 auto_id = self.auto_id 246 255 if auto_id and not attrs.has_key('id') and not widget.attrs.has_key('id'): … … 249 258 data = self.form.initial.get(self.name, self.field.initial) 250 259 else: 251 260 data = self.data 252 return widget.render(self.html_name, data, attrs=attrs )261 return widget.render(self.html_name, data, attrs=attrs, serialization=serialization) 253 262 254 def as_text(self, attrs=None ):263 def as_text(self, attrs=None, serialization=SERIALIZATION_DEFAULT): 255 264 """ 256 265 Returns a string of HTML for representing this as an <input type="text">. 257 266 """ 258 return self.as_widget(TextInput(), attrs )267 return self.as_widget(TextInput(), attrs, serialization) 259 268 260 def as_textarea(self, attrs=None ):269 def as_textarea(self, attrs=None, serialization=SERIALIZATION_DEFAULT): 261 270 "Returns a string of HTML for representing this as a <textarea>." 262 271 return self.as_widget(Textarea(), attrs) 263 272 264 def as_hidden(self, attrs=None ):273 def as_hidden(self, attrs=None, serialization=SERIALIZATION_DEFAULT): 265 274 """ 266 275 Returns a string of HTML for representing this as an <input type="hidden">. 267 276 """ 268 return self.as_widget(self.field.hidden_widget(), attrs )277 return self.as_widget(self.field.hidden_widget(), attrs, serialization) 269 278 270 279 def _data(self): 271 280 """ -
django/newforms/widgets.py
14 14 from django.utils.html import escape 15 15 from django.utils.translation import gettext 16 16 from itertools import chain 17 from serializations import end_empty_element, SERIALIZATION_DEFAULT 17 18 18 19 try: 19 20 set # Only available in Python 2.4+ … … 26 27 def __init__(self, attrs=None): 27 28 self.attrs = attrs or {} 28 29 29 def render(self, name, value, attrs=None ):30 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 30 31 """ 31 32 Returns this Widget rendered as HTML, as a Unicode string. 32 33 … … 69 70 """ 70 71 input_type = None # Subclasses must define this. 71 72 72 def render(self, name, value, attrs=None ):73 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 73 74 if value is None: value = '' 74 75 final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) 75 76 if value != '': final_attrs['value'] = smart_unicode(value) # Only add the 'value' attribute if a value is non-empty. 76 return u'<input%s />' % flatatt(final_attrs)77 return u'<input%s%s' % (flatatt(final_attrs), end_empty_element(u'input',serialization)); 77 78 78 79 class TextInput(Input): 79 80 input_type = 'text' … … 85 86 self.attrs = attrs or {} 86 87 self.render_value = render_value 87 88 88 def render(self, name, value, attrs=None ):89 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 89 90 if not self.render_value: value=None 90 return super(PasswordInput, self).render(name, value, attrs )91 return super(PasswordInput, self).render(name, value, attrs, serialization) 91 92 92 93 class HiddenInput(Input): 93 94 input_type = 'hidden' … … 103 104 self.attrs = attrs or {} 104 105 self.choices = choices 105 106 106 def render(self, name, value, attrs=None, choices=() ):107 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 107 108 if value is None: value = [] 108 109 final_attrs = self.build_attrs(attrs, type=self.input_type, name=name) 109 return u'\n'.join([(u'<input%s />' % flatatt(dict(value=smart_unicode(v), **final_attrs))) for v in value])110 return u'\n'.join([(u'<input%s%s' % (flatatt(dict(value=smart_unicode(v), **final_attrs)), end_empty_element(u'input',serialization))) for v in value]) 110 111 111 112 def value_from_datadict(self, data, name): 112 113 if isinstance(data, MultiValueDict): … … 117 118 input_type = 'file' 118 119 119 120 class Textarea(Widget): 120 def render(self, name, value, attrs=None ):121 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 121 122 if value is None: value = '' 122 123 value = smart_unicode(value) 123 124 final_attrs = self.build_attrs(attrs, name=name) … … 130 131 self.attrs = attrs or {} 131 132 self.check_test = check_test 132 133 133 def render(self, name, value, attrs=None ):134 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 134 135 final_attrs = self.build_attrs(attrs, type='checkbox', name=name) 135 136 try: 136 137 result = self.check_test(value) … … 140 141 final_attrs['checked'] = 'checked' 141 142 if value not in ('', True, False, None): 142 143 final_attrs['value'] = smart_unicode(value) # Only add the 'value' attribute if a value is non-empty. 143 return u'<input%s />' % flatatt(final_attrs)144 return u'<input%s%s' % (flatatt(final_attrs),end_empty_element(u'input',serialization)) 144 145 145 146 class Select(Widget): 146 147 def __init__(self, attrs=None, choices=()): … … 150 151 # more than once. 151 152 self.choices = list(choices) 152 153 153 def render(self, name, value, attrs=None, choices=() ):154 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 154 155 if value is None: value = '' 155 156 final_attrs = self.build_attrs(attrs, name=name) 156 157 output = [u'<select%s>' % flatatt(final_attrs)] … … 170 171 choices = ((u'1', gettext('Unknown')), (u'2', gettext('Yes')), (u'3', gettext('No'))) 171 172 super(NullBooleanSelect, self).__init__(attrs, choices) 172 173 173 def render(self, name, value, attrs=None, choices=() ):174 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 174 175 try: 175 176 value = {True: u'2', False: u'3', u'2': u'2', u'3': u'3'}[value] 176 177 except KeyError: 177 178 value = u'1' 178 return super(NullBooleanSelect, self).render(name, value, attrs, choices )179 return super(NullBooleanSelect, self).render(name, value, attrs, choices, serialization) 179 180 180 181 def value_from_datadict(self, data, name): 181 182 value = data.get(name, None) … … 187 188 self.attrs = attrs or {} 188 189 self.choices = choices 189 190 190 def render(self, name, value, attrs=None, choices=() ):191 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 191 192 if value is None: value = [] 192 193 final_attrs = self.build_attrs(attrs, name=name) 193 194 output = [u'<select multiple="multiple"%s>' % flatatt(final_attrs)] … … 213 214 self.choice_label = smart_unicode(choice[1]) 214 215 self.index = index 215 216 216 def __unicode__(self ):217 return u'<label>%s %s</label>' % (self.tag( ), self.choice_label)217 def __unicode__(self, serialization=SERIALIZATION_DEFAULT): 218 return u'<label>%s %s</label>' % (self.tag(serialization), self.choice_label) 218 219 219 220 def is_checked(self): 220 221 return self.value == self.choice_value 221 222 222 def tag(self ):223 def tag(self,serialization=SERIALIZATION_DEFAULT): 223 224 if self.attrs.has_key('id'): 224 225 self.attrs['id'] = '%s_%s' % (self.attrs['id'], self.index) 225 226 final_attrs = dict(self.attrs, type='radio', name=self.name, value=self.choice_value) 226 227 if self.is_checked(): 227 228 final_attrs['checked'] = 'checked' 228 return u'<input%s />' % flatatt(final_attrs)229 return u'<input%s%s' % (flatatt(final_attrs),end_empty_element(u'input',serialization)) 229 230 230 231 class RadioFieldRenderer(StrAndUnicode): 231 232 "An object used by RadioSelect to enable customization of radio widgets." 232 def __init__(self, name, value, attrs, choices ):233 def __init__(self, name, value, attrs, choices, serialization=SERIALIZATION_DEFAULT): 233 234 self.name, self.value, self.attrs = name, value, attrs 234 235 self.choices = choices 236 self.serialization = serialization; 235 237 236 238 def __iter__(self): 237 239 for i, choice in enumerate(self.choices): … … 241 243 choice = self.choices[idx] # Let the IndexError propogate 242 244 return RadioInput(self.name, self.value, self.attrs.copy(), choice, idx) 243 245 244 def __unicode__(self ):246 def __unicode__(self, serialization): 245 247 "Outputs a <ul> for this set of radio fields." 246 248 return u'<ul>\n%s\n</ul>' % u'\n'.join([u'<li>%s</li>' % w for w in self]) 247 249 248 250 class RadioSelect(Select): 249 def render(self, name, value, attrs=None, choices=() ):251 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 250 252 "Returns a RadioFieldRenderer instance rather than a Unicode string." 251 253 if value is None: value = '' 252 254 str_value = smart_unicode(value) # Normalize to string. 253 255 attrs = attrs or {} 254 return RadioFieldRenderer(name, str_value, attrs, list(chain(self.choices, choices)) )256 return RadioFieldRenderer(name, str_value, attrs, list(chain(self.choices, choices)), serialization) 255 257 256 258 def id_for_label(self, id_): 257 259 # RadioSelect is represented by multiple <input type="radio"> fields, … … 264 266 id_for_label = classmethod(id_for_label) 265 267 266 268 class CheckboxSelectMultiple(SelectMultiple): 267 def render(self, name, value, attrs=None, choices=() ):269 def render(self, name, value, attrs=None, choices=(), serialization=SERIALIZATION_DEFAULT): 268 270 if value is None: value = [] 269 271 has_id = attrs and attrs.has_key('id') 270 272 final_attrs = self.build_attrs(attrs, name=name) … … 277 279 final_attrs = dict(final_attrs, id='%s_%s' % (attrs['id'], i)) 278 280 cb = CheckboxInput(final_attrs, check_test=lambda value: value in str_values) 279 281 option_value = smart_unicode(option_value) 280 rendered_cb = cb.render(name, option_value )282 rendered_cb = cb.render(name, option_value, serialization=serialization) 281 283 output.append(u'<li><label>%s %s</label></li>' % (rendered_cb, escape(smart_unicode(option_label)))) 282 284 output.append(u'</ul>') 283 285 return u'\n'.join(output) … … 311 313 self.widgets = [isinstance(w, type) and w() or w for w in widgets] 312 314 super(MultiWidget, self).__init__(attrs) 313 315 314 def render(self, name, value, attrs=None ):316 def render(self, name, value, attrs=None, serialization=SERIALIZATION_DEFAULT): 315 317 # value is a list of values, each corresponding to a widget 316 318 # in self.widgets. 317 319 if not isinstance(value, list): … … 322 324 widget_value = value[i] 323 325 except KeyError: 324 326 widget_value = None 325 output.append(widget.render(name + '_%s' % i, widget_value, attrs ))327 output.append(widget.render(name + '_%s' % i, widget_value, attrs, serialization)) 326 328 return self.format_output(output) 327 329 328 330 def value_from_datadict(self, data, name):