diff options
| author | Claude Paroz <claude@2xlibre.net> | 2013-02-23 09:45:56 +0100 |
|---|---|---|
| committer | Claude Paroz <claude@2xlibre.net> | 2013-02-23 10:18:08 +0100 |
| commit | 7ec2a21be15af5b2c7513482c3bcfdd1e12782ed (patch) | |
| tree | 13c7d8bdaca60c246d6de8166ad3f66f04dc7a58 /django/forms | |
| parent | dcf651c27edff13236fda0a480059b57dbe6e074 (diff) | |
Fixed #19686 -- Added HTML5 number input type
Thanks Simon Charette for his help on the patch. Refs #16630.
Diffstat (limited to 'django/forms')
| -rw-r--r-- | django/forms/fields.py | 45 | ||||
| -rw-r--r-- | django/forms/widgets.py | 6 |
2 files changed, 39 insertions, 12 deletions
diff --git a/django/forms/fields.py b/django/forms/fields.py index c547d1456c..621d3801f2 100644 --- a/django/forms/fields.py +++ b/django/forms/fields.py @@ -19,7 +19,7 @@ from django.core import validators from django.core.exceptions import ValidationError from django.forms.util import ErrorList, from_current_timezone, to_current_timezone from django.forms.widgets import ( - TextInput, PasswordInput, EmailInput, URLInput, HiddenInput, + TextInput, NumberInput, EmailInput, URLInput, HiddenInput, MultipleHiddenInput, ClearableFileInput, CheckboxInput, Select, NullBooleanSelect, SelectMultiple, DateInput, DateTimeInput, TimeInput, SplitDateTimeWidget, SplitHiddenDateTimeWidget, FILE_INPUT_CONTRADICTION @@ -234,6 +234,7 @@ class IntegerField(Field): def __init__(self, max_value=None, min_value=None, *args, **kwargs): self.max_value, self.min_value = max_value, min_value + kwargs.setdefault('widget', NumberInput if not kwargs.get('localize') else self.widget) super(IntegerField, self).__init__(*args, **kwargs) if max_value is not None: @@ -257,6 +258,16 @@ class IntegerField(Field): raise ValidationError(self.error_messages['invalid']) return value + def widget_attrs(self, widget): + attrs = super(IntegerField, self).widget_attrs(widget) + if isinstance(widget, NumberInput): + if self.min_value is not None: + attrs['min'] = self.min_value + if self.max_value is not None: + attrs['max'] = self.max_value + return attrs + + class FloatField(IntegerField): default_error_messages = { 'invalid': _('Enter a number.'), @@ -278,25 +289,24 @@ class FloatField(IntegerField): raise ValidationError(self.error_messages['invalid']) return value -class DecimalField(Field): + def widget_attrs(self, widget): + attrs = super(FloatField, self).widget_attrs(widget) + if isinstance(widget, NumberInput): + attrs.setdefault('step', 'any') + return attrs + + +class DecimalField(IntegerField): default_error_messages = { 'invalid': _('Enter a number.'), - 'max_value': _('Ensure this value is less than or equal to %(limit_value)s.'), - 'min_value': _('Ensure this value is greater than or equal to %(limit_value)s.'), 'max_digits': _('Ensure that there are no more than %s digits in total.'), 'max_decimal_places': _('Ensure that there are no more than %s decimal places.'), 'max_whole_digits': _('Ensure that there are no more than %s digits before the decimal point.') } def __init__(self, max_value=None, min_value=None, max_digits=None, decimal_places=None, *args, **kwargs): - self.max_value, self.min_value = max_value, min_value self.max_digits, self.decimal_places = max_digits, decimal_places - Field.__init__(self, *args, **kwargs) - - if max_value is not None: - self.validators.append(validators.MaxValueValidator(max_value)) - if min_value is not None: - self.validators.append(validators.MinValueValidator(min_value)) + super(DecimalField, self).__init__(max_value, min_value, *args, **kwargs) def to_python(self, value): """ @@ -345,6 +355,19 @@ class DecimalField(Field): raise ValidationError(self.error_messages['max_whole_digits'] % (self.max_digits - self.decimal_places)) return value + def widget_attrs(self, widget): + attrs = super(DecimalField, self).widget_attrs(widget) + if isinstance(widget, NumberInput): + if self.max_digits is not None: + max_length = self.max_digits + 1 # for the sign + if self.decimal_places is None or self.decimal_places > 0: + max_length += 1 # for the dot + attrs['maxlength'] = max_length + if self.decimal_places: + attrs['step'] = '0.%s1' % ('0' * (self.decimal_places-1)) + return attrs + + class BaseTemporalField(Field): def __init__(self, input_formats=None, *args, **kwargs): diff --git a/django/forms/widgets.py b/django/forms/widgets.py index e906ed5bc6..026e8dc36a 100644 --- a/django/forms/widgets.py +++ b/django/forms/widgets.py @@ -23,7 +23,7 @@ from django.utils import datetime_safe, formats, six __all__ = ( 'Media', 'MediaDefiningClass', 'Widget', 'TextInput', - 'EmailInput', 'URLInput', 'PasswordInput', + 'EmailInput', 'URLInput', 'NumberInput', 'PasswordInput', 'HiddenInput', 'MultipleHiddenInput', 'ClearableFileInput', 'FileInput', 'DateInput', 'DateTimeInput', 'TimeInput', 'Textarea', 'CheckboxInput', 'Select', 'NullBooleanSelect', 'SelectMultiple', 'RadioSelect', @@ -252,6 +252,10 @@ class TextInput(Input): super(TextInput, self).__init__(attrs) +class NumberInput(TextInput): + input_type = 'number' + + class EmailInput(TextInput): input_type = 'email' |
