Code

Ticket #16630: html5-input-types-take1.patch

File html5-input-types-take1.patch, 7.2 KB (added by jonash, 3 years ago)
  • django/forms/fields.py

    diff --git a/django/forms/fields.py b/django/forms/fields.py
    index 113a5aa..f1328a7 100644
    a b from django.utils.ipv6 import clean_ipv6_address 
    2424from django.core.validators import EMPTY_VALUES 
    2525 
    2626from util import ErrorList 
    27 from widgets import (TextInput, PasswordInput, HiddenInput, 
    28     MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, 
     27from widgets import (TextInput, IntegerInput, EmailInput, URLInput, PasswordInput, 
     28    HiddenInput, MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, 
    2929    NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, 
    3030    SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION) 
    3131 
    class CharField(Field): 
    194194        return smart_unicode(value) 
    195195 
    196196    def widget_attrs(self, widget): 
    197         if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)): 
     197        attrs = super(CharField, self).widget_attrs(widget) 
     198        if self.max_length is not None and isinstance(widget, TextInput): 
    198199            # The HTML attribute is maxlength, not max_length. 
    199             return {'maxlength': str(self.max_length)} 
     200            attrs['maxlength'] = self.max_length 
     201        return attrs 
    200202 
    201203class IntegerField(Field): 
     204    widget = IntegerInput 
    202205    default_error_messages = { 
    203206        'invalid': _(u'Enter a whole number.'), 
    204207        'max_value': _(u'Ensure this value is less than or equal to %(limit_value)s.'), 
    class IntegerField(Field): 
    230233            raise ValidationError(self.error_messages['invalid']) 
    231234        return value 
    232235 
     236    def widget_attrs(self, widget): 
     237        attrs = super(IntegerField, self).widget_attrs(widget) 
     238        if self.min_value: 
     239            attrs['min'] = self.min_value 
     240        if self.max_value: 
     241            attrs['max'] = self.max_value 
     242        return attrs 
     243 
    233244class FloatField(IntegerField): 
    234245    default_error_messages = { 
    235246        'invalid': _(u'Enter a number.'), 
    class FloatField(IntegerField): 
    251262            raise ValidationError(self.error_messages['invalid']) 
    252263        return value 
    253264 
    254 class DecimalField(Field): 
     265    def widget_attrs(self, widget): 
     266        attrs = super(FloatField, self).widget_attrs(widget) 
     267        attrs['step'] = 'any' 
     268        return attrs 
     269 
     270class DecimalField(IntegerField): 
    255271    default_error_messages = { 
    256272        'invalid': _(u'Enter a number.'), 
    257         'max_value': _(u'Ensure this value is less than or equal to %(limit_value)s.'), 
    258         'min_value': _(u'Ensure this value is greater than or equal to %(limit_value)s.'), 
    259273        'max_digits': _('Ensure that there are no more than %s digits in total.'), 
    260274        'max_decimal_places': _('Ensure that there are no more than %s decimal places.'), 
    261275        'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.') 
    262276    } 
    263277 
    264278    def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs): 
    265         self.max_value, self.min_value = max_value, min_value 
    266279        self.max_digits, self.decimal_places = max_digits, decimal_places 
    267         Field.__init__(self, *args, **kwargs) 
    268  
    269         if max_value is not None: 
    270             self.validators.append(validators.MaxValueValidator(max_value)) 
    271         if min_value is not None: 
    272             self.validators.append(validators.MinValueValidator(min_value)) 
     280        super(DecimalField, self).__init__(max_value, min_value, *args, **kwargs) 
    273281 
    274282    def to_python(self, value): 
    275283        """ 
    class DecimalField(Field): 
    318326            raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) 
    319327        return value 
    320328 
     329    def widget_attrs(self, widget): 
     330        attrs = super(DecimalField, self).widget_attrs(widget) 
     331        if self.max_digits: 
     332            attrs['maxlength'] = self.max_digits + 1 # for the dot 
     333        if self.decimal_places: 
     334            attrs['step'] = '0.%s1' % ('0' * (self.decimal_places-1)) 
     335        return attrs 
     336 
    321337class BaseTemporalField(Field): 
    322338 
    323339    def __init__(self, input_formats=None, *args, **kwargs): 
    class RegexField(CharField): 
    445461        self.validators.append(validators.RegexValidator(regex=regex)) 
    446462 
    447463class EmailField(CharField): 
     464    widget = EmailInput 
    448465    default_error_messages = { 
    449466        'invalid': _(u'Enter a valid e-mail address.'), 
    450467    } 
    class ImageField(FileField): 
    571588        return f 
    572589 
    573590class URLField(CharField): 
     591    widget = URLInput 
    574592    default_error_messages = { 
    575593        'invalid': _(u'Enter a valid URL.'), 
    576594        'invalid_link': _(u'This URL appears to be a broken link.'), 
  • django/forms/widgets.py

    diff --git a/django/forms/widgets.py b/django/forms/widgets.py
    index 9b95c31..b9f405b 100644
    a b from django.utils.safestring import mark_safe 
    1717from django.utils import datetime_safe, formats 
    1818 
    1919__all__ = ( 
    20     'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'PasswordInput', 
    21     'HiddenInput', 'MultipleHiddenInput', 'ClearableFileInput', 
    22     'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput', 
    23     'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', 
    24     'CheckboxSelectMultiple', 'MultiWidget', 
    25     'SplitDateTimeWidget', 
     20    'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'EmailInput', 'URLInput', 
     21    'IntegerInput', 'PasswordInput', 'HiddenInput', 'MultipleHiddenInput', 
     22    'ClearableFileInput', 'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 
     23    'Textarea', 'CheckboxInput', 'Select', 'NullBooleanSelect', 'SelectMultiple', 
     24    'RadioSelect', 'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget', 
    2625) 
    2726 
    2827MEDIA_TYPES = ('css','js') 
    class Input(Widget): 
    233232class TextInput(Input): 
    234233    input_type = 'text' 
    235234 
    236 class PasswordInput(Input): 
     235class IntegerInput(TextInput): 
     236    input_type = 'number' 
     237 
     238class EmailInput(TextInput): 
     239    input_type = 'email' 
     240 
     241class URLInput(TextInput): 
     242    input_type = 'url' 
     243 
     244class PasswordInput(TextInput): 
    237245    input_type = 'password' 
    238246 
    239247    def __init__(self, attrs=None, render_value=False): 
    class Textarea(Widget): 
    369377        return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs), 
    370378                conditional_escape(force_unicode(value)))) 
    371379 
    372 class DateInput(Input): 
    373     input_type = 'text' 
    374  
     380class DateInput(TextInput): 
    375381    def __init__(self, attrs=None, format=None): 
    376382        super(DateInput, self).__init__(attrs) 
    377383        if format: 
    class DateInput(Input): 
    400406            pass 
    401407        return super(DateInput, self)._has_changed(self._format_value(initial), data) 
    402408 
    403 class DateTimeInput(Input): 
    404     input_type = 'text' 
    405  
     409class DateTimeInput(TextInput): 
    406410    def __init__(self, attrs=None, format=None): 
    407411        super(DateTimeInput, self).__init__(attrs) 
    408412        if format: 
    class DateTimeInput(Input): 
    431435            pass 
    432436        return super(DateTimeInput, self)._has_changed(self._format_value(initial), data) 
    433437 
    434 class TimeInput(Input): 
    435     input_type = 'text' 
    436  
     438class TimeInput(TextInput): 
    437439    def __init__(self, attrs=None, format=None): 
    438440        super(TimeInput, self).__init__(attrs) 
    439441        if format: