Additional zope.formlib Widgets
Project description
Changes for z3c.widget
0.3.0 (2010-11-16)
Added translation for french.
Updated tests to run with zope.formlib 4.0 and zope.schema 3.6.
Using Python’s doctest module instead of depreacted zope.testing.doctest[unit].
Added doctests to long_description to be visible on PyPI.
2008/01/29 0.2.1
add translation for hungarian and romanian languages
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 translation for english to get i18n working in some browsers
2007/09/19 0.1.6
added cheesehop classification, registered there
fixed typos
2007/09/05 0.1.5
bugfix: browse butten will now be enabled after cancel was clicked in the open file dialog
do not set the progessbar to 100% before the upload was started
bugfix: files will not be uploaded if no limit was set
2007/09/05 0.1.4
dealing file size during upload. If one or more files are bigger than the passed size each one of them will be ignored during upload but listed below the progress bar after the upload of the working files is done.
displaying the maximal allowed file size (if it’s contained in the config file)
2007/09/03 0.1.3
bugfix: too much quoting.
2007/09/03 0.1.2
using passed config url instead of hard coded flashuploadvars.xml
2007/08/06 0.1.1
flashupload: better skinnability for upload.swf. cleanup folder structure for flash stuff.
2007/06/14 0.1.0:
z3c.widget.image: added translations for es
update to newest bootstrap.py version
Autocomplete Widgets
Autocomplete widgets are an alternative to normal select widgets.
>>> from z3c.widget.autocomplete.widget import AutoCompleteWidget
Let us create a vocabulary.
>>> from zope.schema.vocabulary import SimpleVocabulary >>> from zope.publisher.browser import TestRequest >>> from zope import schema, component, interface >>> items = ((u'value1',1,u'Title1'), ... (u'value2',2,u'Title2'), ... (u'value3',3,u'Title3')) >>> terms = map(lambda i: SimpleVocabulary.createTerm(*i),items) >>> voc = SimpleVocabulary(terms) >>> [term.title for term in voc] [u'Title1', u'Title2', u'Title3'] >>> field = schema.Choice(__name__='foo', ... missing_value=None, ... vocabulary=voc) >>> request = TestRequest() >>> widget = AutoCompleteWidget(field, request) >>> widget <z3c.widget.autocomplete.widget.AutoCompleteWidget object at ...> >>> print widget() <input class="textType" id="field.foo" name="field.foo" type="text" value="" /> <div id="field.foo.target" class="autoComplete"></div> <script type="text/javascript"> new Ajax.Autocompleter('field.foo','field.foo.target', 'http://127.0.0.1/++widget++field.foo/suggestions' ,options={ paramName: 'value' }); </script>
Let’s add some input. Note that the input must match the title of the vocabulary term.
>>> request.form['field.foo']=u'Title1' >>> widget.getInputValue() u'value1'
If we have no matching title a ConversionError is raised.
>>> request.form['field.foo']=u'Unknown' >>> widget.getInputValue() Traceback (most recent call last): ... ConversionError: ('Invalid value', u'Unknown')
Also the form value is the title of the term with the given value.
>>> widget._toFormValue('value1') u'Title1'>>> suggestions = widget.getSuggestions('Title') >>> [title for title in suggestions] [u'Title1', u'Title2', u'Title3'] >>> suggestions = widget.getSuggestions('Title1') >>> [title for title in suggestions] [u'Title1'] >>> suggestions = widget.getSuggestions('ABC') >>> [title for title in suggestions] [] >>> suggestions = widget.getSuggestions('title') >>> [title for title in suggestions] [u'Title1', u'Title2', u'Title3']
AutoCompleteWidget Demo
This demo packe provides a simple content class which uses the z3c autocomplete widget.
>>> from zope.testbrowser.testing import Browser >>> browser = Browser() >>> browser.handleErrors = False >>> browser.addHeader('Authorization', 'Basic mgr:mgrpw') >>> browser.open('http://localhost/@@contents.html')
It can be added by clicking on the “Autocomplete Widget Demo” link in the add menu. And giving it a name.
>>> link = browser.getLink('Autocomplete Widget Demo') >>> link.click() >>> nameCtrl = browser.getControl(name='new_value') >>> nameCtrl.value = 'mydemo' >>> applyCtrl = browser.getControl('Apply') >>> applyCtrl.click() >>> link = browser.getLink('mydemo') >>> link.click() >>> browser.url 'http://localhost/mydemo/@@edit.html'
Let us test the widget rendering by direct access.
>>> browser.open('http://localhost/mydemo/@@edit.html/++widget++country') >>> print browser.contents <input class="textType" ... </script>
The suggestions are proveded by its own view.
>>> browser.open('http://localhost/mydemo/@@edit.html/++widget++country/suggestions') >>> print browser.contents>>> browser.open('http://localhost/++lang++en/mydemo/@@edit.html/++widget++country/suggestions?value=a') >>> print browser.contents <BLANKLINE> <ul> <li>Algeria</li> <li>Andorra</li> <li>Antigua and Barbuda</li> <li>Afghanistan</li> <li>Anguilla</li> <li>Armenia</li> <li>Albania</li> <li>Angola</li> <li>Antarctica</li> <li>American Samoa</li> <li>Argentina</li> <li>Australia</li> <li>Austria</li> <li>Aruba</li> <li>Azerbaijan</li> </ul> <BLANKLINE> <BLANKLINE>
Suggestions are translated.
>>> browser.open('http://localhost/++lang++de/mydemo/@@edit.html/++widget++country/suggestions?value=a') >>> print browser.contents <BLANKLINE> <ul> <li>Amerikanische Jungferninseln</li> <li>Amerikanisch-Ozeanien</li> <li>Algerien</li> <li>Andorra</li> <li>Antigua und Barbuda</li> <li>Afghanistan</li> <li>Anguilla</li> <li>Armenien</li> <li>Albanien</li> <li>Angola</li> <li>Antarktis</li> <li>Amerikanisch-Samoa</li> <li>Argentinien</li> <li>Australien</li> <li>Aruba</li> <li>Aserbaidschan</li> </ul> <BLANKLINE> <BLANKLINE>
Country selection Widgets
This package provides widgets to select a country. The dropdown type is registered as a default for the Country schema.
The pain was to sort the options after the translation.
Before we can start, we have to do a little bit of setup:
>>> import zope.component >>> import zope.schema >>> import zope.app.form.browser >>> from z3c.widget.country.widget import CountryInputDropdown >>> from z3c.widget.country import ICountry >>> from z3c.i18n.iso import territoryVocabularyFactory >>> from zope.publisher.interfaces.browser import IBrowserRequest
First we have to create a field and a request:
>>> from z3c.widget.country import Country>>> countryFld = Country( ... __name__='country', ... title=u'Country', ... description=u'Select a Country')>>> from zope.publisher.browser import TestRequest >>> request = TestRequest()
Now we can initialize the widget.
>>> class Content(object): ... country = None >>> content = Content() >>> boundCountry = countryFld.bind(content)>>> widget = CountryInputDropdown(boundCountry, ... territoryVocabularyFactory(None), request)
Let’s make sure that all fields have the correct value:
>>> widget.name 'field.country'>>> widget.label u'Country'>>> widget.hint u'Select a Country'>>> widget.visible True
Let’s see how the widget is rendered:
>>> print widget() <div> <div class="value"> <select id="field.country" name="field.country" size="1" > <option value="AF">Afghanistan</option> <option value="AL">Albania</option> <option value="DZ">Algeria</option> ... <option value="HU">Hungary</option> <option value="IS">Iceland</option> <option value="IN">India</option> ... <option value="ZM">Zambia</option> <option value="ZW">Zimbabwe</option> </select> ...
#Let’s see the german translation: #z3c.i18n registrations required!!! # # >>> request = TestRequest(HTTP_ACCEPT_LANGUAGE=’de’) # # >>> widget = CountryInputDropdown(boundCountry, # … territoryVocabularyFactory(None), request) # # >>> print widget() # <div> # <div class=”value”> # <select id=”field.country” name=”field.country” size=”1” > # <option value=”AF”>Afghanistan</option> # <option value=”AL”>Albania</option> # <option value=”DZ”>Algeria</option> # … # <option value=”HU”>Hungary</option> # <option value=”IS”>Iceland</option> # <option value=”IN”>India</option> # … # <option value=”ZM”>Zambia</option> # <option value=”ZW”>Zimbabwe</option> # </select> # …
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.__class__ <class 'zope.formlib.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
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: (u'Invalid value', InvalidValue("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: (u'Invalid value', InvalidValue("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: (u'Invalid value', InvalidValue("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>
DropDownDateWidget
>>> from z3c.widget.dropdowndatewidget.widget import DropDownDateWidget>>> from zope.publisher.browser import TestRequest >>> request = TestRequest()
Widgets are use for fields.
>>> from zope.schema import Date >>> dateField = Date(__name__='foo', title=u'Foo')>>> widget = DropDownDateWidget(dateField, request)>>> widget.name 'field.foo' >>> widget.label u'Foo' >>> widget.hasInput() False
We need to provide some input.
>>> request.form['field.foo.day'] = '1' >>> widget.hasInput() False >>> request.form['field.foo.month'] = '6' >>> widget.hasInput() False >>> request.form['field.foo.year'] = '1963' >>> widget.hasInput() True
Read the value.
>>> widget.getInputValue() datetime.date(1963, 6, 1)
Let’s render the widget.
>>> print widget() <div class="dropDownDateWidget"><select class="dayField" id="field.foo.day" name="field.foo.day">...</select> <select class="monthField" id="field.foo.month" name="field.foo.month">...</select> <select class="yearField" id="field.foo.year" name="field.foo.year">...</select> </div>
And if we set a value.
>>> from datetime import date >>> widget.setRenderedValue(date(1977, 4, 3)) >>> print widget() <div class="dropDownDateWidget"><select ...<option selected="selected" value="03">... <select ...<option selected="selected" value="04">... <select ...<option selected="selected" value="1977">... ...
FLASH UPLOAD WIDGET
the flashupload vars page configures the flash frontend
>>> from z3c.widget.flashupload import upload >>> from zope.publisher.browser import TestRequest >>> from zope.app.pagetemplate import ViewPageTemplateFile >>> from zope.app.pagetemplate.simpleviewclass import SimpleViewClass >>> request = TestRequest() >>> context = object() >>> viewClass = SimpleViewClass( ... 'flashuploadvars.pt', bases=(upload.FlashUploadVars,)) >>> view = viewClass(context, request) >>> print view() <?xml version="1.0" ?> <var> <var name="file_progress">File Progress</var> <var name="overall_progress">Overall Progress</var> <var name="error">Error on uploading files</var> <var name="uploadcomplete">all files uploaded</var> <var name="uploadpartial">files uploaded</var> <var name="notuploaded">files were not uploaded because they're too big</var> <var name="maxfilesize">maximum file size is</var> </var>>>> view.allowedFileTypes = ('.jpg', '.gif') >>> print view() <?xml version="1.0" ?> <var> ... <var name="allowedFileType">.jpg</var> <var name="allowedFileType">.gif</var> </var>
The Image Widget
this image widget should be used as a custom_widget for image fields. comparing to the default widget in zope3 it does not delete the data in the field if the “delete” checkbox is not explicitly selected.
Adding an Image
>>> import zope.schema >>> from zope.publisher.browser import TestRequest >>> from zope import interface >>> from zope.schema.fieldproperty import FieldProperty >>> from zope.app.file.interfaces import IImage >>> from z3c.widget.image.widget import ImageWidget >>> from zope.app.file.image import Image
create a content type with an image field.
>>> class ITestObject(interface.Interface): ... image = zope.schema.Object( ... title=u'Image', ... schema=IImage) >>> class TestObject(object): ... interface.implements(ITestObject) ... image = FieldProperty(ITestObject['image'])>>> obj = TestObject()>>> field = ITestObject['image'].bind(obj)
Send the request without any image information. the empty field should not be changed…
>>> request = TestRequest(form={'field.image' : u''}) >>> widget = ImageWidget(field, request) >>> widget._getFormInput() is None True
Send some Image information to the field. the image information should be stored in the field as a Image Object
>>> request = TestRequest(form={'field.image' : u'PNG123Test'}) >>> widget = ImageWidget(field, request) >>> widget._getFormInput() <zope.app.file.image.Image object at ...>
Now we save the field again, but without any new image data. the old image information should not be lost
>>> obj.image = Image(u'PNG123Test') >>> request = TestRequest(form={'field.image' : u''}) >>> widget = ImageWidget(field, request) >>> widget._getFormInput() is obj.image True
Now we want to delete the image. the forminput should be None now.
>>> request = TestRequest(form={'field.image' : u'', ... 'field.image.delete': u'true'}) >>> widget = ImageWidget(field, request) >>> widget._getFormInput() is None True>>> print widget() <div class="z3cImageWidget"> <input type="file" name="field.image" id="field.image" /><br/> <input type="checkbox" name="field.image.delete" value="true" />delete image </div>
The Widget Namespace
The widget namespace provides a way to traverse to the widgets of a formlib form.
>>> from z3c.widget.namespace.namespace import WidgetHandler
Let us define a form to test this behaviour.
>>> from zope.formlib import form >>> from zope import interface, schema >>> class IMyContent(interface.Interface): ... title = schema.TextLine(title=u'Title') >>> class MyContent(object): ... interface.implements(IMyContent) ... title=None >>> content = MyContent() >>> from zope.publisher.browser import TestRequest >>> request = TestRequest() >>> class MyForm(form.EditForm): ... form_fields = form.Fields(IMyContent) >>> view = MyForm(content,request) >>> handler = WidgetHandler(view,request) >>> handler.traverse('title',None) <zope.formlib.textwidgets.TextWidget object at ...>
Optional Dropdown Widgets
The Optional Dropdown Widget simulates the common desktop widget of a combo box, which can also receive a custom entry.
Before we can start, we have to do a little bit of setup:
>>> import zope.component >>> import zope.schema >>> import zope.app.form.browser >>> from zope.publisher.interfaces.browser import IBrowserRequest>>> zope.component.provideAdapter( ... zope.app.form.browser.TextWidget, ... (zope.schema.interfaces.ITextLine, IBrowserRequest), ... zope.app.form.interfaces.IInputWidget)
First we have to create a field and a request:
>>> from z3c.schema.optchoice import OptionalChoice>>> optchoice = OptionalChoice( ... __name__='occupation', ... title=u'Occupation', ... description=u'The Occupation', ... values=(u'Programmer', u'Designer', u'Project Manager'), ... value_type=zope.schema.TextLine())>>> from zope.publisher.browser import TestRequest >>> request = TestRequest()
Now we can initialize widget.
>>> class Content(object): ... occupation = None >>> content = Content() >>> boundOptChoice = optchoice.bind(content)>>> from z3c.widget.optdropdown import OptionalDropdownWidget >>> widget = OptionalDropdownWidget(boundOptChoice, request)
Let’s make sure that all fields have the correct value:
>>> widget.name 'field.occupation'>>> widget.label u'Occupation'>>> widget.hint u'The Occupation'>>> widget.visible True>>> widget.required True
The constructor should have also created 2 widgets:
>>> widget.customWidget <zope.formlib.textwidgets.TextWidget object at ...> >>> widget.dropdownWidget <zope.formlib.itemswidgets.DropdownWidget object at ...>
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 value, it will send the information to the custom widget:
>>> print widget.customWidget() <... value="" /> >>> 'selected=""' in widget.dropdownWidget() False>>> widget.setRenderedValue(u'Scientist')>>> print widget.customWidget() <... value="Scientist" /> >>> 'selected=""' in widget.dropdownWidget() False
After resetting the widget passing in one of the choices in the vocabulary, the value should be displayed in the dropdown:
>>> widget.setRenderedValue(u'Designer')>>> print widget.customWidget() <... value="" /> >>> print widget.dropdownWidget() <div> ... <option selected="selected" value="Designer">Designer</option> ... </div>
setPrefix(prefix) Method
The prefix determines the name of the widget and the sub-widgets.
>>> widget.name 'field.occupation' >>> widget.dropdownWidget.name 'field.occupation.occupation' >>> widget.customWidget.name 'field.occupation.custom'>>> widget.setPrefix('test.')>>> widget.name 'test.occupation' >>> widget.dropdownWidget.name 'test.occupation.occupation' >>> widget.customWidget.name 'test.occupation.custom'
getInputValue() Method
This method returns a value based on the input; the data is assumed to be valid. In our case that means, if we entered a custom value, it is returned:
>>> request = TestRequest(form={ ... 'field.occupation.custom': u'Teacher'})>>> widget = OptionalDropdownWidget(boundOptChoice, request)>>> widget.getInputValue() u'Teacher'
On the other hand, if we selected a choice from the vocabulary, it should be returned:
>>> request = TestRequest(form={ ... 'field.occupation.occupation': u'Designer'})>>> widget = OptionalDropdownWidget(boundOptChoice, request)>>> widget.getInputValue() u'Designer'
applyChanges(content) Method
This method applies the new value to the passed content. However, it must be smart enough to detect whether the values really changed.
>>> request = TestRequest(form={ ... 'field.occupation.custom': u'Teacher'})>>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.applyChanges(content) True >>> content.occupation u'Teacher'>>> widget.applyChanges(content) False>>> request = TestRequest(form={ ... 'field.occupation.occupation': u'Designer'})>>> widget = OptionalDropdownWidget(boundOptChoice, request)>>> widget.applyChanges(content) True >>> content.occupation u'Designer'>>> widget.applyChanges(content) False
hasInput() Method
This mehtod checks for any input, but does not validate it. In our case this means that either a choice has been selected or the the custom value has been entered.
>>> request = TestRequest() >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.hasInput() False>>> request = TestRequest(form={ ... 'field.occupation.custom': u'Teacher\nBad Stuff'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.hasInput() True>>> request = TestRequest(form={ ... 'field.occupation.occupation': u'Waitress'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.hasInput() True
hasValidInput() Method
Additionally to checking for any input, this method also checks whether the input is valid:
>>> request = TestRequest() >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.hasValidInput() False>>> request = TestRequest(form={ ... 'field.occupation.occupation': u'Waitress'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.hasValidInput() False>>> request = TestRequest(form={ ... 'field.occupation.occupation': u'Designer'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.hasValidInput() True>>> request = TestRequest(form={ ... 'field.occupation.custom': u'Teacher\nBad Stuff'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.hasValidInput() False>>> request = TestRequest(form={ ... 'field.occupation.custom': u'Teacher'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.hasValidInput() True
error() Method
Again, we have our two cases. If an error occured in the dropdown, it is reported:
>>> from zope.app.form.interfaces import IWidgetInputError >>> from zope.app.form.browser.exception import WidgetInputErrorView >>> from zope.app.form.browser.interfaces import IWidgetInputErrorView>>> zope.component.provideAdapter( ... WidgetInputErrorView, ... (IWidgetInputError, IBrowserRequest), IWidgetInputErrorView)>>> request = TestRequest(form={ ... 'field.occupation.occupation': u'Designer'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.getInputValue() u'Designer' >>> widget.error() ''>>> request = TestRequest(form={ ... 'field.occupation.occupation': u'Waitress'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request)>>> widget.getInputValue() Traceback (most recent call last): ... ConversionError: (u'Invalid value', InvalidValue("token u'Waitress' not found in vocabulary")) >>> widget.error() u'<span class="error">Invalid value</span>'
Otherwise the custom widget’s errors are reported:
>>> request = TestRequest(form={ ... 'field.occupation.custom': u'Teacher'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.getInputValue() u'Teacher' >>> widget.error() ''>>> request = TestRequest(form={ ... 'field.occupation.custom': u'Teacher\nBad Stuff'}) >>> widget = OptionalDropdownWidget(boundOptChoice, request)>>> widget.getInputValue() Traceback (most recent call last): ... WidgetInputError: ('custom', u'', ConstraintNotSatisfied(u'Teacher\nBad Stuff')) >>> widget.error() u'<span class="error">Constraint not satisfied</span>'
__call__() Method
This method renders the widget using the sub-widgets. It simply adds the two widgets’ output placing the connector between them:
>>> request = TestRequest(form={ ... 'field.occupation.custom': u'Teacher'})>>> widget = OptionalDropdownWidget(boundOptChoice, request) >>> widget.connector u'<br />\n'>>> print widget() <div> <div class="value"> <select id="field.occupation.occupation" name="field.occupation.occupation" size="1" > <option selected="selected" value="">(nothing selected)</option> <option value="Programmer">Programmer</option> <option value="Designer">Designer</option> <option value="Project Manager">Project Manager</option> </select> </div> <input name="field.occupation.occupation-empty-marker" type="hidden" value="1" /> </div><br /> <input class="textType" id="field.occupation.custom" name="field.occupation.custom" size="20" type="text" value="Teacher" />
SequenceTable Widget
This package provides a Sequence Widget just as zope.app.form.browser.sequencewidget. The main difference is that it places the subobject’s fields horizontally in a table. That means a kind of voucher-item forms are piece of cake to do.
There is also a widget (SequenceTableJSWidget) which does the add/remove item in the browser with javascript. The trick is to embed an invisible template of an empty row in the HTML, add that each time a new row is required.
- Drawbacks of JS:
Validation is done ONLY when the complete form is submitted to the server.
Submitting the form and using the Back button of the browser does not work.
WARNING!
The subobject MUST have subwidgets. That is usually the case if the subobject is based on zope.schema.Object.
TODO
Tests. Some are there, some are copied from z.a.form.browser and need fix.
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.formlib.textwidgets.TextWidget object at ...> >>> widget.widgets['second'] <zope.formlib.textwidgets.TextWidget object at ...> >>> widget.widgets['third'] <zope.formlib.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', ConstraintNotSatisfied(u'1234'))>>> widget._error.__class__ <class 'zope.formlib.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
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', ConstraintNotSatisfied(u'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', ConstraintNotSatisfied(u'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', ConstraintNotSatisfied(u'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" />
HTML-Editor Widget TinyMCE
This package provides a WYSIWYG-Editor-Widget for HTML-Content, by using the greate TinyMCE editor (see: http://tinymce.moxiecode.com/).
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.formlib.textwidgets.TextWidget object at ...> >>> widget.widgets['second'] <zope.formlib.textwidgets.TextWidget object at ...> >>> widget.widgets['third'] <zope.formlib.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', ConstraintNotSatisfied(u'1234'))>>> widget._error.__class__ <class 'zope.formlib.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
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', ConstraintNotSatisfied(u'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', ConstraintNotSatisfied(u'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', ConstraintNotSatisfied(u'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" />
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.