Skip to content

Commit

Permalink
- Add text input mask capability to
Browse files Browse the repository at this point in the history
  ``deform.widget.CheckedInputWidget``.
  • Loading branch information
mcdonc committed May 16, 2010
1 parent 113050f commit 73a87fc
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 15 deletions.
3 changes: 3 additions & 0 deletions CHANGES.txt
Expand Up @@ -6,6 +6,9 @@ Next release

- Add text input mask capability to ``deform.widget.TextInputWidget``.

- Add text input mask capability to
``deform.widget.CheckedInputWidget``.

0.2 (2010-05-13)
----------------

Expand Down
13 changes: 13 additions & 0 deletions deform/templates/checked_input.pt
@@ -1,5 +1,7 @@
<div>

<input type="hidden" name="__start__" value="${field.name}:mapping"/>

<div>
<label for="${field.oid}">${subject}</label>
<input type="text" name="value" value="${cstruct}"
Expand All @@ -10,6 +12,17 @@
<input type="text" name="confirm" value="${confirm}"
tal:attributes="size field.widget.size" id="${field.oid}-confirm"/>
</div>

<script tal:condition="field.widget.mask" type="text/javascript">
jQuery(function($) {
$("#${field.oid}").mask("${field.widget.mask}",
{placeholder:"${field.widget.mask_placeholder}"});
$("#${field.oid}-confirm").mask("${field.widget.mask}",
{placeholder:"${field.widget.mask_placeholder}"});
});
</script>

<input type="hidden" name="__end__" value="${field.name}:mapping"/>

</div>

31 changes: 30 additions & 1 deletion deform/widget.py
Expand Up @@ -152,7 +152,7 @@ class TextInputWidget(Widget):
When this option is used, the :term:`jquery.maskedinput`
library must be loaded into the page serving the form for the
mask argument to have any effect.
mask argument to have any effect. See :ref:`masked_input`.
mask_placeholder
The placeholder for required nonliteral elements when a mask
Expand Down Expand Up @@ -430,13 +430,42 @@ class CheckedInputWidget(Widget):
mismatch_message
The message to be displayed when the value in the primary
field doesn't match the value in the confirm field.
mask
A :term:`jquery.maskedinput` input mask, as a string. Both
input fields will use this mask.
a - Represents an alpha character (A-Z,a-z)
9 - Represents a numeric character (0-9)
* - Represents an alphanumeric character (A-Z,a-z,0-9)
All other characters in the mask will be considered mask
literals.
Example masks:
Date: 99/99/9999
US Phone: (999) 999-9999
US SSN: 999-99-9999
When this option is used, the :term:`jquery.maskedinput`
library must be loaded into the page serving the form for the
mask argument to have any effect. See :ref:`masked_input`.
mask_placeholder
The placeholder for required nonliteral elements when a mask
is used. Default: ``_`` (underscore).
"""
template = 'checked_input'
readonly_template = 'readonly/checked_input'
size = None
mismatch_message = _('Fields did not match')
subject = _('Value')
confirm_subject = _('Confirm Value')
mask = None
mask_placeholder = "_"

def serialize(self, field, cstruct=None, readonly=False):
if cstruct is None:
Expand Down
19 changes: 19 additions & 0 deletions deformdemo/app.py
Expand Up @@ -244,6 +244,25 @@ class Schema(colander.Schema):
form['password'].widget = deform.widget.CheckedPasswordWidget(size=20)
return self.render_form(form)

@bfg_view(renderer='templates/form.pt', name='checkedinput_withmask')
@demonstrate('Checked Input Widget (With Input Mask)')
def checkedinput_withmask(self):
class Schema(colander.Schema):
ssn = colander.SchemaNode(
colander.String(),
title = 'Social Security Number',
description='Type your Social Security Number and confirm it',
)
schema = Schema()
form = deform.Form(schema, buttons=('submit',))
form['ssn'].widget = deform.widget.CheckedInputWidget(
subject='SSN',
confirm_subject='Confirm SSN',
mask = '999-99-9999',
mask_placeholder = '#',
size=40)
return self.render_form(form)

@bfg_view(renderer='templates/form.pt', name='mapping')
@demonstrate('Mapping Widget')
def mapping(self):
Expand Down
44 changes: 41 additions & 3 deletions deformdemo/tests/test_demo.py
Expand Up @@ -176,6 +176,43 @@ def test_submit_success(self):
self.assertEqual(browser.get_text('css=#captured'),
"{'email': u'user@example.com'}")

class CheckedInputWidgetWithMaskTests(unittest.TestCase):
url = "/checkedinput_withmask/"
def test_render_default(self):
browser.open(self.url)
browser.wait_for_page_to_load("30000")
self.assertEqual(browser.get_text('css=.req'), '*')
self.assertEqual(browser.get_text('css=#captured'), 'None')
self.assertEqual(browser.get_value('deformField1'), '')
self.assertEqual(browser.get_value('deformField1-confirm'), '')
self.failIf(browser.is_element_present('css=.errorMsgLbl'))

def test_type_bad_input(self):
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.focus('deformField1')
browser.key_press('deformField1', 'a')
browser.focus('deformField1-confirm')
browser.key_press('deformField1-confirm', 'a')
self.assertEqual(browser.get_value('deformField1'), '')
self.failUnless(
browser.get_value('deformField1-confirm') in ('', '###-##-####'))

def test_submit_success(self):
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.focus('deformField1')
for key in '140118866':
browser.key_press('deformField1', key)
browser.focus('deformField1-confirm')
for key in '140118866':
browser.key_press('deformField1-confirm', key)
browser.click('submit')
browser.wait_for_page_to_load("30000")
self.assertEqual(browser.get_text('css=#captured'),
u"{'ssn': u'140-11-8866'}")


class CheckedPasswordWidgetTests(unittest.TestCase):
url = "/checkedpassword/"
def test_render_default(self):
Expand Down Expand Up @@ -1716,21 +1753,22 @@ def test_type_bad_input(self):
browser.focus('deformField2')
browser.key_press('deformField2', 'a')
self.assertEqual(browser.get_value('deformField1'), '')
self.assertEqual(browser.get_value('deformField2'), '')
self.failUnless(
browser.get_value('deformField2') in ('', '__/__/____'))

def test_submit_success(self):
browser.open(self.url)
browser.wait_for_page_to_load("30000")
browser.focus('deformField1')
for key in '141740312':
for key in '140118866':
browser.key_press('deformField1', key)
browser.focus('deformField2')
for key in '10102010':
browser.key_press('deformField2', key)
browser.click('submit')
browser.wait_for_page_to_load("30000")
self.assertEqual(browser.get_text('css=#captured'),
u"{'date': u'10/10/2010', 'ssn': u'141-74-0312'}")
u"{'date': u'10/10/2010', 'ssn': u'140-11-8866'}")


if __name__ == '__main__':
Expand Down
25 changes: 14 additions & 11 deletions docs/basics.rst
Expand Up @@ -559,20 +559,14 @@ widgets provided by Deform are not sufficient, see
:ref:`writing_a_widget` for more information about writing a custom
widget.

Creating a New Schema Type
--------------------------

Sometimes the default schema types offered by Colander may not be
sufficient to model structures in your application. See the `Colander
documentation about defining a new schema type
<http://docs.repoze.org/colander/#defining-a-new-type>`_ when this
becomes true.
.. _masked_input:

Using Text Input Masks
----------------------
~~~~~~~~~~~~~~~~~~~~~~

The :class:`deform.widget.TextInputWidget` widget allows for the use
of a fixed-length text input mask. Use of a text input mask causes
The :class:`deform.widget.TextInputWidget` and
:class:`deform.widget.CheckedInputWidget` widgets allow for the use of
a fixed-length text input mask. Use of a text input mask causes
placeholder text to be placed in the text field input, and restricts
the type and length of the characters input into the text field.

Expand Down Expand Up @@ -626,3 +620,12 @@ validation of the field; it is purely a UI affordance. If the data
must be checked at input time a separate :term:`validator` should be
attached to the related schema node.

Creating a New Schema Type
--------------------------

Sometimes the default schema types offered by Colander may not be
sufficient to model structures in your application. See the `Colander
documentation about defining a new schema type
<http://docs.repoze.org/colander/#defining-a-new-type>`_ when this
becomes true.

0 comments on commit 73a87fc

Please sign in to comment.