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

File html5-input-types-take1.patch, 7.2 KB (added by jonash, 4 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:
Back to Top