[Html-widget] HTML::Widget::Element::Field

Carl Franks fireartist at gmail.com
Tue Nov 7 14:54:41 GMT 2006


On 07/11/06, Carl Franks <fireartist at gmail.com> wrote:
> On 06/11/06, Brian Kirkbride <brian.kirkbride at deeperbydesign.com> wrote:
> > Carl Franks wrote:
> > > On 06/11/06, Zbigniew Lukasiak <zzbbyy at gmail.com> wrote:
> > >> Hi,
> > >>
> > >> Now when I think about this I think that you are probably right that
> > >> the designer does not normally need to change the type of the field.
> > >> The attributes, possibility to intersperse the inputs with additional
> > >> tags and to change the order of fields should be quite reasonable
> > >> range of customisation.  I would not care too much about fieldsets and
> > >> ul/ols in HTML::Widget - I would just left that for the templating,
> > >> but I would generate the hidden fields by the start_form helper.
> > >>
> > >> Unfortuntely I don't have any experience with designers in a Catalyst
> > >> project.  The interface_config.dat should not be too complicated - and
> > >> it can be made a bit simpler by choosing a separate directory for it
> > >> and having separate files for each Controller, and also by using some
> > >> config language instead of Perl datastructures.  But if it is only
> > >> used by InstantCRUD than I am afraid people would not accept it.
> > >>
> > >> And where is that guy that started me thinking about this with his
> > >> Rails email?
> > >
> > > I've been thinking some more about my idea of parsing a form out of a
> > > html/xml file, and it's maybe not as stupid as it first sounds.
> > > It also doesn't even require any template markup.
> > >
> > > Point H-W to any html/xml file, or a variable already containing the
> > > markup.
> > > Search for a form with the same name as the widget, or failing that
> > > the first form in the file.
> > >
> > > For any markup which isn't a form input/button field, save it, so it
> > > can be output later unchanged.
> > > For any form input/button field, create a new element using the
> > > attributes/content from the markup.
> > >
> > > You've then got a ready-made $widget which you can add constraints and
> > > filters to.
> > >
> > > You could even then add any app-wide hidden fields to the end of the
> > > widget, and they'll be included within the FORM tags, without the
> > > designer having to know about it.
> > >
> > > If I can get it working as I envisage, it's certainly something I'd use.
> > > Is it likely to solve the problem you're looking at?
> > > I'll have a hack, and see if I can come up with some working code.
> > >
> > > Carl
> > >
> >
> >
> > One possible issue: how to handle error markup?
> >
> > One way would be to assume an attribute of id="{fieldname}_error" indicates a
> > DOM node that would be removed on success or it's content replaced with the
> > error message on error.
> >
> > Another would be to have some sort of conditional markup.
> >
> > The former would be less flexible, the latter ventures a bit too far into the
> > realm of templates IMHO.
> >
> > Overall, I still think that this would be a great way to get form design into
> > the view and out of the controller/model.
>
> I see errors being handled as they are now - they are not marked-up in
> the html file, but are added by the code as needed.
> You can override Element.pm and Container.pm to change how errors are
> generated. This could eventually also allow error markup being defined
> in another html file, rather than the code.

Hmm, I'm not sure about this.
I've gotten it working for Hidden and Textfield elements, with
roundtrip tests passing.
The Hidden element was very simple to implement, but the Textfield was
a different matter.

The way it works is:
The html is parsed with HTML::TokeParser::Simple.
Give each HTML::Widget::Element::* class a chance to parse each token.
If one returns an Element, it's added to the widget and we go on to
the next token. If nothing wants to handle it, we add it to the widget
as a new 'Raw' Element which ensures all unknown markup is output
again in the $result.as_xml

Now that's easy for a simple Textfield element
<input type="text" />
however, it's not so easy for a Textfield which has a label(), and
(optionally) a comment().
This means that the Textfield element also has to be able to handle:
<label>LABEL
  <span>COMMENT</span>
  <input type="text />
</label>

So that it can create an Element equivalent to:
$w->element( 'Textfield' )
  ->label( 'LABEL' )
  ->comment( 'COMMENT' );

This is necessary, because if the widget needs to add an Error, that
has to be integrated as:
<label class="labels_with_errors">LABEL
  <span>COMMENT</span>
  <span class="fields_with_errors">
    <input type="text" />
  </span>
</label>
<span class="error_messages">
  <span>ERROR MESSAGE</span>
</span>

Now, it's working so far, but...
* If you want a 'label' or 'comment', it has to be in the same format
as the Element would generate it. To customise it, you would have to
sub-class the Element, and handle the parsing yourself, which isn't
simple.
* We can only handle arbitrary markup /between/ elements. We can't
handle arbitrary markup within the 'label' tags, which means the level
of customization you can do is pretty much limited to changing
attributes on the tags that are already there.
(okay, we probably could make this work better, but doing so may make
it more fragile)
* If you provide a custom element Container, you effectively have to
provide your own sub-class of every element, so that it can handle the
new layout.

So, is this feature worth it?
It'll let designers add arbitrary markup (except within labels),
reorder / add / remove elements / customise attributes, and work with
html - which they already know.
However, it doesn't provide the power of a custom Container (can't
change how labels are rendered), doesn't allow error-message markup,
and may break the application if fed particularly bad markup.

Carl



More information about the Html-widget mailing list