============================
Select Widget, missing terms
============================
The select widget allows you to select one or more values from a set of given
options. The "SELECT" and "OPTION" elements are described here:
http://www.w3.org/TR/1999/REC-html401-19991224/interact/forms.html#edef-SELECT
As for all widgets, the select widget must provide the new ``IWidget``
interface:
>>> from z3c.form import interfaces
>>> from z3c.form.browser import select
The widget can be instantiated only using the request:
>>> from z3c.form.testing import TestRequest
>>> request = TestRequest()
>>> widget = select.SelectWidget(request)
Before rendering the widget, one has to set the name and id of the widget:
>>> widget.id = 'widget-id'
>>> widget.name = 'widget.name'
We also need to register the template for at least the widget and request:
>>> import zope.component
>>> from zope.pagetemplate.interfaces import IPageTemplate
>>> from z3c.form.testing import getPath
>>> from z3c.form.widget import WidgetTemplateFactory
>>> zope.component.provideAdapter(
... WidgetTemplateFactory(getPath('select_input.pt'), 'text/html'),
... (None, None, None, None, interfaces.ISelectWidget),
... IPageTemplate, name=interfaces.INPUT_MODE)
We need some context:
>>> class IPerson(zope.interface.Interface):
... rating = zope.schema.Choice(
... vocabulary='Ratings')
>>> @zope.interface.implementer(IPerson)
... class Person(object):
... pass
>>> person = Person()
Let's provide some values for this widget. We can do this by defining a source
providing ``ITerms``. This source uses descriminators which will fit our setup.
>>> import zope.schema.interfaces
>>> from zope.schema.vocabulary import SimpleVocabulary
>>> from zope.schema.vocabulary import SimpleTerm
>>> import z3c.form.term
>>> from zope.schema import vocabulary
>>> ratings = vocabulary.SimpleVocabulary([
... vocabulary.SimpleVocabulary.createTerm(0, '0', u'bad'),
... vocabulary.SimpleVocabulary.createTerm(1, '1', u'okay'),
... vocabulary.SimpleVocabulary.createTerm(2, '2', u'good')
... ])
>>> def RatingsVocabulary(obj):
... return ratings
>>> vr = vocabulary.getVocabularyRegistry()
>>> vr.register('Ratings', RatingsVocabulary)
>>> class SelectionTerms(z3c.form.term.MissingChoiceTermsVocabulary):
... def __init__(self, context, request, form, field, widget):
... self.context = context
... self.field = field
... self.terms = ratings
... self.widget = widget
...
... def _makeMissingTerm(self, token):
... if token == 'x':
... return super(SelectionTerms, self)._makeMissingTerm(token)
... else:
... raise LookupError
>>> zope.component.provideAdapter(SelectionTerms,
... (None, interfaces.IFormLayer, None, None, interfaces.ISelectWidget) )
>>> import z3c.form.datamanager
>>> zope.component.provideAdapter(z3c.form.datamanager.AttributeField)
Now let's try if we get widget values:
>>> widget.update()
>>> print(widget.render())
If we set the widget value to "x", then it should be present and selected:
>>> widget.value = ['x']
>>> widget.context = person
>>> widget.field = IPerson['rating']
>>> zope.interface.alsoProvides(widget, interfaces.IContextAware)
>>> person.rating = 'x'
>>> widget.terms = None
>>> widget.update()
>>> print(widget.render())
If we set the widget value to "y", then it should NOT be around:
>>> widget.value = ['y']
>>> widget.update()
>>> print(widget.render())
Let's now make sure that we can extract user entered data from a widget:
>>> widget.request = TestRequest(form={'widget.name': ['c']})
>>> widget.update()
>>> widget.extract()
Well, only of it matches the context's current value:
>>> widget.request = TestRequest(form={'widget.name': ['x']})
>>> widget.update()
>>> widget.extract()
['x']
When "No value" is selected, then no verification against the terms is done:
>>> widget.request = TestRequest(form={'widget.name': ['--NOVALUE--']})
>>> widget.update()
>>> widget.extract(default=1)
['--NOVALUE--']
Let's now make sure that we can extract user entered missing data from a widget:
>>> widget.request = TestRequest(form={'widget.name': ['x']})
>>> widget.update()
>>> widget.extract()
['x']
>>> widget.request = TestRequest(form={'widget.name': ['y']})
>>> widget.update()
>>> widget.extract()
Unfortunately, when nothing is selected, we do not get an empty list sent into
the request, but simply no entry at all. For this we have the empty marker, so
that:
>>> widget.request = TestRequest(form={'widget.name-empty-marker': '1'})
>>> widget.update()
>>> widget.extract()
[]
If nothing is found in the request, the default is returned:
>>> widget.request = TestRequest()
>>> widget.update()
>>> widget.extract(default=1)
1
Let's now make sure that a bogus value causes extract to return the default as
described by the interface:
>>> widget.request = TestRequest(form={'widget.name': ['y']})
>>> widget.update()
>>> widget.extract(default=1)
1
Display Widget
--------------
The select widget comes with a template for ``DISPLAY_MODE``. Let's
register it first:
>>> zope.component.provideAdapter(
... WidgetTemplateFactory(getPath('select_display.pt'), 'text/html'),
... (None, None, None, None, interfaces.ISelectWidget),
... IPageTemplate, name=interfaces.DISPLAY_MODE)
Let's see what happens if we have values that are not in the vocabulary:
>>> widget.required = True
>>> widget.mode = interfaces.DISPLAY_MODE
>>> widget.value = ['0', '1', 'x']
>>> widget.update()
>>> print(widget.render())
bad,
okay,
Missing: x
Hidden Widget
-------------
The select widget comes with a template for ``HIDDEN_MODE``. Let's
register it first:
>>> zope.component.provideAdapter(
... WidgetTemplateFactory(getPath('select_hidden.pt'), 'text/html'),
... (None, None, None, None, interfaces.ISelectWidget),
... IPageTemplate, name=interfaces.HIDDEN_MODE)
Let's see what happens if we have values that are not in the vocabulary:
>>> widget.mode = interfaces.HIDDEN_MODE
>>> widget.value = ['0', 'x']
>>> widget.update()
>>> print(widget.render())