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

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

From: Andy Schwartz <andy.schwartz_at_oracle.com>
Date: Tue, 29 May 2012 16:25:09 -0400

On 5/25/12 11:00 PM, Edward Burns wrote:
> SECTION: EG list discussion summary
>
>
> 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.

The name <f:attributes> suggests that this would perform the equivalent
of multiple <f:attribute> tags - ie. I would expect this to populate the
component's attribute map rather than the passthru attribute map.

Imre proposed that we add a "passthrough" attribute to <f:attributes> to
control which map is being targeted. If we are considering going down
this route, I would prefer that split this up into two tags:

- <f:attributes> for populating the component attribute map
- <f:passThroughAttributes> for populating the passthru attribute map

Though I also like Imre's suggestion of a "p:attributes" attribute, eg:

<h:inputText p:attributes="#{el.to.map}"/>


> Later in the thread, Phill Webb
> suggested using XML namespaced attributes as another way to opt-in.

I really like this approach since it makes the intention clear and
easily allows the page author to tack on bonus attributes.

> 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.

Yeah. I still don't get this why this configuration data would be
initially specified by JSON. Paul provided some additional clarification:

> jQuery UI + EL comes into action for example when you use REST or CDI
> producers to serve your JSON configuration for jQuery UI widgets so
> you can retrieve it using EL in your JSF components (the ones that
> will generate the widgets).

Okay, so sounds like the point is that there may be cases where data is
provided by external sources (eg. a web service) that only coughs up
JSON. I am still not convinced that the right solution is to require
components that bind to collections to also support JSON->collection
type conversion. Seems that this would be more easily handled via either:

- Java glue code. Or...
- EL functions that perform the JSON->collection conversion.

> 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.

I am not convinced that we need to support JSON-based literals. Again,
if we do want to support this, we need to look at collection-based
attributes more generally. I would so much rather that we start small -
ie. start with:

<f:attributes value="#{el.to.map}"/>

And come back to the complexities of how best to use JSON for literal
representations for collection-based attributes.

> 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.

Yep.

Imre's proposal included some suggestions for attribute filtering. I
suspect that this is going to be important if we want to apply
<f:attributes> to the composite component case.

> 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.

We already have existing behavior for "unknown" attributes: they are
added to the component's attribute map.

I am not a fan of changing this behavior to pass unknown attributes
through to the browser. I agree with Frank's general point that we need
to make life easier for web designer-centric page authoring. However, I
don't think that merging component and HTML attributes into a single
space is the way to go.

Instead, I would prefer that we:

1. Introduce a way to include passthru attributes on component tags
that makes the distinction between component vs. HTML attributes clear.
2. Introduce improvements to the jsfc approach to page authoring that
will allow this to be used in a more natural way by web designers (and
covers more cases than are currently covered today).

For #2, perhaps we should start by discussing what our ideal syntax
might be for the web designer-centric use case.

We've touched on one trivial use case - ie. a simple "passthru
component" case:

<div class="foo" jsfc="jsfc">

This is fine for cases where there is no interesting behavior - just
some rendered output.

Is there more that we could do for more interesting cases that include
server-side/postback behavior? For example, should we be looking for
ways to make it easier to enhance designer-provided HTML content, eg:

<button class="checkout-button">Checkout</button>

With a minimal amount of bonus JSF content:

<button class="checkout-button"
c:action="#{el.to.checkout}">Checkout</button>

Rather than just looking at how to enhance JSF tags with bonus HTML
attributes?


> 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.

Like Frank mentioned, I don't see how composite components are a
solution to this problem. My understanding is that the goal is to
provide a way for page authors to explicitly specify HTML attributes to
be included in the content rendered by existing Java-based
components/renderers. Allowing passthru attributes to trump other
rendered attributes seems like an important part of the solution.


> 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.

Right. My concerns are more that:

- We've already got behavior for "unknown" attributes. And...
- Mixing component and passthru attributes into a single namespace is
going to be confusing for page authors.

> 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>

<f:attributes> seems like a fine short-cut for specifying multiple
<f:attribute> values. If we want to provide a way to populate the
passthru attribute map in a similar manner, I would prefer that we break
this out into a separate tag (or attribute).

> and its<cc:attributes> cousin for this case.

Do we need <cc:attributes>? Not sure I get this.

> This also
> gives us a self-contained place to support inline JSON.

Can we hold off on supporting inline JSON until we've:

a) Got minimal support for pass through attributes in place. And...
b) Had a chance to consider this within a wider context?

I just don't see inline JSON as being a critical part of the initial
feature set.

If it is, then we need to at least do a) and b) above before we decide
how to move forward.

> 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

Maybe just:

> http://java.sun.com/jsf/passThrough

In case we later decide to to apply this to tag names?

> 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.

This should populate the component's attribute map. If we want a
similar solution for populating the passthru attribute map, we can add a
separate tag (or a namespaced attribute).

One important question that we need to answer is when the map population
is performed. Is this at Facelet apply/execution time? Or do we do
something more clever/tricky to allow binding to different maps in
stamping (eg. h:dataTable, ui:repeat) cases?


> 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.

I would prefer that we omit this until we have a chance to consider the
use of literal JSON representations more broadly.

Andy

> 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
>