[Zope-Checkins] CVS: Zope3/lib/python/Zope/App/Forms/Views/Browser - BrowserWidget.py:1.1 Converter.py:1.1 IBrowserWidget.py:1.1 Widget.py:1.1 FormView.py:1.3 TextWidget.py:1.2 configure.zcml:1.2

Stephan Richter srichter@cbu.edu
Sun, 14 Jul 2002 09:33:24 -0400


Update of /cvs-repository/Zope3/lib/python/Zope/App/Forms/Views/Browser
In directory cvs.zope.org:/tmp/cvs-serv5853/Zope/App/Forms/Views/Browser

Modified Files:
	FormView.py TextWidget.py configure.zcml 
Added Files:
	BrowserWidget.py Converter.py IBrowserWidget.py Widget.py 
Log Message:
- I finished the Schema code. We now have the following Fields defined
  by default: String, Boolean, Integer, Float, Tuple, List, Dictionary

- I also reworked the Validator in a major way. A Validator now does only 
  one thing, such as check that a value has the right type. The Validators
  are then put into a ContainerValidator which runs through all the 
  specified Validators. BTW, I hope you like the code... I do. :)

- Rewrote and added new tests. Note that there are no explicit tests for 
  the Validators, since they are tested already through the Field validate
  method.

- Started working on Forms. There is a whole lot of work to be done there.
  More checkins on that later...


=== Added File Zope3/lib/python/Zope/App/Forms/Views/Browser/BrowserWidget.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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: BrowserWidget.py,v 1.1 2002/07/14 13:32:53 srichter Exp $
"""
from Zope.ComponentArchitecture import getAdapter
from IBrowserWidget import IBrowserWidget
from Zope.App.Formulator.Widget import Widget
from Zope.App.Formulator.IPropertyFieldAdapter import IPropertyFieldAdapter


class BrowserWidget(Widget, BrowserView):
    """A field widget that knows how to display itself as HTML."""

    __implements__ = IBrowserWidget

    propertyNames = Widget.propertyNames + \
                    ['tag', 'type', 'cssClass', 'hidden', 'extra']
    
    tag = 'input'
    type = 'text'
    cssClass = ''
    hidden = 0
    extra = ''

    def getValueFromRequest(self, REQUEST):
        """ """
        return REQUEST.get('field_'+self.context.id, None)


    def _getValueToInsert(self, REQUEST):
        """ """
        field = self.context
        if REQUEST and (('field_'+field.id) in REQUEST):
            return REQUEST['field_'+field.id]
        else:
            return getAdapter(field, IPropertyFieldAdapter).\
                   getPropertyInContext()
            

    def render(self, REQUEST=None):
        """Renders this widget as HTML using property values in field.
        """
        return renderElement(self.getValue('tag'),
                             type = self.getValue('type'),
                             name = self.context.id,
                             value = self._getValueToInsert(REQUEST),
                             cssClass = self.getValue('cssClass'),
                             extra = self.getValue('extra'))

        
    def render_hidden(self, REQUEST=None):
        """Renders this widget as a hidden field.
        """
        return renderElement(self.getValue('tag'),
                             type = 'hidden',
                             name = self.context.id,
                             value = self._getValueToInsert(REQUEST),
                             cssClass = self.getValue('cssClass'),
                             extra = self.getValue('extra'))



def renderTag(tag, **kw):
    """Render the tag. Well, not all of it, as we may want to / it.
    """
    attr_list = []

    kw['name'] = 'field_' + kw['name']

    # special case handling for css_class
    if 'cssClass' in kw:
        if kw['cssClass'] != "":
            attr_list.append('class="%s"' % kw['cssClass'])
        del kw['cssClass']

    # special case handling for extra 'raw' code
    if 'extra' in kw:
        extra = kw['extra'] # could be empty string but we don't care
        del kw['extra']
    else:
        extra = ""

    # handle other attributes
    for key, value in kw.items():
        if value == None:
            value = key
        attr_list.append('%s="%s"' % (key, str(value)))
            
    attr_str = " ".join(attr_list)
    return "<%s %s %s" % (tag, attr_str, extra)


def renderElement(tag, **kw):
    if 'contents' in kw:
        contents = kw['contents']
        del kw['contents']
        return "%s>%s</%s>" % (apply(renderTag, (tag,), kw), contents, tag)
    else:
        return apply(renderTag, (tag,), kw) + " />"


=== Added File Zope3/lib/python/Zope/App/Forms/Views/Browser/Converter.py ===
##############################################################################
#
# Copyright (c) 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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: Converter.py,v 1.1 2002/07/14 13:32:53 srichter Exp $
"""
from Zope.App.Forms.Converter import *
from Schema.IField import *


class RequestToFieldConverter(Converter):
    """Base class that defines how to convert from the Request to a Field.
    Note that the value argument for the convert method is a string
    containing the name of the variable in the Request."""
    __convert_from__ = IRequest
    __convert_to__ = IField
    
    field_prefix = 'field_'        

    def convert(self, value):
        'See Zope.App.Forms.IConverter.IConverter'
        request = self.context
        raw_value = request.form.get(self.field_prefix+value)
        return raw_value


class RequestToStringConverter(Converter):
    """A specific class converting the in the request contained variable to
    a string."""
    __convert_from__ = IRequest
    __convert_to__ = IString


class RequestToIntegerConverter(ContainerConverter):
    """Convert from Request to an Integer."""
    converters = [RequestToStringConverter, StringToIntegerConverter]


class RequestToFloatConverter(ContainerConverter):
    """Convert from Request to an Float."""
    converters = [RequestToStringConverter, StringToFloatConverter]


=== Added File Zope3/lib/python/Zope/App/Forms/Views/Browser/IBrowserWidget.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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: IBrowserWidget.py,v 1.1 2002/07/14 13:32:53 srichter Exp $
"""

from Zope.App.Forms.IWidget import IWidget


class IBrowserWidget(IWidget):
    """A field widget contains all the properties that are required
       to represent a field. Properties include css_sheet, 
       default value and so on.
    """


    def render(field, key, value):
        """Renders this widget as HTML using property values in field."""

        
    def render_hidden(field, key, value):
        """Renders this widget as a hidden field."""
        


=== Added File Zope3/lib/python/Zope/App/Forms/Views/Browser/Widget.py ===
##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
# 
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (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: Widget.py,v 1.1 2002/07/14 13:32:53 srichter Exp $
"""
from types import ListTypes

from Zope.ComponentArchitecture import getAdapter
from Zope.App.Forms.Views.Browser.IBrowserWidget import IBrowserWidget
from Zope.App.Forms.IPropertyFieldAdapter import IPropertyFieldAdapter
from Zope.App.Forms.Widget import Widget


class BrowserWidget(Widget, BrowserView):
    """A field widget that knows how to display itself as HTML."""
    __implements__ = IBrowserWidget
    propertyNames = Widget.propertyNames + \
                    ['tag', 'type', 'cssClass', 'hidden', 'extra']
    
    tag = 'input'
    type = 'text'
    cssClass = ''
    hidden = 0
    extra = ''

    def _getValueToInsert(self):
        """Get a value to be inserted as the value of the input"""
        request = self.request
        field = self.context
        if request and (('field_'+field.id) in request):
            return request['field_'+field.id]
        else:
            return getAdapter(field, IPropertyFieldAdapter).\
                   getPropertyInContext()
        
            
    def render(self, field, key, value):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        return renderElement(self.getValue('tag'),
                             type = self.getValue('type'),
                             name = self.context.id,
                             value = self._getValueToInsert(),
                             cssClass = self.getValue('cssClass'),
                             extra = self.getValue('extra'))


    def render_hidden(self, field, key, value):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        return renderElement(self.getValue('tag'),
                             type = 'hidden',
                             name = self.context.id,
                             value = self._getValueToInsert(),
                             cssClass = self.getValue('cssClass'),
                             extra = self.getValue('extra'))


class CheckBoxWidget(BrowserWidget):
    """Checkbox widget"""
    propertyNames = BrowserWidget.propertyNames + \
                     ['extra', 'default']

    type = 'checkbox'
    default = 0
    extra = ''

    def render(self, REQUEST=None):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        if self._getValueToInsert(REQUEST):
            return renderElement(self.getValue('tag'),
                                 type = self.getValue('type'),
                                 name = self.context.id,
                                 checked = None,
                                 cssClass = self.getValue('cssClass'),
                                 extra = self.getValue('extra'))
        else:
            return renderElement(self.getValue('tag'),
                                 type = self.getValue('type'),
                                 name = self.context.id,
                                 cssClass = self.getValue('cssClass'),
                                 size = self.getValue('displayWidth'),
                                 extra = self.getValue('extra'))


class FileWidget(TextWidget):
    """File Widget"""
    type = 'file'

    def render(self, REQUEST=None):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        displayMaxWidth = self.getValue('displayMaxWidth') or 0
        if displayMaxWidth > 0:
            return renderElement(self.getValue('tag'),
                                 type = self.getValue('type'),
                                 name = self.context.id,
                                 cssClass = self.getValue('cssClass'),
                                 size = self.getValue('displayWidth'),
                                 maxlength = displayMaxWidth,
                                 extra = self.getValue('extra'))
        else:
            return renderElement(self.getValue('tag'),
                                 type = self.getValue('type'),
                                 name = self.context.id,
                                 cssClass = self.getValue('cssClass'),
                                 size = self.getValue('displayWidth'),
                                 extra = self.getValue('extra'))


class ItemsWidget(Widget):
    """A widget that has a number of items in it."""
    items = []


class ListWidget(SingleItemsWidget):
    """List widget."""
    __implements__ = SingleItemsWidget.__implements__
    property_names = Widget.property_names +\
                     ['firstItem', 'items', 'size', 'extra']
    size = 5

    def render(self, REQUEST=None):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        renderedItems = self.renderItems(field, key, value, REQUEST)
        return render_element('select',
                              name='',
                              cssClass=field.get_value('cssClass'),
                              size=field.get_value('size'),
                              contents=string.join(renderedItems, "\n"),
                              extra=field.get_value('extra'))

    
    def renderItem(self, text, value, key, css_class):
        return render_element('option', contents=text, value=value)


    def renderSelectedItem(self, text, value, key, css_class):
        return render_element('option', contents=text, value=value,
                              selected=None)

        
class MultiItemsWidget(ItemsWidget):
    """A widget with a number of items that has multiple selectable items."""
    default = []
        
    def render_items(self, field, key, value):
        # need to deal with single item selects
        if not isinstance(values, ListTypes):
            value = [value]
        items = field.get_value('items')
        css_class = field.get_value('css_class')
        rendered_items = []
        for item in items:
            try:
                item_text, item_value = item
            except ValueError:
                item_text = item
                item_value = item

            if item_value in value:
                rendered_item = self.render_selected_item(item_text,
                                                          item_value,
                                                          key,
                                                          css_class)
            else:
                rendered_item = self.render_item(item_text,
                                                 item_value,
                                                 key,
                                                 css_class)

            rendered_items.append(rendered_item)

        return rendered_items


class MultiListWidget(MultiItemsWidget):
    """List widget with multiple select."""
    property_names = Widget.property_names +\
                     ['items', 'size', 'extra']
    size = 5

    def render(self, ):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        rendered_items = self.render_items(field, key, value)

        return render_element('select',
                              name=key,
                              multiple=None,
                              css_class=field.get_value('css_class'),
                              size=field.get_value('size'),
                              contents=string.join(rendered_items, "\n"),
                              extra=field.get_value('extra'))
    
    def render_item(self, text, value, key, css_class):
        return render_element('option', contents=text, value=value)

    def render_selected_item(self, text, value, key, css_class):
        return render_element('option', contents=text, value=value,
                              selected=None)
    

class MultiCheckBoxWidget(MultiItemsWidget):
    """Multiple checkbox widget."""
    property_names = Widget.property_names +\
                     ['items', 'orientation']
    orientation = "vertical"
                                   
    def render(self):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        field = self.context
        rendered_items = self.render_items(field, key, value)
        orientation = field.get_value('orientation')
        if orientation == 'horizontal':
            return string.join(rendered_items, "&nbsp;&nbsp;")
        else:
            return string.join(rendered_items, "<br />")
    
    def render_item(self, text, value, key, css_class):
        return render_element('input',
                              type="checkbox",
                              css_class=css_class,
                              name=key,
                              value=value) + text
    
    def render_selected_item(self, text, value, key, css_class):
        return render_element('input',
                              type="checkbox",
                              css_class=css_class,
                              name=key,
                              value=value,
                              checked=None) + text


class PasswordWidget(TextWidget):
    """Password Widget"
    def render(self):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        field = self.context
        display_maxwidth = field.get_value('display_maxwidth') or 0
        if display_maxwidth > 0:
            return render_element("input",
                                  type="password",
                                  name=key,
                                  css_class=field.get_value('css_class'),
                                  value=value,
                                  size=field.get_value('display_width'),
                                  maxlength=display_maxwidth,
                                  extra=field.get_value('extra'))
        else:
            return render_element("input",
                                  type="password",
                                  name=key,
                                  css_class=field.get_value('css_class'),
                                  value=value,
                                  size=field.get_value('display_width'),
                                  extra=field.get_value('extra'))


class RadioWidget(SingleItemsWidget):
    """Radio buttons widget."""
    property_names = Widget.property_names +\
                     ['first_item', 'items', 'orientation']
    orientation = "vertical"
                                   
    def render(self):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        field = self.context
        rendered_items = self.render_items(field, key, value)
        orientation = field.get_value('orientation')
        if orientation == 'horizontal':
            return string.join(rendered_items, "&nbsp;&nbsp;")
        else:
            return string.join(rendered_items, "<br />")

    def render_item(self, text, value, key, css_class):
        return render_element('input',
                              type="radio",
                              css_class=css_class,
                              name=key,
                              value=value) + text
    
    def render_selected_item(self, text, value, key, css_class):
        return render_element('input',
                              type="radio",
                              css_class=css_class,
                              name=key,
                              value=value,
                              checked=None) + text


class SingleItemsWidget(ItemsWidget):
    """A widget with a number of items that has only a single
    selectable item."""
    default = ""
    first_item = 0    

    def render_items(self, field, key, value):
        # get items
        items = field.get_value('items')
    
        # check if we want to select first item
        if not value and field.get_value('first_item') and len(items) > 0:
            try:
                text, value = items[0]
            except ValueError:
                value = items[0]
                
        css_class = field.get_value('css_class')
        
        # FIXME: what if we run into multiple items with same value?
        rendered_items = []
        for item in items:
            try:
                item_text, item_value = item
            except ValueError:
                item_text = item
                item_value = item

            if item_value == value:
                rendered_item = self.render_selected_item(item_text,
                                                          item_value,
                                                          key,
                                                          css_class)
            else:
                rendered_item = self.render_item(item_text,
                                                 item_value,
                                                 key,
                                                 css_class)
                
            rendered_items.append(rendered_item)

        return rendered_items


class TextAreaWidget(BrowserWidget):
    """Textarea widget."""
    propertyNames = BrowserWidget.propertyNames +\
                     ['width', 'height', 'extra']
    
    default = ""
    width = 80
    height = 15
    extra=""
    
    def render(self):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        return renderElement("textarea",
                             name=self.context.id,
                             css_class=self.getValue('cssClass'),
                             cols=self.getValue('width'),
                             rows=self.getValue('height'),
                             contents=self._getValueToInsert(),
                             extra=self.getValue('extra'))


class TextWidget(BrowserWidget):
    """Text widget."""
    propertyNames = BrowserWidget.propertyNames + \
                     ['displayWidth', 'displayMaxWidth', 'extra', 'default']
    default = ''
    displayWidth = 20
    displayMaxWidth = ''
    extra = ''

    def render(self):
        'See Zope.App.Forms.Views.Browser.IBrowserWidget.IBrowserWidget'
        displayMaxWidth = self.getValue('displayMaxWidth') or 0
        if displayMaxWidth > 0:
            return renderElement(self.getValue('tag'),
                                 type = self.getValue('type'),
                                 name = self.context.id,
                                 value = self._getValueToInsert(REQUEST),
                                 cssClass = self.getValue('cssClass'),
                                 size = self.getValue('displayWidth'),
                                 maxlength = displayMaxWidth,
                                 extra = self.getValue('extra'))
        else:
            return renderElement(self.getValue('tag'),
                                 type = self.getValue('type'),
                                 name = self.context.id,
                                 value = self._getValueToInsert(REQUEST),
                                 cssClass = self.getValue('cssClass'),
                                 size = self.getValue('displayWidth'),
                                 extra = self.getValue('extra'))



def renderTag(tag, **kw):
    """Render the tag. Well, not all of it, as we may want to / it.
    """
    attr_list = []

    kw['name'] = 'field_' + kw['name']

    # special case handling for css_class
    if 'cssClass' in kw:
        if kw['cssClass'] != "":
            attr_list.append('class="%s"' % kw['cssClass'])
        del kw['cssClass']

    # special case handling for extra 'raw' code
    if 'extra' in kw:
        extra = kw['extra'] # could be empty string but we don't care
        del kw['extra']
    else:
        extra = ""

    # handle other attributes
    for key, value in kw.items():
        if value == None:
            value = key
        attr_list.append('%s="%s"' % (key, str(value)))
            
    attr_str = " ".join(attr_list)
    return "<%s %s %s" % (tag, attr_str, extra)


def renderElement(tag, **kw):
    if 'contents' in kw:
        contents = kw['contents']
        del kw['contents']
        return "%s>%s</%s>" % (apply(renderTag, (tag,), kw), contents, tag)
    else:
        return apply(renderTag, (tag,), kw) + " />"


=== Zope3/lib/python/Zope/App/Forms/Views/Browser/FormView.py 1.2 => 1.3 ===
+##############################################################################
+#
+# Copyright (c) 2002 Zope Corporation and Contributors.
+# All Rights Reserved.
+# 
+# This software is subject to the provisions of the Zope Public License,
+# Version 2.0 (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$
+"""
 from Zope.Publisher.Browser.BrowserView import BrowserView
 from Interface import Interface
 from Schema.IField import IField
 from Zope.ComponentArchitecture import getView
 import Schema
-from Schema import _Schema # XXX wire up, should really fix this :)
 
-class ITestSchema(Interface):
-    alpha = Schema.Str(title="Alpha")
-    beta = Schema.Bool(title="Beta")
-    
 class FormView(BrowserView):
     def getWidgetsForSchema(self, schema, view_name):
         """Given a schema and a desired field name, get a list of


=== Zope3/lib/python/Zope/App/Forms/Views/Browser/TextWidget.py 1.1 => 1.2 ===
 from Zope.Publisher.Browser.BrowserView import BrowserView
 
 class TextWidget(BrowserView):
+
     def render(self):
         return '<input type="text" name="%s" value="%s" />' %\
                (self.context.title, self.context.default)
 
-    


=== Zope3/lib/python/Zope/App/Forms/Views/Browser/configure.zcml 1.1 => 1.2 ===
   <!-- Form Widget View Directives -->
   <browser:view
       permission="Zope.View"
-      for="Schema.IField.IStr"
+      for="Schema.IField.IString"
       name="normal"
       factory=".TextWidget." />
 
   <browser:view
       permission="Zope.View"
-      for="Schema.IField.IBool"
+      for="Schema.IField.IBoolean"
       name="normal"
       factory=".CheckboxWidget." />