[Zope3-checkins] CVS: Zope3/src/zope/app/form/browser - objectwidget.pt:1.1.2.1 add.pt:1.3.2.1 interfaces.py:1.3.2.1 objectwidget.py:1.1.8.1 widget.py:1.8.2.1 widget_macros.pt:1.1.2.1

Martijn Faassen m.faassen at vet.uu.nl
Tue May 11 05:10:56 EDT 2004


Update of /cvs-repository/Zope3/src/zope/app/form/browser
In directory cvs.zope.org:/tmp/cvs-serv20906/src/zope/app/form/browser

Modified Files:
      Tag: faassen-interfaces-branch
	add.pt interfaces.py objectwidget.py widget.py 
	widget_macros.pt 
Added Files:
      Tag: faassen-interfaces-branch
	objectwidget.pt 
Log Message:
Sync up with changes in HEAD (so I can generate up to date patch file).


=== Added File Zope3/src/zope/app/form/browser/objectwidget.pt ===
<fieldset>
  <legend tal:content="context/legendTitle">The Legend</legend>
  <tal:block repeat="widget context/subwidgets">
    <metal:block use-macro="context/@@form_macros/widget_row" />
  </tal:block>
</fieldset>


=== Zope3/src/zope/app/form/browser/add.pt 1.3 => 1.3.2.1 ===
--- Zope3/src/zope/app/form/browser/add.pt:1.3	Thu May  6 11:46:05 2004
+++ Zope3/src/zope/app/form/browser/add.pt	Tue May 11 05:10:19 2004
@@ -51,7 +51,7 @@
                  i18n:attributes='value refresh-button' />
           <input type='submit' value='Add' name='UPDATE_SUBMIT'
                  i18n:attributes='value add-button' />
-	  <span tal:condition="context/nameAllowed" tal:omit-tag="">
+          <span tal:condition="context/nameAllowed|nothing" tal:omit-tag="">
                &nbsp;&nbsp;<b i18n:translate="">Object Name</b>&nbsp;&nbsp;    
               <input type='text' name='add_input_name'
                      tal:attributes="value context/contentName" /> 


=== Zope3/src/zope/app/form/browser/interfaces.py 1.3 => 1.3.2.1 ===
--- Zope3/src/zope/app/form/browser/interfaces.py:1.3	Sat Apr 24 19:19:42 2004
+++ Zope3/src/zope/app/form/browser/interfaces.py	Tue May 11 05:10:19 2004
@@ -18,7 +18,7 @@
 from zope.app.form.interfaces import IWidget
 
 class IAddFormCustomization(Interface):
-    """This interface defined methods of add forms that can be overridden
+    """API for add form customization.
 
     Classes supplied when defining add forms may need to override some
     of these methods.
@@ -39,7 +39,6 @@
         content = <create the content from the data>
         content = self.add(content) # content wrapped in some context
         <set after-add attributes on content>
-
     """
 
     def createAndAdd(data):
@@ -54,7 +53,7 @@
         """
 
     def add(content):
-        """Add the given content
+        """Add the given content.
 
         This method is overridden when the context of the add form is
         not an IAdding.  In this case, the class that customizes the
@@ -76,40 +75,22 @@
         i.e. it delegates to the IAdding view.
         """
 
-
 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.
-    """
+    """A widget for use in a web browser UI."""
 
-    def __call__(): # XXX promote to IWidget?
-        """Render the widget
-        """
+    def __call__():
+        """Render the widget."""
 
     def hidden():
-        """Render the widget as a hidden field
-        """
-
-    def label():
-        """Render a label tag"""
+        """Render the widget as a hidden field."""
 
-    def error(): # XXX promote to IWidget?
+    def error():
         """Render the validation error for the widget, or return
         an empty string if no error"""
 
-    def row():
-        """Render the widget as two or three div elements,
-           for the label, the field and possibly the validation error
-
-        For example:
-          <div class="label">label</div><div class="field">field</div>
-          <div class="error">Validation error message</div>
-        """
-
 
 class IFormCollaborationView(Interface):
-    """Views that collaborate to create a single form
+    """Views that collaborate to create a single form.
 
     When a form is applied, the changes in the form need to
     be applied to individual views, which update objects as
@@ -134,8 +115,7 @@
         """
 
     def update():
-        """Update the form with data from the request.
-        """
+        """Update the form with data from the request."""
 
 
 class IVocabularyQueryView(Interface):


=== Zope3/src/zope/app/form/browser/objectwidget.py 1.1 => 1.1.8.1 ===
--- Zope3/src/zope/app/form/browser/objectwidget.py:1.1	Wed Mar 17 12:35:02 2004
+++ Zope3/src/zope/app/form/browser/objectwidget.py	Tue May 11 05:10:19 2004
@@ -21,7 +21,21 @@
 from zope.app.form.interfaces import IInputWidget
 from zope.app.form.browser.widget import BrowserWidget
 from zope.app.form.utility import setUpEditWidgets, applyWidgetsChanges
+from zope.app.pagetemplate.viewpagetemplatefile import ViewPageTemplateFile
 
+
+class ObjectWidgetView:
+
+    template = ViewPageTemplateFile('objectwidget.pt')
+    
+    def __init__(self, context, request):
+        self.context = context
+        self.request = request
+        
+    def __call__(self):
+        return self.template()
+    
+    
 class ObjectWidget(BrowserWidget):
     """A widget over an Interface that contains Fields.
 
@@ -38,6 +52,9 @@
 
     def __init__(self, context, request, factory, **kw):
         super(ObjectWidget, self).__init__(context, request)
+        
+        # define view that renders the widget
+        self.view = ObjectWidgetView(self, request)
 
         # factory used to create content that this widget (field)
         # represents
@@ -63,33 +80,23 @@
                          context=self.context)
 
     def __call__(self):
-        """Render the widget
-        """
-        render = []
-
-        # XXX see if there's some widget layout already
-
-        # generate each widget from fields in the schema
-        field = self.context
-        title = field.title or field.__name__
-        render.append('<fieldset><legend>%s</legend>'%title)
-        for name, widget in self.getSubWidgets():
-            render.append(widget.row())
-        render.append('</fieldset>')
-
-        return '\n'.join(render)
-
-    def getSubWidgets(self):
-        l = []
-        for name in self.names:
-            l.append((name, getattr(self, '%s_widget'%name)))
-        return l
+        return self.view()
+        
+    def legendTitle(self):
+        return self.context.title or self.context.__name__
+
+    def getSubWidget(self, name):
+        return getattr(self, '%s_widget' % name)
+            
+    def subwidgets(self):
+        return [self.getSubWidget(name) for name in self.names]
 
     def hidden(self):
-        ''' Render the list as hidden fields '''
-        for name, widget in self.getSubWidgets():
-            s += widget.hidden()
-        return s
+        """Render the list as hidden fields."""
+        result = []
+        for name in self.names:
+            result.append(getSubwidget(name).hidden())
+        return "".join(result)
 
     def getInputValue(self):
         """Return converted and validated widget data.
@@ -101,8 +108,8 @@
         does this).
         """
         content = self.factory()
-        for name, widget in self.getSubWidgets():
-            setattr(content, name, widget.getInputValue())
+        for name in self.names:
+            setattr(content, name, self.getSubWidget(name).getInputValue())
         return content
 
     def applyChanges(self, content):
@@ -130,8 +137,8 @@
 
         Return True if there is data and False otherwise.
         """
-        for name, widget in self.getSubWidgets():
-            if widget.hasInput():
+        for name in self.names:
+            if self.getSubWidget(name).hasInput():
                 return True
         return False
 
@@ -143,7 +150,7 @@
         """
         # re-call setupwidgets with the content
         self._setUpEditWidgets()
-        for name, widget in self.getSubWidgets():
-            widget.setRenderedValue(getattr(value, name, None))
+        for name in self.names:
+            self.getSubWidget(name).setRenderedValue(getattr(value, name, None))
             
 


=== Zope3/src/zope/app/form/browser/widget.py 1.8 => 1.8.2.1 ===
--- Zope3/src/zope/app/form/browser/widget.py:1.8	Sat Apr 24 19:19:42 2004
+++ Zope3/src/zope/app/form/browser/widget.py	Tue May 11 05:10:19 2004
@@ -38,94 +38,123 @@
     labels, titles, and descriptions are translated and the
     errors are rendered with the view machinery, so we need to set up
     a lot of machinery to support translation and views:
-        
-    >>> setUp() # now we have to set up an error view...
-    >>> from zope.app.form.interfaces import IWidgetInputError
-    >>> from zope.app.publisher.browser import BrowserView
-    >>> from cgi import escape
-    >>> class SnippetErrorView(BrowserView):
-    ...     implements(IWidgetInputErrorView)
-    ...     def snippet(self):
-    ...         return escape(self.context.errors[0])
-    ...
-    >>> ztapi.browserViewProviding(IWidgetInputError, SnippetErrorView,
-    ...                            IWidgetInputErrorView)
-    >>> from zope.publisher.browser import TestRequest
-
-    And now the tests proper...
-
-    >>> from zope.schema import Field
-    >>> import re
-    >>> isFriendly=re.compile(".*hello.*").match
-    >>> field = Field(__name__='foo', title=u'Foo', constraint=isFriendly)
-    >>> request = TestRequest(form={
-    ... 'field.foo': u'hello\\r\\nworld',
-    ... 'baz.foo': u'bye world'})
-    >>> widget = BrowserWidget(field, request)
-    >>> widget.name
-    'field.foo'
-    >>> widget.title
-    u'Foo'
-    >>> widget.hasInput()
-    True
-    >>> widget.getInputValue()
-    u'hello\\r\\nworld'
-    >>> widget.required
-    True
-    >>> widget._error is None
-    True
-    >>> widget.error()
-    ''
-    >>> widget.setRenderedValue('Hey\\nfolks')
-    >>> widget.getInputValue()
-    u'hello\\r\\nworld'
-    >>> widget._error is None
-    True
-    >>> widget.error()
-    ''
-
-    >>> widget.setPrefix('baz')
-    >>> widget.name
-    'baz.foo'
-    >>> widget.error()
-    ''
-    >>> try:
-    ...     widget.getInputValue()
-    ... except WidgetInputError:
-    ...     print widget._error.errors
-    bye world
-    >>> widget.error()
-    u'bye world'
-    >>> widget._error = None # clean up for next round of tests
-
-    >>> widget.setPrefix('test')
-    >>> widget.name
-    'test.foo'
-    >>> widget._error is None
-    True
-    >>> widget.error()
-    ''
-    >>> widget.hasInput()
-    False
-    >>> widget.getInputValue()
-    Traceback (most recent call last):
-    ...
-    MissingInputError: ('test.foo', u'Foo', None)
-    >>> field.required = False
-    >>> widget.request.form['test.foo'] = u''
-    >>> widget.required
-    False
-    >>> widget.getInputValue() == field.missing_value
-    True
-    >>> widget._error is None
-    True
-    >>> widget.error()
-    ''
 
-    >>> print widget.label()
-    <label for="test.foo">Foo</label>
-
-    Now we clean up.
+	  >>> setUp() # now we have to set up an error view...
+	  >>> from zope.app.form.interfaces import IWidgetInputError
+	  >>> from zope.app.publisher.browser import BrowserView
+	  >>> from cgi import escape
+	  >>> class SnippetErrorView(BrowserView):
+	  ...     implements(IWidgetInputErrorView)
+	  ...     def snippet(self):
+	  ...         return escape(self.context.errors[0])
+	  ...
+	  >>> ztapi.browserViewProviding(IWidgetInputError, SnippetErrorView,
+	  ...                            IWidgetInputErrorView)
+	  >>> from zope.publisher.browser import TestRequest
+	
+	  >>> from zope.schema import Field
+	  >>> import re
+	  >>> isFriendly=re.compile(".*hello.*").match
+	  >>> field = Field(__name__='foo', title=u'Foo', constraint=isFriendly)
+	  >>> request = TestRequest(form={
+	  ...     'field.foo': u'hello\\r\\nworld',
+	  ...     'baz.foo': u'bye world'})
+	  >>> widget = BrowserWidget(field, request)
+
+    Widgets are named using their field's name:
+
+      >>> widget.name
+      'field.foo'
+
+    The default implementation for the widget label is to use the field title:
+
+      >>> widget.label
+      u'Foo'
+
+    According the request, the widget has input because 'field.foo' is
+    present:
+
+      >>> widget.hasInput()
+      True
+      >>> widget.getInputValue()
+      u'hello\\r\\nworld'
+
+    Widgets maintain an error state, which is used to communicate invalid
+    input or other errors:
+
+      >>> widget._error is None
+      True
+      >>> widget.error()
+      ''
+
+    setRenderedValue is used to specify the value displayed by the widget to
+    the user. This value, however, is not the same as the input value, which
+    is read from the request:
+
+      >>> widget.setRenderedValue('Hey\\nfolks')
+      >>> widget.getInputValue()
+      u'hello\\r\\nworld'
+      >>> widget._error is None
+      True
+      >>> widget.error()
+      ''
+
+    You can modify the prefix used to create the widget name as follows:
+
+      >>> widget.setPrefix('baz')
+      >>> widget.name
+      'baz.foo'
+
+    The modification of the widget's name changes the input the widget reads
+    from the request. Instead of reading input from 'field.foo', the widget
+    now reads input from 'baz.foo'. In this case, the input from 'baz.foo'
+    (see request above) violates the isFriendly constraint on field 'foo':
+
+      >>> widget.error()
+      ''
+      >>> try:
+      ...     widget.getInputValue()
+      ... except WidgetInputError:
+      ...     print widget._error.errors
+      bye world
+      >>> widget.error()
+      u'bye world'
+      >>> widget._error = None # clean up for next round of tests
+
+    Changing the widget prefix/name, again, changes the input the widget uses
+    from the request:
+
+      >>> widget.setPrefix('test')
+      >>> widget.name
+      'test.foo'
+      >>> widget._error is None
+      True
+      >>> widget.error()
+      ''
+      >>> widget.hasInput()
+      False
+      >>> widget.getInputValue()
+      Traceback (most recent call last):
+      ...
+      MissingInputError: ('test.foo', u'Foo', None)
+
+    Whether or not the widget requires input depends on its field's required
+    attribute:
+
+      >>> field.required
+      True
+      >>> widget.required
+      True
+      >>> field.required = False
+      >>> widget.request.form['test.foo'] = u''
+      >>> widget.required
+      False
+      >>> widget.getInputValue() == field.missing_value
+      True
+      >>> widget._error is None
+      True
+      >>> widget.error()
+      ''
 
     >>> tearDown()
     """
@@ -138,7 +167,7 @@
     extra = u''
     _missing = u''
     _error = None
-    
+
     required = property(lambda self: self.context.required)
 
     def hasInput(self):
@@ -170,7 +199,7 @@
         # form input is required, otherwise raise an error
         input = self.request.form.get(self.name)
         if input is None:
-            raise MissingInputError(self.name, self.title, None)
+            raise MissingInputError(self.name, self.label, None)
 
         # convert input to suitable value - may raise conversion error
         value = self._convert(input)
@@ -184,7 +213,7 @@
             field.validate(value)
         except ValidationError, v:
             self._error = WidgetInputError(
-                self.context.__name__, self.title, v)
+                self.context.__name__, self.label, v)
             raise self._error
         return value
 
@@ -247,8 +276,7 @@
         return self._unconvert(value)
 
     def _getDefault(self):
-        # Return the default value for this widget;
-        # may be overridden by subclasses.
+        """Return the default value for this widget."""
         return self.context.default
 
     def __call__(self):
@@ -282,37 +310,18 @@
         self.setRenderedValue(value)
         return self.hidden()
 
-    def label(self):
-        kw = {"for": self.name,
-              "contents": cgi.escape(self.title)}
-        if self.context.description:
-            kw["title"] = self.context.description
-        return renderElement("label", **kw)
-
     def error(self):
         if self._error:
             return zapi.getViewProviding(self._error, IWidgetInputErrorView,
                                          self.request).snippet()
         return ""
 
-    def labelClass(self):
-        return self.context.required and "label required" or "label"
 
-    def row(self):
-        if self._error:
-            return u'<div class="%s">%s</div><div class="field">%s</div>' \
-                   u'<div class="error">%s</div>' % (self.labelClass(),
-                                                     self.label(), self(),
-                                                     self.error())
-        else:
-            return u'<div class="%s">%s</div><div class="field">%s</div>' % (
-                self.labelClass(), self.label(), self())
-                
 class DisplayWidget(BrowserWidget):
 
     def __call__(self):
         return self._showData()
-        
+
 # XXX Note, some HTML quoting is needed in renderTag and renderElement.
 def renderTag(tag, **kw):
     """Render the tag. Well, not all of it, as we may want to / it."""
@@ -374,14 +383,14 @@
         return u"%s>%s</%s>" % (renderTag(tag, **kw), contents, tag)
     else:
         return renderTag(tag, **kw) + " />"
-        
+
 
 def setUp():
     import zope.app.tests.placelesssetup
     global setUp
     setUp = zope.app.tests.placelesssetup.setUp
     setUp()
-    
+
 
 def tearDown():
     import zope.app.tests.placelesssetup


=== Zope3/src/zope/app/form/browser/widget_macros.pt 1.1 => 1.1.2.1 ===
--- Zope3/src/zope/app/form/browser/widget_macros.pt:1.1	Mon May  3 22:01:24 2004
+++ Zope3/src/zope/app/form/browser/widget_macros.pt	Tue May 11 05:10:19 2004
@@ -2,14 +2,20 @@
   <body>
     <metal:block define-macro="widget_rows">
       <div class="row" tal:repeat="widget view/widgets">
-        <div class="label" tal:content="structure widget/label">Name</div>
-        <div class="field" tal:content="structure widget">
-          <input type="text" style="width:100%"/>
-        </div>
-        <div class="error" tal:define="error widget/error"
-          tal:condition="error" tal:content="structure error">
-          The Error
-        </div>
+        <metal:block define-macro="widget_row">
+          <div class="label">
+            <label for="field.name" title="The widget's hint"
+              tal:attributes="for widget/name; title widget/hint"
+              tal:content="widget/label">The Label</label>
+          </div>
+          <div class="field" tal:content="structure widget">
+            <input type="text" style="width:100%"/>
+          </div>
+          <div class="error" tal:define="error widget/error"
+            tal:condition="error" tal:content="structure error">
+            The Error
+          </div>
+        </metal:block>
       </div>
     </metal:block>
   </body>




More information about the Zope3-Checkins mailing list