[Checkins] SVN: z3c.widget/trunk/src/z3c/widget/optdropdown/
Implementation of an input widget for optchoice. Let's see
how it works;
Stephan Richter
srichter at cosmos.phy.tufts.edu
Thu Dec 28 14:13:16 EST 2006
Log message for revision 71660:
Implementation of an input widget for optchoice. Let's see how it works;
I'll probably tweak it a little bit more.
Changed:
A z3c.widget/trunk/src/z3c/widget/optdropdown/
A z3c.widget/trunk/src/z3c/widget/optdropdown/DEPENDENCIES.cfg
A z3c.widget/trunk/src/z3c/widget/optdropdown/README.txt
A z3c.widget/trunk/src/z3c/widget/optdropdown/SETUP.cfg
A z3c.widget/trunk/src/z3c/widget/optdropdown/__init__.py
A z3c.widget/trunk/src/z3c/widget/optdropdown/configure.zcml
A z3c.widget/trunk/src/z3c/widget/optdropdown/tests.py
A z3c.widget/trunk/src/z3c/widget/optdropdown/widget.py
A z3c.widget/trunk/src/z3c/widget/optdropdown/z3c.widget.optdropdown-configure.zcml
-=-
Added: z3c.widget/trunk/src/z3c/widget/optdropdown/DEPENDENCIES.cfg
===================================================================
--- z3c.widget/trunk/src/z3c/widget/optdropdown/DEPENDENCIES.cfg 2006-12-28 16:20:08 UTC (rev 71659)
+++ z3c.widget/trunk/src/z3c/widget/optdropdown/DEPENDENCIES.cfg 2006-12-28 19:13:13 UTC (rev 71660)
@@ -0,0 +1 @@
+z3c.field.optchoice
Added: z3c.widget/trunk/src/z3c/widget/optdropdown/README.txt
===================================================================
--- z3c.widget/trunk/src/z3c/widget/optdropdown/README.txt 2006-12-28 16:20:08 UTC (rev 71659)
+++ z3c.widget/trunk/src/z3c/widget/optdropdown/README.txt 2006-12-28 19:13:13 UTC (rev 71660)
@@ -0,0 +1,351 @@
+=========================
+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.app.form.browser.textwidgets.TextWidget object at ...>
+ >>> widget.dropdownWidget
+ <zope.app.form.browser.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
+
+
+hidden() Method
+~~~~~~~~~~~~~~~
+
+This method is implemented by simply concatenating the two widget's hidden
+output:
+
+ >>> request = TestRequest()
+ >>> widget = OptionalDropdownWidget(boundOptChoice, request)
+ >>> widget.setRenderedValue(u'Designer')
+ >>> print widget.hidden()
+ <input class="hiddenType" id="field.occupation.occupation"
+ name="field.occupation.occupation" type="hidden" value="Designer" />
+ <input class="hiddenType" id="field.occupation.custom"
+ name="field.occupation.custom" type="hidden" value="" />
+
+ >>> widget.setRenderedValue(u'Teacher')
+ >>> print widget.hidden()
+ <input class="hiddenType" id="field.occupation.occupation"
+ name="field.occupation.occupation" type="hidden" value="" />
+ <input class="hiddenType" id="field.occupation.custom"
+ name="field.occupation.custom" type="hidden" value="Teacher" />
+
+
+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: ('Invalid value', 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'', Teacher Bad 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 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" />
Property changes on: z3c.widget/trunk/src/z3c/widget/optdropdown/README.txt
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.widget/trunk/src/z3c/widget/optdropdown/SETUP.cfg
===================================================================
--- z3c.widget/trunk/src/z3c/widget/optdropdown/SETUP.cfg 2006-12-28 16:20:08 UTC (rev 71659)
+++ z3c.widget/trunk/src/z3c/widget/optdropdown/SETUP.cfg 2006-12-28 19:13:13 UTC (rev 71660)
@@ -0,0 +1,3 @@
+<data-files zopeskel/etc/package-includes>
+ z3c.widget.optdropdown-*.zcml
+</data-files>
Added: z3c.widget/trunk/src/z3c/widget/optdropdown/__init__.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/optdropdown/__init__.py 2006-12-28 16:20:08 UTC (rev 71659)
+++ z3c.widget/trunk/src/z3c/widget/optdropdown/__init__.py 2006-12-28 19:13:13 UTC (rev 71660)
@@ -0,0 +1,19 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Optional Dropdown Widget
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+from z3c.widget.optdropdown.widget import OptionalDropdownWidget
Property changes on: z3c.widget/trunk/src/z3c/widget/optdropdown/__init__.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: z3c.widget/trunk/src/z3c/widget/optdropdown/configure.zcml
===================================================================
--- z3c.widget/trunk/src/z3c/widget/optdropdown/configure.zcml 2006-12-28 16:20:08 UTC (rev 71659)
+++ z3c.widget/trunk/src/z3c/widget/optdropdown/configure.zcml 2006-12-28 19:13:13 UTC (rev 71660)
@@ -0,0 +1,13 @@
+<configure
+ xmlns="http://namespaces.zope.org/zope"
+ i18n_domain="z3c.widget">
+
+ <view
+ type="zope.publisher.interfaces.browser.IBrowserRequest"
+ for="z3c.schema.optchoice.IOptionalCoice"
+ provides="zope.app.form.interfaces.IInputWidget"
+ factory=".widget.IOptionalDropDown"
+ permission="zope.Public"
+ />
+
+</configure>
Property changes on: z3c.widget/trunk/src/z3c/widget/optdropdown/configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
Added: z3c.widget/trunk/src/z3c/widget/optdropdown/tests.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/optdropdown/tests.py 2006-12-28 16:20:08 UTC (rev 71659)
+++ z3c.widget/trunk/src/z3c/widget/optdropdown/tests.py 2006-12-28 19:13:13 UTC (rev 71660)
@@ -0,0 +1,35 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Optional Dropdown Widget Tests
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import doctest
+import unittest
+from zope.testing import doctestunit
+from zope.app.testing import placelesssetup
+
+def test_suite():
+ return unittest.TestSuite((
+ doctestunit.DocFileSuite(
+ 'README.txt',
+ setUp=placelesssetup.setUp, tearDown=placelesssetup.tearDown,
+ globs={'pprint': doctestunit.pprint},
+ optionflags=doctest.NORMALIZE_WHITESPACE|doctest.ELLIPSIS),
+ ))
+
+if __name__ == '__main__':
+ unittest.main(defaultTest='test_suite')
+
Property changes on: z3c.widget/trunk/src/z3c/widget/optdropdown/tests.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: z3c.widget/trunk/src/z3c/widget/optdropdown/widget.py
===================================================================
--- z3c.widget/trunk/src/z3c/widget/optdropdown/widget.py 2006-12-28 16:20:08 UTC (rev 71659)
+++ z3c.widget/trunk/src/z3c/widget/optdropdown/widget.py 2006-12-28 19:13:13 UTC (rev 71660)
@@ -0,0 +1,118 @@
+##############################################################################
+#
+# 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.
+#
+##############################################################################
+"""Optional Dropdown Widget
+
+$Id$
+"""
+__docformat__ = "reStructuredText"
+import zope.component
+from zope.app import form
+from zope.app.form import browser
+
+class OptionalDropdownWidget(object):
+ """Optional Dropdown Widget"""
+ zope.interface.implements(browser.interfaces.IBrowserWidget,
+ form.interfaces.IInputWidget)
+
+ connector = u'<br />\n'
+
+ _prefix = 'field.'
+
+ # 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
+ # Setup the custom value widget
+ field.value_type.__name__ = 'custom'
+ self.customWidget = zope.component.getMultiAdapter(
+ (field.value_type, request), form.interfaces.IInputWidget)
+ # Setup the dropdown widget
+ self.dropdownWidget = form.browser.DropdownWidget(
+ field, field.vocabulary, request)
+ # Setting the prefix again, sets everything up correctly
+ self.setPrefix(self._prefix)
+
+ def setRenderedValue(self, value):
+ """See zope.app.form.interfaces.IWidget"""
+ if value in self.context.vocabulary:
+ self.dropdownWidget.setRenderedValue(value)
+ self.customWidget.setRenderedValue(
+ self.context.value_type.missing_value)
+ else:
+ self.customWidget.setRenderedValue(value)
+ self.dropdownWidget.setRenderedValue(
+ self.context.missing_value)
+
+ 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__
+ self.customWidget.setPrefix(self.name+'.')
+ self.dropdownWidget.setPrefix(self.name+'.')
+
+ def getInputValue(self):
+ """See zope.app.form.interfaces.IInputWidget"""
+ if self.customWidget.hasInput():
+ return self.customWidget.getInputValue()
+ else:
+ return self.dropdownWidget.getInputValue()
+
+ 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 of an existing scoresystem 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.dropdownWidget.hasInput() or self.customWidget.hasInput()
+
+ def hasValidInput(self):
+ """See zope.app.form.interfaces.IInputWidget"""
+ return (self.dropdownWidget.hasValidInput() or
+ self.customWidget.hasValidInput())
+
+ def hidden(self):
+ """See zope.app.form.browser.interfaces.IBrowserWidget"""
+ return '\n'.join((self.dropdownWidget.hidden(),
+ self.customWidget.hidden()))
+
+
+ def error(self):
+ """See zope.app.form.browser.interfaces.IBrowserWidget"""
+ dropdownError = self.dropdownWidget.error()
+ if dropdownError:
+ return dropdownError
+ return self.customWidget.error()
+
+
+ def __call__(self):
+ """See zope.app.form.browser.interfaces.IBrowserWidget"""
+ return self.connector.join((self.dropdownWidget(), self.customWidget()))
Property changes on: z3c.widget/trunk/src/z3c/widget/optdropdown/widget.py
___________________________________________________________________
Name: svn:keywords
+ Id
Added: z3c.widget/trunk/src/z3c/widget/optdropdown/z3c.widget.optdropdown-configure.zcml
===================================================================
--- z3c.widget/trunk/src/z3c/widget/optdropdown/z3c.widget.optdropdown-configure.zcml 2006-12-28 16:20:08 UTC (rev 71659)
+++ z3c.widget/trunk/src/z3c/widget/optdropdown/z3c.widget.optdropdown-configure.zcml 2006-12-28 19:13:13 UTC (rev 71660)
@@ -0,0 +1 @@
+<include package="z3c.widget.flashupload" />
\ No newline at end of file
Property changes on: z3c.widget/trunk/src/z3c/widget/optdropdown/z3c.widget.optdropdown-configure.zcml
___________________________________________________________________
Name: svn:eol-style
+ native
More information about the Checkins
mailing list