Skip to content

Commit

Permalink
- Added IField.showDefault and IWidget.showDefault
Browse files Browse the repository at this point in the history
  That controls whether the widget should look for field default values
  to display. This can be really helpful in EditForms, where you don't
  want to have default values instead of actual (missing) values.
  By default it is True to provide backwards compatibility.
  • Loading branch information
Adam Groszer committed Jul 11, 2012
1 parent 36891d2 commit 79b1871
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 11 deletions.
6 changes: 6 additions & 0 deletions CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ CHANGES

- Avoid dependency on ZODB3.

- Added IField.showDefault and IWidget.showDefault
That controls whether the widget should look for field default values
to display. This can be really helpful in EditForms, where you don't
want to have default values instead of actual (missing) values.
By default it is True to provide backwards compatibility.

2.6.1 (2012-01-30)
------------------

Expand Down
9 changes: 5 additions & 4 deletions src/z3c/form/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import zope.location
import zope.schema.interfaces

from z3c.form import interfaces, util, error
from z3c.form import interfaces, util
from z3c.form.error import MultipleErrors
from z3c.form.widget import AfterWidgetUpdateEvent

Expand Down Expand Up @@ -67,7 +67,7 @@ class Field(object):
widgetFactory = WidgetFactoryProperty()

def __init__(self, field, name=None, prefix='', mode=None, interface=None,
ignoreContext=None):
ignoreContext=None, showDefault=None):
self.field = field
if name is None:
name = field.__name__
Expand All @@ -79,6 +79,7 @@ def __init__(self, field, name=None, prefix='', mode=None, interface=None,
interface = field.interface
self.interface = interface
self.ignoreContext = ignoreContext
self.showDefault = showDefault

def __repr__(self):
return '<%s %r>' % (self.__class__.__name__, self.__name__)
Expand Down Expand Up @@ -138,7 +139,6 @@ def __init__(self, *args, **kw):
self._data_keys.append(name)
self._data[name] = form_field


def select(self, *names, **kwargs):
"""See interfaces.IFields"""
prefix = kwargs.pop('prefix', None)
Expand All @@ -153,7 +153,6 @@ def select(self, *names, **kwargs):
if field.field.interface is interface])
return self.__class__(*[mapping[name] for name in names])


def omit(self, *names, **kwargs):
"""See interfaces.IFields"""
prefix = kwargs.pop('prefix', None)
Expand Down Expand Up @@ -269,6 +268,8 @@ def update(self):
# Step 6: Set some variables
widget.ignoreContext = ignoreContext
widget.ignoreRequest = self.ignoreRequest
if field.showDefault is not None:
widget.showDefault = field.showDefault
# Step 7: Set the mode of the widget
widget.mode = mode
# Step 8: Update the widget
Expand Down
45 changes: 41 additions & 4 deletions src/z3c/form/field.txt
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,21 @@ constructor that are used to set up the fields:
>>> manager['country'].ignoreContext
False

* ``showDefault``

The ``showDefault`` can be set on fields.

>>> manager = field.Fields(IPerson)
>>> manager['country'].showDefault

>>> manager = field.Fields(IPerson, showDefault=True)
>>> manager['country'].showDefault
True

>>> manager = field.Fields(IPerson, showDefault=False)
>>> manager['country'].showDefault
False


Fields Widget Manager
---------------------
Expand All @@ -330,12 +345,12 @@ definitions and create widgets for them. Thus, let's create a schema first:

>>> class LastNameTooShort(zope.schema.interfaces.ValidationError):
... """The last name is too short."""

>>> def lastNameConstraint(value):
... if value and value == value.lower():
... raise zope.interface.Invalid(u"Name must have at least one capital letter")
... return True

>>> class IPerson(zope.interface.Interface):
... id = zope.schema.TextLine(
... title=u'ID',
Expand Down Expand Up @@ -628,6 +643,28 @@ this selection for you:
'input'


``showDefault``
---------------

``showDefault`` by default is True

>>> manager['firstName'].showDefault
True

``showDefault`` gets set on the widget based on the field's setting.

>>> personForm.fields['firstName'].showDefault = False

>>> manager.update()
>>> manager['firstName'].showDefault
False

>>> personForm.fields['firstName'].showDefault = True

>>> manager.update()
>>> manager['firstName'].showDefault
True

Required fields
---------------

Expand Down Expand Up @@ -735,7 +772,7 @@ a convenient way to raise errors where we mainly care about providing a custom
error message.

>>> request = TestRequest(form={
... 'form.widgets.firstName': u'Stephan',
... 'form.widgets.firstName': u'Stephan',
... 'form.widgets.lastName': u'richter',
... 'form.widgets.id': u'srichter'})
>>> manager = field.FieldWidgets(personForm, request, context)
Expand All @@ -744,7 +781,7 @@ error message.
>>> extracted = manager.extract()
>>> extracted
({'firstName': u'Stephan'}, (<InvalidErrorViewSnippet for Invalid>,))

>>> extracted[1][0].createMessage()
u'Name must have at least one capital letter'

Expand Down
14 changes: 14 additions & 0 deletions src/z3c/form/interfaces.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,13 @@ class IField(zope.interface.Interface):
default=None,
missing_value=None)

showDefault = zope.schema.Bool(
title=_('Show default value'),
description=_('A flag, when set, makes the widget to display'
'field|adapter provided default values.'),
default=True,
required=False)


class IFields(ISelectionManager):
"""IField manager."""
Expand Down Expand Up @@ -436,6 +443,13 @@ class IWidget(ILocation):
default=True,
required=False)

showDefault = zope.schema.Bool(
title=_('Show default value'),
description=_('A flag, when set, makes the widget to display'
'field|adapter provided default values.'),
default=True,
required=False)

def extract(default=NO_VALUE):
"""Extract the string value(s) of the widget from the form.
Expand Down
7 changes: 5 additions & 2 deletions src/z3c/form/widget.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class Widget(zope.location.Location):
template = None
ignoreRequest = FieldProperty(interfaces.IWidget['ignoreRequest'])
setErrors = FieldProperty(interfaces.IWidget['setErrors'])
showDefault = FieldProperty(interfaces.IWidget['showDefault'])

# The following attributes are for convenience. They are declared in
# extensions to the simple widget.
Expand Down Expand Up @@ -106,12 +107,14 @@ def update(self):
# that requires fixing zope.schema first
if ((value is self.field.missing_value or
value is interfaces.NO_VALUE) and
self.field.default is not None):
self.field.default is not None and
self.showDefault):
value = self.field.default
lookForDefault = True
# Step 1.3: If we still have not found a value, then we try to get it
# from an attribute value
if value is interfaces.NO_VALUE or lookForDefault:
if ((value is interfaces.NO_VALUE or lookForDefault)
and self.showDefault):
adapter = zope.component.queryMultiAdapter(
(self.context, self.request, self.form, self.field, self),
interfaces.IValue, name='default')
Expand Down
23 changes: 22 additions & 1 deletion src/z3c/form/widget.txt
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,9 @@ be set as the context of the widget:

>>> class Person(object):
... age = 45
>>> person = Person()

>>> ageWidget.context = Person()
>>> ageWidget.context = person
>>> zope.interface.alsoProvides(ageWidget, interfaces.IContextAware)

The result is that the context value takes over precendence over the default
Expand All @@ -250,6 +251,26 @@ the context. Registering a data manager for the widget does the trick:
>>> print ageWidget.render()
<input type="text" name="age" value="45" />

If the context value is unknown (None), the default value kicks in.

>>> person.age = None

>>> ageWidget.update()
>>> print ageWidget.render()
<input type="text" name="age" value="30" />

Unless the widget is explicitely asked to not to show defaults.
This is handy for EditForms.

>>> ageWidget.showDefault = False

>>> ageWidget.update()
>>> print ageWidget.render()
<input type="text" name="age" value="" />

>>> ageWidget.showDefault = True
>>> person.age = 45

The context can be explicitely ignored, making the widget display the default
value again:

Expand Down

0 comments on commit 79b1871

Please sign in to comment.