[Zope3-checkins] CVS: Zope3/src/zope/app/browser/form - add.pt:1.7 addwizard.pt:1.2 addwizard.py:1.3 edit.pt:1.9 editwizard.pt:1.3 editwizard.py:1.5 meta.zcml:1.16 widget.py:1.40
Stuart Bishop
zen@shangri-la.dropbear.id.au
Mon, 14 Jul 2003 11:28:59 -0400
Update of /cvs-repository/Zope3/src/zope/app/browser/form
In directory cvs.zope.org:/tmp/cvs-serv24906/src/zope/app/browser/form
Modified Files:
add.pt addwizard.pt addwizard.py edit.pt editwizard.pt
editwizard.py meta.zcml widget.py
Log Message:
- Make Widget validation errors humanly readable, it a half-arsed sort of way.
Widgets have spawned an 'error' attribute, set by getData.
- Display validation errors next to the dud input in Widget.row()
- Make description a tooltip of a Widget's label. This is currently done
by abusing the <acronym> tag.
- addwizard and editwizard work again with the recent editview changes
=== Zope3/src/zope/app/browser/form/add.pt 1.6 => 1.7 ===
--- Zope3/src/zope/app/browser/form/add.pt:1.6 Wed Jun 25 14:43:04 2003
+++ Zope3/src/zope/app/browser/form/add.pt Mon Jul 14 11:28:23 2003
@@ -19,15 +19,11 @@
tal:condition="status"
tal:content="status" />
- <div tal:condition="view/errors">
- <ul>
- <li tal:repeat="error view/errors">
- <strong tal:content="error/__class__" i18n:translate="">
- Error Type</strong>:
- <span tal:content="error">Error text</span>
- </li>
- </ul>
- </div>
+ <p tal:condition="view/errors">
+ <span i18n:translate="">There are</span>
+ <strong tal:content="python:len(view.errors)">6</strong>
+ <span i18n:translate="">input errors.</span>
+ </p>
<div metal:define-slot="extra_info" tal:replace="nothing">
</div>
=== Zope3/src/zope/app/browser/form/addwizard.pt 1.1 => 1.2 ===
--- Zope3/src/zope/app/browser/form/addwizard.pt:1.1 Sun Jul 13 00:05:58 2003
+++ Zope3/src/zope/app/browser/form/addwizard.pt Mon Jul 14 11:28:23 2003
@@ -40,6 +40,7 @@
tal:content="structure widget/row">
<div class="label">Name</div>
<div class="field"><input type="text" style="width:100%" /></div>
+ <div class="error">Error message</div>
</div>
<div class="row"
metal:define-slot="extra_bottom" tal:replace="nothing">
=== Zope3/src/zope/app/browser/form/addwizard.py 1.2 => 1.3 ===
--- Zope3/src/zope/app/browser/form/addwizard.py:1.2 Sun Jul 13 00:47:35 2003
+++ Zope3/src/zope/app/browser/form/addwizard.py Mon Jul 14 11:28:23 2003
@@ -99,7 +99,7 @@
publish(self.context, ObjectCreatedEvent(content))
- content = self.add(content)
+ content = self.context.add(content)
adapted = getAdapter(content, self.schema)
@@ -117,10 +117,6 @@
self.request.response.redirect(self.context.nextURL())
return False
- def add(self, content):
- # Cut & Paste from add.py
- return self.context.add(content)
-
def AddWizardViewFactory(
name, schema, permission, layer, panes, fields,
@@ -161,7 +157,7 @@
layer='default', template=None,
for_='zope.app.interfaces.container.IAdding', class_=None,
arguments='',keyword_arguments='', set_before_add='', set_after_add='',
- menu=None, title=None, use_session='yes'
+ menu=None, description='', title=None, use_session='yes'
):
self.name = name
@@ -187,7 +183,7 @@
"they must both be specified")
actions = menuItemDirective(
_context, menu, for_, '@@' + name, title,
- permission=permission)
+ permission=permission, description=description)
else:
actions = []
=== Zope3/src/zope/app/browser/form/edit.pt 1.8 => 1.9 ===
--- Zope3/src/zope/app/browser/form/edit.pt:1.8 Thu Apr 10 02:17:34 2003
+++ Zope3/src/zope/app/browser/form/edit.pt Mon Jul 14 11:28:23 2003
@@ -20,15 +20,11 @@
tal:condition="status"
tal:content="status" />
- <div tal:condition="view/errors">
- <ul>
- <li tal:repeat="error view/errors">
- <strong tal:content="error/__class__" i18n:translate="">
- Error Type</strong>:
- <span tal:content="error">Error text</span>
- </li>
- </ul>
- </div>
+ <p tal:condition="view/errors">
+ <span i18n:translate="">There are</span>
+ <strong tal:content="python:len(view.errors)">6</strong>
+ <span i18n:translate="">input errors.</span>
+ </p>
<div metal:define-slot="extra_info" tal:replace="nothing">
</div>
=== Zope3/src/zope/app/browser/form/editwizard.pt 1.2 => 1.3 ===
--- Zope3/src/zope/app/browser/form/editwizard.pt:1.2 Sun Jul 13 00:05:58 2003
+++ Zope3/src/zope/app/browser/form/editwizard.pt Mon Jul 14 11:28:23 2003
@@ -17,16 +17,6 @@
<p tal:condition="view/feedback" tal:content="view/feedback" />
- <div tal:condition="view/errors">
- <ul>
- <li tal:repeat="error view/errors">
- <strong tal:content="error/__class__" i18n:translate="">
- Error Type</strong>:
- <span tal:content="error">Error text</span>
- </li>
- </ul>
- </div>
-
<div metal:define-slot="extra_info" tal:replace="nothing">
</div>
=== Zope3/src/zope/app/browser/form/editwizard.py 1.4 => 1.5 ===
--- Zope3/src/zope/app/browser/form/editwizard.py:1.4 Sun Jul 13 00:47:35 2003
+++ Zope3/src/zope/app/browser/form/editwizard.py Mon Jul 14 11:28:23 2003
@@ -31,7 +31,8 @@
from zope.security.checker import defineChecker, NamesChecker
from zope.app.context import ContextWrapper
from zope.component.view import provideView
-from zope.app.form.utility import setUpEditWidgets, getWidgetsData
+from zope.app.form.utility \
+ import setUpEditWidgets, getWidgetsData, applyWidgetsChanges
from zope.app.interfaces.form import WidgetInputError
from submit import Next, Previous, Update
from zope.app.interfaces.form import WidgetsError
@@ -111,7 +112,7 @@
else:
# First page
self._current_pane_idx = 0
- self.errors = []
+ self.errors = {}
self.label = self.currentPane().label
self._choose_buttons()
return
@@ -126,8 +127,11 @@
self, self.schema, strict=True, set_missing=True,
names=names, exclude_readonly=True
)
- self.errors = []
+ self.errors = {}
except WidgetsError, errors:
+ errors = {}
+ for k, label, msg in errors:
+ errors[k] = msg
self.errors = errors
else:
@@ -167,6 +171,15 @@
self.show_next = (self._current_pane_idx < len(self.panes) - 1)
self.show_previous = self._current_pane_idx > 0
+
+ def apply_update(self, storage):
+ ''' Save changes to our content object '''
+ for k,v in storage.items():
+ getattr(self,k).setData(v)
+ return not applyWidgetsChanges(
+ self, self.adapted, self.schema,
+ names=self.fieldNames, exclude_readonly=True
+ )
def renderHidden(self):
''' Render state as hidden fields. Also render hidden fields to
=== Zope3/src/zope/app/browser/form/meta.zcml 1.15 => 1.16 ===
--- Zope3/src/zope/app/browser/form/meta.zcml:1.15 Mon Jul 14 05:07:08 2003
+++ Zope3/src/zope/app/browser/form/meta.zcml Mon Jul 14 11:28:23 2003
@@ -136,6 +136,16 @@
</description>
</attribute>
+ <attribute name="description" required="no">
+ <description>
+ A longer description of the add form.
+
+ A UI may display this with the item or display it when the
+ user requests more assistance.
+ </description>
+ </attribute>
+
+
<attribute name="use_session" required="no">
<description>
If 'no', hidden input controls are used to maintain state
=== Zope3/src/zope/app/browser/form/widget.py 1.39 => 1.40 ===
--- Zope3/src/zope/app/browser/form/widget.py:1.39 Sun Jul 13 03:57:43 2003
+++ Zope3/src/zope/app/browser/form/widget.py Mon Jul 14 11:28:23 2003
@@ -37,6 +37,7 @@
from zope.app.datetimeutils import DateTimeError
from zope.schema import getFieldNamesInOrder
from zope.schema.interfaces import ValidationError
+from zope.schema.errornames import RequiredMissing
ListTypes = list, tuple
@@ -59,23 +60,34 @@
u'hello\\r\\nworld'
>>> int(widget.required)
1
+ >>> widget.error is None
+ 1
>>> widget.setData('Hey\\nfolks')
>>> widget.getData()
u'hello\\r\\nworld'
+ >>> widget.error is None
+ 1
>>> widget.setPrefix('test')
>>> widget.name
'test.foo'
+ >>> widget.error is None
+ 1
>>> int(widget.haveData())
0
>>> widget.getData()
Traceback (most recent call last):
...
- MissingInputError: ('foo', u'Foo', 'the field is required')
+ MissingInputError: ('foo', u'Foo', u'Input is required')
+ >>> widget.error is not None
+ 1
>>> field.required = False
>>> int(widget.required)
0
- >>> widget.getData()
+ >>> widget.getData() is None
+ 1
+ >>> widget.error is None
+ 1
When we generate labels, the labels are translated, so we need to set up
a lot of machinery to support translation:
@@ -97,6 +109,7 @@
cssClass = ''
extra = ''
_missing = None
+ error = None
def haveData(self):
if self.name in self.request.form:
@@ -106,11 +119,14 @@
def getData(self, optional=0):
field = self.context
value = self.request.form.get(self.name, self) # self used as marker
+ self.error = None
if value is self:
# No user input
if field.required and not optional:
- raise MissingInputError(field.__name__, field.title,
- 'the field is required')
+ self.error = MissingInputError(
+ field.__name__, field.title, RequiredMissing
+ )
+ raise self.error
return field.default
value = self._convert(value)
@@ -118,9 +134,9 @@
try:
field.validate(value)
except ValidationError, v:
- raise WidgetInputError(self.context.__name__,
- self.title, str(v))
-
+ self.error = WidgetInputError(self.context.__name__,
+ self.title, v)
+ raise self.error
return value
def validate(self):
@@ -196,14 +212,27 @@
title = ts.translate(self.title, "zope", context=self.request)
if title is None:
title = self.title
- return '<label for="%s">%s</label>' % (
- self.name,
- title,
- )
+ # TODO: Use a JavaScript tooltip instead of an abuse of the
+ # acronym HTML tag.
+ desc = self.context.description
+ if desc:
+ return '<label for="%s"><acronym title="%s">%s</acronym></label>'%(
+ self.name, desc, title,
+ )
+ else:
+ return '<label for="%s">%s</label>' % (
+ self.name, title,
+ )
def row(self):
- return '<div class="label">%s</div><div class="field">%s</div>' % (
- self.label(), self())
+ if self.error:
+ error = zapi.getView(self.error, 'snippet', self.request)()
+ return '<div class="label">%s</div><div class="field">%s</div>' \
+ '<div class="error">%s</div>' % (self.label(), self(), error)
+ else:
+ return '<div class="label">%s</div><div class="field">%s</div>' % (
+ self.label(), self()
+ )
class DisplayWidget(BrowserWidget):