You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(10) |
Dec
(4) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(1) |
Feb
(8) |
Mar
(8) |
Apr
(4) |
May
(19) |
Jun
(1) |
Jul
(1) |
Aug
(18) |
Sep
(18) |
Oct
(19) |
Nov
(75) |
Dec
(80) |
2006 |
Jan
(86) |
Feb
(61) |
Mar
(60) |
Apr
(47) |
May
(39) |
Jun
(16) |
Jul
(30) |
Aug
(13) |
Sep
(13) |
Oct
(21) |
Nov
(1) |
Dec
(10) |
2007 |
Jan
(2) |
Feb
(7) |
Mar
(9) |
Apr
(3) |
May
(9) |
Jun
(4) |
Jul
(1) |
Aug
(2) |
Sep
|
Oct
(12) |
Nov
(1) |
Dec
(7) |
2008 |
Jan
|
Feb
(2) |
Mar
(14) |
Apr
(9) |
May
(23) |
Jun
(4) |
Jul
|
Aug
(13) |
Sep
(8) |
Oct
(15) |
Nov
(40) |
Dec
(14) |
2009 |
Jan
|
Feb
(4) |
Mar
(10) |
Apr
(2) |
May
(2) |
Jun
(1) |
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2010 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2011 |
Jan
|
Feb
|
Mar
|
Apr
|
May
(1) |
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <sub...@co...> - 2004-12-03 20:08:01
|
Author: ianb Date: 2004-12-03 20:07:55 +0000 (Fri, 03 Dec 2004) New Revision: 439 Modified: trunk/Validator/validator/validators.py Log: * Made error message in DateConverter match the date format that the settings indicate. * Look for DateTime-like objects when unconverting TimeConverter objects (objects with attributes hour and minute) Modified: trunk/Validator/validator/validators.py =================================================================== --- trunk/Validator/validator/validators.py 2004-12-03 14:48:39 UTC (rev 438) +++ trunk/Validator/validator/validators.py 2004-12-03 20:07:55 UTC (rev 439) @@ -1045,7 +1045,7 @@ 9: 30, 10: 31, 11: 30, 12: 31} messages = { - 'badFormat': 'Please enter the date in the form dd/mm/yyyy', + 'badFormat': 'Please enter the date in the form %(format)s', 'monthRange': 'Please enter a month from 1 to 12', 'invalidDay': 'Please enter a valid day', 'dayRange': 'That month only has %(days)i days', @@ -1053,7 +1053,7 @@ 'unknownMonthName': "Unknown month name: %(month)s", 'invalidYear': 'Please enter a number for the year', 'fourDigitYear': 'Please enter a four-digit year', - 'wrongFormat': 'Please enter the date in the form mm/yyyy', + 'wrongFormat': 'Please enter the date in the form %(format)s', } def __init__(self, *args, **kw): @@ -1077,7 +1077,8 @@ self.assert_string(value, state) match = self._day_date_re.search(value) if not match: - raise Invalid(self.message('badFormat', state), + raise Invalid(self.message('badFormat', state, + format=self.month_style), value, state) day = int(match.group(1)) try: @@ -1135,7 +1136,8 @@ def convert_month(self, value, state): match = self._month_date_re.search(value) if not match: - raise Invalid(self.message('wrongFormat', state), + raise Invalid(self.message('wrongFormat', state, + format='mm/yyyy'), value, state) month = self.make_month(match.group(1)) year = self.make_year(match.group(2), state) @@ -1316,7 +1318,9 @@ def _from_python(self, value, state): if isinstance(value, (str, unicode)): return value - if len(value) == 3: + if hasattr(value, 'hour'): + hour, minute = value.hour, value.minute + elif len(value) == 3: hour, minute, second = value elif len(value) == 2: hour, minute = value |
From: Ian B. <ia...@co...> - 2004-11-15 20:25:10
|
Michel Thadeu Sabchuk wrote: > Hi guys! > > Is there a tool to autogenerate forms with formencode? I heard (read) > about formprocessor but I couldn't find it in validator module. I think > this is a designer job, but I don't have a designer :) Also, during the > program development I think it's easy to make the form autogenerated... FormEncode.htmlview had stuff for this. At some point I'd like to bring that code back, but I'm not sure what its role will be. It's in the repository still. The other option is to automatically generate the HTML, and then let the user edit that as they choose. This is more flexible, and might be an easy way jumpstart development, but won't follow updates very well. (A clever HTML generator could parse the page, note the missing elements, and then append them to the bottom of the form). -- Ian Bicking / ia...@co... / http://blog.ianbicking.org |
From: Michel T. S. <mic...@ya...> - 2004-11-14 02:57:34
|
Hi all! I try to use this behavior without sucess, I think I can be doing something wrong: class MyValidator(validators.FancyValidator): if_missing=-1 ... This way my class will use -1 as the value if the validator was used inside a Schema and the Schema key for the validator was not found, won't it? Is this another syntax valid too: class MySchema(schema.Schema): my_validator=MyValidator(if_missing=-1) I can't make it works... Thanks any help! -- Michel Thadeu Sabchuk Curitiba/PR |
From: Michel T. S. <mic...@ya...> - 2004-11-14 01:09:11
|
Hi guys! Is there a tool to autogenerate forms with formencode? I heard (read) about formprocessor but I couldn't find it in validator module. I think this is a designer job, but I don't have a designer :) Also, during the program development I think it's easy to make the form autogenerated... -- Michel Thadeu Sabchuk Curitiba/PR |
From: Michel T. S. <mic...@ya...> - 2004-11-12 22:19:28
|
Hi guys, my first participation on this list was unsucessfull, I sent the message to wrong list... Well, I enjoy FormEncode, I think it's very flexible, I am FunFormKit user and I agree it is too restrict and becomes too complicated :) I first have a question about the htmlfill, I try it with sucess using the default substitution and the tag <form:error.../> but I have a problem with <form:iferror...></form:iferror>. The strange thing is that the <form:error> function works well, but the iferror not, first when I show the form, after replace the default values the <form:iferror> is not supressed. When I try to send wrong data (to force the form fail), I get an Exception: File "/usr/lib/python2.3/site-packages/validator/htmlfill.py", line 68, in feed HTMLParser.HTMLParser.feed(self, data) File "/usr/lib/python2.3/HTMLParser.py", line 108, in feed self.goahead(0) File "/usr/lib/python2.3/HTMLParser.py", line 150, in goahead k = self.parse_endtag(i) File "/usr/lib/python2.3/HTMLParser.py", line 329, in parse_endtag self.handle_endtag(tag.lower()) File "/usr/lib/python2.3/site-packages/validator/htmlfill.py", line 127, in handle_endtag self.handle_end_iferror() TypeError: handle_end_iferror() takes exactly 2 arguments (1 given) How do you work with FormEncode + Webware? I think on a way and implement something, I wrote a class to handle the form validation and the error processing: # file: FormServlet.py from validator import htmlfill from validator.schema import Schema from validator import validators from validator.variabledecode import NestedVariables class StandardSchema(Schema): name=validators.NotEmpty() age=validators.Int() class FormServlet: schema=StandardSchema def processForm(self): rawFields=self.request().fields() dictFields=validators.to_python(NestedVariables, rawFields) if not rawFields: # this time the form was not submitted, is it true? pass else: # if the form was submitted # first I define the action to execute when the form will be processed for action in dictFields['action'].values(): if action.has_key(None): # first I find the proper action button try: methodToInvoke=action['methodToInvoke'] # try to use it's method to invoke except KeyError: # and if none was specified methodToInvoke='processFormData' # use a standard method to invoke if action.has_key('suppressValidation'): getattr(self, methodToInvoke)(rawFields) return try: # I try to validate it processedFields=validators.to_python(self.schema, dict([(key, dictFields[key]) for key in self.schema.fields.keys()])) getattr(self, methodToInvoke)(processedFields) return except validators.Invalid, error: # if an error occours parser=htmlfill.FillingParser(rawFields, errors=error.unpack_errors()) parser.feed(self.response()._strmOut.buffer()) # I feed the parser with the page content self.response()._strmOut.clear() # clear the old page content self.write(parser.text()) # and write the parsed page content parser.close() def sleep(self, t): """This way FormServlet should be the first class on extension.""" self.processForm() try: self.__class__.__bases__[1].sleep(self, t) except IndexError: raise Exception, 'the Servlet should be extended from two other, the FormServlet and a BaseServlet' def processFormData(self, fields): """A sample method to handle the data submitted and validated/converted.""" pass # end of file # file Teste.py # a example of use to the above class from Modelo import Modelo # modelo could be Page from FormServlet import FormServlet from validator.schema import Schema from validator import validators class Registro(Schema): name=validators.NotEmpty() age=validators.Int() class Teste(FormServlet, Modelo): titulo='Teste' schema=Registro def writeBody(self, **kw): # writeBody could be writeContent self.write('''\ <form method="post"> <table> <tr> <td>Name: <form:error name="name"></td><td><input type="text" name="name"></td> </tr> <tr> <td>Age: <form:error name="age"></td><td><input type="text" name="age"></td> </tr> </table> <p> <input type="submit" name="action.send" value="Send Data"> <input type="hidden" name="action.send.methodToInvoke" value="sendData"> <input type="submit" name="action.cancel" value="Cancel Operation"> <input type="hidden" name="action.cancel.methodToInvoke" value="cancelOperation"> <input type="hidden" name="action.cancel.suppressValidation" value="True"> </p> </form>''') def sendData(self, fields): self.write('<h4>OK!!!</h4>') def cancelOperation(self, fields): self.write('<h4>Cancel!!!</h4>') # end of file This is only a first try, I think I can change the action handling method, the design should not know how an action suppress validation or what is the method to invoke when the action is clicked. The important thing is the need of compatibility between the Schema validator and the form design... Do you have suggestions? Are anybody working on something similar to this? Thanks for all attention... -- Michel Thadeu Sabchuk Curitiba/PR |
From: <sub...@co...> - 2004-11-12 18:47:15
|
Author: ianb Date: 2004-11-12 09:30:08 -0500 (Fri, 12 Nov 2004) New Revision: 365 Modified: trunk/Validator/validator/htmlfill.py Log: Removed bad argument from end_iferror Modified: trunk/Validator/validator/htmlfill.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/Validator/validator/htmlfill.py 2004-11-11 18:57:53 UTC (rev 36= 4) +++ trunk/Validator/validator/htmlfill.py 2004-11-12 14:30:08 UTC (rev 36= 5) @@ -134,7 +134,7 @@ self.skip_error =3D True self.skip_next =3D True =20 - def handle_end_iferror(self, attrs): + def handle_end_iferror(self): self.in_error =3D None self.skip_error =3D False self.skip_next =3D False |
From: <sub...@co...> - 2004-11-12 05:20:37
|
Author: ianb Date: 2004-11-10 12:39:09 -0500 (Wed, 10 Nov 2004) New Revision: 339 Modified: trunk/Validator/docs/Design.txt Log: Talk about unconversion Modified: trunk/Validator/docs/Design.txt =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/Validator/docs/Design.txt 2004-11-10 17:38:56 UTC (rev 338) +++ trunk/Validator/docs/Design.txt 2004-11-10 17:39:09 UTC (rev 339) @@ -97,6 +97,34 @@ =20 .. _adapted: =20 +Two sides, two aspects +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Validator does both validation and version at the same time. +Validation necessarily happens with every conversion; for instance, +you may want to convert string representation of dates to internal +date objects; that conversion can fail if the string representation is +malformed. + +To keep things simple, there's only one operation: conversion. An +exception raised means there was an error. If you just want to +validate, that's a conversion that doesn't do anything. + +Similarly, there's two sides to the system, the foreign data and the +local data. In Validator the local data is called "python" (meaning, +a natural Python data structure), so we convert ``to_python`` and +``from_python``. Unlike some systems, Validator explicitly converts +*both* directions. + +For instance, consider the date conversion. In one form, you may want +a date like ``mm/dd/yyyy``. It's easy enough to make the necessary +converter; but the date object that results doesn't know how it's +supposed to be formatted for that form. ``repr`` or *any* method that +binds an object to its form representation is a bad idea. The +converter best knows how to undo its work. + +(This becomes even more interesting with compound validators.) + Adaptation =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =20 |
From: <sub...@co...> - 2004-11-12 04:47:11
|
Author: ianb Date: 2004-11-10 12:38:56 -0500 (Wed, 10 Nov 2004) New Revision: 338 Modified: trunk/Validator/validator/htmlfill.py Log: Better error message Modified: trunk/Validator/validator/htmlfill.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/Validator/validator/htmlfill.py 2004-11-05 18:34:33 UTC (rev 33= 7) +++ trunk/Validator/validator/htmlfill.py 2004-11-10 17:38:56 UTC (rev 33= 8) @@ -81,9 +81,13 @@ assert not unused, ( "These keys from defaults were not used in the form: %s" % unused.keys()) - assert not unused_errors, ( - "These keys from errors were not used in the form: %s" - % unused_errors.keys()) + if unused_errors: + error_text =3D [] + for key in unused_errors.keys(): + error_text.append("%s: %s" % (key, self.errors[key])= ) + assert False, ( + "These errors were not used in the form: %s" %=20 + ', '.join(error_text)) =20 def add_key(self, key): self.used_keys[key] =3D 1 |
From: <sub...@co...> - 2004-11-05 22:50:53
|
Author: ianb Date: 2004-11-05 13:34:33 -0500 (Fri, 05 Nov 2004) New Revision: 337 Modified: trunk/Validator/docs/Design.txt Log: Small changes Modified: trunk/Validator/docs/Design.txt =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/Validator/docs/Design.txt 2004-11-05 18:34:17 UTC (rev 336) +++ trunk/Validator/docs/Design.txt 2004-11-05 18:34:33 UTC (rev 337) @@ -2,6 +2,8 @@ Validator Design ++++++++++++++++ =20 +.. contents:: + This is a document to describe why Validator looks the way it looks, and how it fits into other applications. It also talks some about the false starts I've made. @@ -53,6 +55,8 @@ lname =3D StringCol(notNull=3DTrue) mi =3D StringCol() =20 +.. _SQLObject: http://sqlobject.org + It is tempting to take the restrictions of the ``Address`` class and automatically come up with a validation schema. This may yet be a viable goal, but in practical terms validation tends to be both more |
From: <sub...@co...> - 2004-11-05 22:47:18
|
Author: ianb Date: 2004-11-05 13:30:53 -0500 (Fri, 05 Nov 2004) New Revision: 335 Added: trunk/Validator/docs/Design.txt Log: Added document about Added: trunk/Validator/docs/Design.txt =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/Validator/docs/Design.txt 2004-11-05 17:24:01 UTC (rev 334) +++ trunk/Validator/docs/Design.txt 2004-11-05 18:30:53 UTC (rev 335) @@ -0,0 +1,141 @@ +++++++++++++++++ +Validator Design +++++++++++++++++ + +This is a document to describe why Validator looks the way it looks, +and how it fits into other applications. It also talks some about the +false starts I've made. + + -- `Ian Bicking`_ + +.. _Ian Bicking: http://ianbicking.org + +Basic Metaphor +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +Validator is performs look-before-you-leap validation. The idea being +that you check all the data related to an operation, then apply it. +The alternative might be a transactional system, where you just start +applying the data and if there's a problem you raise an exception. +Someplace else you catch the exception and roll back the transaction. +Of course, Validator works fine with this system, but unlike this you +can use it without transactions. + +Validator generally works on primitive types (though you could extend +it to deal with your own types if you wish). This fits in with +look-before-you-leap; often your domain objects won't exist until +after you apply the user's request, so it's necessary to work on an +early form of the data. Also, Validator doesn't know anything about +your domain objects or classes; it's just easier to keep it this way. + +Validation only operates on a single value at a time. The key idea is +that the single value can itself be compound. So where some +validation packages have a built-in notion of fields, Validator simply +validates a dictionary; that it applies sub-validators to values in +that dictionary is an implementation detail internal to the validator. + +Domain Objects +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +These are your objects, specific to your application. I know nothing +about them, and cannot know. Validator tries to make few requirements +on how these objects look. + +Validation as directional, not intrinsic +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +One false start I've made is an attempt to tie validators into the +objects they validate against. E.g., you might have a SQLObject_ +class like:: + + class Address(SQLObject): + fname =3D StringCol(notNull=3DTrue) + lname =3D StringCol(notNull=3DTrue) + mi =3D StringCol() + +It is tempting to take the restrictions of the ``Address`` class and +automatically come up with a validation schema. This may yet be a +viable goal, but in practical terms validation tends to be both more +and less restrictive. =20 + +Often in an API we are more restrictive than we may be in a user +interface, demanding that everything be specified explicitly. In a UI +we may assist the user by filling in values on their behalf. The +specifics of this depend on the UI and the objects in question. + +At the same time, we are often more restrictive in a UI. For +instance, we may demand that the user enter something that appears to +be a valid phone number. But for historical reasons, we may not make +that demand for objects that already exist, or we may put in a tight +restriction on the UI keeping in mind that it can more easily be +relaxed and refined than a restriction in the domain objects or +underlying database. Also, we may trust the programmer to use the API +in a reasonable way, but we seldom trust the user under any +circumstance. + +In essence, there is an "inside" and an "outside". Validator is a +toolkit for bridging those two areas in a sensible manner. The +specific way we bridge this depends on the nature of the user +interface. An XML-RPC interface can make some assumptions that a GUI +cannot make. An HTML interface can typically make even less +assumptions, including the basic integrity of the input data. It +isn't reasonable that the object should know about all means of +inputs, and the varying UI requirements of those inputs; user +interfaces are volatile, and more art than science, but domain objects +work better when they remain stable. + +It also didn't work well to annotate domain objects with validation +schemas, though the option remains open. Any object can be used as a +validator, so long as it can be adapted_ into a validator, so +potentially a domain class could be used as a validator, if you +register an adapter that can strip out the validation annotations. +But I leave this to the reader. + +.. _adapted: + +Adaptation +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +So, now, adaptation. Validator uses PyProtocols_, which is an +interface/adaptation package (similar to Zope's interfaces). + +The basic idea behind adaptation is that objects can fulfill multiple +roles. When you adapt an object, you either see if the object +supports the given interface (``validator.interfaces.IValidator``), or +if there's any adapter registered that can convert your object. +PyProtocols describes it in more detail. + +.. _PyProtocols: http://peak.telecommunity.com/PyProtocols.html + +In the future, I might make PyProtocols optional, implementing some +stubs so that everything works in its absence. + +Presentation +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D + +FormEncode included form generation in addition to validation. The +form generation worked okay; it was reasonably attractive, and in many +ways quite powerful. I might revisit it. But generation is limited. +It works *great* at first, then you hit a wall -- you want to make a +change, and you just *can't*, it doesn't fit into the automatic +generation. + +At this point, my preferred form generation is with htmlfill_. In +this model, you write the form however you want (maybe even generating +it in some fashion) and use ``htmlfill`` to fill in the default values +and report errors. + +.. _htmlfill: htmlfill.html + +Declarative and Imperative +=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D + +All of the objects -- schemas, repeating elements, individual +validators -- can be created imperatively, though more declarative +styles often look better (specifically using subclassing instead of +construction). You are free to build validations from other sources. + +It would be cool, for instance, to augment htmlfill_ to look for +things like ``form:required`` or ``form:match-regex``, etc., and build +a validation schema out of that. + |
From: <sub...@co...> - 2004-11-05 19:20:14
|
Author: ianb Date: 2004-11-05 10:03:53 -0500 (Fri, 05 Nov 2004) New Revision: 332 Modified: trunk/FormEncode/docs/PyCon.txt Log: Fixed some reST markup Modified: trunk/FormEncode/docs/PyCon.txt =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/docs/PyCon.txt 2004-11-05 15:03:30 UTC (rev 331) +++ trunk/FormEncode/docs/PyCon.txt 2004-11-05 15:03:53 UTC (rev 332) @@ -44,9 +44,9 @@ maintainer of SQLObject_ and PyLogo_, as well as a maintainer of Webware_. =20 -.. SQLObject: http://sqlobject.org -.. PyLogo: http://pylogo.org -.. Webware: http://webware.sf.net +.. _SQLObject: http://sqlobject.org +.. _PyLogo: http://pylogo.org +.. _Webware: http://webware.sf.net =20 Presentation Summary =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D @@ -110,39 +110,56 @@ =3D=3D=3D=3D=3D=3D=3D =20 * Introducing me. ("Hi, I'm me") + * History (FunFormKit_); describe previous efforts, and the problems - with those efforts. Some of what lead to a rewrite. + with those efforts. Some of what lead to a rewrite. + * Design goals: + * Avoid coupling. Describe the use of interfaces and adapters (describe the concept of interfaces and adapters in this context? Probably not enough time), how they can be used to provide multiple personalities for an object (important to us: the validation personality and the form personality) + * Quick prototyping. Avoid boilerplate, made default behavior reasonably functional. (these are covered more in the examples) + * Does not exclude later fine-grained refinement. + * Doesn't take over control flow. Has an imperative interface, and doesn't hook into the framework at all. + * Examples: (I'm not sure how best to do these, as the body of the presentation is embedded in the examples, but the examples can be lengthy to present, despite their short code length... depending on the time slot it may make sense to use these examples as asides to a more narrative description of FormEncode's features and design principals) + * Edit an address: + * Define a validation scheme (8 lines + import) + * Define form fields and layout (edit those 8 lines, add one line) + * Hook it into a simple web application (~10 more lines) + * Compound forms: + * Name + multiple addresses (using above example) (3 more lines, ~5 more lines in the application). + * Use the validation with XMLRPC (~10 more application lines) + * Tie the validation into a object/class (in this example a SQLObject_ class for addresses) (12 lines for SQLObject, validation schema expressed inline, retarget application to SQLObject backend). + * Conclusion: "I've run over time, so I won't be able to finish the examples." =20 .. _FunFormKit: http://funformkit.sf.net .. _SQLObject: http://sqlobject.org +.. _formencode: http://formencode.org |
From: <sub...@co...> - 2004-03-23 16:41:36
|
Author: ianb Date: 2004-03-23 07:46:46 -0500 (Tue, 23 Mar 2004) New Revision: 77 Added: trunk/FormEncode/experimental/FormEncodeKit/Examples/ColorPicker.py trunk/FormEncode/experimental/FormEncodeKit/Examples/SitePage.py trunk/FormEncode/experimental/FormEncodeKit/Examples/Workflow.py trunk/FormEncode/experimental/FormEncodeKit/Examples/net216.gif trunk/FormEncode/experimental/FormEncodeKit/Examples/style.css Modified: trunk/FormEncode/docs/PyConOutline.txt trunk/FormEncode/experimental/FormEncodeKit/Examples/Address.py trunk/FormEncode/experimental/FormEncodeKit/Examples/AddressList.py trunk/FormEncode/experimental/FormEncodeKit/Examples/Register.py trunk/FormEncode/experimental/FormEncodeKit/Properties.py trunk/FormEncode/src/htmlview.py trunk/FormEncode/src/validators.py Log: Expanded and refined the examples, added some code for prettier layout. Modified: trunk/FormEncode/docs/PyConOutline.txt =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/docs/PyConOutline.txt 2004-03-22 12:35:04 UTC (rev 7= 6) +++ trunk/FormEncode/docs/PyConOutline.txt 2004-03-23 12:46:46 UTC (rev 7= 7) @@ -17,8 +17,27 @@ *Show a complicated form with more layout, repeating fields, advanced widgets* =20 -The basic problems are common to other areas. +The basic problems are common to other application libraries. There's +two pitfalls: libraries that cannot be scaled to more complex use, and +libraries that are too complicated to get started with or too +complicated to integrate with your application (and you other +libraries). People frequently put effort into these problems -- +typically reimplementing a complex library you've become dissatisfied +with, or adding features or wrappers to a library that doesn't fit +all your needs. This is often a case of jumping from the frying pan +into the fire, though the person who has escaped one trap to fall +into another will often not realize it until the library gets wider +use. =20 +FormEncode's History +-------------------- + +FormEncode is preceded by FunFormKit, a Webware-specific form +generation and validation library. FunFormKit possessed many of the +features that FormEncode now has, but was itself structurally naive, +and ultimately unmaintainable. As such, FormEncode is informed by a +past failure, and avoids many mistakes as a result. + Hello World ----------- =20 @@ -28,7 +47,7 @@ =20 print "Hello World!" =20 -This is an extremely valuable feature for Python! A FormEncode hello +This is an extremely valuable feature of Python! A FormEncode hello world looks like:: =20 # Framework boilerplate :( @@ -105,7 +124,12 @@ ---------------- =20 Frequently people write unnecessary libraries, which encapsulate a -pattern that is more easily used as simply a pattern. +pattern that is more easily used as simply a pattern. So one of the +first things we should ask of a library -- especially when +considering writing a new library -- is if the result is truly more +effective than a documented pattern (keeping in mind that documenting +a pattern is almost always easier than documenting a library, and +doesn't require any programming and little support). =20 In the second form of the FormEncode-less examples I show above, I use a basic pattern of form processing, one which I've personally used in @@ -122,7 +146,7 @@ (including changes in requirements) require changes to another that's okay. * By definition, it does just what you need and doesn't do what you - don't need (at least if it's not over-engineered). + don't need (at least if you practice self-restraint). =20 These advantages are part of why there are a large number of in-house form libraries. A replacement has to justify itself in three ways:=20 @@ -200,10 +224,13 @@ processor is build into the framework itself, often under the guise of MVC development. =20 -FormEncode very specifically does not do this, so that you can use the -form processing using your own conditionals and flow control, and -integrate it into an application without making it into a FormEncode -(tm) application. +FormEncode very specifically does not do this at the top level, so +that you can use the form processing using your own conditionals and +flow control, and integrate it into an application without making it +into a FormEncode (tm) application. The validation still takes +control from the programmer, as the control proces in validation +delegation is one of FormEncode's most central features, and not +easily distilled into a pattern. =20 =20 Delegate Everything Possible @@ -284,7 +311,7 @@ kinds of validators, never to compose validators. So if, for instance, you want to make sure an email address is valid but also shorter than a certain length, you can do so by composing two -validators (using ``All(Email(), MaxLength(10))``). =20 +validators (using ``All(Email(), MaxLength(50))``). =20 =20 This composition also happens behind the scenes, when complex input widgets have to transform and validate input; e.g., @@ -312,9 +339,9 @@ =20 Static configuration (e.g., with XML) can easily be achieved through a programmatic interface, but an interface that expects static -configuration not necessarily allow for runtime reconfiguration, or -will use a pull-style configuration, where the framework queries the -configuration and a complete mock configuration has to be +configuration will not necessarily allow for runtime reconfiguration, +or will use a pull-style configuration, where the framework queries +the configuration and a complete mock configuration has to be constructed. =20 Some of the strategies that FormEncode uses to make it easier to use @@ -322,8 +349,8 @@ =20 * Immutable ("Value") objects where possible, avoiding complicated setup procedures or hidden initialization. Once you've created the - code for a form by hand, you know everything you need to know to - create it programmatically. + code for a form by hand, you know (almost) everything you need to know= to + create it programmatically. Everything except: * Though nested structures can be declared with classes to make the definition more aesthetically pleasing, these map directly to methods. Example:: @@ -361,4 +388,5 @@ =20 For instance, a form of validation might be to ensure the user has permission to access something -- we don't allow for this -specifically, but by putting the user object into=20 +specifically, but by putting the user object into the "state" we allow +the end user to get at this information. Modified: trunk/FormEncode/experimental/FormEncodeKit/Examples/Address.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/experimental/FormEncodeKit/Examples/Address.py 2004-= 03-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/experimental/FormEncodeKit/Examples/Address.py 2004-= 03-23 12:46:46 UTC (rev 77) @@ -1,11 +1,15 @@ -from Component.CPage import CPage - +from SitePage import SitePage from formencode import validators, htmlview, schema from FormEncodeKit.FormComponent import FormComponent =20 +class NumberLayout(htmlview.ForEachLayout): + def htmlField(self, i, request): + text =3D htmlview.ForEachLayout.htmlField(self, i, request) + return '<div class=3D"number">%s</div>' % text + class AddressSchema(schema.Schema): =20 - view =3D htmlview.SchemaLayout + view =3D htmlview.TableLayout firstName =3D validators.String(notEmpty=3DTrue, view=3Dhtmlview.Tex= t(), n=3D'fname') lastName =3D validators.String(notEmpty=3DTrue, view=3Dhtmlview.Text= (), @@ -13,10 +17,10 @@ =20 class numbers(validators.ForEach): =20 - view =3D htmlview.ForEachLayout + view =3D NumberLayout =20 class phone(schema.Schema): - view =3D htmlview.TableLayout + view =3D htmlview.TableLayout(tableClass=3D'phonetable') number =3D validators.PhoneNumber( ifEmpty=3DNone, view=3Dhtmlview.Text(), n=3D'number') type =3D validators.String( @@ -60,7 +64,7 @@ print htmlview.adaptHTMLView(AddressSchema) print htmlview.adaptHTMLView(AddressSchema.fields['numbers']) =20 -class Address(CPage): +class Address(SitePage): =20 components =3D [FormComponent()] =20 @@ -71,7 +75,6 @@ return httpRequest =20 def writeContent(self): - self.write('<a href=3D"Address">Reset</a><br>') self._options =3D {} ses =3D self.session() =20 Modified: trunk/FormEncode/experimental/FormEncodeKit/Examples/AddressLis= t.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/experimental/FormEncodeKit/Examples/AddressList.py 2= 004-03-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/experimental/FormEncodeKit/Examples/AddressList.py 2= 004-03-23 12:46:46 UTC (rev 77) @@ -7,12 +7,20 @@ =20 class AddressListSchema(schema.Schema): =20 - view =3D htmlview.TableLayout + view =3D htmlview.FormTableLayout(layout=3D['addresses', ['addAddres= s', 'submit']]) =20 class addresses(validators.ForEach): + class item1(AddressSchema): - view =3D htmlview.TableLayout - useFieldset =3D True + =20 + view =3D htmlview.FormTableLayout(layout=3D[ + ['firstName', 'lastName'], + 'numbers', + ['addNumber', 'delNumber'], + ['delete', 'up']], + useFieldset=3DTrue, + legend=3D'Address') + =20 submit =3D None delete =3D validators.String(view=3Dhtmlview.SubmitButton( methodToInvoke=3D"delAddress", @@ -45,8 +53,6 @@ return '<br>\n'.join(result) render =3D classmethod(render) =20 -print 'X', htmlview.adaptHTMLView(AddressListSchema) - class AddressList(Address): =20 components =3D [FormComponent()] @@ -70,12 +76,12 @@ return httpRequest =20 def writeContent(self): - self.write('<a href=3D"AddressList">Restart</a><br>\n') ses =3D self.session() =20 self._options =3D {} valid, addressList =3D self.processForm() print "RESULT", valid, addressList + errors =3D None if valid =3D=3D "partial": httpRequest =3D addressList addressList =3D ses.value('addressList', {}) @@ -87,11 +93,13 @@ addressList =3D self.formSchema.cleanup(addressList) ses.setValue('addressList', addressList) else: + errors =3D addressList addressList =3D ses.value('addressList', {'addresses': []}) self.renderAddresses(addressList) + pprint(['OP', self._options, errors]) + if not self._options and not errors: + self._options.setdefault('addresses', {})['repetitions'] =3D= 1 pprint(["OP", self._options]) - if not self._options: - self._options.setdefault('addresses', {})['repetitions'] =3D= 1 self.writeForm(defaults=3DaddressList, options=3Dself._options) =20 def renderAddresses(self, input): Added: trunk/FormEncode/experimental/FormEncodeKit/Examples/ColorPicker.p= y =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/experimental/FormEncodeKit/Examples/ColorPicker.py 2= 004-03-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/experimental/FormEncodeKit/Examples/ColorPicker.py 2= 004-03-23 12:46:46 UTC (rev 77) @@ -0,0 +1,37 @@ +from WebKit.Page import Page + +imageURL =3D 'net216.gif' + +class ColorPicker(Page): + + def writeHTML(self): + field =3D self.request().field + formName =3D field('form') + fieldName =3D field('field') + colorID =3D field('colid') + =20 + self.write('<html><head><title>Pick a color</title>\n') + self.write('''\ +<script language=3D"JavaScript"><!-- +function SendColor(color) { + pdoc =3D window.opener.document; + pdoc.forms['%(formName)s'].elements['%(fieldName)s'].value =3D "#" += color; + el =3D pdoc.getElementById('%(colorID)s'); + if (el && el.style) { + el.style.backgroundColor =3D "#" + color; + } + window.close(); +} +// --></script> +''' % {'formName': formName, 'fieldName': fieldName, 'colorID': colorID}= ) + self.write('</head>\n') + self.write('<body bgcolor=3D"#ffffff">\n') + self.write('<img src=3D"%s" width=3D"292" height=3D"196" border=3D= "0" alt=3D"" usemap=3D"#webpal">\n' % imageURL) + self.write('<map name=3D"webpal">') + self.writeColors() + self.write('</map>\n') + self.write('<center><form><input type=3D"hidden" name=3D"id" val= ue=3D""><input type=3D"button" onclick=3D"window.close()" value=3D"cancel= "></form></center></body></html>\n') + + def writeColors(self): + ## Okay, this is crude, but whatever... + self.write('''<!--- Row 1 ---><area coords=3D"2,2,18,18" href=3D= "javascript:{SendColor(\'330000\')}" onclick=3D"SendColor(\'330000\');ret= urn false"><area coords=3D"18,2,34,18" href=3D"javascript:{SendColor(\'33= 3300\')}" onclick=3D"SendColor(\'333300\');return false"><area coords=3D"= 34,2,50,18" href=3D"javascript:{SendColor(\'336600\')}" onclick=3D"SendCo= lor(\'336600\');return false"><area coords=3D"50,2,66,18" href=3D"javascr= ipt:{SendColor(\'339900\')}" onclick=3D"SendColor(\'339900\');return fals= e"><area coords=3D"66,2,82,18" href=3D"javascript:{SendColor(\'33CC00\')}= " onclick=3D"SendColor(\'33CC00\');return false"><area coords=3D"82,2,98,= 18" href=3D"javascript:{SendColor(\'33FF00\')}" onclick=3D"SendColor(\'33= FF00\');return false"><area coords=3D"98,2,114,18" href=3D"javascript:{Se= ndColor(\'66FF00\')}" onclick=3D"SendColor(\'66FF00\');return false"><are= a coords=3D"114,2,130,18" href=3D"javascript:{SendColor(\'66CC00\')}" onc= lick=3D"SendColor(\'66CC00\');return false"><area coords=3D"130,2,146,18"= href=3D"javascript:{SendColor(\'669900\')}" onclick=3D"SendColor(\'66990= 0\');return false"><area coords=3D"146,2,162,18" href=3D"javascript:{Send= Color(\'666600\')}" onclick=3D"SendColor(\'666600\');return false"><area = coords=3D"162,2,178,18" href=3D"javascript:{SendColor(\'663300\')}" oncli= ck=3D"SendColor(\'663300\');return false"><area coords=3D"178,2,194,18" h= ref=3D"javascript:{SendColor(\'660000\')}" onclick=3D"SendColor(\'660000\= ');return false"><area coords=3D"194,2,210,18" href=3D"javascript:{SendCo= lor(\'FF0000\')}" onclick=3D"SendColor(\'FF0000\');return false"><area co= ords=3D"210,2,226,18" href=3D"javascript:{SendColor(\'FF3300\')}" onclick= =3D"SendColor(\'FF3300\');return false"><area coords=3D"226,2,242,18" hre= f=3D"javascript:{SendColor(\'FF6600\')}" onclick=3D"SendColor(\'FF6600\')= ;return false"><area coords=3D"242,2,258,18" href=3D"javascript:{SendColo= r(\'FF9900\')}" onclick=3D"SendColor(\'FF9900\');return false"><area coor= ds=3D"258,2,274,18" href=3D"javascript:{SendColor(\'FFCC00\')}" onclick=3D= "SendColor(\'FFCC00\');return false"><area coords=3D"274,2,290,18" href=3D= "javascript:{SendColor(\'FFFF00\')}" onclick=3D"SendColor(\'FFFF00\');ret= urn false"><!--- Row 2 ---><area coords=3D"2,18,18,34" href=3D"javascript= :{SendColor(\'330033\')}" onclick=3D"SendColor(\'330033\');return false">= <area coords=3D"18,18,34,34" href=3D"javascript:{SendColor(\'333333\')}" = onclick=3D"SendColor(\'333333\');return false"><area coords=3D"34,18,50,3= 4" href=3D"javascript:{SendColor(\'336633\')}" onclick=3D"SendColor(\'336= 633\');return false"><area coords=3D"50,18,66,34" href=3D"javascript:{Sen= dColor(\'339933\')}" onclick=3D"SendColor(\'339933\');return false"><area= coords=3D"66,18,82,34" href=3D"javascript:{SendColor(\'33CC33\')}" oncli= ck=3D"SendColor(\'33CC33\');return false"><area coords=3D"82,18,98,34" hr= ef=3D"javascript:{SendColor(\'33FF33\')}" onclick=3D"SendColor(\'33FF33\'= );return false"><area coords=3D"98,18,114,34" href=3D"javascript:{SendCol= or(\'66FF33\')}" onclick=3D"SendColor(\'66FF33\');return false"><area coo= rds=3D"114,18,130,34" href=3D"javascript:{SendColor(\'66CC33\')}" onclick= =3D"SendColor(\'66CC33\');return false"><area coords=3D"130,18,146,34" hr= ef=3D"javascript:{SendColor(\'669933\')}" onclick=3D"SendColor(\'669933\'= );return false"><area coords=3D"146,18,162,34" href=3D"javascript:{SendCo= lor(\'666633\')}" onclick=3D"SendColor(\'666633\');return false"><area co= ords=3D"162,18,178,34" href=3D"javascript:{SendColor(\'663333\')}" onclic= k=3D"SendColor(\'663333\');return false"><area coords=3D"178,18,194,34" h= ref=3D"javascript:{SendColor(\'660033\')}" onclick=3D"SendColor(\'660033\= ');return false"><area coords=3D"194,18,210,34" href=3D"javascript:{SendC= olor(\'FF0033\')}" onclick=3D"SendColor(\'FF0033\');return false"><area c= oords=3D"210,18,226,34" href=3D"javascript:{SendColor(\'FF3333\')}" oncli= ck=3D"SendColor(\'FF3333\');return false"><area coords=3D"226,18,242,34" = href=3D"javascript:{SendColor(\'FF6633\')}" onclick=3D"SendColor(\'FF6633= \');return false"><area coords=3D"242,18,258,34" href=3D"javascript:{Send= Color(\'FF9933\')}" onclick=3D"SendColor(\'FF9933\');return false"><area = coords=3D"258,18,274,34" href=3D"javascript:{SendColor(\'FFCC33\')}" oncl= ick=3D"SendColor(\'FFCC33\');return false"><area coords=3D"274,18,290,34"= href=3D"javascript:{SendColor(\'FFFF33\')}" onclick=3D"SendColor(\'FFFF3= 3\');return false"><!--- Row 3 ---><area coords=3D"2,34,18,50" href=3D"ja= vascript:{SendColor(\'330066\')}" onclick=3D"SendColor(\'330066\');return= false"><area coords=3D"18,34,34,50" href=3D"javascript:{SendColor(\'3333= 66\')}" onclick=3D"SendColor(\'333366\');return false"><area coords=3D"34= ,34,50,50" href=3D"javascript:{SendColor(\'336666\')}" onclick=3D"SendCol= or(\'336666\');return false"><area coords=3D"50,34,66,50" href=3D"javascr= ipt:{SendColor(\'339966\')}" onclick=3D"SendColor(\'339966\');return fals= e"><area coords=3D"66,34,82,50" href=3D"javascript:{SendColor(\'33CC66\')= }" onclick=3D"SendColor(\'33CC66\');return false"><area coords=3D"82,34,9= 8,50" href=3D"javascript:{SendColor(\'33FF66\')}" onclick=3D"SendColor(\'= 33FF66\');return false"><area coords=3D"98,34,114,50" href=3D"javascript:= {SendColor(\'66FF66\')}" onclick=3D"SendColor(\'66FF66\');return false"><= area coords=3D"114,34,130,50" href=3D"javascript:{SendColor(\'66CC66\')}"= onclick=3D"SendColor(\'66CC66\');return false"><area coords=3D"130,34,14= 6,50" href=3D"javascript:{SendColor(\'669966\')}" onclick=3D"SendColor(\'= 669966\');return false"><area coords=3D"146,34,162,50" href=3D"javascript= :{SendColor(\'666666\')}" onclick=3D"SendColor(\'666666\');return false">= <area coords=3D"162,34,178,50" href=3D"javascript:{SendColor(\'663366\')}= " onclick=3D"SendColor(\'663366\');return false"><area coords=3D"178,34,1= 94,50" href=3D"javascript:{SendColor(\'660066\')}" onclick=3D"SendColor(\= '660066\');return false"><area coords=3D"194,34,210,50" href=3D"javascrip= t:{SendColor(\'FF0066\')}" onclick=3D"SendColor(\'FF0066\');return false"= ><area coords=3D"210,34,226,50" href=3D"javascript:{SendColor(\'FF3366\')= }" onclick=3D"SendColor(\'FF3366\');return false"><area coords=3D"226,34,= 242,50" href=3D"javascript:{SendColor(\'FF6666\')}" onclick=3D"SendColor(= \'FF6666\');return false"><area coords=3D"242,34,258,50" href=3D"javascri= pt:{SendColor(\'FF9966\')}" onclick=3D"SendColor(\'FF9966\');return false= "><area coords=3D"258,34,274,50" href=3D"javascript:{SendColor(\'FFCC66\'= )}" onclick=3D"SendColor(\'FFCC66\');return false"><area coords=3D"274,34= ,290,50" href=3D"javascript:{SendColor(\'FFFF66\')}" onclick=3D"SendColor= (\'FFFF66\');return false"><!--- Row 4 ---><area coords=3D"2,50,18,66" hr= ef=3D"javascript:{SendColor(\'330099\')}" onclick=3D"SendColor(\'330099\'= );return false"><area coords=3D"18,50,34,66" href=3D"javascript:{SendColo= r(\'333399\')}" onclick=3D"SendColor(\'333399\');return false"><area coor= ds=3D"34,50,50,66" href=3D"javascript:{SendColor(\'336699\')}" onclick=3D= "SendColor(\'336699\');return false"><area coords=3D"50,50,66,66" href=3D= "javascript:{SendColor(\'339999\')}" onclick=3D"SendColor(\'339999\');ret= urn false"><area coords=3D"66,50,82,66" href=3D"javascript:{SendColor(\'3= 3CC99\')}" onclick=3D"SendColor(\'33CC99\');return false"><area coords=3D= "82,50,98,66" href=3D"javascript:{SendColor(\'33FF99\')}" onclick=3D"Send= Color(\'33FF99\');return false"><area coords=3D"98,50,114,66" href=3D"jav= ascript:{SendColor(\'66FF99\')}" onclick=3D"SendColor(\'66FF99\');return = false"><area coords=3D"114,50,130,66" href=3D"javascript:{SendColor(\'66C= C99\')}" onclick=3D"SendColor(\'66CC99\');return false"><area coords=3D"1= 30,50,146,66" href=3D"javascript:{SendColor(\'669999\')}" onclick=3D"Send= Color(\'669999\');return false"><area coords=3D"146,50,162,66" href=3D"ja= vascript:{SendColor(\'666699\')}" onclick=3D"SendColor(\'666699\');return= false"><area coords=3D"162,50,178,66" href=3D"javascript:{SendColor(\'66= 3399\')}" onclick=3D"SendColor(\'663399\');return false"><area coords=3D"= 178,50,194,66" href=3D"javascript:{SendColor(\'660099\')}" onclick=3D"Sen= dColor(\'660099\');return false"><area coords=3D"194,50,210,66" href=3D"j= avascript:{SendColor(\'FF0099\')}" onclick=3D"SendColor(\'FF0099\');retur= n false"><area coords=3D"210,50,226,66" href=3D"javascript:{SendColor(\'F= F3399\')}" onclick=3D"SendColor(\'FF3399\');return false"><area coords=3D= "226,50,242,66" href=3D"javascript:{SendColor(\'FF6699\')}" onclick=3D"Se= ndColor(\'FF6699\');return false"><area coords=3D"242,50,258,66" href=3D"= javascript:{SendColor(\'FF9999\')}" onclick=3D"SendColor(\'FF9999\');retu= rn false"><area coords=3D"258,50,274,66" href=3D"javascript:{SendColor(\'= FFCC99\')}" onclick=3D"SendColor(\'FFCC99\');return false"><area coords=3D= "274,50,290,66" href=3D"javascript:{SendColor(\'FFFF99\')}" onclick=3D"Se= ndColor(\'FFFF99\');return false"><!--- Row 5 ---><area coords=3D"2,66,18= ,82" href=3D"javascript:{SendColor(\'3300CC\')}" onclick=3D"SendColor(\'3= 300CC\');return false"><area coords=3D"18,66,34,82" href=3D"javascript:{S= endColor(\'3333CC\')}" onclick=3D"SendColor(\'3333CC\');return false"><ar= ea coords=3D"34,66,50,82" href=3D"javascript:{SendColor(\'3366CC\')}" onc= lick=3D"SendColor(\'3366CC\');return false"><area coords=3D"50,66,66,82" = href=3D"javascript:{SendColor(\'3399CC\')}" onclick=3D"SendColor(\'3399CC= \');return false"><area coords=3D"66,66,82,82" href=3D"javascript:{SendCo= lor(\'33CCCC\')}" onclick=3D"SendColor(\'33CCCC\');return false"><area co= ords=3D"82,66,98,82" href=3D"javascript:{SendColor(\'33FFCC\')}" onclick=3D= "SendColor(\'33FFCC\');return false"><area coords=3D"98,66,114,82" href=3D= "javascript:{SendColor(\'66FFCC\')}" onclick=3D"SendColor(\'66FFCC\');ret= urn false"><area coords=3D"114,66,130,82" href=3D"javascript:{SendColor(\= '66CCCC\')}" onclick=3D"SendColor(\'66CCCC\');return false"><area coords=3D= "130,66,146,82" href=3D"javascript:{SendColor(\'6699CC\')}" onclick=3D"Se= ndColor(\'6699CC\');return false"><area coords=3D"146,66,162,82" href=3D"= javascript:{SendColor(\'6666CC\')}" onclick=3D"SendColor(\'6666CC\');retu= rn false"><area coords=3D"162,66,178,82" href=3D"javascript:{SendColor(\'= 6633CC\')}" onclick=3D"SendColor(\'6633CC\');return false"><area coords=3D= "178,66,194,82" href=3D"javascript:{SendColor(\'6600CC\')}" onclick=3D"Se= ndColor(\'6600CC\');return false"><area coords=3D"194,66,210,82" href=3D"= javascript:{SendColor(\'FF00CC\')}" onclick=3D"SendColor(\'FF00CC\');retu= rn false"><area coords=3D"210,66,226,82" href=3D"javascript:{SendColor(\'= FF33CC\')}" onclick=3D"SendColor(\'FF33CC\');return false"><area coords=3D= "226,66,242,82" href=3D"javascript:{SendColor(\'FF66CC\')}" onclick=3D"Se= ndColor(\'FF66CC\');return false"><area coords=3D"242,66,258,82" href=3D"= javascript:{SendColor(\'FF99CC\')}" onclick=3D"SendColor(\'FF99CC\');retu= rn false"><area coords=3D"258,66,274,82" href=3D"javascript:{SendColor(\'= FFCCCC\')}" onclick=3D"SendColor(\'FFCCCC\');return false"><area coords=3D= "274,66,290,82" href=3D"javascript:{SendColor(\'FFFFCC\')}" onclick=3D"Se= ndColor(\'FFFFCC\');return false"><!--- Row 6 ---><area coords=3D"2,82,18= ,98" href=3D"javascript:{SendColor(\'3300FF\')}" onclick=3D"SendColor(\'3= 300FF\');return false"><area coords=3D"18,82,34,98" href=3D"javascript:{S= endColor(\'3333FF\')}" onclick=3D"SendColor(\'3333FF\');return false"><ar= ea coords=3D"34,82,50,98" href=3D"javascript:{SendColor(\'3366FF\')}" onc= lick=3D"SendColor(\'3366FF\');return false"><area coords=3D"50,82,66,98" = href=3D"javascript:{SendColor(\'3399FF\')}" onclick=3D"SendColor(\'3399FF= \');return false"><area coords=3D"66,82,82,98" href=3D"javascript:{SendCo= lor(\'33CCFF\')}" onclick=3D"SendColor(\'33CCFF\');return false"><area co= ords=3D"82,82,98,98" href=3D"javascript:{SendColor(\'33FFFF\')}" onclick=3D= "SendColor(\'33FFFF\');return false"><area coords=3D"98,82,114,98" href=3D= "javascript:{SendColor(\'66FFFF\')}" onclick=3D"SendColor(\'66FFFF\');ret= urn false"><area coords=3D"114,82,130,98" href=3D"javascript:{SendColor(\= '66CCFF\')}" onclick=3D"SendColor(\'66CCFF\');return false"><area coords=3D= "130,82,146,98" href=3D"javascript:{SendColor(\'6699FF\')}" onclick=3D"Se= ndColor(\'6699FF\');return false"><area coords=3D"146,82,162,98" href=3D"= javascript:{SendColor(\'6666FF\')}" onclick=3D"SendColor(\'6666FF\');retu= rn false"><area coords=3D"162,82,178,98" href=3D"javascript:{SendColor(\'= 6633FF\')}" onclick=3D"SendColor(\'6633FF\');return false"><area coords=3D= "178,82,194,98" href=3D"javascript:{SendColor(\'6600FF\')}" onclick=3D"Se= ndColor(\'6600FF\');return false"><area coords=3D"194,82,210,98" href=3D"= javascript:{SendColor(\'FF00FF\')}" onclick=3D"SendColor(\'FF00FF\');retu= rn false"><area coords=3D"210,82,226,98" href=3D"javascript:{SendColor(\'= FF33FF\')}" onclick=3D"SendColor(\'FF33FF\');return false"><area coords=3D= "226,82,242,98" href=3D"javascript:{SendColor(\'FF66FF\')}" onclick=3D"Se= ndColor(\'FF66FF\');return false"><area coords=3D"242,82,258,98" href=3D"= javascript:{SendColor(\'FF99FF\')}" onclick=3D"SendColor(\'FF99FF\');retu= rn false"><area coords=3D"258,82,274,98" href=3D"javascript:{SendColor(\'= FFCCFF\')}" onclick=3D"SendColor(\'FFCCFF\');return false"><area coords=3D= "274,82,290,98" href=3D"javascript:{SendColor(\'FFFFFF\')}" onclick=3D"Se= ndColor(\'FFFFFF\');return false"><!--- Row 7 ---><area coords=3D"2,98,18= ,114" href=3D"javascript:{SendColor(\'0000FF\')}" onclick=3D"SendColor(\'= 0000FF\');return false"><area coords=3D"18,98,34,114" href=3D"javascript:= {SendColor(\'0033FF\')}" onclick=3D"SendColor(\'0033FF\');return false"><= area coords=3D"34,98,50,114" href=3D"javascript:{SendColor(\'0066FF\')}" = onclick=3D"SendColor(\'0066FF\');return false"><area coords=3D"50,98,66,1= 14" href=3D"javascript:{SendColor(\'0099FF\')}" onclick=3D"SendColor(\'00= 99FF\');return false"><area coords=3D"66,98,82,114" href=3D"javascript:{S= endColor(\'00CCFF\')}" onclick=3D"SendColor(\'00CCFF\');return false"><ar= ea coords=3D"82,98,98,114" href=3D"javascript:{SendColor(\'00FFFF\')}" on= click=3D"SendColor(\'00FFFF\');return false"><area coords=3D"98,98,114,11= 4" href=3D"javascript:{SendColor(\'99FFFF\')}" onclick=3D"SendColor(\'99F= FFF\');return false"><area coords=3D"114,98,130,114" href=3D"javascript:{= SendColor(\'99CCFF\')}" onclick=3D"SendColor(\'99CCFF\');return false"><a= rea coords=3D"130,98,146,114" href=3D"javascript:{SendColor(\'9999FF\')}"= onclick=3D"SendColor(\'9999FF\');return false"><area coords=3D"146,98,16= 2,114" href=3D"javascript:{SendColor(\'9966FF\')}" onclick=3D"SendColor(\= '9966FF\');return false"><area coords=3D"162,98,178,114" href=3D"javascri= pt:{SendColor(\'9933FF\')}" onclick=3D"SendColor(\'9933FF\');return false= "><area coords=3D"178,98,194,114" href=3D"javascript:{SendColor(\'9900FF\= ')}" onclick=3D"SendColor(\'9900FF\');return false"><area coords=3D"194,9= 8,210,114" href=3D"javascript:{SendColor(\'CC00FF\')}" onclick=3D"SendCol= or(\'CC00FF\');return false"><area coords=3D"210,98,226,114" href=3D"java= script:{SendColor(\'CC33FF\')}" onclick=3D"SendColor(\'CC33FF\');return f= alse"><area coords=3D"226,98,242,114" href=3D"javascript:{SendColor(\'CC6= 6FF\')}" onclick=3D"SendColor(\'CC66FF\');return false"><area coords=3D"2= 42,98,258,114" href=3D"javascript:{SendColor(\'CC99FF\')}" onclick=3D"Sen= dColor(\'CC99FF\');return false"><area coords=3D"258,98,274,114" href=3D"= javascript:{SendColor(\'CCCCFF\')}" onclick=3D"SendColor(\'CCCCFF\');retu= rn false"><area coords=3D"274,98,290,114" href=3D"javascript:{SendColor(\= 'CCFFFF\')}" onclick=3D"SendColor(\'CCFFFF\');return false"><!--- Row 8 -= --><area coords=3D"2,114,18,130" href=3D"javascript:{SendColor(\'0000CC\'= )}" onclick=3D"SendColor(\'0000CC\');return false"><area coords=3D"18,114= ,34,130" href=3D"javascript:{SendColor(\'0033CC\')}" onclick=3D"SendColor= (\'0033CC\');return false"><area coords=3D"34,114,50,130" href=3D"javascr= ipt:{SendColor(\'0066CC\')}" onclick=3D"SendColor(\'0066CC\');return fals= e"><area coords=3D"50,114,66,130" href=3D"javascript:{SendColor(\'0099CC\= ')}" onclick=3D"SendColor(\'0099CC\');return false"><area coords=3D"66,11= 4,82,130" href=3D"javascript:{SendColor(\'00CCCC\')}" onclick=3D"SendColo= r(\'00CCCC\');return false"><area coords=3D"82,114,98,130" href=3D"javasc= ript:{SendColor(\'00FFCC\')}" onclick=3D"SendColor(\'00FFCC\');return fal= se"><area coords=3D"98,114,114,130" href=3D"javascript:{SendColor(\'99FFC= C\')}" onclick=3D"SendColor(\'99FFCC\');return false"><area coords=3D"114= ,114,130,130" href=3D"javascript:{SendColor(\'99CCCC\')}" onclick=3D"Send= Color(\'99CCCC\');return false"><area coords=3D"130,114,146,130" href=3D"= javascript:{SendColor(\'9999CC\')}" onclick=3D"SendColor(\'9999CC\');retu= rn false"><area coords=3D"146,114,162,130" href=3D"javascript:{SendColor(= \'9966CC\')}" onclick=3D"SendColor(\'9966CC\');return false"><area coords= =3D"162,114,178,130" href=3D"javascript:{SendColor(\'9933CC\')}" onclick=3D= "SendColor(\'9933CC\');return false"><area coords=3D"178,114,194,130" hre= f=3D"javascript:{SendColor(\'9900CC\')}" onclick=3D"SendColor(\'9900CC\')= ;return false"><area coords=3D"194,114,210,130" href=3D"javascript:{SendC= olor(\'CC00CC\')}" onclick=3D"SendColor(\'CC00CC\');return false"><area c= oords=3D"210,114,226,130" href=3D"javascript:{SendColor(\'CC33CC\')}" onc= lick=3D"SendColor(\'CC33CC\');return false"><area coords=3D"226,114,242,1= 30" href=3D"javascript:{SendColor(\'CC66CC\')}" onclick=3D"SendColor(\'CC= 66CC\');return false"><area coords=3D"242,114,258,130" href=3D"javascript= :{SendColor(\'CC99CC\')}" onclick=3D"SendColor(\'CC99CC\');return false">= <area coords=3D"258,114,274,130" href=3D"javascript:{SendColor(\'CCCCCC\'= )}" onclick=3D"SendColor(\'CCCCCC\');return false"><area coords=3D"274,11= 4,290,130" href=3D"javascript:{SendColor(\'CCFFCC\')}" onclick=3D"SendCol= or(\'CCFFCC\');return false"><!--- Row 9 ---><area coords=3D"2,130,18,146= " href=3D"javascript:{SendColor(\'000099\')}" onclick=3D"SendColor(\'0000= 99\');return false"><area coords=3D"18,130,34,146" href=3D"javascript:{Se= ndColor(\'003399\')}" onclick=3D"SendColor(\'003399\');return false"><are= a coords=3D"34,130,50,146" href=3D"javascript:{SendColor(\'006699\')}" on= click=3D"SendColor(\'006699\');return false"><area coords=3D"50,130,66,14= 6" href=3D"javascript:{SendColor(\'009999\')}" onclick=3D"SendColor(\'009= 999\');return false"><area coords=3D"66,130,82,146" href=3D"javascript:{S= endColor(\'00CC99\')}" onclick=3D"SendColor(\'00CC99\');return false"><ar= ea coords=3D"82,130,98,146" href=3D"javascript:{SendColor(\'00FF99\')}" o= nclick=3D"SendColor(\'00FF99\');return false"><area coords=3D"98,130,114,= 146" href=3D"javascript:{SendColor(\'99FF99\')}" onclick=3D"SendColor(\'9= 9FF99\');return false"><area coords=3D"114,130,130,146" href=3D"javascrip= t:{SendColor(\'99CC99\')}" onclick=3D"SendColor(\'99CC99\');return false"= ><area coords=3D"130,130,146,146" href=3D"javascript:{SendColor(\'999999\= ')}" onclick=3D"SendColor(\'999999\');return false"><area coords=3D"146,1= 30,162,146" href=3D"javascript:{SendColor(\'996699\')}" onclick=3D"SendCo= lor(\'996699\');return false"><area coords=3D"162,130,178,146" href=3D"ja= vascript:{SendColor(\'993399\')}" onclick=3D"SendColor(\'993399\');return= false"><area coords=3D"178,130,194,146" href=3D"javascript:{SendColor(\'= 990099\')}" onclick=3D"SendColor(\'990099\');return false"><area coords=3D= "194,130,210,146" href=3D"javascript:{SendColor(\'CC0099\')}" onclick=3D"= SendColor(\'CC0099\');return false"><area coords=3D"210,130,226,146" href= =3D"javascript:{SendColor(\'CC3399\')}" onclick=3D"SendColor(\'CC3399\');= return false"><area coords=3D"226,130,242,146" href=3D"javascript:{SendCo= lor(\'CC6699\')}" onclick=3D"SendColor(\'CC6699\');return false"><area co= ords=3D"242,130,258,146" href=3D"javascript:{SendColor(\'CC9999\')}" oncl= ick=3D"SendColor(\'CC9999\');return false"><area coords=3D"258,130,274,14= 6" href=3D"javascript:{SendColor(\'CCCC99\')}" onclick=3D"SendColor(\'CCC= C99\');return false"><area coords=3D"274,130,290,146" href=3D"javascript:= {SendColor(\'CCFF99\')}" onclick=3D"SendColor(\'CCFF99\');return false"><= !--- Row 10 ---><area coords=3D"2,146,18,162" href=3D"javascript:{SendCol= or(\'000066\')}" onclick=3D"SendColor(\'000066\');return false"><area coo= rds=3D"18,146,34,162" href=3D"javascript:{SendColor(\'003366\')}" onclick= =3D"SendColor(\'003366\');return false"><area coords=3D"34,146,50,162" hr= ef=3D"javascript:{SendColor(\'006666\')}" onclick=3D"SendColor(\'006666\'= );return false"><area coords=3D"50,146,66,162" href=3D"javascript:{SendCo= lor(\'009966\')}" onclick=3D"SendColor(\'009966\');return false"><area co= ords=3D"66,146,82,162" href=3D"javascript:{SendColor(\'00CC66\')}" onclic= k=3D"SendColor(\'00CC66\');return false"><area coords=3D"82,146,98,162" h= ref=3D"javascript:{SendColor(\'00FF66\')}" onclick=3D"SendColor(\'00FF66\= ');return false"><area coords=3D"98,146,114,162" href=3D"javascript:{Send= Color(\'99FF66\')}" onclick=3D"SendColor(\'99FF66\');return false"><area = coords=3D"114,146,130,162" href=3D"javascript:{SendColor(\'99CC66\')}" on= click=3D"SendColor(\'99CC66\');return false"><area coords=3D"130,146,146,= 162" href=3D"javascript:{SendColor(\'999966\')}" onclick=3D"SendColor(\'9= 99966\');return false"><area coords=3D"146,146,162,162" href=3D"javascrip= t:{SendColor(\'996666\')}" onclick=3D"SendColor(\'996666\');return false"= ><area coords=3D"162,146,178,162" href=3D"javascript:{SendColor(\'993366\= ')}" onclick=3D"SendColor(\'993366\');return false"><area coords=3D"178,1= 46,194,162" href=3D"javascript:{SendColor(\'990066\')}" onclick=3D"SendCo= lor(\'990066\');return false"><area coords=3D"194,146,210,162" href=3D"ja= vascript:{SendColor(\'CC0066\')}" onclick=3D"SendColor(\'CC0066\');return= false"><area coords=3D"210,146,226,162" href=3D"javascript:{SendColor(\'= CC3366\')}" onclick=3D"SendColor(\'CC3366\');return false"><area coords=3D= "226,146,242,162" href=3D"javascript:{SendColor(\'CC6666\')}" onclick=3D"= SendColor(\'CC6666\');return false"><area coords=3D"242,146,258,162" href= =3D"javascript:{SendColor(\'CC9966\')}" onclick=3D"SendColor(\'CC9966\');= return false"><area coords=3D"258,146,274,162" href=3D"javascript:{SendCo= lor(\'CCCC66\')}" onclick=3D"SendColor(\'CCCC66\');return false"><area co= ords=3D"274,146,290,162" href=3D"javascript:{SendColor(\'CCFF66\')}" oncl= ick=3D"SendColor(\'CCFF66\');return false"><!--- Row 11 ---><area coords=3D= "2,162,18,178" href=3D"javascript:{SendColor(\'000033\')}" onclick=3D"Sen= dColor(\'000033\');return false"><area coords=3D"18,162,34,178" href=3D"j= avascript:{SendColor(\'003333\')}" onclick=3D"SendColor(\'003333\');retur= n false"><area coords=3D"34,162,50,178" href=3D"javascript:{SendColor(\'0= 06633\')}" onclick=3D"SendColor(\'006633\');return false"><area coords=3D= "50,162,66,178" href=3D"javascript:{SendColor(\'009933\')}" onclick=3D"Se= ndColor(\'009933\');return false"><area coords=3D"66,162,82,178" href=3D"= javascript:{SendColor(\'00CC33\')}" onclick=3D"SendColor(\'00CC33\');retu= rn false"><area coords=3D"82,162,98,178" href=3D"javascript:{SendColor(\'= 00FF33\')}" onclick=3D"SendColor(\'00FF33\');return false"><area coords=3D= "98,162,114,178" href=3D"javascript:{SendColor(\'99FF33\')}" onclick=3D"S= endColor(\'99FF33\');return false"><area coords=3D"114,162,130,178" href=3D= "javascript:{SendColor(\'99CC33\')}" onclick=3D"SendColor(\'99CC33\');ret= urn false"><area coords=3D"130,162,146,178" href=3D"javascript:{SendColor= (\'999933\')}" onclick=3D"SendColor(\'999933\');return false"><area coord= s=3D"146,162,162,178" href=3D"javascript:{SendColor(\'996633\')}" onclick= =3D"SendColor(\'996633\');return false"><area coords=3D"162,162,178,178" = href=3D"javascript:{SendColor(\'993333\')}" onclick=3D"SendColor(\'993333= \');return false"><area coords=3D"178,162,194,178" href=3D"javascript:{Se= ndColor(\'990033\')}" onclick=3D"SendColor(\'990033\');return false"><are= a coords=3D"194,162,210,178" href=3D"javascript:{SendColor(\'CC0033\')}" = onclick=3D"SendColor(\'CC0033\');return false"><area coords=3D"210,162,22= 6,178" href=3D"javascript:{SendColor(\'CC3333\')}" onclick=3D"SendColor(\= 'CC3333\');return false"><area coords=3D"226,162,242,178" href=3D"javascr= ipt:{SendColor(\'CC6633\')}" onclick=3D"SendColor(\'CC6633\');return fals= e"><area coords=3D"242,162,258,178" href=3D"javascript:{SendColor(\'CC993= 3\')}" onclick=3D"SendColor(\'CC9933\');return false"><area coords=3D"258= ,162,274,178" href=3D"javascript:{SendColor(\'CCCC33\')}" onclick=3D"Send= Color(\'CCCC33\');return false"><area coords=3D"274,162,290,178" href=3D"= javascript:{SendColor(\'CCFF33\')}" onclick=3D"SendColor(\'CCFF33\');retu= rn false"><!--- Row 12 ---><area coords=3D"2,178,18,194" href=3D"javascri= pt:{SendColor(\'000000\')}" onclick=3D"SendColor(\'000000\');return false= "><area coords=3D"18,178,34,194" href=3D"javascript:{SendColor(\'003300\'= )}" onclick=3D"SendColor(\'003300\');return false"><area coords=3D"34,178= ,50,194" href=3D"javascript:{SendColor(\'006600\')}" onclick=3D"SendColor= (\'006600\');return false"><area coords=3D"50,178,66,194" href=3D"javascr= ipt:{SendColor(\'009900\')}" onclick=3D"SendColor(\'009900\');return fals= e"><area coords=3D"66,178,82,194" href=3D"javascript:{SendColor(\'00CC00\= ')}" onclick=3D"SendColor(\'00CC00\');return false"><area coords=3D"82,17= 8,98,194" href=3D"javascript:{SendColor(\'00FF00\')}" onclick=3D"SendColo= r(\'00FF00\');return false"><area coords=3D"98,178,114,194" href=3D"javas= cript:{SendColor(\'99FF00\')}" onclick=3D"SendColor(\'99FF00\');return fa= lse"><area coords=3D"114,178,130,194" href=3D"javascript:{SendColor(\'99C= C00\')}" onclick=3D"SendColor(\'99CC00\');return false"><area coords=3D"1= 30,178,146,194" href=3D"javascript:{SendColor(\'999900\')}" onclick=3D"Se= ndColor(\'999900\');return false"><area coords=3D"146,178,162,194" href=3D= "javascript:{SendColor(\'996600\')}" onclick=3D"SendColor(\'996600\');ret= urn false"><area coords=3D"162,178,178,194" href=3D"javascript:{SendColor= (\'993300\')}" onclick=3D"SendColor(\'993300\');return false"><area coord= s=3D"178,178,194,194" href=3D"javascript:{SendColor(\'990000\')}" onclick= =3D"SendColor(\'990000\');return false"><area coords=3D"194,178,210,194" = href=3D"javascript:{SendColor(\'CC0000\')}" onclick=3D"SendColor(\'CC0000= \');return false"><area coords=3D"210,178,226,194" href=3D"javascript:{Se= ndColor(\'CC3300\')}" onclick=3D"SendColor(\'CC3300\');return false"><are= a coords=3D"226,178,242,194" href=3D"javascript:{SendColor(\'CC6600\')}" = onclick=3D"SendColor(\'CC6600\');return false"><area coords=3D"242,178,25= 8,194" href=3D"javascript:{SendColor(\'CC9900\')}" onclick=3D"SendColor(\= 'CC9900\');return false"><area coords=3D"258,178,274,194" href=3D"javascr= ipt:{SendColor(\'CCCC00\')}" onclick=3D"SendColor(\'CCCC00\');return fals= e"><area coords=3D"274,178,290,194" href=3D"javascript:{SendColor(\'CCFF0= 0\')}" onclick=3D"SendColor(\'CCFF00\');return false">''') Modified: trunk/FormEncode/experimental/FormEncodeKit/Examples/Register.p= y =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/experimental/FormEncodeKit/Examples/Register.py 2004= -03-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/experimental/FormEncodeKit/Examples/Register.py 2004= -03-23 12:46:46 UTC (rev 77) @@ -1,32 +1,66 @@ -from Component.CPage import CPage +from SitePage import SitePage from formencode import validators, htmlview, schema from FormEncodeKit.FormComponent import FormComponent =20 +class StreetAddress(schema.Schema): + view =3D htmlview.FormTableLayout(layout=3D['street1', 'street2', + ['city', 'state', 'zip']]) + =20 + street1 =3D validators.String(view=3Dhtmlview.Text(size=3D30), + notEmpty=3DTrue, description=3D'Street A= ddress') + street2 =3D htmlview.Text(description=3D'', size=3D30) + city =3D validators.String(view=3Dhtmlview.Text(size=3D15), + notEmpty=3DTrue) + state =3D validators.StateProvince(notEmpty=3DTrue, + view=3Dhtmlview.Text(size=3D2, maxl= ength=3D2)) + zip =3D validators.PostalCode(notEmpty=3DTrue, + view=3Dhtmlview.Text(size=3D10, maxlengt= h=3D10)) + +class UniqueUsernameValidator(validators.FancyValidator): + =20 + messages =3D {'usernameTaken': 'The username %(username)s is already= in use'} + + def validatePython(self, value, state): + if value in ('john', 'doe', 'admin', 'root'): + raise validators.Invalid(self.message('usernameTaken', state= , + username=3Dvalue), + value, state) + class RegisterSchema(schema.Schema): - fname =3D validators.String(htmlview=3Dhtmlview.Text) - lname =3D validators.String(htmlview=3Dhtmlview.Text, - notEmpty=3DTrue) - password =3D validators.String(htmlview=3Dhtmlview.Password, - notEmpty=3DTrue) + + class view(htmlview.FormTableLayout): + layout =3D ['email', + 'username', + ['fname', 'lname'], + ['password', 'confirm_password'], + 'address', + 'birthday', + 'submit'] + =20 + email =3D validators.Email(view=3Dhtmlview.Text(size=3D40), + notEmpty=3DTrue) + username =3D validators.All(UniqueUsernameValidator( + view=3Dhtmlview.Text(size=3D40), notEmpty=3DTrue), + validators.PlainText()) + fname =3D validators.String(view=3Dhtmlview.Text, + description=3D'First') + lname =3D validators.String(view=3Dhtmlview.Text, + notEmpty=3DTrue, description=3D'Last') + password =3D validators.String(view=3Dhtmlview.Password, + notEmpty=3DTrue, + description=3D'Password') + confirm_password =3D htmlview.Password(description=3D'Confirm') + + address =3D StreetAddress + birthday =3D validators.DateConverter(view=3Dhtmlview.Text(size=3D10= ), + notEmpty=3DTrue) + =20 submit =3D htmlview.SubmitButton() + + chainedValidators =3D [validators.FieldsMatch('password', 'confirm_p= assword')] =20 -class Register(CPage): +class Register(SitePage): =20 components =3D [FormComponent()] =20 - class form(htmlview.Form): - fname =3D htmlview.Text() - lname =3D htmlview.Text(validator=3Dvalidators.NotEmpty()) - password =3D htmlview.Password(validator=3Dvalidators.NotEmpty()= ) - submit =3D htmlview.SubmitButton - formSchema =3D RegisterSchema - - def writeContent(self): - valid, data =3D self.processForm() - print 'VALID: %s (%r)' % (valid, data) - if not valid: - self.writeForm() - else: - for key, value in data.items(): - self.write('%s=3D%r<br>\n' % (key, value)) Added: trunk/FormEncode/experimental/FormEncodeKit/Examples/SitePage.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/experimental/FormEncodeKit/Examples/SitePage.py 2004= -03-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/experimental/FormEncodeKit/Examples/SitePage.py 2004= -03-23 12:46:46 UTC (rev 77) @@ -0,0 +1,39 @@ +from Component.CPage import CPage + +class SitePage(CPage): + + def writeStyleSheet(self): + self.writeln('\t<link rel=3Dstylesheet href=3Dstyle.css type=3Dt= ext/css>') + + def writeHeader(self): + self.write(''' + <table width=3D"100%%" style=3D"padding: 10px; background-color:= #000066; color: #ffffff; font-family: sans-serif;"> + <tr><td align=3Dleft>FormEncode: %s</td> + <td align=3Dright><a href=3D"%s" style=3D"color: #ffffff">Reset<= /a> | + <a href=3D"./" style=3D"color: #ffffff">Main</a></td></tr> + </table> + ''' % (self.htTitle(), self.name())) + + def writeFooter(self): + pass + + def writeBodyParts(self): + self.writeHeader() + self.writeContent() + self.writeFooter() + + def writeContent(self): + valid, data =3D self.processForm() + print 'VALID: %s (%r)' % (valid, data) + if not valid: + self.writeForm() + else: + self.writeData(data) + + def writeData(self, data):=20 + self.write('<table>') + for key, value in data.items(): + self.write('<tr><td>%s:</td>' % key) + self.write('<td>%s</td></tr>\n' % self.htmlEncode(repr(value= ))) + self.write('</table>') + =20 Added: trunk/FormEncode/experimental/FormEncodeKit/Examples/Workflow.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/experimental/FormEncodeKit/Examples/Workflow.py 2004= -03-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/experimental/FormEncodeKit/Examples/Workflow.py 2004= -03-23 12:46:46 UTC (rev 77) @@ -0,0 +1,19 @@ +from SitePage import SitePage +from formencode import validators, htmlview, schema +from FormEncodeKit.FormComponent import FormComponent + +class WorkflowSchema(schema.Schema): + + view =3D htmlview.FormTableLayout(layout=3D[['name', 'comment', 'col= or']]) + + name =3D validators.PlainText(view=3Dhtmlview.Text(), + notEmpty=3DTrue, size=3D10) + comment =3D htmlview.Text(size=3D20) + color =3D htmlview.ColorPicker(colorPickerURL=3D"ColorPicker") + +class Workflow(SitePage): + + components =3D [FormComponent()] + class formSchema(WorkflowSchema): + view =3D WorkflowSchema.view(layout=3DWorkflowSchema.view.layout= + ['submit']) + submit =3D htmlview.SubmitButton() Added: trunk/FormEncode/experimental/FormEncodeKit/Examples/net216.gif =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D (Binary files differ) Property changes on: trunk/FormEncode/experimental/FormEncodeKit/Examples= /net216.gif ___________________________________________________________________ Name: svn:mime-type + application/octet-stream Added: trunk/FormEncode/experimental/FormEncodeKit/Examples/style.css =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/experimental/FormEncodeKit/Examples/style.css 2004-0= 3-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/experimental/FormEncodeKit/Examples/style.css 2004-0= 3-23 12:46:46 UTC (rev 77) @@ -0,0 +1,18 @@ +body { + font-family: Helvetica, Arial, sans-serif; +} + +i, em { + font-family: Times New Roman, Times, seris; +} + +table.phonetable { + background-color: #eeeeee; + border: 2px solid #aaaaaa; +} + +b.formerror { + background-color: #660000; + color: #ffffff; + font-weight: normal; +} \ No newline at end of file Modified: trunk/FormEncode/experimental/FormEncodeKit/Properties.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/experimental/FormEncodeKit/Properties.py 2004-03-22 = 12:35:04 UTC (rev 76) +++ trunk/FormEncode/experimental/FormEncodeKit/Properties.py 2004-03-23 = 12:46:46 UTC (rev 77) @@ -15,5 +15,6 @@ 'Register', 'Address', 'AddressList', + 'Workflow', ] } Modified: trunk/FormEncode/src/htmlview.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/src/htmlview.py 2004-03-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/src/htmlview.py 2004-03-23 12:46:46 UTC (rev 77) @@ -66,7 +66,6 @@ except NotImplementedError: self.field =3D None assert self.field, "Validator has no view: %r" % self.rawVal= idator - print "FIELD:", self.rawValidator, self.field else: self.field =3D field try: @@ -405,17 +404,27 @@ formName =3D None enctype =3D Exclude =20 + def __init__(self, *args, **kw): + Declarative.__init__(self, *args, **kw) + self._javascript =3D {} + def html(self, httpRequest=3DNone, defaults=3DNone, options=3DNone, errors=3DNone, state=3DNone): + assert not self._javascript, "Leftover Javascript! %s" % self._j= avascript assert self.action, "You must provide an action" request =3D FormRequest( httpRequest=3DhttpRequest, defaults=3Ddefaults, options=3Dop= tions, errors=3Derrors, state=3Dstate, validator=3Dself.schema, form=3Dself) contents =3D request.html() + js =3D '\n\n'.join(self._javascript.values()) + if js: + js =3D html.script(language=3D"JavaScript", + c=3Dhtml.comment('\n', js, '\n// ')) contents =3D html( html.input.hidden(name=3D'_formName_', value=3Dself.formName), + js, contents) return html.form( action=3Dself.action, @@ -427,14 +436,18 @@ #html.input.hidden(name=3D"_formID_", value=3Dself.formName)= , #contents)) =20 + def addJavaScript(self, name, javascript): + self._javascript[name] =3D javascript + class SchemaLayout(Field): =20 appendLabel =3D ':' appendError =3D '' - errorClass =3D Exclude + errorClass =3D 'formerror' useFieldset =3D False legend =3D None requiresLabel =3D False + fieldsetClass =3D 'formfieldset' =20 def html(self, request): assert request.compound, "SchemaLayouts are meant to be used wit= h Schema objects (%r with %r)" % (request, self) @@ -447,7 +460,7 @@ hidden.append(subRequest.html()) else: text.append(self.htmlField(name, subRequest)) - return self.wrapFieldset(self.wrapFields(''.join(text+hidden), r= equest), + return self.wrapFieldset(self.wrapFields('\n'.join(text+hidden),= request), request) =20 def getError(self, request): @@ -473,7 +486,8 @@ if error: return html(html.b(error, request.option('appendError', self), - class_=3Drequest.option('errorClass', sel= f))) + class_=3Drequest.option('errorClass', sel= f)), + html.br) else: return '' =20 @@ -493,17 +507,18 @@ legend =3D html.legend(legend) else: legend =3D '' - return html.fieldset(legend, text) + return html.fieldset(legend, text, + class_=3Drequest.option('fieldsetClass', se= lf)) =20 Schema.view =3D SchemaLayout() =20 class TableLayout(SchemaLayout): =20 width =3D Exclude - labelClass =3D Exclude - fieldClass =3D Exclude + labelClass =3D 'formlabel' + fieldClass =3D 'formfield' labelAlign =3D Exclude - tableClass =3D Exclude + tableClass =3D 'formtable' =20 def htmlField(self, name, request): return html.tr( @@ -532,9 +547,10 @@ for line in layout: if isinstance(line, (str, unicode)): line =3D [line] - text.append(self.htmlLine(self, line, request)) + text.append(self.htmlLine(line, request)) # @@: Should check that there aren't forgotten fields here - return self.wrapFieldset(self.wrapFields(''.join(text))) + return self.wrapFieldset(self.wrapFields(''.join(text), request)= , + request) =20 def htmlLine(self, line, request): cells =3D [] @@ -548,9 +564,13 @@ else: sub =3D request[item] label =3D self.formatLabel(sub) - cells.append(html.td(label, + if label: + label =3D html(label, html.br) + cells.append(html.td('\n', label,=20 self.formatError(sub), - sub.html())) + sub.html(), + valign=3D"bottom")) + cells.append('\n') return html.table(html.tr(c=3Dcells)) =20 class ForEachLayout(SchemaLayout): @@ -1750,6 +1770,7 @@ Field.__init__(self, **kw) =20 def htmlInput(self, request): + self.addJavascript(request) colorPickerURL =3D request.option('colorPickerURL', self) assert colorPickerURL, 'You must give a base URL for the color p= icker' name =3D request.name @@ -1762,22 +1783,26 @@ style=3D"background-color: %s; border: thin black so= lid;" % defaultColor, c=3D" "), html.td( - html.input.text(size=3D8, maxlength=3D6, + html.input.text(size=3D8, + onChange=3D"document.getElementById('%s').st= yle.backgroundColor =3D this.value; return true" % colorID, name=3Dname, value=3Drequest.default()), html.input.button(value=3D"pick", onClick=3D"colorpick(this, '%s', '%s')" % = (name, colorID))))]) =20 - def formJavascript(self, options, state): - return {'ColorPicker:%s' % self.colorPickerURL: """\ + def addJavascript(self, request): + request.form.addJavaScript( + name=3D'ColorPicker:%s' % request.option('colorPickerURL', s= elf), + javascript=3D"""\ function colorpick(element, textFieldName, colorID) { win =3D window.open('%s?form=3D' - + escape(element.form.name) + + escape(element.form.attributes.name.value) + '&field=3D' + escape(textFieldName) + '&colid=3D' + escape(colorID), '_blank', 'dependent=3Dno,directories=3Dno,width=3D300,heigh= t=3D130,location=3Dno,menubar=3Dno,status=3Dno,toolbar=3Dno'); } -""" % self.colorPickerURL} +""" % self.colorPickerURL) + =20 =20 ######################################## ## Some compound field generators Modified: trunk/FormEncode/src/validators.py =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D --- trunk/FormEncode/src/validators.py 2004-03-22 12:35:04 UTC (rev 76) +++ trunk/FormEncode/src/validators.py 2004-03-23 12:46:46 UTC (rev 77) @@ -1670,7 +1670,7 @@ showMatch =3D False fieldNames =3D None validatePartialForm =3D True - __unpackfields__ =3D ('*', 'fieldNames') + __unpackargs__ =3D ('*', 'fieldNames') =20 messages =3D { 'invalid': "Fields do not match (should be %(match)s)", @@ -1683,12 +1683,13 @@ return self.validate(fieldDict) =20 - def validate(self, fieldDict, state): - ref =3D fieldDict[self._fieldNames[0]] + def validatePython(self, fieldDict, state): + print "Checking:", self.fieldNames, fieldDict + ref =3D fieldDict[self.fieldNames[0]] errors =3D {} - for name in self._fieldNames[1:]: + for name in self.fieldNames[1:]: if fieldDict.get(name, '') !=3D ref: - if self._showMatch: + if self.showMatch: errors[name] =3D self.message('invalid', state, match=3Dref) else: |