[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" />
+ <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" />
+ <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" />
+<span tal:replace="structure view/widgets/month" />
+<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" /> —
+ <input class="textType" id="field.field.second" name="field.field.second"
+ size="2" type="text" value="45" /> —
+ <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" /> —
+ <input class="textType" id="field.field.second" name="field.field.second"
+ size="2" type="text" value="45" /> —
+ <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" /> —
+<span tal:replace="structure view/widgets/second" /> —
+<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" />)
+ <input class="textType" id="field.field.second" name="field.field.second"
+ size="3" type="text" value="456" /> —
+ <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" />)
+ <input class="textType" id="field.field.second" name="field.field.second"
+ size="3" type="text" value="456" /> —
+ <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" />)
+<span tal:replace="structure view/widgets/second" /> —
+<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