[Checkins] SVN: z3c.widget/trunk/ - feature: Added a date-selection widget.

Stephan Richter srichter at cosmos.phy.tufts.edu
Fri Sep 21 09:05:44 EDT 2007


Log message for revision 79795:
  - feature: Added a date-selection widget.
  - feature: Added a social security number widget.
  - feature: Added a US phone number widget.
  
  

Changed:
  U   z3c.widget/trunk/CHANGES.txt
  A   z3c.widget/trunk/src/z3c/widget/dateselect/
  A   z3c.widget/trunk/src/z3c/widget/dateselect/README.txt
  A   z3c.widget/trunk/src/z3c/widget/dateselect/__init__.py
  A   z3c.widget/trunk/src/z3c/widget/dateselect/browser.py
  A   z3c.widget/trunk/src/z3c/widget/dateselect/configure.zcml
  A   z3c.widget/trunk/src/z3c/widget/dateselect/testing.py
  A   z3c.widget/trunk/src/z3c/widget/dateselect/tests.py
  A   z3c.widget/trunk/src/z3c/widget/dateselect/widget-date.pt
  A   z3c.widget/trunk/src/z3c/widget/ssn/
  A   z3c.widget/trunk/src/z3c/widget/ssn/README.txt
  A   z3c.widget/trunk/src/z3c/widget/ssn/__init__.py
  A   z3c.widget/trunk/src/z3c/widget/ssn/browser.py
  A   z3c.widget/trunk/src/z3c/widget/ssn/testing.py
  A   z3c.widget/trunk/src/z3c/widget/ssn/tests.py
  A   z3c.widget/trunk/src/z3c/widget/ssn/widget-ssn.pt
  A   z3c.widget/trunk/src/z3c/widget/usphone/
  A   z3c.widget/trunk/src/z3c/widget/usphone/README.txt
  A   z3c.widget/trunk/src/z3c/widget/usphone/__init__.py
  A   z3c.widget/trunk/src/z3c/widget/usphone/browser.py
  A   z3c.widget/trunk/src/z3c/widget/usphone/testing.py
  A   z3c.widget/trunk/src/z3c/widget/usphone/tests.py
  A   z3c.widget/trunk/src/z3c/widget/usphone/widget-phone.pt

-=-
Modified: z3c.widget/trunk/CHANGES.txt
===================================================================
--- z3c.widget/trunk/CHANGES.txt	2007-09-21 13:05:01 UTC (rev 79794)
+++ z3c.widget/trunk/CHANGES.txt	2007-09-21 13:05:43 UTC (rev 79795)
@@ -3,6 +3,13 @@
 ======================
 
 
+2007/09/21 0.2.0
+================
+
+ - feature: Added a date-selection widget.
+ - feature: Added a social security number widget.
+ - feature: Added a US phone number widget.
+
 2007/09/19 0.1.7
 ================
 

Added: z3c.widget/trunk/src/z3c/widget/dateselect/README.txt
===================================================================
--- z3c.widget/trunk/src/z3c/widget/dateselect/README.txt	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/dateselect/README.txt	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,413 @@
+=====================
+Date Selection Widget
+=====================
+
+The ``DateSelectWidget`` widget provides three select boxes presenting the
+day, month and year.
+
+First we have to create a field and a request. Note that we can set the
+year range in this widget:
+
+  >>> import datetime
+  >>> from z3c.schema.dateselect import DateSelect
+  >>> from z3c.widget.dateselect.browser import DateSelectWidget
+
+  >>> field = DateSelect(
+  ...     title=u'Birthday',
+  ...     description=u'Somebodys birthday',
+  ...     yearRange=range(1930, 2007),
+  ...     required=True)
+  >>> field.__name__ = 'field'
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+
+Now we can initialize widget.
+
+  >>> widget = DateSelectWidget(field, request)
+
+Let's make sure that all fields have the correct value:
+
+  >>> widget.name
+  'field.field'
+
+  >>> widget.label
+  u'Birthday'
+
+  >>> widget.hint
+  u'Somebodys birthday'
+
+  >>> widget.visible
+  True
+
+  >>> widget.required
+  True
+
+The constructor should have also created 3 widgets:
+
+  >>> widget.widgets['year']
+  <z3c.widget.dateselect.browser.DropdownWidget object at ...>
+  >>> widget.widgets['month']
+  <z3c.widget.dateselect.browser.DropdownWidget object at ...>
+  >>> widget.widgets['day']
+  <z3c.widget.dateselect.browser.DropdownWidget object at ...>
+
+let's also test the year range:
+
+  >>> '1929' in widget.widgets['year'].vocabulary.by_token.keys()
+  False
+  >>> '1930' in widget.widgets['year'].vocabulary.by_token.keys()
+  True
+  >>> '2006' in widget.widgets['year'].vocabulary.by_token.keys()
+  True
+  >>> '2007' in widget.widgets['year'].vocabulary.by_token.keys()
+  False
+
+Test another year range:
+
+  >>> field2 = DateSelect(
+  ...     title=u'Another Birthday',
+  ...     yearRange=range(2000, 2010))
+  >>> field2.__name__ = 'field'
+  >>> widget2 = DateSelectWidget(field2, request)
+
+  >>> '1930' in widget2.widgets['year'].vocabulary.by_token.keys()
+  False
+  >>> '2000' in widget2.widgets['year'].vocabulary.by_token.keys()
+  True
+  >>> '2009' in widget2.widgets['year'].vocabulary.by_token.keys()
+  True
+  >>> '2010' in widget2.widgets['year'].vocabulary.by_token.keys()
+  False
+
+
+``setRenderedValue(value)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The first method is ``setRenderedValue()``. The widget has two use cases,
+based on the type of value. If the value is a custom score system, it will
+send the information to the custom, min and max widget:
+
+  >>> widget = DateSelectWidget(field, request)
+  >>> year = 2000
+  >>> month = 12
+  >>> day = 31
+  >>> data = datetime.date(year, month, day)
+  >>> widget.setRenderedValue(data)
+
+  >>> 'value="2000"' in widget()
+  True
+  >>> 'value="12"' in widget()
+  True
+  >>> 'value="31"' in widget()
+  True
+
+
+``setPrefix(prefix)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The prefix determines the name of the widget and all its sub-widgets.
+
+  >>> widget.name
+  'field.field'
+  >>> widget.widgets['year'].name
+  'field.field.year'
+  >>> widget.widgets['month'].name
+  'field.field.month'
+  >>> widget.widgets['day'].name
+  'field.field.day'
+
+  >>> widget.setPrefix('test.')
+
+  >>> widget.name
+  'test.field'
+  >>> widget.widgets['year'].name
+  'test.field.year'
+  >>> widget.widgets['month'].name
+  'test.field.month'
+  >>> widget.widgets['day'].name
+  'test.field.day'
+
+If the prefix does not end in a dot, one is added:
+
+  >>> widget.setPrefix('test')
+
+  >>> widget.name
+  'test.field'
+  >>> widget.widgets['year'].name
+  'test.field.year'
+  >>> widget.widgets['month'].name
+  'test.field.month'
+  >>> widget.widgets['day'].name
+  'test.field.day'
+
+
+``getInputValue()`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method returns a date object:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '24'})
+
+  >>> widget = DateSelectWidget(field, request)
+
+  >>> value = widget.getInputValue()
+  >>> value.year
+  2006
+  >>> value.month
+  2
+  >>> value.day
+  24
+
+If a set of values does not produce a valid date object, a value error is
+raised:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '29'})
+
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('field', u'Birthday', u'day is out of range for month')
+
+  >>> widget._error
+  <zope.app.form.interfaces.WidgetInputError ...>
+
+
+``applyChanges(content)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method applies the new date to the passed content. However, it
+must be smart enough to detect whether the values really changed.
+
+  >>> class Content(object):
+  ...     field = None
+  >>> content = Content()
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '24'})
+
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.applyChanges(content)
+  True
+  >>> content.field
+  datetime.date(2006, 2, 24)
+
+  >>> widget.applyChanges(content)
+  False
+
+
+``hasInput()`` Method
+~~~~~~~~~~~~~~~~~~~~~
+
+This method checks for any input, but does not validate it.
+
+  >>> request = TestRequest()
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.month': '2'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.day': '24'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '24'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasInput()
+  True
+
+
+``hasValidInput()`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Additionally to checking for any input, this method also checks whether the
+input is valid:
+
+  >>> request = TestRequest()
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.month': '2'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.day': '24'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '24'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.hasValidInput()
+  True
+
+
+``hidden()`` Method
+~~~~~~~~~~~~~~~~~~~
+
+This method is renders the output as hidden fields:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '24'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> print widget.hidden()
+  <input class="hiddenType" id="field.field.year" name="field.field.year"
+         type="hidden" value="2006" />
+  <input class="hiddenType" id="field.field.month" name="field.field.month"
+         type="hidden" value="2"  />
+  <input class="hiddenType" id="field.field.day" name="field.field.day"
+         type="hidden" value="24"  />
+
+
+``error()`` Method
+~~~~~~~~~~~~~~~~~~
+
+Let's test some bad data and check the error handling.
+
+The day field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '99'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  ConversionError: ('Invalid value', token '99' not found in vocabulary)
+  >>> print widget.error()
+  <span class="error">Invalid value</span>
+
+The month field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '0',
+  ...     'field.field.day': '31'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  ConversionError: ('Invalid value', token '0' not found in vocabulary)
+  >>> print widget.error()
+  <span class="error">Invalid value</span>
+
+The year field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '1900',
+  ...     'field.field.month': '1',
+  ...     'field.field.day': '31'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  ConversionError: ('Invalid value', token '1900' not found in vocabulary)
+  >>> print widget.error()
+  <span class="error">Invalid value</span>
+
+The single inputs were correct, but did not create a valid date.
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '1980',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '31'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('field', u'Birthday', u'day is out of range for month')
+
+  >>> print widget.error()
+  <span class="error">day is out of range for month</span>
+
+No error occurred:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '1980',
+  ...     'field.field.month': '1',
+  ...     'field.field.day': '31'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> widget.getInputValue()
+  datetime.date(1980, 1, 31)
+  >>> widget.error()
+  ''
+
+
+``__call__()`` Method
+~~~~~~~~~~~~~~~~~~~~~
+
+This method renders the widget using the sub-widgets. Let's see the output:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.year': '2006',
+  ...     'field.field.month': '2',
+  ...     'field.field.day': '24'})
+  >>> widget = DateSelectWidget(field, request)
+  >>> print widget()
+  <select id="field.field.day" name="field.field.day" size="1" >
+  <option value="1">1</option>
+  ...
+  <option value="23">23</option>
+  <option selected="selected" value="24">24</option>
+  <option value="25">25</option>
+  ...
+  <option value="31">31</option>
+  </select><input name="field.field.day-empty-marker" type="hidden"
+                  value="1" />&nbsp;
+  <select id="field.field.month" name="field.field.month" size="1" >
+  <option value="1">1</option>
+  <option selected="selected" value="2">2</option>
+  <option value="3">3</option>
+  ...
+  <option value="12">12</option>
+  </select><input name="field.field.month-empty-marker" type="hidden"
+                  value="1" />&nbsp;
+  <select id="field.field.year" name="field.field.year" size="1" >
+  <option value="1930">1930</option>
+  ...
+  <option value="2005">2005</option>
+  <option selected="selected" value="2006">2006</option>
+  </select><input
+      name="field.field.year-empty-marker" type="hidden" value="1" />
+  <BLANKLINE>


Property changes on: z3c.widget/trunk/src/z3c/widget/dateselect/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.widget/trunk/src/z3c/widget/dateselect/__init__.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/dateselect/__init__.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/dateselect/__init__.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1 @@
+# Make a package


Property changes on: z3c.widget/trunk/src/z3c/widget/dateselect/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/dateselect/browser.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/dateselect/browser.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/dateselect/browser.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,259 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = 'reStructuredText'
+
+import datetime
+import zope.interface
+import zope.schema
+from zope.formlib import form
+from zope.app.form.interfaces import IInputWidget
+from zope.app.form.interfaces import WidgetInputError
+from zope.app.form.browser.interfaces import IBrowserWidget
+from zope.app.form import browser
+from zope.app.pagetemplate import ViewPageTemplateFile
+from zope.app.zapi import getMultiAdapter
+from zope.app.form.browser.interfaces import IWidgetInputErrorView
+
+from z3c.i18n import MessageFactory as _
+
+
+class DropdownWidget(browser.SelectWidget):
+    """Variation of the SelectWidget that uses a drop-down list.
+
+    This widget renders no div tags arround the select tag. This is needed
+    for rendering select tags as sub widgets in the DateSelectWidget.
+    """
+    size = 1
+
+    def __call__(self):
+        """See IBrowserWidget."""
+        value = self._getFormValue()
+        contents = []
+        have_results = False
+
+        contents.append(self.renderValue(value))
+        contents.append(self._emptyMarker())
+        return "".join(contents)
+
+
+class WidgetDataSource(object):
+    """Provides a cofigurable date range source."""
+    zope.interface.implements(zope.schema.interfaces.IContextSourceBinder)
+
+    def __call__(self, context):
+        """Returns a data range vocabulary."""
+        yearRange = context.yearRange
+        return zope.schema.vocabulary.SimpleVocabulary.fromValues(yearRange)
+
+
+class IDateSelectData(zope.interface.Interface):
+    """A schema used to generate a date widget."""
+
+    year = zope.schema.Choice(
+        title=_('Year'),
+        description=_('The year.'),
+        source=WidgetDataSource(),
+        required=True)
+
+    month = zope.schema.Choice(
+        title=_('Month'),
+        description=_('The month.'),
+        values=range(1, 13),
+        required=True)
+
+    day = zope.schema.Choice(
+        title=_('Day'),
+        description=_('The day.'),
+        values=range(1, 32),
+        required=True)
+
+    yearRange = zope.interface.Attribute(u"Year range.")
+
+
+class DateSelectDataForDateSelectWidget(object):
+    """DateSelectData for DateSelectWidget adapter
+
+    This adapter knows how to handle get and set the day, month and year
+    for a DateSelectWidget and is also able to set a the right values in
+    the year vocabulary given from the yearRange attribute in the
+    DateSelectWidget.
+    Note: this adapter is internal used for setUpEditWidget in formlib and 
+    not registred in the adapter registry.
+    """
+
+    zope.interface.implements(IDateSelectData)
+
+    def __init__(self, context, date):
+        self.context = context
+        self.date = date
+
+    @apply
+    def day():
+        def get(self):
+            return self.date.day
+        def set(self, value):
+            self.date.day = value
+        return property(get, set)
+
+    @apply
+    def month():
+        def get(self):
+            return self.date.month
+        def set(self, value):
+            self.date.month = value
+        return property(get, set)
+
+    @apply
+    def year():
+        def get(self):
+            return self.date.year
+        def set(self, value):
+            self.date.year = value
+        return property(get, set)
+
+    @property
+    def yearRange(self):
+        return self.context.yearRange
+
+
+class DateSelectWidget(object):
+    """Date Widget with multi select options."""
+    zope.interface.implements(IBrowserWidget, IInputWidget)
+
+    template = ViewPageTemplateFile('widget-date.pt')
+    _prefix = 'field.'
+    _error = None
+    widgets = {}
+
+    # See zope.app.form.interfaces.IWidget
+    name = None
+    label = property(lambda self: self.context.title)
+    hint = property(lambda self: self.context.description)
+    visible = True
+    # See zope.app.form.interfaces.IInputWidget
+    required = property(lambda self: self.context.required)
+    # See smart.field.IDateSelect
+    yearRange = property(lambda self: self.context.yearRange)
+
+    def __init__(self, field, request):
+        self.context = field
+        self.request = request
+        if self.context.initialDate:
+            self.initialDate = self.context.initialDate 
+        else:
+            self.initialDate = datetime.date.today()
+        value = field.query(field.context, default=self.initialDate)
+        if value is None:
+            # can't be None, set given start date, which is a valid value
+            value = self.initialDate
+
+        self.name = self._prefix + field.__name__
+
+        adapters = {}
+        adapters[IDateSelectData] = DateSelectDataForDateSelectWidget(self, 
+            value)
+        self.widgets = form.setUpEditWidgets(form.FormFields(IDateSelectData), 
+            self.name, value, request, adapters=adapters)
+
+    def setRenderedValue(self, value):
+        """See zope.app.form.interfaces.IWidget"""
+        if isinstance(value, datetime.date):
+            self.widgets['year'].setRenderedValue(value.year)
+            self.widgets['month'].setRenderedValue(value.month)
+            self.widgets['day'].setRenderedValue(value.day)
+
+
+    def setPrefix(self, prefix):
+        """See zope.app.form.interfaces.IWidget"""
+        # Set the prefix locally
+        if not prefix.endswith("."):
+            prefix += '.'
+        self._prefix = prefix
+        self.name = prefix + self.context.__name__
+        # Now distribute it to the sub-widgets
+        for widget in [self.widgets[name]
+                       for name in ['year', 'month', 'day']]:
+            widget.setPrefix(self.name+'.')
+
+
+    def getInputValue(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        self._error = None
+        year = self.widgets['year'].getInputValue()
+        month = self.widgets['month'].getInputValue()
+        day = self.widgets['day'].getInputValue()
+        try:
+            return datetime.date(year, month, day)
+        except ValueError, v:
+            self._error = WidgetInputError(
+                self.context.__name__, self.label, _(v))
+            raise self._error
+
+    def applyChanges(self, content):
+        """See zope.app.form.interfaces.IInputWidget"""
+        field = self.context
+        new_value = self.getInputValue()
+        old_value = field.query(content, self)
+        # The selection has not changed
+        if new_value == old_value:
+            return False
+        field.set(content, new_value)
+        return True
+
+
+    def hasInput(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        return (self.widgets['year'].hasInput() and
+                (self.widgets['month'].hasInput() and
+                 self.widgets['day'].hasInput()))
+
+
+    def hasValidInput(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        return (self.widgets['year'].hasValidInput() and
+            self.widgets['month'].hasValidInput() and
+            self.widgets['day'].hasValidInput())
+
+
+    def hidden(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        output = []
+        output.append(self.widgets['year'].hidden())
+        output.append(self.widgets['month'].hidden())
+        output.append(self.widgets['day'].hidden())
+        return '\n'.join(output)
+
+
+    def error(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        if self._error:
+            return getMultiAdapter((self._error, self.request),
+                                        IWidgetInputErrorView).snippet()
+        year_error = self.widgets['year'].error()
+        if year_error:
+            return year_error
+        month_error = self.widgets['month'].error()
+        if month_error:
+            return month_error
+        day_error = self.widgets['day'].error()
+        if day_error:
+            return day_error
+        return ""
+
+    def __call__(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        return self.template()


Property changes on: z3c.widget/trunk/src/z3c/widget/dateselect/browser.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/dateselect/configure.zcml
===================================================================
--- z3c.widget/trunk/src/z3c/widget/dateselect/configure.zcml	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/dateselect/configure.zcml	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,13 @@
+<configure
+    xmlns="http://namespaces.zope.org/zope">
+
+  <!-- Date widget -->
+  <view
+      type="z3c.layer.minimal.IMinimalBrowserLayer"
+      for="z3c.schema.dateselect.IDateSelect"
+      provides="zope.app.form.interfaces.IInputWidget"
+      factory=".browser.DateSelectWidget"
+      permission="zope.Public"
+      />
+
+</configure>


Property changes on: z3c.widget/trunk/src/z3c/widget/dateselect/configure.zcml
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.widget/trunk/src/z3c/widget/dateselect/testing.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/dateselect/testing.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/dateselect/testing.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,41 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.schema.interfaces import IChoice, IDate, IIterableVocabulary
+from zope.app.form.interfaces import IInputWidget, IWidgetInputError
+from zope.app.form.browser import DateWidget, ChoiceInputWidget
+from zope.app.form.browser.interfaces import IWidgetInputErrorView
+from zope.app.form.browser.exception import WidgetInputErrorView
+from zope.app.testing import setup, ztapi
+
+from z3c.widget.dateselect.browser import DropdownWidget
+
+def setUp(test):
+    setup.placefulSetUp()
+    ztapi.browserViewProviding(IChoice, ChoiceInputWidget, IInputWidget)
+    ztapi.browserViewProviding(IDate, DateWidget, IInputWidget)
+    ztapi.provideMultiView((IChoice, IIterableVocabulary), IBrowserRequest,
+                           IInputWidget, '', DropdownWidget)
+    # errors in forms
+    ztapi.browserViewProviding(IWidgetInputError, WidgetInputErrorView,
+                               IWidgetInputErrorView)
+
+
+def tearDown(test):
+    setup.placefulTearDown()


Property changes on: z3c.widget/trunk/src/z3c/widget/dateselect/testing.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/dateselect/tests.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/dateselect/tests.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/dateselect/tests.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import doctest
+import unittest
+import zope.schema
+from zope.testing.doctestunit import DocFileSuite
+
+from z3c.widget.dateselect import testing
+
+
+def test_suite():
+    return unittest.TestSuite((
+        DocFileSuite('README.txt',
+                     setUp=testing.setUp, tearDown=testing.tearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
+        ))
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: z3c.widget/trunk/src/z3c/widget/dateselect/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/dateselect/widget-date.pt
===================================================================
--- z3c.widget/trunk/src/z3c/widget/dateselect/widget-date.pt	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/dateselect/widget-date.pt	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,3 @@
+<span tal:replace="structure view/widgets/day" />&nbsp;
+<span tal:replace="structure view/widgets/month" />&nbsp;
+<span tal:replace="structure view/widgets/year" />


Property changes on: z3c.widget/trunk/src/z3c/widget/dateselect/widget-date.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.widget/trunk/src/z3c/widget/ssn/README.txt
===================================================================
--- z3c.widget/trunk/src/z3c/widget/ssn/README.txt	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/ssn/README.txt	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,339 @@
+==========
+SSN Widget
+==========
+
+The social security number widget can be used as a custom widget for text line
+fields, enforcing a particular layout.
+
+First we have to create a field and a request:
+
+  >>> import datetime
+  >>> import zope.schema
+
+  >>> field = zope.schema.TextLine(
+  ...     title=u'SSN',
+  ...     description=u'Social Security Number',
+  ...     required=True)
+  >>> field.__name__ = 'field'
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+
+Now we can initialize widget.
+
+  >>> from z3c.widget.ssn.browser import SSNWidget
+  >>> widget = SSNWidget(field, request)
+
+Let's make sure that all fields have the correct value:
+
+  >>> widget.name
+  'field.field'
+
+  >>> widget.label
+  u'SSN'
+
+  >>> widget.hint
+  u'Social Security Number'
+
+  >>> widget.visible
+  True
+
+  >>> widget.required
+  True
+
+The constructor should have also created 3 sub-widgets:
+
+  >>> widget.widgets['first']
+  <zope.app.form.browser.textwidgets.TextWidget object at ...>
+  >>> widget.widgets['second']
+  <zope.app.form.browser.textwidgets.TextWidget object at ...>
+  >>> widget.widgets['third']
+  <zope.app.form.browser.textwidgets.TextWidget object at ...>
+
+
+``setRenderedValue(value)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The first method is ``setRenderedValue()``. The widget has two use cases,
+based on the type of value:
+
+  >>> widget = SSNWidget(field, request)
+  >>> widget.setRenderedValue(u'123-45-6789')
+  >>> print widget()
+  <input class="textType" id="field.field.first" name="field.field.first"
+         size="3" type="text" value="123"  />&nbsp;&mdash;&nbsp;
+  <input class="textType" id="field.field.second" name="field.field.second"
+         size="2" type="text" value="45"  />&nbsp;&mdash;&nbsp;
+  <input class="textType" id="field.field.third" name="field.field.third"
+         size="4" type="text" value="6789"  />
+
+
+``setPrefix(prefix)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The prefix determines the name of the widget and all its sub-widgets.
+
+  >>> widget.name
+  'field.field'
+  >>> widget.widgets['first'].name
+  'field.field.first'
+  >>> widget.widgets['second'].name
+  'field.field.second'
+  >>> widget.widgets['third'].name
+  'field.field.third'
+
+  >>> widget.setPrefix('test.')
+
+  >>> widget.name
+  'test.field'
+  >>> widget.widgets['first'].name
+  'test.field.first'
+  >>> widget.widgets['second'].name
+  'test.field.second'
+  >>> widget.widgets['third'].name
+  'test.field.third'
+
+If the prefix does not end in a dot, one is added:
+
+  >>> widget.setPrefix('test')
+
+  >>> widget.name
+  'test.field'
+  >>> widget.widgets['first'].name
+  'test.field.first'
+  >>> widget.widgets['second'].name
+  'test.field.second'
+  >>> widget.widgets['third'].name
+  'test.field.third'
+
+
+``getInputValue()`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method returns the full SSN string:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '6789'})
+
+  >>> widget = SSNWidget(field, request)
+
+  >>> value = widget.getInputValue()
+  >>> value
+  u'123-45-6789'
+
+If a set of values does not produce a valid string, a value error is
+raised:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '1234',
+  ...     'field.field.second': '56',
+  ...     'field.field.third': '7890'})
+
+  >>> widget = SSNWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('first', u'Frst three digits', 1234)
+
+  >>> widget._error
+  <zope.app.form.interfaces.WidgetInputError ...>
+
+
+``applyChanges(content)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method applies the new SSN to the passed content. However, it
+must be smart enough to detect whether the values really changed.
+
+  >>> class Content(object):
+  ...     field = None
+  >>> content = Content()
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '6789'})
+
+  >>> widget = SSNWidget(field, request)
+  >>> widget.applyChanges(content)
+  True
+  >>> content.field
+  u'123-45-6789'
+
+  >>> widget.applyChanges(content)
+  False
+
+
+``hasInput()`` Method
+~~~~~~~~~~~~~~~~~~~~~
+
+This method checks for any input, but does not validate it.
+
+  >>> request = TestRequest()
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.second': '45'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasInput()
+  True
+
+
+``hasValidInput()`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Additionally to checking for any input, this method also checks whether the
+input is valid:
+
+  >>> request = TestRequest()
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.second': '45'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.hasValidInput()
+  True
+
+
+``hidden()`` Method
+~~~~~~~~~~~~~~~~~~~
+
+This method is renders the output as hidden fields:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> print widget.hidden()
+  <input class="hiddenType" id="field.field.first" name="field.field.first"
+         type="hidden" value="123" />
+  <input class="hiddenType" id="field.field.second" name="field.field.second"
+         type="hidden" value="45"  />
+  <input class="hiddenType" id="field.field.third" name="field.field.third"
+         type="hidden" value="6789"  />
+
+
+``error()`` Method
+~~~~~~~~~~~~~~~~~~
+
+Let's test some bad data and check the error handling.
+
+The third field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '678'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('third', u'Third four digits', 678)
+  >>> print widget.error()
+  <span class="error">Constraint not satisfied</span>
+
+The second field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '4-',
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('second', u'Second two digits', 4-)
+  >>> print widget.error()
+  <span class="error">Constraint not satisfied</span>
+
+The first field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': 'xxx',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('first', u'Frst three digits', xxx)
+  >>> print widget.error()
+  <span class="error">Constraint not satisfied</span>
+
+No error occurred:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> widget.getInputValue()
+  u'123-45-6789'
+  >>> widget.error()
+  ''
+
+
+``__call__()`` Method
+~~~~~~~~~~~~~~~~~~~~~
+
+This method renders the widget using the sub-widgets. Let's see the output:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45',
+  ...     'field.field.third': '6789'})
+  >>> widget = SSNWidget(field, request)
+  >>> print widget()
+  <input class="textType" id="field.field.first" name="field.field.first"
+         size="3" type="text" value="123"  />&nbsp;&mdash;&nbsp;
+  <input class="textType" id="field.field.second" name="field.field.second"
+         size="2" type="text" value="45"  />&nbsp;&mdash;&nbsp;
+  <input class="textType" id="field.field.third" name="field.field.third"
+         size="4" type="text" value="6789"  />


Property changes on: z3c.widget/trunk/src/z3c/widget/ssn/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.widget/trunk/src/z3c/widget/ssn/__init__.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/ssn/__init__.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/ssn/__init__.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1 @@
+# Make a package


Property changes on: z3c.widget/trunk/src/z3c/widget/ssn/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/ssn/browser.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/ssn/browser.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/ssn/browser.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,205 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = 'reStructuredText'
+
+import datetime
+import re
+import zope.interface
+import zope.schema
+from zope.formlib import form
+from zope.app.form.interfaces import IInputWidget
+from zope.app.form.interfaces import WidgetInputError
+from zope.app.form.browser.interfaces import IBrowserWidget
+from zope.app.form import browser
+from zope.app.pagetemplate import ViewPageTemplateFile
+from zope.app.zapi import getMultiAdapter
+from zope.app.form.browser.interfaces import IWidgetInputErrorView
+
+from z3c.i18n import MessageFactory as _
+
+
+class ISSNData(zope.interface.Interface):
+    """A schema used to generate a SSN widget."""
+
+    first = zope.schema.TextLine(
+        title=_('Frst three digits'),
+        description=_('The first three digits of the SSN.'),
+        min_length=3,
+        max_length=3,
+        constraint=re.compile(r'^[0-9]{3}$').search,
+        required=True)
+
+    second = zope.schema.TextLine(
+        title=_('Second two digits'),
+        description=_('The second two digits of the SSN.'),
+        min_length=2,
+        max_length=2,
+        constraint=re.compile(r'^[0-9]{2}$').search,
+        required=True)
+
+    third = zope.schema.TextLine(
+        title=_('Third four digits'),
+        description=_('The third four digits of the SSN.'),
+        min_length=4,
+        max_length=4,
+        constraint=re.compile(r'^[0-9]{4}$').search,
+        required=True)
+
+
+class SSNWidgetData(object):
+    """Social Security Number Data"""
+    zope.interface.implements(ISSNData)
+
+    first = None
+    second = None
+    third = None
+
+    def __init__(self, context, number=None):
+        self.context = context
+        if number:
+            self.first, self.second, self.third = number.split('-')
+
+    @property
+    def number(self):
+        return u'-'.join((self.first, self.second, self.third))
+
+
+class SSNWidget(object):
+    """Social Security Number Widget"""
+    zope.interface.implements(IBrowserWidget, IInputWidget)
+
+    template = ViewPageTemplateFile('widget-ssn.pt')
+    _prefix = 'field.'
+    _error = None
+    widgets = {}
+
+    # See zope.app.form.interfaces.IWidget
+    name = None
+    label = property(lambda self: self.context.title)
+    hint = property(lambda self: self.context.description)
+    visible = True
+    # See zope.app.form.interfaces.IInputWidget
+    required = property(lambda self: self.context.required)
+
+    def __init__(self, field, request):
+        self.context = field
+        self.request = request
+        self.name = self._prefix + field.__name__
+
+        value = field.query(field.context)
+        adapters = {}
+        adapters[ISSNData] = SSNWidgetData(self, value)
+        self.widgets = form.setUpEditWidgets(
+            form.FormFields(ISSNData),
+            self.name, value, request, adapters=adapters)
+        self.widgets['first'].displayWidth = 3
+        self.widgets['second'].displayWidth = 2
+        self.widgets['third'].displayWidth = 4
+
+    def setRenderedValue(self, value):
+        """See zope.app.form.interfaces.IWidget"""
+        if isinstance(value, unicode):
+            first, second, third = value.split('-')
+            self.widgets['first'].setRenderedValue(first)
+            self.widgets['second'].setRenderedValue(second)
+            self.widgets['third'].setRenderedValue(third)
+
+
+    def setPrefix(self, prefix):
+        """See zope.app.form.interfaces.IWidget"""
+        # Set the prefix locally
+        if not prefix.endswith("."):
+            prefix += '.'
+        self._prefix = prefix
+        self.name = prefix + self.context.__name__
+        # Now distribute it to the sub-widgets
+        for widget in [
+                self.widgets[name] for name in ['first', 'second', 'third']]:
+            widget.setPrefix(self.name+'.')
+
+
+    def getInputValue(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        self._error = None
+        try:
+            return u'-'.join((
+                self.widgets['first'].getInputValue(),
+                self.widgets['second'].getInputValue(),
+                self.widgets['third'].getInputValue() ))
+        except ValueError, v:
+            self._error = WidgetInputError(
+                self.context.__name__, self.label, _(v))
+            raise self._error
+        except WidgetInputError, e:
+            self._error = e
+            raise e
+
+
+    def applyChanges(self, content):
+        """See zope.app.form.interfaces.IInputWidget"""
+        field = self.context
+        new_value = self.getInputValue()
+        old_value = field.query(content, self)
+        # The selection has not changed
+        if new_value == old_value:
+            return False
+        field.set(content, new_value)
+        return True
+
+
+    def hasInput(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        return (self.widgets['first'].hasInput() and
+                (self.widgets['second'].hasInput() and
+                 self.widgets['third'].hasInput()))
+
+
+    def hasValidInput(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        return (self.widgets['first'].hasValidInput() and
+            self.widgets['second'].hasValidInput() and
+            self.widgets['third'].hasValidInput())
+
+
+    def hidden(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        output = []
+        output.append(self.widgets['first'].hidden())
+        output.append(self.widgets['second'].hidden())
+        output.append(self.widgets['third'].hidden())
+        return '\n'.join(output)
+
+
+    def error(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        if self._error:
+            return getMultiAdapter((self._error, self.request),
+                                        IWidgetInputErrorView).snippet()
+        first_error = self.widgets['first'].error()
+        if first_error:
+            return first_error
+        second_error = self.widgets['second'].error()
+        if second_error:
+            return second_error
+        third_error = self.widgets['third'].error()
+        if third_error:
+            return third_error
+        return ""
+
+    def __call__(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        return self.template()


Property changes on: z3c.widget/trunk/src/z3c/widget/ssn/browser.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/ssn/testing.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/ssn/testing.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/ssn/testing.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,36 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.schema.interfaces import ITextLine
+from zope.app.form.interfaces import IInputWidget, IWidgetInputError
+from zope.app.form.browser import TextWidget
+from zope.app.form.browser.interfaces import IWidgetInputErrorView
+from zope.app.form.browser.exception import WidgetInputErrorView
+from zope.app.testing import setup, ztapi
+
+def setUp(test):
+    setup.placefulSetUp()
+    ztapi.browserViewProviding(ITextLine, TextWidget, IInputWidget)
+    # errors in forms
+    ztapi.browserViewProviding(IWidgetInputError, WidgetInputErrorView,
+                               IWidgetInputErrorView)
+
+
+def tearDown(test):
+    setup.placefulTearDown()


Property changes on: z3c.widget/trunk/src/z3c/widget/ssn/testing.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/ssn/tests.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/ssn/tests.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/ssn/tests.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import doctest
+import unittest
+import zope.schema
+from zope.testing.doctestunit import DocFileSuite
+
+from z3c.widget.ssn import testing
+
+
+def test_suite():
+    return unittest.TestSuite((
+        DocFileSuite('README.txt',
+                     setUp=testing.setUp, tearDown=testing.tearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
+        ))
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: z3c.widget/trunk/src/z3c/widget/ssn/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/ssn/widget-ssn.pt
===================================================================
--- z3c.widget/trunk/src/z3c/widget/ssn/widget-ssn.pt	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/ssn/widget-ssn.pt	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,3 @@
+<span tal:replace="structure view/widgets/first" />&nbsp;&mdash;&nbsp;
+<span tal:replace="structure view/widgets/second" />&nbsp;&mdash;&nbsp;
+<span tal:replace="structure view/widgets/third" />


Property changes on: z3c.widget/trunk/src/z3c/widget/ssn/widget-ssn.pt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.widget/trunk/src/z3c/widget/usphone/README.txt
===================================================================
--- z3c.widget/trunk/src/z3c/widget/usphone/README.txt	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/usphone/README.txt	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,342 @@
+===============
+US Phone Widget
+===============
+
+The US phone number widget can be used as a custom widget for text line
+fields, enforcing a particular layout.
+
+First we have to create a field and a request:
+
+  >>> import datetime
+  >>> import zope.schema
+
+  >>> field = zope.schema.TextLine(
+  ...     title=u'Phone',
+  ...     description=u'Phone Number',
+  ...     required=True)
+  >>> field.__name__ = 'field'
+
+  >>> from zope.publisher.browser import TestRequest
+  >>> request = TestRequest()
+
+Now we can initialize widget.
+
+  >>> from z3c.widget.usphone.browser import PhoneWidget
+  >>> widget = PhoneWidget(field, request)
+
+Let's make sure that all fields have the correct value:
+
+  >>> widget.name
+  'field.field'
+
+  >>> widget.label
+  u'Phone'
+
+  >>> widget.hint
+  u'Phone Number'
+
+  >>> widget.visible
+  True
+
+  >>> widget.required
+  True
+
+The constructor should have also created 3 sub-widgets:
+
+  >>> widget.widgets['first']
+  <zope.app.form.browser.textwidgets.TextWidget object at ...>
+  >>> widget.widgets['second']
+  <zope.app.form.browser.textwidgets.TextWidget object at ...>
+  >>> widget.widgets['third']
+  <zope.app.form.browser.textwidgets.TextWidget object at ...>
+
+
+``setRenderedValue(value)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The first method is ``setRenderedValue()``. The widget has two use cases,
+based on the type of value:
+
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.setRenderedValue(u'123-456-7890')
+  >>> print widget()
+  (<input class="textType" id="field.field.first" name="field.field.first"
+          size="3" type="text" value="123"  />)&nbsp;
+  <input class="textType" id="field.field.second" name="field.field.second"
+         size="3" type="text" value="456"  />&nbsp;&mdash;&nbsp;
+  <input class="textType" id="field.field.third" name="field.field.third"
+         size="4" type="text" value="7890"  />
+
+
+``setPrefix(prefix)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The prefix determines the name of the widget and all its sub-widgets.
+
+  >>> widget.name
+  'field.field'
+  >>> widget.widgets['first'].name
+  'field.field.first'
+  >>> widget.widgets['second'].name
+  'field.field.second'
+  >>> widget.widgets['third'].name
+  'field.field.third'
+
+  >>> widget.setPrefix('test.')
+
+  >>> widget.name
+  'test.field'
+  >>> widget.widgets['first'].name
+  'test.field.first'
+  >>> widget.widgets['second'].name
+  'test.field.second'
+  >>> widget.widgets['third'].name
+  'test.field.third'
+
+If the prefix does not end in a dot, one is added:
+
+  >>> widget.setPrefix('test')
+
+  >>> widget.name
+  'test.field'
+  >>> widget.widgets['first'].name
+  'test.field.first'
+  >>> widget.widgets['second'].name
+  'test.field.second'
+  >>> widget.widgets['third'].name
+  'test.field.third'
+
+
+``getInputValue()`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method returns the full phone string:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '7890'})
+
+  >>> widget = PhoneWidget(field, request)
+
+  >>> value = widget.getInputValue()
+  >>> value
+  u'123-456-7890'
+
+If a set of values does not produce a valid string, a value error is
+raised:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '1234',
+  ...     'field.field.second': '56',
+  ...     'field.field.third': '7890'})
+
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('first', u'Area Code', 1234)
+
+  >>> widget._error
+  <zope.app.form.interfaces.WidgetInputError ...>
+
+
+``applyChanges(content)`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This method applies the new phone number to the passed content. However, it
+must be smart enough to detect whether the values really changed.
+
+  >>> class Content(object):
+  ...     field = None
+  >>> content = Content()
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '7890'})
+
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.applyChanges(content)
+  True
+  >>> content.field
+  u'123-456-7890'
+
+  >>> widget.applyChanges(content)
+  False
+
+
+``hasInput()`` Method
+~~~~~~~~~~~~~~~~~~~~~
+
+This method checks for any input, but does not validate it.
+
+  >>> request = TestRequest()
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.second': '456'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasInput()
+  True
+
+
+``hasValidInput()`` Method
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Additionally to checking for any input, this method also checks whether the
+input is valid:
+
+  >>> request = TestRequest()
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.second': '456'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasValidInput()
+  False
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.hasValidInput()
+  True
+
+
+``hidden()`` Method
+~~~~~~~~~~~~~~~~~~~
+
+This method is renders the output as hidden fields:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> print widget.hidden()
+  <input class="hiddenType" id="field.field.first" name="field.field.first"
+         type="hidden" value="123" />
+  <input class="hiddenType" id="field.field.second" name="field.field.second"
+         type="hidden" value="456"  />
+  <input class="hiddenType" id="field.field.third" name="field.field.third"
+         type="hidden" value="7890"  />
+
+
+``error()`` Method
+~~~~~~~~~~~~~~~~~~
+
+Let's test some bad data and check the error handling.
+
+The third field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '78901'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('third', u'Four Digits', 78901)
+
+  >>> print widget.error()
+  <span class="error">Constraint not satisfied</span>
+
+The second field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '45-',
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('second', u'Three Digits', 45-)
+
+  >>> print widget.error()
+  <span class="error">Constraint not satisfied</span>
+
+The first field contains an invalid value:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': 'xxx',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.getInputValue()
+  Traceback (most recent call last):
+  ...
+  WidgetInputError: ('first', u'Area Code', xxx)
+
+  >>> print widget.error()
+  <span class="error">Constraint not satisfied</span>
+
+No error occurred:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> widget.getInputValue()
+  u'123-456-7890'
+  >>> widget.error()
+  ''
+
+
+``__call__()`` Method
+~~~~~~~~~~~~~~~~~~~~~
+
+This method renders the widget using the sub-widgets. Let's see the output:
+
+  >>> request = TestRequest(form={
+  ...     'field.field.first': '123',
+  ...     'field.field.second': '456',
+  ...     'field.field.third': '7890'})
+  >>> widget = PhoneWidget(field, request)
+  >>> print widget()
+  (<input class="textType" id="field.field.first" name="field.field.first"
+          size="3" type="text" value="123"  />)&nbsp;
+  <input class="textType" id="field.field.second" name="field.field.second"
+         size="3" type="text" value="456"  />&nbsp;&mdash;&nbsp;
+  <input class="textType" id="field.field.third" name="field.field.third"
+         size="4" type="text" value="7890"  />


Property changes on: z3c.widget/trunk/src/z3c/widget/usphone/README.txt
___________________________________________________________________
Name: svn:eol-style
   + native

Added: z3c.widget/trunk/src/z3c/widget/usphone/__init__.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/usphone/__init__.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/usphone/__init__.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1 @@
+# Make a package


Property changes on: z3c.widget/trunk/src/z3c/widget/usphone/__init__.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/usphone/browser.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/usphone/browser.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/usphone/browser.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,205 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = 'reStructuredText'
+
+import datetime
+import re
+import zope.interface
+import zope.schema
+from zope.formlib import form
+from zope.app.form.interfaces import IInputWidget
+from zope.app.form.interfaces import WidgetInputError
+from zope.app.form.browser.interfaces import IBrowserWidget
+from zope.app.form import browser
+from zope.app.pagetemplate import ViewPageTemplateFile
+from zope.app.zapi import getMultiAdapter
+from zope.app.form.browser.interfaces import IWidgetInputErrorView
+
+from z3c.i18n import MessageFactory as _
+
+
+class IPhoneData(zope.interface.Interface):
+    """A schema used to generate a Phone widget."""
+
+    first = zope.schema.TextLine(
+        title=_('Area Code'),
+        description=_('The area code of the phone number.'),
+        min_length=3,
+        max_length=3,
+        constraint=re.compile(r'^[0-9]{3}$').search,
+        required=True)
+
+    second = zope.schema.TextLine(
+        title=_('Three Digits'),
+        description=_('The first three digits of the phone number.'),
+        min_length=3,
+        max_length=3,
+        constraint=re.compile(r'^[0-9]{3}$').search,
+        required=True)
+
+    third = zope.schema.TextLine(
+        title=_('Four Digits'),
+        description=_('The second four digits of the phone number.'),
+        min_length=4,
+        max_length=4,
+        constraint=re.compile(r'^[0-9]{4}$').search,
+        required=True)
+
+
+class PhoneWidgetData(object):
+    """Social Security Number Data"""
+    zope.interface.implements(IPhoneData)
+
+    first = None
+    second = None
+    third = None
+
+    def __init__(self, context, number=None):
+        self.context = context
+        if number:
+            self.first, self.second, self.third = number.split('-')
+
+    @property
+    def number(self):
+        return u'-'.join((self.first, self.second, self.third))
+
+
+class PhoneWidget(object):
+    """Social Security Number Widget"""
+    zope.interface.implements(IBrowserWidget, IInputWidget)
+
+    template = ViewPageTemplateFile('widget-phone.pt')
+    _prefix = 'field.'
+    _error = None
+    widgets = {}
+
+    # See zope.app.form.interfaces.IWidget
+    name = None
+    label = property(lambda self: self.context.title)
+    hint = property(lambda self: self.context.description)
+    visible = True
+    # See zope.app.form.interfaces.IInputWidget
+    required = property(lambda self: self.context.required)
+
+    def __init__(self, field, request):
+        self.context = field
+        self.request = request
+        self.name = self._prefix + field.__name__
+
+        value = field.query(field.context)
+        adapters = {}
+        adapters[IPhoneData] = PhoneWidgetData(self, value)
+        self.widgets = form.setUpEditWidgets(
+            form.FormFields(IPhoneData),
+            self.name, value, request, adapters=adapters)
+        self.widgets['first'].displayWidth = 3
+        self.widgets['second'].displayWidth = 3
+        self.widgets['third'].displayWidth = 4
+
+    def setRenderedValue(self, value):
+        """See zope.app.form.interfaces.IWidget"""
+        if isinstance(value, unicode):
+            first, second, third = value.split('-')
+            self.widgets['first'].setRenderedValue(first)
+            self.widgets['second'].setRenderedValue(second)
+            self.widgets['third'].setRenderedValue(third)
+
+
+    def setPrefix(self, prefix):
+        """See zope.app.form.interfaces.IWidget"""
+        # Set the prefix locally
+        if not prefix.endswith("."):
+            prefix += '.'
+        self._prefix = prefix
+        self.name = prefix + self.context.__name__
+        # Now distribute it to the sub-widgets
+        for widget in [
+                self.widgets[name] for name in ['first', 'second', 'third']]:
+            widget.setPrefix(self.name+'.')
+
+
+    def getInputValue(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        self._error = None
+        try:
+            return u'-'.join((
+                self.widgets['first'].getInputValue(),
+                self.widgets['second'].getInputValue(),
+                self.widgets['third'].getInputValue() ))
+        except ValueError, v:
+            self._error = WidgetInputError(
+                self.context.__name__, self.label, _(v))
+            raise self._error
+        except WidgetInputError, e:
+            self._error = e
+            raise e
+
+
+    def applyChanges(self, content):
+        """See zope.app.form.interfaces.IInputWidget"""
+        field = self.context
+        new_value = self.getInputValue()
+        old_value = field.query(content, self)
+        # The selection has not changed
+        if new_value == old_value:
+            return False
+        field.set(content, new_value)
+        return True
+
+
+    def hasInput(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        return (self.widgets['first'].hasInput() and
+                (self.widgets['second'].hasInput() and
+                 self.widgets['third'].hasInput()))
+
+
+    def hasValidInput(self):
+        """See zope.app.form.interfaces.IInputWidget"""
+        return (self.widgets['first'].hasValidInput() and
+            self.widgets['second'].hasValidInput() and
+            self.widgets['third'].hasValidInput())
+
+
+    def hidden(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        output = []
+        output.append(self.widgets['first'].hidden())
+        output.append(self.widgets['second'].hidden())
+        output.append(self.widgets['third'].hidden())
+        return '\n'.join(output)
+
+
+    def error(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        if self._error:
+            return getMultiAdapter((self._error, self.request),
+                                        IWidgetInputErrorView).snippet()
+        first_error = self.widgets['first'].error()
+        if first_error:
+            return first_error
+        second_error = self.widgets['second'].error()
+        if second_error:
+            return second_error
+        third_error = self.widgets['third'].error()
+        if third_error:
+            return third_error
+        return ""
+
+    def __call__(self):
+        """See zope.app.form.browser.interfaces.IBrowserWidget"""
+        return self.template()


Property changes on: z3c.widget/trunk/src/z3c/widget/usphone/browser.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/usphone/testing.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/usphone/testing.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/usphone/testing.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,36 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = 'restructuredtext'
+
+from zope.publisher.interfaces.browser import IBrowserRequest
+from zope.schema.interfaces import ITextLine
+from zope.app.form.interfaces import IInputWidget, IWidgetInputError
+from zope.app.form.browser import TextWidget
+from zope.app.form.browser.interfaces import IWidgetInputErrorView
+from zope.app.form.browser.exception import WidgetInputErrorView
+from zope.app.testing import setup, ztapi
+
+def setUp(test):
+    setup.placefulSetUp()
+    ztapi.browserViewProviding(ITextLine, TextWidget, IInputWidget)
+    # errors in forms
+    ztapi.browserViewProviding(IWidgetInputError, WidgetInputErrorView,
+                               IWidgetInputErrorView)
+
+
+def tearDown(test):
+    setup.placefulTearDown()


Property changes on: z3c.widget/trunk/src/z3c/widget/usphone/testing.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/usphone/tests.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/usphone/tests.py	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/usphone/tests.py	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,37 @@
+##############################################################################
+#
+# Copyright (c) 2006 Zope Foundation and Contributors.
+# All Rights Reserved.
+#
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
+# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
+# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
+# FOR A PARTICULAR PURPOSE.
+#
+##############################################################################
+"""
+$Id$
+"""
+__docformat__ = "reStructuredText"
+
+import doctest
+import unittest
+import zope.schema
+from zope.testing.doctestunit import DocFileSuite
+
+from z3c.widget.usphone import testing
+
+
+def test_suite():
+    return unittest.TestSuite((
+        DocFileSuite('README.txt',
+                     setUp=testing.setUp, tearDown=testing.tearDown,
+                     optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS,
+                     ),
+        ))
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='test_suite')


Property changes on: z3c.widget/trunk/src/z3c/widget/usphone/tests.py
___________________________________________________________________
Name: svn:keywords
   + Id

Added: z3c.widget/trunk/src/z3c/widget/usphone/widget-phone.pt
===================================================================
--- z3c.widget/trunk/src/z3c/widget/usphone/widget-phone.pt	                        (rev 0)
+++ z3c.widget/trunk/src/z3c/widget/usphone/widget-phone.pt	2007-09-21 13:05:43 UTC (rev 79795)
@@ -0,0 +1,3 @@
+(<span tal:replace="structure view/widgets/first" />)&nbsp;
+<span tal:replace="structure view/widgets/second" />&nbsp;&mdash;&nbsp;
+<span tal:replace="structure view/widgets/third" />


Property changes on: z3c.widget/trunk/src/z3c/widget/usphone/widget-phone.pt
___________________________________________________________________
Name: svn:eol-style
   + native



More information about the Checkins mailing list