Skip to content

Commit

Permalink
Merge pull request #25 from toscawidgets/feature/html5-validators
Browse files Browse the repository at this point in the history
New HTML5 input types
  • Loading branch information
moschlar committed Aug 27, 2013
2 parents 13b39b0 + cacd0f4 commit 0bcf254
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 9 deletions.
2 changes: 1 addition & 1 deletion tests/test_widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ class TestCheckbox(WidgetTest):

def test_value_false(self):
params = {'value': False}
expected = '<input type="checkbox" class="something"/>'
expected = '<input type="checkbox" class="something">'
for engine in self._get_all_possible_engines():
yield (self._check_rendering_vs_expected,
engine, self.attrs, params, expected)
Expand Down
6 changes: 6 additions & 0 deletions tw2/forms/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
CheckBox,
CheckBoxList,
CheckBoxTable,
ColorField,
EmailField,
FieldSet,
FileField,
FileValidator,
Expand All @@ -25,12 +27,15 @@
ListLayout,
MultipleSelectField,
MultipleSelectionField,
NumberField,
PasswordField,
RadioButton,
RadioButtonList,
RadioButtonTable,
RangeField,
ResetButton,
RowLayout,
SearchField,
SelectionField,
SeparatedCheckBoxTable,
SeparatedRadioButtonTable,
Expand All @@ -43,6 +48,7 @@
TableLayout,
TextField,
TextArea,
UrlField,
VerticalCheckBoxTable,
VerticalRadioButtonTable,
)
Expand Down
2 changes: 2 additions & 0 deletions tw2/forms/calendars.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
Portions of this document have been taken in part and modified from the
original tw.forms codebase written primarily by Alberto Valaverde
TODO: HTML5 type attribute support with native support detection and fallback
"""
import re
from datetime import datetime, date
Expand Down
25 changes: 24 additions & 1 deletion tw2/forms/samples.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@


class DemoTextField(twf.TextField):
placeholder = "Search..."
placeholder = "Type up to 7 characters..."
maxlength = 7


class DemoChildren(twc.CompoundWidget):
Expand Down Expand Up @@ -120,3 +121,25 @@ def address(self):
]

fields = [DummyObject.name, DummyObject.address]


class DemoEmailField(twf.EmailField):
placeholder = 'Enter your Email-Address...'


class DemoUrlField(twf.UrlField):
placeholder = 'http://toscawidgets.org'


class DemoNumberField(twf.NumberField):
min = 0
max = 10
step = 2
value = 8


class DemoRangeField(twf.RangeField):
min = 0
max = 10
step = 2
value = 8
125 changes: 118 additions & 7 deletions tw2/forms/widgets.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,35 @@ def required(self):
)


class TextFieldMixin(twc.Widget):
'''Misc mixin class with attributes for textual input fields'''
maxlength = twc.Param('Maximum length of field',
attribute=True, default=None)
placeholder = twc.Param('Placeholder text (HTML5 only)',
attribute=True, default=None)


class InputField(FormField):
type = twc.Variable('Type of input field',
default=twc.Required,
attribute=True)

value = twc.Param(attribute=True)

required = twc.Param('Input field is required',
attribute=True, default=None)

autofocus = twc.Param('Autofocus form field (HTML5 only)',
attribute=True, default=None)

template = "tw2.forms.templates.input_field"

def prepare(self):
super(InputField, self).prepare()
self.safe_modify('attrs')
self.attrs['required'] = 'required' if self.required in [True, 'required'] else None # Why not 'required' if self.required in [True, 'required'] else None ?
self.required = None # Needed because self.required would otherwise overwrite self.attrs['required'] again


class PostlabeledInputField(InputField):
""" Inherits :class:`InputField`, but with a :attr:`text`
Expand All @@ -41,18 +63,14 @@ class PostlabeledInputField(InputField):
template = "tw2.forms.templates.postlabeled_input_field"


class TextField(InputField):
class TextField(TextFieldMixin, InputField):
size = twc.Param('Size of the field', default=None, attribute=True)
placeholder = twc.Param(
'Placeholder text (HTML5 Only)', attribute=True, default=None)
type = 'text'


class TextArea(FormField):
class TextArea(TextFieldMixin, FormField):
rows = twc.Param('Number of rows', default=None, attribute=True)
cols = twc.Param('Number of columns', default=None, attribute=True)
placeholder = twc.Param(
'Placeholder text (HTML5 Only)', attribute=True, default=None)
template = "tw2.forms.templates.textarea"


Expand Down Expand Up @@ -82,7 +100,7 @@ class RadioButton(InputField):
default=False)


class PasswordField(InputField):
class PasswordField(TextFieldMixin, InputField):
"""
A password field. This never displays a value passed into the widget,
although it does redisplay entered values on validation failure. If no
Expand Down Expand Up @@ -242,6 +260,97 @@ def prepare(self):
self.attrs['src'] = self.src # TBD: hack!


#--
# HTML5 Mixins
#--

class HTML5PatternMixin(twc.Widget):
'''HTML5 mixin for input field regex pattern matching
See http://html5pattern.com/ for common patterns.
TODO: Configure server-side validator
'''
pattern = twc.Param('JavaScript regex to match field with',
attribute=True, default=None)


class HTML5MinMaxMixin(twc.Widget):
'''HTML5 mixin for input field value limits
TODO: Configure server-side validator
'''
min = twc.Param('Minimum value for field',
attribute=True, default=None)
max = twc.Param('Maximum value for field',
attribute=True, default=None)


class HTML5StepMixin(twc.Widget):
'''HTML5 mixin for input field step size'''
step = twc.Param('The step size between numbers',
attribute=True, default=None)


class HTML5NumberMixin(HTML5MinMaxMixin, HTML5StepMixin):
'''HTML5 mixin for number input fields'''
pass


#--
# HTML5 Fields
#--

class EmailField(TextField):
'''An email input field (HTML5 only).
Will fallback to a normal text input field on browser not supporting HTML5.
'''
type = 'email'
validator = twc.EmailValidator


class UrlField(TextField):
'''An url input field (HTML5 only).
Will fallback to a normal text input field on browser not supporting HTML5.
'''
type = 'url'
validator = twc.UrlValidator


class NumberField(HTML5NumberMixin, TextField):
'''A number spinbox (HTML5 only).
Will fallback to a normal text input field on browser not supporting HTML5.
'''
type = 'number'


class RangeField(HTML5NumberMixin, TextField):
'''A number slider (HTML5 only).
Will fallback to a normal text input field on browser not supporting HTML5.
'''
type = 'range'


class SearchField(TextField):
'''A search box (HTML5 only).
Will fallback to a normal text input field on browser not supporting HTML5.
'''
type = 'search'


class ColorField(TextField):
'''A color picker field (HTML5 only).
Will fallback to a normal text input field on browser not supporting HTML5.
'''
type = 'color'


#--
# Selection fields
#--
Expand Down Expand Up @@ -678,6 +787,8 @@ class Form(twc.DisplayOnlyWidget):
buttons = twc.Param('List of additional buttons to be placed at the ' +
'bottom of the form',
default=[])
novalidate = twc.Param('Turn off HTML5 form validation',
attribute=True, default=None)

attrs = {'enctype': 'multipart/form-data'}
id_suffix = 'form'
Expand Down

0 comments on commit 0bcf254

Please sign in to comment.