Skip to content

Commit

Permalink
Backport for fix of #721
Browse files Browse the repository at this point in the history
  • Loading branch information
Jacob Holm committed Dec 20, 2006
1 parent 241572e commit f3ddeaa
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 25 deletions.
62 changes: 37 additions & 25 deletions form.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@

_identifier = re.compile('[A-Za-z][a-zA-Z0-9_]*$')

def expandPrefix(prefix):
"""Expand prefix string by adding a trailing period if needed.
expandPrefix(p) should be used instead of p+'.' in most contexts.
"""
if prefix and not prefix.endswith('.'):
return prefix + '.'
return prefix

class FormField:

interface.implements(interfaces.IFormField)
Expand All @@ -62,9 +71,7 @@ def __init__(self, field, name=None, prefix='',
if name is None:
name = field.__name__
assert name
if prefix:
name = prefix + '.' + name
self.__name__ = name
self.__name__ = expandPrefix(prefix) + name
self.prefix = prefix
self.for_display = for_display
self.for_input = for_input
Expand Down Expand Up @@ -166,12 +173,23 @@ class Widgets(object):

interface.implements(interfaces.IWidgets)

def __init__(self, widgets, prefix_length):
def __init__(self, widgets, prefix_length=None, prefix=None):
self.__Widgets_widgets_items__ = widgets
self.__Widgets_widgets_list__ = [w for (i, w) in widgets]
self.__Widgets_widgets_dict__ = dict(
[(w.name[prefix_length:], w) for (i, w) in widgets]
)
if prefix is None:
# BBB Allow old code using the prefix_length argument.
if prefix_length is None:
raise TypeError(
"One of 'prefix_length' and 'prefix' is required."
)
self.__Widgets_widgets_dict__ = dict(
[(w.name[prefix_length:], w) for (i, w) in widgets]
)
else:
prefix = expandPrefix(prefix)
self.__Widgets_widgets_dict__ = dict(
[(_widgetKey(w, prefix), w) for (i, w) in widgets]
)

def __iter__(self):
return iter(self.__Widgets_widgets_list__)
Expand Down Expand Up @@ -257,7 +275,7 @@ def setUpWidgets(form_fields,

prefix = form_prefix
if form_field.prefix:
prefix += '.' + form_field.prefix
prefix = expandPrefix(prefix) + form_field.prefix

widget.setPrefix(prefix)

Expand All @@ -274,7 +292,7 @@ def setUpWidgets(form_fields,

widgets.append((not readonly, widget))

return Widgets(widgets, len(form_prefix)+1)
return Widgets(widgets, prefix=form_prefix)

def setUpInputWidgets(form_fields, form_prefix, context, request,
form=None, ignore_request=False):
Expand All @@ -285,7 +303,7 @@ def setUpInputWidgets(form_fields, form_prefix, context, request,

prefix = form_prefix
if form_field.prefix:
prefix += '.' + form_field.prefix
prefix = expandPrefix(prefix) + form_field.prefix

widget.setPrefix(prefix)

Expand All @@ -297,7 +315,7 @@ def setUpInputWidgets(form_fields, form_prefix, context, request,
widget.setRenderedValue(value)

widgets.append((True, widget))
return Widgets(widgets, len(form_prefix)+1)
return Widgets(widgets, prefix=form_prefix)


def _createWidget(form_field, field, request, iface):
Expand All @@ -309,7 +327,7 @@ def _createWidget(form_field, field, request, iface):

def getWidgetsData(widgets, form_prefix, data):
errors = []
form_prefix += '.'
form_prefix = expandPrefix(form_prefix)

for input, widget in widgets.__iter_input_and_widget__():
if input and IInputWidget.providedBy(widget):
Expand Down Expand Up @@ -376,7 +394,7 @@ def setUpEditWidgets(form_fields, form_prefix, context, request,

prefix = form_prefix
if form_field.prefix:
prefix += '.' + form_field.prefix
prefix = expandPrefix(prefix) + form_field.prefix

widget.setPrefix(prefix)

Expand All @@ -387,7 +405,7 @@ def setUpEditWidgets(form_fields, form_prefix, context, request,

widgets.append((not readonly, widget))

return Widgets(widgets, len(form_prefix)+1)
return Widgets(widgets, prefix=form_prefix)

def setUpDataWidgets(form_fields, form_prefix, context, request, data=(),
for_display=False, ignore_request=False):
Expand All @@ -403,7 +421,8 @@ def setUpDataWidgets(form_fields, form_prefix, context, request, data=(),

prefix = form_prefix
if form_field.prefix:
prefix += '.' + form_field.prefix
prefix = expandPrefix(prefix) + form_field.prefix

widget.setPrefix(prefix)

if ((form_field.__name__ in data)
Expand All @@ -413,7 +432,7 @@ def setUpDataWidgets(form_fields, form_prefix, context, request, data=(),

widgets.append((not readonly, widget))

return Widgets(widgets, len(form_prefix)+1)
return Widgets(widgets, prefix=form_prefix)


class NoInputData(interface.Invalid):
Expand Down Expand Up @@ -546,7 +565,7 @@ def __init__(self, label, **options):
else:
name = label.encode('hex')

self.__name__ = prefix + '.' + name
self.__name__ = expandPrefix(prefix) + name

if data is None:
data = {}
Expand All @@ -558,21 +577,14 @@ def __get__(self, form, class_=None):
result = self.__class__.__new__(self.__class__)
result.__dict__.update(self.__dict__)
result.form = form
result.__name__ = form.prefix + '.' + result.__name__
result.__name__ = expandPrefix(form.prefix) + result.__name__
interface.alsoProvides(result, interfaces.IBoundAction)
return result

def available(self):
condition = self.condition
return (condition is None) or condition(self.form, self)

def submitted(self):
if not self.available():
return False
form = self.form
name = "%s.%s" % (form.prefix, self.__name__)
return name in form.request.form

def validate(self, data):
if self.validator is not None:
return self.validator(self.form, self, data)
Expand Down
100 changes: 100 additions & 0 deletions form.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1636,3 +1636,103 @@ and invariant errors shouldn't, because they don't come from a widget.
Therefore, a simple division such as the following should suffice.

# TODO

Omitting the form prefix
------------------------

For certain use cases (e.g. forms that post data to a different server whose
software you do not control) it is important to be able to generate forms
*without* a prefix. Using an empty string for the prefix omits it entirely.

>>> form_fields = form.Fields(IOrder).select('name')
>>> request = TestRequest()
>>> widgets = form.setUpWidgets(form_fields, '', None, request)
>>> print widgets['name']() # doctest: +NORMALIZE_WHITESPACE
<input class="textType" id="name" name="name" size="20"
type="text" value="" />

Of course, getting the widget data still works.

>>> request.form['name'] = 'foo'
>>> widgets = form.setUpWidgets(form_fields, '', None, request)
>>> data = {}
>>> form.getWidgetsData(widgets, '', data)
[]
>>> data
{'name': u'foo'}

And the value from the request is also visible in the rendered form.

>>> print widgets['name']() # doctest: +NORMALIZE_WHITESPACE
<input class="textType" id="name" name="name" size="20"
type="text" value="foo" />

The same is true when using the other setup*Widgets helpers.

>>> widgets = form.setUpInputWidgets(form_fields, '', None, request)
>>> print widgets['name']() # doctest: +NORMALIZE_WHITESPACE
<input class="textType" id="name" name="name" size="20"
type="text" value="foo" />

>>> order = Order(42)
>>> widgets = form.setUpEditWidgets(form_fields, '', order, request)
>>> print widgets['name']() # doctest: +NORMALIZE_WHITESPACE
<input class="textType" id="name" name="name" size="20"
type="text" value="foo" />

>>> widgets = form.setUpDataWidgets(form_fields, '', None, request)
>>> print widgets['name']() # doctest: +NORMALIZE_WHITESPACE
<input class="textType" id="name" name="name" size="20"
type="text" value="foo" />

Form actions have their own prefix in addition to the form prefix. This can be
suppressed for each action by passing the empty string as the 'prefix'
argument.

>>> class MyForm(form.Form):
...
... prefix = ''
... form_fields = form.Fields()
...
... @form.action('Button 1', name='button1')
... def handle_button1(self, action, data):
... self.status = 'Button 1 detected'
...
... @form.action('Button 2', prefix='', name='button2')
... def handle_button2(self, action, data):
... self.status = 'Button 2 detected'
...
>>> request = TestRequest()
>>> request.form['actions.button1'] = ''
>>> print MyForm(None, request)() # doctest: +NORMALIZE_WHITESPACE
Button 1 detected
<input type="submit" id="actions.button1" name="actions.button1"
value="Button 1" class="button" />
<input type="submit" id="button2" name="button2"
value="Button 2" class="button" />
>>> request = TestRequest()
>>> request.form['button2'] = ''
>>> print MyForm(None, request)() # doctest: +NORMALIZE_WHITESPACE
Button 2 detected
<input type="submit" id="actions.button1" name="actions.button1"
value="Button 1" class="button" />
<input type="submit" id="button2" name="button2"
value="Button 2" class="button" />

It is also possible to keep the form prefix and just suppress the 'actions' prefix.

>>> class MyForm(form.Form):
...
... form_fields = form.Fields()
...
... @form.action('Button', prefix='', name='button')
... def handle_button(self, action, data):
... self.status = 'Button detected'
...
>>> request = TestRequest()
>>> request.form['form.button'] = ''
>>> print MyForm(None, request)() # doctest: +NORMALIZE_WHITESPACE
Button detected
<input type="submit" id="form.button" name="form.button"
value="Button" class="button" />

0 comments on commit f3ddeaa

Please sign in to comment.