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

File html5-input-types-take3.patch, 8.0 KB (added by jonash, 3 years ago)

Against [17904]

  • django/forms/fields.py

    diff --git a/django/forms/fields.py b/django/forms/fields.py
    index 49f29db..581101a 100644
    a b except ImportError: 
    1818from django.core import validators
    1919from django.core.exceptions import ValidationError
    2020from django.forms.util import ErrorList, from_current_timezone, to_current_timezone
    21 from django.forms.widgets import (TextInput, PasswordInput, HiddenInput,
     21from django.forms.widgets import (
     22    TextInput, IntegerInput, PasswordInput, EmailInput, URLInput, HiddenInput,
    2223    MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select,
    2324    NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput,
    24     SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION)
     25    SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION
     26)
    2527from django.utils import formats
    2628from django.utils.encoding import smart_unicode, smart_str, force_unicode
    2729from django.utils.ipv6 import clean_ipv6_address
    from django.utils.translation import ugettext_lazy as _ 
    3032# Provide this import for backwards compatibility.
    3133from django.core.validators import EMPTY_VALUES
    3234
    33 
    3435__all__ = (
    3536    'Field', 'CharField', 'IntegerField',
    3637    'DateField', 'TimeField', 'DateTimeField', 'TimeField',
    class CharField(Field): 
    198199
    199200    def widget_attrs(self, widget):
    200201        attrs = super(CharField, self).widget_attrs(widget)
    201         if self.max_length is not None and isinstance(widget, (TextInput, PasswordInput)):
     202        if self.max_length is not None and isinstance(widget, TextInput):
    202203            # The HTML attribute is maxlength, not max_length.
    203204            attrs.update({'maxlength': str(self.max_length)})
    204205        return attrs
    205206
    206207class IntegerField(Field):
     208    widget = IntegerInput
    207209    default_error_messages = {
    208210        'invalid': _(u'Enter a whole number.'),
    209211        'max_value': _(u'Ensure this value is less than or equal to %(limit_value)s.'),
    class IntegerField(Field): 
    235237            raise ValidationError(self.error_messages['invalid'])
    236238        return value
    237239
     240    def widget_attrs(self, widget):
     241        attrs = super(IntegerField, self).widget_attrs(widget)
     242        if self.min_value:
     243            attrs['min'] = self.min_value
     244        if self.max_value:
     245            attrs['max'] = self.max_value
     246        return attrs
     247
    238248class FloatField(IntegerField):
    239249    default_error_messages = {
    240250        'invalid': _(u'Enter a number.'),
    class FloatField(IntegerField): 
    256266            raise ValidationError(self.error_messages['invalid'])
    257267        return value
    258268
    259 class DecimalField(Field):
     269    def widget_attrs(self, widget):
     270        attrs = super(FloatField, self).widget_attrs(widget)
     271        attrs['step'] = 'any'
     272        return attrs
     273
     274class DecimalField(IntegerField):
    260275    default_error_messages = {
    261276        'invalid': _(u'Enter a number.'),
    262         'max_value': _(u'Ensure this value is less than or equal to %(limit_value)s.'),
    263         'min_value': _(u'Ensure this value is greater than or equal to %(limit_value)s.'),
    264277        'max_digits': _('Ensure that there are no more than %s digits in total.'),
    265278        'max_decimal_places': _('Ensure that there are no more than %s decimal places.'),
    266279        'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.')
    267280    }
    268281
    269282    def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs):
    270         self.max_value, self.min_value = max_value, min_value
    271283        self.max_digits, self.decimal_places = max_digits, decimal_places
    272         Field.__init__(self, *args, **kwargs)
    273 
    274         if max_value is not None:
    275             self.validators.append(validators.MaxValueValidator(max_value))
    276         if min_value is not None:
    277             self.validators.append(validators.MinValueValidator(min_value))
     284        super(DecimalField, self).__init__(max_value, min_value, *args, **kwargs)
    278285
    279286    def to_python(self, value):
    280287        """
    class DecimalField(Field): 
    323330            raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places))
    324331        return value
    325332
     333    def widget_attrs(self, widget):
     334        attrs = super(DecimalField, self).widget_attrs(widget)
     335        if self.max_digits:
     336            attrs['maxlength'] = self.max_digits + 1 # for the dot
     337        if self.decimal_places:
     338            attrs['step'] = '0.%s1' % ('0' * (self.decimal_places-1))
     339        return attrs
     340
    326341class BaseTemporalField(Field):
    327342
    328343    def __init__(self, input_formats=None, *args, **kwargs):
    class RegexField(CharField): 
    459474    regex = property(_get_regex, _set_regex)
    460475
    461476class EmailField(CharField):
     477    widget = EmailInput
    462478    default_error_messages = {
    463479        'invalid': _(u'Enter a valid e-mail address.'),
    464480    }
    class ImageField(FileField): 
    585601        return f
    586602
    587603class URLField(CharField):
     604    widget = URLInput
    588605    default_error_messages = {
    589606        'invalid': _(u'Enter a valid URL.'),
    590607    }
  • django/forms/widgets.py

    diff --git a/django/forms/widgets.py b/django/forms/widgets.py
    index 1fbef98..5ca7186 100644
    a b from django.utils.safestring import mark_safe 
    1919from django.utils import datetime_safe, formats
    2020
    2121__all__ = (
    22     'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'PasswordInput',
    23     'HiddenInput', 'MultipleHiddenInput', 'ClearableFileInput',
    24     'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput',
    25     'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
    26     'CheckboxSelectMultiple', 'MultiWidget',
    27     'SplitDateTimeWidget',
     22    'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'EmailInput', 'URLInput',
     23    'IntegerInput', 'PasswordInput', 'HiddenInput', 'MultipleHiddenInput',
     24    'ClearableFileInput', 'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput',
     25    'Textarea', 'CheckboxInput', 'Select', 'NullBooleanSelect', 'SelectMultiple',
     26    'RadioSelect', 'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
    2827)
    2928
    3029MEDIA_TYPES = ('css','js')
    class Input(Widget): 
    242241    """
    243242    input_type = None # Subclasses must define this.
    244243
     244    def __init__(self, attrs=None, input_type=None):
     245        if input_type is not None:
     246            self.input_type = input_type
     247        super(Input, self).__init__(attrs)
     248
    245249    def _format_value(self, value):
    246250        if self.is_localized:
    247251            return formats.localize_input(value)
    class Input(Widget): 
    259263class TextInput(Input):
    260264    input_type = 'text'
    261265
    262 class PasswordInput(Input):
     266class IntegerInput(TextInput):
     267    input_type = 'number'
     268
     269class EmailInput(TextInput):
     270    input_type = 'email'
     271
     272class URLInput(TextInput):
     273    input_type = 'url'
     274
     275class PasswordInput(TextInput):
    263276    input_type = 'password'
    264277
    265278    def __init__(self, attrs=None, render_value=False):
    class Textarea(Widget): 
    395408        return mark_safe(u'<textarea%s>%s</textarea>' % (flatatt(final_attrs),
    396409                conditional_escape(force_unicode(value))))
    397410
    398 class DateInput(Input):
    399     input_type = 'text'
    400 
     411class DateInput(TextInput):
    401412    def __init__(self, attrs=None, format=None):
    402413        super(DateInput, self).__init__(attrs)
    403414        if format:
    class DateInput(Input): 
    426437            pass
    427438        return super(DateInput, self)._has_changed(self._format_value(initial), data)
    428439
    429 class DateTimeInput(Input):
    430     input_type = 'text'
    431 
     440class DateTimeInput(TextInput):
    432441    def __init__(self, attrs=None, format=None):
    433442        super(DateTimeInput, self).__init__(attrs)
    434443        if format:
    class DateTimeInput(Input): 
    457466            pass
    458467        return super(DateTimeInput, self)._has_changed(self._format_value(initial), data)
    459468
    460 class TimeInput(Input):
    461     input_type = 'text'
    462 
     469class TimeInput(TextInput):
    463470    def __init__(self, attrs=None, format=None):
    464471        super(TimeInput, self).__init__(attrs)
    465472        if format:
Back to Top