
I am trying to customise my Formless layout based on examples/customform.py, but I'm not sure how I can group inputs in fieldsets. eg. http://rafb.net/paste/results/dhZOhk37.html That's my ideal layout, can anyone give me hints on howto achieve it? -RichardW.

Richard Wall wrote:
I am trying to customise my Formless layout based on examples/customform.py, but I'm not sure how I can group inputs in fieldsets.
Good question. I asked the same one a while back (no reply - maybe the mail didn't get through). I mused: I suspect I can subclass annotate.Typed or use the complexType stuff to somehow group a textbox and dropdown together into one logical bit of HTML that is rendered as a single "control" ...but other commitments have kept me from revisiting this
I get a 404
That's my ideal layout, can anyone give me hints on howto achieve it?
Let me know if you find out!

Phil Mayers wrote:
Richard Wall wrote:
I am trying to customise my Formless layout based on examples/customform.py, but I'm not sure how I can group inputs in fieldsets. Good question. I asked the same one a while back (no reply - maybe the mail didn't get through). I mused:
It did, but I didn't spot it until after I'd posted my message. I've learned alot since.
I suspect I can subclass annotate.Typed or use the complexType stuff to somehow group a textbox and dropdown together into one logical bit of HTML that is rendered as a single "control" ...but other commitments have kept me from revisiting this
For custom output look at custom renderers. You have to register them as adaptors using compy.registerAdaptor. Read this article if adaptors are new to you (they were to me)... http://twistedmatrix.com/projects/core/documentation/howto/components.html Incase your wondering where Nevow registers it's default adaptors (I did) they're in nevow/__init__.py. Some examples... A multiple choice element (missing from Nevow)... http://deadbeefbabe.org/paste/888 ...I'd like to see this (or something similar) included as default. It's a very common form pattern. A date parser element. User can enter date into text box however they want... http://deadbeefbabe.org/paste/889 A fix for the output of radio lists... http://deadbeefbabe.org/paste/890
eg. http://rafb.net/paste/results/dhZOhk37.html I get a 404
I think they expire after a while. Have used another pastebin here.
That's my ideal layout, can anyone give me hints on howto achieve it? Let me know if you find out!
I found out on #twisted.web from fog, STemplar and others. First checkout examples/customform.py from Nevow svn but it doesn't demonstrate argument slots (as opposed to argument patterns) Here's an example of argument slots and patterns... http://rafb.net/paste/results/Tko2XM57.html So you do get control over each arguments layout and position. The default Nevow argument pattern doesn't validate (div inside span!). Using dl,dt,dd makes more sense. You might also want to apply this patch to nevow... http://divmod.org/users/roundup.twistd/nevow/issue203 Hope this saves you some time. -RichardW.

Phil, Have just learnt on irc that a replacement for formless is imminent... svn://pollenation.net/forms/trunk -RichardW. Richard Wall wrote:
Phil Mayers wrote:
Richard Wall wrote:
I am trying to customise my Formless layout based on examples/customform.py, but I'm not sure how I can group inputs in fieldsets.
Good question. I asked the same one a while back (no reply - maybe the mail didn't get through). I mused:
It did, but I didn't spot it until after I'd posted my message. I've learned alot since.
I suspect I can subclass annotate.Typed or use the complexType stuff to somehow group a textbox and dropdown together into one logical bit of HTML that is rendered as a single "control" ...but other commitments have kept me from revisiting this
For custom output look at custom renderers. You have to register them as adaptors using compy.registerAdaptor.
Read this article if adaptors are new to you (they were to me)... http://twistedmatrix.com/projects/core/documentation/howto/components.html
Incase your wondering where Nevow registers it's default adaptors (I did) they're in nevow/__init__.py.
Some examples...
A multiple choice element (missing from Nevow)... http://deadbeefbabe.org/paste/888 ...I'd like to see this (or something similar) included as default. It's a very common form pattern.
A date parser element. User can enter date into text box however they want... http://deadbeefbabe.org/paste/889
A fix for the output of radio lists... http://deadbeefbabe.org/paste/890
I get a 404
I think they expire after a while. Have used another pastebin here.
That's my ideal layout, can anyone give me hints on howto achieve it?
Let me know if you find out!
I found out on #twisted.web from fog, STemplar and others.
First checkout examples/customform.py from Nevow svn but it doesn't demonstrate argument slots (as opposed to argument patterns)
Here's an example of argument slots and patterns... http://rafb.net/paste/results/Tko2XM57.html
So you do get control over each arguments layout and position. The default Nevow argument pattern doesn't validate (div inside span!). Using dl,dt,dd makes more sense.
You might also want to apply this patch to nevow... http://divmod.org/users/roundup.twistd/nevow/issue203
Hope this saves you some time.
-RichardW.

Richard Wall wrote:
Phil,
Have just learnt on irc that a replacement for formless is imminent... svn://pollenation.net/forms/trunk
Grr, I keep telling people this in #twisted.web ... forms is *not* a replacement for formless. Feel free to use forms if it meets your needs but it's really only an HTML forms toolkit. Perhaps I should explain my reasoning for forms better ... Formless is really a naked object implementation. Formless is about exposing the interface (attributes and methods) of an application's object on the web. In theory, formless is agnostic about how and where the forms are used although, at present, there is only webform. Christopher Armstrong (radix) once wrote a GTK+ renderer for formless typed interfaces but I think it's probably dead now. forms, by comparison, is not about object interfaces; it's about explicitly creating a Form, adding fields to it, rendering it, and processing it (with validation). Because forms is only interested in HTML, it also allows a field's widget to be switched easily, without having to create a new Typed subclass. For instance, I can add a Date field to a forms form and choose to render that as a text input, three inputs (dd/mm/yyyy) or even a <select> list of predefined dates, just by changing the widget. My original goal with forms was to provide a reasonably flexible HTML forms package that developers *and* formless.webform could use. It will never replace formless because it's working at a lower level but it could potentially replace a lot of formless.webform. Unfortunately, I've never had time to achieve the formless part of that goal but forms is quite usable as it is. In some ways, formless is actually more flexible than forms because it supports almost complete customisation of the HTML output (see Nevow's customform example). Personally, I find it quite cumbersome to use and, since writing forms, I have not needed to customise the form to that extent anyway. I have to admit that there are times when better control of the generated HTML would be nice, but I've always got away with it so far :). <rant> While I'm on the subject ;-) ... my pet hate is seeing people "abuse" formless: using a nested TypedInterface to group attributes so they are on the same form and submitted in one request; using autocallable to submit a bunch of attributes because storing the data is easier in a method than trying to hook into formless after the attributes are set. I also dislike having to subclass Typed to provide a different widget, even though the value I get back does not change. </rant> Anyway, please try forms out and let me and the other Nevow developers know what you think of it. If there is enough interest, and I can find time, I will happily move it into Nevow. Heck, I'll even write some tests for it ;-). If we can get formless.webform to use it, without breaking everything people are already doing, then even better. Cheers, Matt
-RichardW.
Richard Wall wrote:
Phil Mayers wrote:
Richard Wall wrote:
I am trying to customise my Formless layout based on examples/customform.py, but I'm not sure how I can group inputs in fieldsets.
Good question. I asked the same one a while back (no reply - maybe the mail didn't get through). I mused:
It did, but I didn't spot it until after I'd posted my message. I've learned alot since.
I suspect I can subclass annotate.Typed or use the complexType stuff to somehow group a textbox and dropdown together into one logical bit of HTML that is rendered as a single "control" ...but other commitments have kept me from revisiting this
For custom output look at custom renderers. You have to register them as adaptors using compy.registerAdaptor.
Read this article if adaptors are new to you (they were to me)... http://twistedmatrix.com/projects/core/documentation/howto/components.html
Incase your wondering where Nevow registers it's default adaptors (I did) they're in nevow/__init__.py.
Some examples...
A multiple choice element (missing from Nevow)... http://deadbeefbabe.org/paste/888 ...I'd like to see this (or something similar) included as default. It's a very common form pattern.
A date parser element. User can enter date into text box however they want... http://deadbeefbabe.org/paste/889
A fix for the output of radio lists... http://deadbeefbabe.org/paste/890
I get a 404
I think they expire after a while. Have used another pastebin here.
That's my ideal layout, can anyone give me hints on howto achieve it?
Let me know if you find out!
I found out on #twisted.web from fog, STemplar and others.
First checkout examples/customform.py from Nevow svn but it doesn't demonstrate argument slots (as opposed to argument patterns)
Here's an example of argument slots and patterns... http://rafb.net/paste/results/Tko2XM57.html
So you do get control over each arguments layout and position. The default Nevow argument pattern doesn't validate (div inside span!). Using dl,dt,dd makes more sense.
You might also want to apply this patch to nevow... http://divmod.org/users/roundup.twistd/nevow/issue203
Hope this saves you some time.
-RichardW.
_______________________________________________ Twisted-web mailing list Twisted-web@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-web
-- __ / \__ Matt Goodall, Pollenation Internet Ltd \__/ \ w: http://www.pollenation.net __/ \__/ e: matt@pollenation.net / \__/ \ t: +44 (0)113 2252500 \__/ \__/ / \ Any views expressed are my own and do not necessarily \__/ reflect the views of my employer.

Matt Goodall wrote:
forms, by comparison, is not about object interfaces; it's about explicitly creating a Form, adding fields to it, rendering it, and processing it (with validation). Because forms is only interested in HTML, it also allows a field's widget to be switched easily, without having to create a new Typed subclass. For instance, I can add a Date field to a forms form and choose to render that as a text input, three inputs (dd/mm/yyyy) or even a <select> list of predefined dates, just by changing the widget.
I might encourage you to think about using the architecture I describe here: http://blog.ianbicking.org/a-theory-on-form-toolkits.html -- either using FormEncode, pieces, or just the general idea. E.g., I think something like FormEncode's htmlfill that used stan could be useful, and FormEncode doesn't currently include anything very good for actual HTML generation. Anyway, I think keeping the parts separate (blank HTML form generation, validation, final form rendering) is really important to making a usable system; without it people just keep creating form toolkits that they later come to hate because the abstraction boundaries don't fit the actual development process. -- Ian Bicking / ianb@colorstudy.com / http://blog.ianbicking.org

Ian Bicking wrote:
I might encourage you to think about using the architecture I describe here: http://blog.ianbicking.org/a-theory-on-form-toolkits.html -- either using FormEncode, pieces, or just the general idea. E.g., I think something like FormEncode's htmlfill that used stan could be useful, and FormEncode doesn't currently include anything very good for actual HTML generation.
Anyway, I think keeping the parts separate (blank HTML form generation, validation, final form rendering) is really important to making a usable system; without it people just keep creating form toolkits that they later come to hate because the abstraction boundaries don't fit the actual development process.
From what Matt said when we talked about forms (quite a lot of times) it is already resusing some concepts from htmlfill.
The basic idea is to separate the types you want, from the widget used to represent them on the page. When you add a new form you choose a name (which is actually a key in the 'validated values'-dict), a type (that knows how to encode and decode from the python application and from the web), a widget (or a widgetFactory when you have grouped widgets). basically both the rendering and the processing share some code obviously: Let's use an example form: from nevow import rend import forms class ModifyPage(rend.Page, forms.ResourceMixin): def form_modify(self, ctx): form = forms.Form(self.modify) contractor_view(form) form.addAction(self.modify) form.data = IContractor(ctx) form.data['numero_contratto'] = self.original return form def modify(self, ctx, form, data): db.ILogic(ctx).modify_contractor(self.original, data) In order to tell the system where to find the form there are 2 things you can do: during rendering you should use: <nevow:invisible nevow:render="form formName" /> or during a POST/GET with an url like: http://localhost:8080/modify/__nevow_form__!!modify what does the system do? During rendering: with nevow:render="form formName" you are calling the method render_form defined in the base forms.ResourceMixin that takes the formName as an argument. During post/get processing: in the Modify's page locateChild the url is split to look for __nevow_form__ and the string after !! is the formName. Both do the same thing now: The Modify page is searched for form_formName method and its return value (a Form instance populated with fields). During form search the form instance is saved on the request to ensure that each form instance is reused during the same request (so that modifications are available at a later time when needed). Then the form is processed in 2 different ways (depending on what you need to do). Rendering: - form object is remembered in the context as iforms.IForm - thanks to the adapter for the form object to IRenderer the form object is directly passed in a stan tag. The Form renderer will take care of rendering. - A new context is created. and the data from the old context is remembered on it (errors, data inserted and such). - The form is rendered in this way: - the form object is iterated through for each field. - each field is rendered, if there are errors they are looked up in iforms.IFormErrors (which was remembered at the beginning). - the render method of the widget is called and it does the following thing: - One of the converters is gathered from the adaptators and the python type is converted into a string. - the result is set as value, the stan representing the widget is returned and sent to the client browser. GET/POST processing: - the method process() is called on the return value of the form_formName method. - arguments are obtained from the request. - the callback in the rend.Page object is found - initialize the FormErrors 'dict' - for each field in the form: - the widget is retrieved from the field name. - the value is processed back to a python type (thanks to the same adapters registry and the same converter) - it is then validated by the type used (remember that the converters adapter registry is made like this: Converter <adapts> type <to> InterfaceForConverter) _validation and coercion are really separate although both called in processInput method of the widget_ the result of validation is the data processed and ready to be used - the callback is called with the result of validation. - if there are errors in the result of validation then you are redirected to the same page with the form, and reusing the same form instance (that we remembered at the beginning of the locateForm) the page is rendered with error information. I think this is all. I could have made some mistakes though. If you think I've talked too much because you already knew all then forgive me, but I'm sure Matt will like to add this stuff to some documentation or general idea, or edit this stuff for a bit of documentation and so on. :) It also helped me to understand forms a bit better. -- Valentino Volonghi aka Dialtone Now Running MacOSX 10.4.1 Blog: http://vvolonghi.blogspot.com http://weever.berlios.de

Valentino Volonghi aka Dialtone wrote:
Rendering: - form object is remembered in the context as iforms.IForm - thanks to the adapter for the form object to IRenderer the form object is directly passed in a stan tag. The Form renderer will take care of rendering. - A new context is created. and the data from the old context is remembered on it (errors, data inserted and such). - The form is rendered in this way: - the form object is iterated through for each field. - each field is rendered, if there are errors they are looked up in iforms.IFormErrors (which was remembered at the beginning). - the render method of the widget is called and it does the following thing: - One of the converters is gathered from the adaptators and the python type is converted into a string. - the result is set as value, the stan representing the widget is returned and sent to the client browser.
I don't understand all the aspects -- I don't know much about Nevow rendering -- but I think what you are describing is the traditional way form toolkits work, except perhaps that validation is better separated than in some cases. I'm proposing that validation and form generation be *completely* seperate. So you get several real data structures. The validation produces something like this: {'field_name': 'field_value', ...} {'field_name': 'error_string', ...} You can package that in an object or whatever, but that's the basic data. Then the form generation produces: <input type="text" name="field_name"> Then a third component (like htmlfill) puts these two items together, but does so with no knowledge of how the data came into being. And the actual logic for redisplaying forms and whatnot should be entirely seperate, because Traditionally form toolkits generate HTML widgets with values and errors already filled in. This binds HTML generation to the validation process, which almost always falls apart eventually, because no one HTML generator is general enough (and the most general HTML generator -- an actual person writing HTML by hand -- should always be allowed for). Maybe form is doing this, but at least it doesn't sound like it is. But it does sound like it uses two-way conversion/validation, which I think is also a very important feature. -- Ian Bicking / ianb@colorstudy.com / http://blog.ianbicking.org

Ian Bicking wrote:
I'm proposing that validation and form generation be *completely* seperate. So you get several real data structures. The validation produces something like this:
{'field_name': 'field_value', ...} {'field_name': 'error_string', ...}
That's how forms works. Perhaps I missed some bits of my reasoning. The validation result is exactly a dict of {'field_name': 'field_value'..} passed to the method which signature is: def callback(self, ctx, form, data) and data is the dict you want. The same is for the error 'dict', but you won't use that since it will be used during re-rendering of the page with error messages.
You can package that in an object or whatever, but that's the basic data. Then the form generation produces:
<input type="text" name="field_name">
right
Then a third component (like htmlfill) puts these two items together, but does so with no knowledge of how the data came into being. And the actual logic for redisplaying forms and whatnot should be entirely seperate, because
I guess htmlfill role is played by FormRenderer which is the one that collects all the form fields and renders each of them.
Traditionally form toolkits generate HTML widgets with values and errors already filled in. This binds HTML generation to the validation process, which almost always falls apart eventually, because no one HTML generator is general enough (and the most general HTML generator -- an actual person writing HTML by hand -- should always be allowed for).
Currently forms doesn't 'support' form customization. Right now it renders itself over this pattern: T.form(id=T.slot('id'), action=T.slot('action'), class_='nevow-form', method='post', enctype='multipart/form-data', **{'accept-charset':'utf-8'})[ T.input(type='hidden', name='_charset_'), T.slot('errors'), T.slot('items'), T.div(id=T.slot('fieldId'), pattern='item', _class=T.slot('class'))[ T.label(_for=T.slot('id'))[T.slot('label')], T.div(_class='inputs')[T.slot('inputs')], T.slot('description'), T.slot('message'), ], T.div(class_='hiddenitems')[ T.slot('hiddenitems'), T.invisible(pattern="hiddenitem")[T.slot('inputs')] ], T.div(class_='actions')[ T.slot('actions'), ], ] The div with pattern="item" is the single slot. message slot is the error message. The FormRenderer is the thing that fills those slot taking them from the right place (it is the controller in an MVC view).
Maybe form is doing this, but at least it doesn't sound like it is. But it does sound like it uses two-way conversion/validation, which I think is also a very important feature.
Yep. Particularly I'd like to show you the interfaces involved. class IType(Interface): def validate(self, value): pass class IWidget(Interface): def render(self, ctx, key, args, errors): pass def processInput(self, ctx, key, args): pass class IConvertible(Interface): def fromType(self, value): pass def toType(self, value): pass class IStringConvertible(IConvertible): pass # other Convertibles -- Valentino Volonghi aka Dialtone Now Running MacOSX 10.4.1 Blog: http://vvolonghi.blogspot.com http://weever.berlios.de
participants (5)
-
Ian Bicking
-
Matt Goodall
-
Phil Mayers
-
Richard Wall
-
Valentino Volonghi aka Dialtone