jsr344-experts@javaserverfaces-spec-public.java.net

[jsr344-experts] [1089-HTML5-data-*attributes] 20120525 REVISED PROPOSAL

From: Edward Burns <edward.burns_at_oracle.com>
Date: Fri, 25 May 2012 20:00:31 -0700

This email is broken down into sections prefixed with SECTION:. If you
want to cut to the chase, look for SECTION: Revised proposal, at the
end.

ACTION: Please reply by 23:59 EDT (GMT - 0400) Tuesday 29 May.

SECTION: Current specification

* Generic passthru attributes are not supported.

* HTML5 data* attributes are supported by means of <f:dataAttribute>, like
  this:

  <h:inputText value="#{bean.postalCode}">
    <f:dataAttribute name="hover-style" value="fancy" />
    <f:dataAttribute name="echo-values" value="always" />
  </h:inputText>

  This would cause the rendering of something like this

  <input type="text" id="j_id34" value="23252"
         data-hover-style="fancy" data-echo-values="always" ></input>

  There is no means for handling arbitrary passthru attributes, just
  arbitrary data-* attributes.

SECTION: EG list discussion summary

Frank also had significant content about a new feature which he called
"a generic dynamic element". Let's tackle that as a separate thread.
This thread will continue to talk only about passthru attributes.

I'm not satisfied with the current specification. It doesn't satisfy
the key use-case of the reporter: pass arbitrary data-* attributes using
a single tag in the page. Several EG members agree that more needs to
be done. Imre Osswald and Frank Caputo noted that we should not limit
the discussion just to data-* attributes but should see data-*
attributes as a special case of passthru attribute.

PW> If pass-though attributes do become part of the spec they should
PW> probably be opt-in. There may be existing code currently using
PW> additional attributes for their own ends. I believe that
PW> UIComponent.getValueExpression() can be used to get any attribute,
PW> so some developers may have attributes in their XHTML that they use
PW> currently but they absolutely do not want exposed to the browser.

AS> Yep. I have the same concern. Currently Facelets dumps unspecified
AS> attributes into the UIComponent's attributes map. Existing apps are
AS> using this for their own purposes and would be negatively impacted
AS> if we simply started passing all of these through to the client.

Limiting the passthru attribute feature to <f:attributes> implicitly
forces an opt-in, so that's good. Later in the thread, Phill Webb
suggested using XML namespaced attributes as another way to opt-in.

Ed proposed <f:dataAttribute json="{ foo : bar}" /> but Andy quickly
pointed out the inappropriateness of this approach with several usage
examples, stating "We need to abstract away the literal type info from
the attribute name." Really, the point of the feature is to allow the
creation of a Map<String,Object> that renderers can use for attributes.

Then, Andy asked, "I don't quite get this - ie. I don't understand how
jQuery comes into the picture when EL binding to a Java managed bean."

MM> I guess the following is true: a JSF component renders a tag which
MM> is dynamically used by a JQuery widget. Additional configuration
MM> data (which jQuery needs to configure this widget) can be passed in
MM> with the data params.

IO> Why limit this to "data" attributes?

IO> I suggest we add a more general <f:attributes> or <f:attribute
IO> values=""> (I prefer the extra one), which should be able to set
IO> any attribute-value(s) on its parent tag.

Let's not even entertain overloading the existing <f:attribute>. Let's
consider <f:attributes >.

IO> <f:attributes name="data" value="#{el.to.map}" /> would be like the
IO> proposed <f:dataAttributes value="#{el.to.map}" />

Let's call this aspect "the attribute name decoration problem", and we
need a good solution for it. Phill Webb's namespaced attribute proposal
is a good solution for it.

IO> If used with json, it should be possible to also add the "value" as
IO> the [body] content of the tag.

Yes, I like that idea, but I'll ammend Imre's suggestion to be

<f:attributes prefix="data">
{
                'toggle': true,
                'duration': #{my.animationSettings.toggleDuration}
                'object': '{"one":"A", "two": "B", "three": "C"}'
}
</f:attributes>

<f:attributes>
{
        'role': 'banner',
}
</f:attributes>

instead of what he proposed.

IO> This should probably get some counterpart in the interface section.

Yes, I agree, and it would employ the same solution to the attribute
name decoration problem as <f:attributes>. Let's solve the
non-composite case first. In any case, we'll stay away from "targets"
because that concept was upsetting to some EG members.

FC> 1) All attributes not handled by a component should be simply
FC> rendered out as they are. Eg. h:inputText doesn't know the attribute
FC> placeholder.

I kinda say this already when it comes to the dataHostingElement concept
in my new "General notes regarding HTML5 support" in the Standard
HTML_BASIC RenderKit specification.

FC> If the value of an unknown attribute is null or "", don't render it.

Sure.

FC> Maybe we could override attributes. Eg. h:inputText doesn't have the
FC> attribute type, but the renderer renders it.

FC> <h:inputText value="#{foo.bar}" type="email"/> would be rendered as
FC> <input type="email" value=""/> because the unknown attribute
FC> overrides it.

FC> The type attribute is just a hint for the client (eg. to change the
FC> keyboard layout) while it doesn't change anything on the server.

AS> I also like Frank's suggestion that we allow this to be used to
AS> override attributes that are rendered by the Renderer:

No, I don't like that at all. If there is a conflict between a passthru
attribute and something the Renderer is required to render, the passthru
attribute loses. This is what composite components are for.

BL> The problem with this being that facelet files are not DTD-less
BL> (shema-less), and so this would be a more complex solution. IMO
BL> however, it would be an effort worth pursuing, as the arbitrary
BL> attribute support would be intrinsic to JSF, and not "bolted on".

Doch, in facelets, you can have any arbitrary attributes and it's not at
all constrained by any XML schema.

FC> UIComponentBase should provide a Map of all unknown attributes to the renderer.

See what I say in the UIComponent.DATA_ATTRIBUTES_KEY javadoc.

AS> One case that does not seem to be covered by the pass-through attribute
AS> approach is the original case that Paul raised - ie. the ability to
AS> specify an arbitrary # of possibly dynamically determined bonus
AS> attributes. If we want to tackle this case, seems like we would still
AS> be stuck with adding some Map<String, Object>-based attribute, eg:

Doch, this case is covered and is the whole point of Imre's
<f:attributes> with some solution to the attribute name decoration
problem.

AS> Getting back to data-* and generic attribute pass through...
AS>
AS> For this case I actually prefer Phil's suggestion of using a namepsace
AS> prefix:

PW> Perhaps a prefix should also be used for unknown attributes to allow
PW> tooling some hints that breaking the facelet schema in this case is
PW> permitted.

Again, this is not needed because there is no facelet schema. It's just
XML. You can put whatever you want in there as long as it is valid XML.

AS> In any case, if we start by adding:

AS> - p:foo="bar" for pass-through attributes on existing (rendering)
AS> component tags.
AS> - passThruAttributes="#{foo.mapOfPassThroughAttributes}"

FC> +1, my proposal was just to ease life of HTML developers, who don't
FC> want to put their attributes into a backing bean, because often they
FC> don't have the skills to do so. And the more complex the clients get
FC> the more specialized the frontend developers will be and the less
FC> they know Java.

Rather than put a new attribute everywhere, which also doesn't help
composite custom component authors either, I like Imre's idea of
<f:attributes> and its <cc:attributes> cousin for this case. This also
gives us a self-contained place to support inline JSON.

ECTION: precedence questions

AS> If we go with two tags:
AS>
AS> <f:dataAttributes value="#{foo.bonusDataAttrs}">
AS> <f:dataAttribute name="foo" value="bar"/>
AS>
AS> I would think that we would spec this such that <f:dataAttribute> would
AS> win over the equivalent value in the EL-bound map.

AS> Would the above tags result in a Map<String, Object> that contains all
AS> of the values specified in the EL-bound map + all of the explicitly
AS> specified <f:dataAttribute> values?

Yes, a union of the two different kinds of sources of values.

MM> I would throw an exception if both are there (just like in Facelets:
MM> you can't specify the same attribute twice, right?)

IO> (I guess with f:attribute you can?)

I haven't confirmed this, but I agree with Imre that you probably can
without complaint.

AS> Would we support multiple <f:dataAttributes> tags for a single
AS> component? For example, in this case:
AS>
AS> <f:dataAttributes value="#{foo.bonusDataAttrs}">
AS> <f:dataAttributes value="#{bar.morebonusDataAttrs}">
AS>
AS> Do we merge the maps? Last one wins? Unsupported?

IO> +1 for merge (Last one wins)

Yes, we merge them and take the union where the last one wins.

AS> Is our Map<String, Object> mutable?

Sure it is, it's just a data structure in the component attributes map.

MM> If we merge, I guess no.

Why not? Once the tag is applied and the Map is populated, there's no
need to make it immutable.

In any case, this SECTION is moot if we go with the namespaced attribute
solution.

SECTION: Revised proposal.

1. Drop <f:dataAttribute> [1]

2. Keep the text in the standard HTML_BASIC renderkit spec that talks
   about what to do with the UIComponent.DATA_ATTRIBUTES_KEY
   attribute. [2] Change the name of the key to
   PASS_THROUGH_ATTRIBUTES_KEY and amend all textual references to
   remove the "data-" ness because the data-ness (if any) will now be
   baked into the keys where it should have been all along.
   Linguistically, data-ness can be replaced with pass through-ness.
   Specify that the map must be Map<String, Object>. The text already
   allows EL for the values, but also allows EL for the keys. We will
   no longer be able to have EL for the keys with this design.

QUESTION: do we want to have a proper JavaBeans getter on UIComponent
instead of UIComponent.PASS_THROUGH_ATTRIBUTES_KEY that is to be used as
a key in UIComponents.getAttributes().get()?

3. Introduce a new facelet XMLNS
   http://java.sun.com/jsf/passThroughAttribute and modify the spec PDF
   section 10.3.2 to require that all tag handlers process any
   attributes with that namespace such that they get pushed into the Map<String, Object>.

4. Add <f:attributes>. This element has a "value" attribute that is a
   ValueExpression that points to Map<String,Object>. The spec for this
   element states that all entries in such a map are copied to the
   PASS_THROUGH_ATTRIBUTES_KEY map.

5. Allow <f:attributes> to have body content that, if present, is
   interpreted as JSON. It is not valid to have both body content and a
   "value" attribute. If you want to do that sort of thing, have
   multiple <f:attributes>. In the case of multiple <f:attributes>
   elements, since each one will be copying its entries to the
   PASS_THROUGH_ATTRIBUTES_KEY map, each successive one will blindly
   overwrite any duplicate entries.

If I missed anything PERTAINING ONLY TO PASS THRU ATTRIBUTES (not pass
through elements), please reply and say so.

Notes: look for the green text to see what was added so far.

[1] https://maven.java.net/service/local/repositories/snapshots/archive/javax/faces/javax.faces-api/2.2-SNAPSHOT/javax.faces-api-2.2-20120525.150835-110-javadoc.jar/!/vdldocs/facelets/f/dataAttribute.html

[2] https://maven.java.net/service/local/repositories/snapshots/archive/javax/faces/javax.faces-api/2.2-SNAPSHOT/javax.faces-api-2.2-20120525.150835-110-javadoc.jar/!/renderkitdocs/HTML_BASIC/renderkit-summary.html

-- 
| edward.burns_at_oracle.com | office: +1 407 458 0017
| homepage:               | http://ridingthecrest.com/