users@javaserverfaces-spec-public.java.net

[jsr344-experts mirror] [jsr344-experts] HTML5 friendly markup (fix inconsistencies and documentation review)

From: Leonardo Uribe <lu4242_at_gmail.com>
Date: Tue, 18 Mar 2014 21:37:58 -0500

Hi

Recently in MyFaces Core 2.2.1 it was found some inconsistencies over the
documentation done for HTML5 friendly markup (javadoc of TagDecorator and
JSF 2.2 section 10.1.4). There are basically 2 problems, that I will
describe below. I have fixed them in MyFaces Core 2.2.2.



The first problem is the documentation and the purpose of <jsf:element ...>
tag is not very clear for the reader. In JSF 2.2 section 10.1.4.1 page
10-8 it says something like this:

"...

<meter jsf:id="meter2" min="#{bean.min}" max="#{bean.max}"
value="350">350 degrees</meter>

...

As in the preceding example, the TagDecorator mechanism is activated but it
is determined that this component should act as a <jsf:element> component
for the purposes of postback processing. The behavior of the <jsf:element>
is normatively specified in the VDLdoc for that tag. The behavior of the
javax.faces.passthrough.Element renderer is normatively specified in the
RenderKitDoc for that renderer ..."

In the javadoc of TagDecorator it says something like this:

"...
If one or more of the attributes of the tag argument are in the
http://xmlns.jcp.org/jsf namespace, obtain a reference to decoratedTag as
described in the following steps and iterate through the list of
TagDecorator instances as described in the preceding step, but pass
decoratedTag to each call to decorate(javax.faces.view.facelets.Tag).

...

* If no matching entry is found, let jsf:element be the value of
targetTag ..."

In few words, it is clear that TagDecorator converts something like
<meter ... into <jsf:element pt:elementName="meter" ... . That's ok.
The problem is what happen to their attributes. This is what the
javadoc of TagDecorator says about how to convert the attributes:

"... If the current attribute's namespace is empty or different from
the argument tag's namespace, let the current attribute be
convertedTagAttribute. This will have the effect of setting the
current attribute as an attribute on the attributes map of the
UIComponent instance represented by this markup. ..."

This mean that the tag is translated from this:

<meter jsf:id="meter2" min="#{bean.min}" max="#{bean.max}"
value="350">350 degrees</meter>

to this:

<jsf:element pt:elementName="meter" id="meter2" min="#{bean.min}"
max="#{bean.max}" value="350">350 degrees</jsf:element>

Take a look at what happened to min, max and value attributes. Applying
the rule written in the spec, the attributes are copied to the component
attribute map. According to the spec, the resulting output will be this:

<meter id="meter2">350 degrees</meter>

Where are the attributes? in the component attribute map like the spec says.
The renderkit javadoc of javax.faces.passthrough.Element doesn't mention
anything about process the attributes in attribute map. What the user
expect is something like this:

<meter id="meter2" min="1" max="400" value="350">350 degrees</meter>

But trying the example with Mojarra 2.2.6 or earlier, it works as the user
expect. How? I did a black box test and it seems the attributes are copied
somehow into the passthrough attribute map, so once the attributes are not
rendered and the tag is closed, they are rendered as passthrough
attributes. It is clear the intention, so I just fixed it in MyFaces, but
the problem is a behavior like that needs to be documented in TagDecorator.

The solution applied in MyFaces was add the necessary lines in TagDecorator
to duplicate the attribute so now the final component looks like this:

<jsf:element pt:elementName="meter" id="meter2" min="#{bean.min}"
p:min="#{bean.min}" max="#{bean.max}" p:max="#{bean.max}"
value="350" p:value="350">350 degrees</jsf:element>

It is not the best we can do, since the renderer never changes for the
component and the attributes of jsf:element can be defined it could be better
to set the remaining attributes in the passthrough attribute map by default,
but it will work well in any case and the overhead is minimal if PSS algorithm
is properly implemented.


The second problem is related to the attributes declared for jsf:element.
The taglib javadoc of jsf:element has these attributes:

* onclick
* ondblclick
* onmousedown
* onmouseup
* onmouseover
* onmousemove
* onmouseout
* onkeypress
* onkeydown
* onkeyup

The same javadoc says something like this too:

"... The component that backs this element must implement
javax.faces.component.behavior.ClientBehaviorHolder and return "click" from
its getDefaultEventName() method. The list of events returned from its
getEventNames() method must include the "on*" attributes below, ommitting
the leading "on". ..."

That's ok. Now try something like this:

<div jsf:id="box1">
    <f:ajax render="..." event="click"/>
</div>

It doesn't work in Mojarra 2.2.6 and earlier versions. I think according to
the spec documentation a case like the previous one should work, but it gets
my attention the fact that the list of attributes that are subject to be
target of client behavior are fixed. Please note the behavior of these
attributes are quite predictable. It should be something that allows you to
customize this part, but at least the following attributes should be there
too:

* onload (supported by <body>, <frame>, <frameset>, <iframe>, <img>,
  <input type="image">, <link>, <script>, <style>)
* onunload (supported by <body>, <frameset>)

Theoretically it doesn't matter if all valid names for html event are
part of jsf:element. I have added onload/onunload in MyFaces 2.2.2, since it
is quite easy to do so and it doesn't affect anything.

regards,

Leonardo Uribe