I ran across this implementing a module that allows the Twitter Bootstrap
framework to be used with Tapestry. I created a mixin called FW (framework)
that supports informal parameters and used a worker to attach it to every
component. The mixin is simple. It just wraps the component in a new element
and renders it's informal parameters around it. Then I created a visitor to
find these elements and change the rendered html match what Bootstrap wants.
The vistors are pluggable by namespace so it's possible to support things
other than Bootstrap and since they are namespaced you can actually support
more than one framework in a project. In my first attempt to support
Bootstrap I found myself reimplementing components because html structure
was not correct for Bootstrap. After a while I decided this what not the
correct way to do things. I also wanted to be able to write this
<t:nav fw.type="tabs">
<t:pagelink page="">Home</t:pagelink>
<t:pagelink page="" active="true">Link</t:pagelink>
</t:nav>
which ends up like this
<ul class="nav nav-tabs">
<li class="active"> # Home </li>
<li> # ... </li>
<li> # ... </li>
</ul>
after a visitor like this
Visitor nav(Element root) {
return new Visitor() {
public void visit(Element element) {
if ( hasName("fw.Nav",element)) {
element.wrap("div","class","nav
nav-tabs");
}
if ( anchor(element)) {
wrapLI(element);
}
}
};
}
and this for a BeanEditForm
in the .tml
<t:beaneditform t:id="user" fw.type="table-bordered"/>
which adds the following around the output of beadeditform.
<fw.BeanEditForm type="table-bordered">
beanedit stuff ...
</fw.BeanEditForm>
Then a visitor finds that marker and does something like this:
Visitor beanEditForm(final Element root) {
return new Visitor() {
public void visit(Element element) {
if ( hasClass("t-beaneditor",
element) ) {
element.forceAttributes("class","popped");
element.visit(beanEditForm(root));
element.pop();
}
if (
hasClass("t-beaneditor-row", element)) {
element.forceAttributes("class","control-group");
}
if ( hasName("input", element))
{
element.wrap("div",
"class","control");
}
if ( hasName("label",element)) {
element.addClassName("control-label");
}
if ( hasName("img", element)) {
element.remove();
}
}
};
}
};
}
That all works great except when the FW mixin is added to the Any or
AbstractLink component. The mixin ends up with the informal parameters and
that's a problem. I'd prefer they just stay with the component which is what
the docs seem to imply. To fix this I created another mixin that renders the
default namespace informal parameters on the components element. It works
but it's a bit messy and without documentation on what should really happen
in this case what I have is not really a generalized fix.
So in this case the ambiguity is causing me problem. Plus the document says
exactly what should happen but the code does not work as documented. The
question is should the code do what the docs say or should the docs be
changed to document what the code actually does? I don't really have a
preference but the current functionality is confusing at best. That said the
current functionality does allow you to add informal parameter support to an
existing component via a mixin. I've been digging around in the component
resources code but I have not found the part assigns the informal parameters
to the component so I'm not really sure how it does work but:
The current mixin docs say this
If the component and a mixin both define a parameter with the same name,
then the component wins: the component's parameter will be bound, and the
mixin's parameter will be unbound.
Alternately, you may prefix the name of the parameter with the unqualified
name of the Mixin class; this eliminates the ambiguity
Perhaps it should be: ( I think this is how it works )
In the case of formal parameters if the component and a mixin both define a
parameter with the same name, then the component wins: the component's
parameter will be bound, and the mixin's parameter will be unbound.
Alternately, you may prefix the name of the parameter with the unqualified
name of the Mixin class; this eliminates the ambiguity
For mixins that support informal parameters the mixin always wins and the
default namespace informal parameters are bound to the first mixin to call
renderInformalParameters. Again you may prefix the name of the parameter
with the unqualified name of the Mixin class. This eliminates the ambiguity
and allows multiple mixins to have informal parameters.
Sorry if this seems like a nit. If the docs were silent about this I would
have just worked around the problem without even mentioning it.
Thanks
Barry
--
View this message in context:
http://tapestry.1045711.n5.nabble.com/Before-I-file-a-JIRA-against-SupportsInformalParameters-tp5456349p5461541.html
Sent from the Tapestry - Dev mailing list archive at Nabble.com.
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]