Make htmlfill only apply to certain named forms
Adam Batkin <[email protected]> Sun, 31 Jan 2010 20:17:15 +0000
| Newsgroups | gmane.comp.python.formencode |
|---|---|
| Message-ID | <[email protected]> |
Hi, I have a use case where it would be good if htmlfill could operate only on a particular named form (<form name="foo">) and leave any other forms alone. For example, if there were two forms on a page, one for logging in (with a username field) and one for creating a new user (also with a username field), the filling-in would only touch the one specified. Attached is a proposed patch that adds this ability. My initial testing has found that it works pretty well. It adds an optional argument to htmlfill.render(): form_name If a form_name is not passed, htmlfill should act exactly the same as before. If a form_name IS passed however, htmlfill will only ever touch the named form (plus any unnamed forms, though I'm not sure if this is a good idea). Thoughts? Comments? Suggestions? Thanks, -Adam Batkin ------------------------------------------------------------------------------ The Planet: dedicated and managed hosting, cloud storage, colocation Stay online with enterprise data centers and the best network in the business Choose flexible plans and management services without long-term contracts Personal 24x7 support from experience hosting pros just a phone call away. http://p.sf.net/sfu/theplanet-com _______________________________________________ FormEncode-discuss mailing list FormEncode-discuss-5NWGOfrQmneRv+LV9MX5uipxlwaOVQ5f@public.gmane.org https://lists.sourceforge.net/lists/listinfo/formencode-discuss
specify-form-name.diff
(text/plain, 7.6 KB)
Index: formencode/htmlfill.py
===================================================================
--- formencode/htmlfill.py (revision 4089)
+++ formencode/htmlfill.py (working copy)
@@ -16,7 +16,7 @@
auto_insert_errors=True, auto_error_formatter=None,
text_as_default=False, listener=None, encoding=None,
error_class='error', prefix_error=True,
- force_defaults=True):
+ force_defaults=True, form_name=None):
"""
Render the ``form`` (which should be a string) given the defaults
and errors. Defaults are the values that go in the input fields
@@ -67,6 +67,10 @@
be cleared, radio and select controls will have no value selected,
and textareas will be emptied. This defaults to ``True``, which is
appropriate the defaults are the result of a form submission.
+
+ ``form_name`` specifies the name of the form to be filled. By default,
+ all matching fields on the page are filled in, but this parameter only
+ matches fields inside forms with the given name attribute.
"""
if defaults is None:
defaults = {}
@@ -83,6 +87,7 @@
prefix_error=prefix_error,
error_class=error_class,
force_defaults=force_defaults,
+ form_name=form_name,
)
p.feed(form)
p.close()
@@ -185,7 +190,7 @@
add_attributes=None, listener=None,
auto_error_formatter=None,
text_as_default=False, encoding=None, prefix_error=True,
- force_defaults=True):
+ force_defaults=True, form_name=None):
RewritingParser.__init__(self)
self.source = None
self.lines = None
@@ -216,6 +221,8 @@
self.encoding = encoding
self.prefix_error = prefix_error
self.force_defaults = force_defaults
+ self.form_name = form_name
+ self.current_form_name = None
def str_compare(self, str1, str2):
"""
@@ -282,13 +289,17 @@
def handle_starttag(self, tag, attrs, startend=False):
self.write_pos()
if tag == 'input':
- self.handle_input(attrs, startend)
+ if self.can_handle_field():
+ self.handle_input(attrs, startend)
elif tag == 'textarea':
- self.handle_textarea(attrs)
+ if self.can_handle_field():
+ self.handle_textarea(attrs)
elif tag == 'select':
- self.handle_select(attrs)
+ if self.can_handle_field():
+ self.handle_select(attrs)
elif tag == 'option':
- self.handle_option(attrs)
+ if self.can_handle_field():
+ self.handle_option(attrs)
return
elif tag == 'form:error':
self.handle_error(attrs)
@@ -296,6 +307,9 @@
elif tag == 'form:iferror':
self.handle_iferror(attrs)
return
+ elif tag == 'form':
+ self.handle_form_start(attrs)
+ return
else:
return
if self.listener:
@@ -304,24 +318,39 @@
def handle_endtag(self, tag):
self.write_pos()
if tag == 'textarea':
- self.handle_end_textarea()
+ if self.can_handle_field():
+ self.handle_end_textarea()
elif tag == 'select':
- self.handle_end_select()
+ if self.can_handle_field():
+ self.handle_end_select()
elif tag == 'form:iferror':
self.handle_end_iferror()
+ elif tag == 'form':
+ self.handle_form_end()
def handle_startendtag(self, tag, attrs):
return self.handle_starttag(tag, attrs, True)
def handle_iferror(self, attrs):
name = self.get_attr(attrs, 'name')
+ form_name = self.get_attr(attrs, 'form_name')
notted = False
if name.startswith('not '):
notted = True
name = name.split(None, 1)[1]
assert name, "Name attribute in <iferror> required (%s)" % self.getpos()
self.in_error = name
- ok = self.errors.get(name)
+
+ if self.form_name and form_name:
+ if self.form_name == form_name:
+ ok = self.errors.get(name)
+ else:
+ ok = False
+ elif not self.can_handle_field():
+ ok = False
+ else:
+ ok = self.errors.get(name)
+
if notted:
ok = not ok
if not ok:
@@ -335,18 +364,23 @@
def handle_error(self, attrs):
name = self.get_attr(attrs, 'name')
+ form_name = self.get_attr(attrs, 'form_name')
formatter = self.get_attr(attrs, 'format') or 'default'
if name is None:
name = self.in_error
assert name is not None, (
"Name attribute in <form:error> required if not contained in "
"<form:iferror> (%i:%i)" % self.getpos())
- error = self.errors.get(name, '')
- if error:
- error = self.error_formatters[formatter](error)
- self.write_text(error)
+ if ((form_name and self.form_name == form_name)
+ or (not form_name and (not self.current_form_name or self.form_name == self.current_form_name))
+ or not self.form_name
+ or self.in_error):
+ error = self.errors.get(name, '')
+ if error:
+ error = self.error_formatters[formatter](error)
+ self.write_text(error)
+ self.used_errors[name] = 1
self.skip_next = True
- self.used_errors[name] = 1
def handle_input(self, attrs, startend):
t = (self.get_attr(attrs, 'type') or 'text').lower()
@@ -522,7 +556,16 @@
break
else:
self._content.insert(0, text)
+
+ def handle_form_start(self, attrs):
+ self.current_form_name = self.get_attr(attrs, 'name')
+ def handle_form_end(self):
+ self.current_form_name = None
+
+ def can_handle_field(self):
+ return not self.form_name or not self.current_form_name or self.current_form_name == self.form_name
+
# This can potentially be extended globally
default_formatter_dict = {'default': default_formatter,
'none': none_formatter,
Index: docs/htmlfill.txt
===================================================================
--- docs/htmlfill.txt (revision 4089)
+++ docs/htmlfill.txt (working copy)
@@ -45,15 +45,20 @@
filling the form with error messages. It defines two special tags for
this purpose:
-``<form:error name="field_name" format="formatter">``:
+``<form:error name="field_name" format="formatter" form_name="formname">``:
This tag is eliminated completely if there is no error for the
named field. Otherwise the error is passed through the given
formatter (``"default"`` if no ``format`` attribute is given).
-``<form:iferror name="field_name">...</form:iferror>``:
+ If a ``form_name`` is specified AND a ``form_name`` is passed
+ when rendering, then this error will only be displayed if it is
+ inside the named form (or an unnamed form) or a ``<form:iferror>`
+ with the same ``form_name``.
+``<form:iferror name="field_name" form_name="formname">...</form:iferror>``:
If the named field doesn't have an error, everything between the
tags will be eliminated. Use ``name="not field_name"`` to invert
the behavior (i.e., include text only if there are no errors for
- the field).
+ the field). If a ``form_name`` is specified AND a ``form_name``
+ is passed when rendering, the action of this tag is inverted.
Formatters are functions that take the error text as a single
argument. (In the future they may take extra arguments as well.)