[Zope3-checkins] CVS: Zope3/src/zope/app/browser/form - widget.py:1.29.4.3
Fred L. Drake, Jr.
fred@zope.com
Mon, 5 May 2003 13:56:09 -0400
Update of /cvs-repository/Zope3/src/zope/app/browser/form
In directory cvs.zope.org:/tmp/cvs-serv1981
Modified Files:
Tag: schema-vocabulary-branch
widget.py
Log Message:
- added single-selection edit widget for simple vocabularies
- refactored _showData() to use a helper to get the default value
- minor code cleanups
=== Zope3/src/zope/app/browser/form/widget.py 1.29.4.2 => 1.29.4.3 ===
--- Zope3/src/zope/app/browser/form/widget.py:1.29.4.2 Fri May 2 18:05:07 2003
+++ Zope3/src/zope/app/browser/form/widget.py Mon May 5 13:56:08 2003
@@ -17,8 +17,6 @@
__metaclass__ = type
-from types import ListType, TupleType
-ListTypes = (ListType, TupleType)
from zope.proxy.introspection import removeAllProxies
from zope.publisher.browser import BrowserView
from zope.app.interfaces.browser.form import IBrowserWidget
@@ -30,6 +28,8 @@
from zope.schema.interfaces import ValidationError
from zope.component import getService, getView
+ListTypes = list, tuple
+
class BrowserWidget(Widget, BrowserView):
"""A field widget that knows how to display itself as HTML."""
@@ -82,16 +82,21 @@
return value
def _showData(self):
- if (self._data is None):
+ if self._data is None:
if self.haveData():
data = self.getData(1)
else:
- data = self.context.default
+ data = self._getDefault()
else:
data = self._data
return self._unconvert(data)
+ def _getDefault(self):
+ # Return the default value for this widget;
+ # may be overridden by subclasses.
+ return self.context.default
+
def __call__(self):
return renderElement(self.getValue('tag'),
type = self.getValue('type'),
@@ -591,7 +596,7 @@
"""A widget with a number of items that has multiple selectable items."""
default = []
- def _convert(self, value, ListTypes = (list, tuple)):
+ def _convert(self, value):
if value is None:
return []
if isinstance(value, ListTypes):
@@ -720,21 +725,36 @@
class VocabularyWidgetBase(BrowserWidget):
"""Convenience base class for vocabulary-based widgets."""
+ type = "vocabulary"
+
def __init__(self, context, request):
self.context = context
self.request = request
self.field = None
+ def _getDefault(self):
+ # Override this since the context is not the field for
+ # vocabulary-based widgets.
+ return self.field.default
+
def setField(self, field):
assert self.field is None
# only allow this to happen for a bound field
assert field.context is not None
self.field = field
self.name = self._prefix + field.__name__
+ if not self.haveData():
+ # not provided by form, so pull data from the content object
+ self.setData(self.field.get(field.context))
def __call__(self):
return self.render()
+ def textForValue(self, term):
+ # Extract the value from the term. This can be overridden to
+ # support more complex term objects.
+ return term.value
+
def render(self):
raise NotImplementedError(
"render() must be implemented by a subclass")
@@ -744,7 +764,81 @@
"""Simple single-selection display that can be used in many cases."""
def render(self):
- return str(self.field.get(self.field.context))
+ value = self.field.get(self.field.context)
+ term = self.field.vocabulary.getTerm(value)
+ return self.textForValue(term)
+
+
+class VocabularyEditWidget(VocabularyWidgetBase):
+ """Single single-selection edit widget.
+
+ This widget can be used when the number of selections isn't going
+ to be very large.
+ """
+ __implements__ = SingleItemsWidget.__implements__
+ propertyNames = (SingleItemsWidget.propertyNames +
+ ['firstItem', 'size', 'extra']
+ )
+ extra = ''
+ firstItem = False
+ size = 5
+ tag = 'select'
+
+ def render(self):
+ rendered_items = self.renderItems(self._showData())
+ return renderElement(self.getValue('tag'),
+ type = self.getValue('type'),
+ name = self.name,
+ id = self.name,
+ cssClass = self.getValue('cssClass'),
+ size = self.getValue('size'),
+ contents = "\n".join(rendered_items),
+ extra = self.getValue('extra'))
+
+ def renderItems(self, value):
+ vocabulary = self.context
+
+ # check if we want to select first item
+ if (value == self._missing
+ and getattr(self.context, 'firstItem', False)
+ and len(vocabulary) > 0):
+ value = iter(vocabulary).next().value
+
+ cssClass = self.getValue('cssClass')
+
+ # multiple items with the same value are not allowed from a
+ # vocabulary, so that need not be considered here
+ rendered_items = []
+ count = 0
+ for term in vocabulary:
+ item_value = term.value
+ item_text = self.textForValue(term)
+
+ if item_value == value:
+ rendered_item = self.renderSelectedItem(count,
+ item_text,
+ item_value,
+ self.name,
+ cssClass)
+ else:
+ rendered_item = self.renderItem(count,
+ item_text,
+ item_value,
+ self.name,
+ cssClass)
+
+ rendered_items.append(rendered_item)
+ count += 1
+
+ return rendered_items
+
+ def renderItem(self, index, text, value, name, cssClass):
+ return renderElement('option', contents=text, value=value,
+ cssClass=cssClass)
+
+ def renderSelectedItem(self, index, text, value, name, cssClass):
+ return renderElement('option', contents=text, value=value,
+ cssClass=cssClass, selected=None)
# XXX Note, some HTML quoting is needed in renderTag and renderElement.
@@ -771,7 +865,8 @@
else:
cssWidgetType = ''
if cssWidgetType or cssClass:
- attr_list.append('class="%s"' % ' '.join((cssClass, cssWidgetType)))
+ names = filter(None, (cssClass, cssWidgetType))
+ attr_list.append('class="%s"' % ' '.join(names))
if 'style' in kw:
if kw['style'] != '':