Wow, that was some dream!

I have to sleep on this for a bit. :) It seems like a very complete solution. I'm wondering if there is some way to simplify it for a first implementation, like don't have code paths for each browser. If one browser doesn't support it, handle it yourself. Then we could add the browser bit as an optimization. Unless it is just as easy to add it up front while we are in the code.

- Jeanne

Simon Lessard wrote:

Hello all,

I'm early today because I had a nightmarish sleep about this issue. There
was a huge blue 'e' hovering above the ground and everything under it was
gray, dull and boring... All movies were starring Steven Seagal and the only
singers left were Brian Adam and Céline Dion, it was HORRIBLE !

Anyway, after waking, I could not find sleep again and I thought about a way
to handle the nasty :hover. It's a small modification from my first
suggestion about it in an attempt to make it less messy. Tell me what you
think of it.

So far the solution for most pseudo-classes tends toward a
Map<ComponentType, List<PseudoClass>> or simply a map of intercepted
pseudo-classes for a given component. How that list will be implemented is yet to be determined though. Anyway, that's not the issue. I thought about maintaining two collections. The first would be the map and the second would be a list of conditionally intercepted pseudo-classes effectively including
all valid CSS pseudo-classes. During CSS generation, the selector would
first be read and transformed in the following form:

<base>(:<interceptedState>)*(::<part>(:<interceptedState>)*)*(:<conditionallyInterceptedState>)*(:<passThroughState>)*

Then the conditionallyInterceptedState would be checked against the agent
for which the CSS is getting rendered to see if that agent lets it pass
through. If so, it would be moved to the passThroughState section of the
selector else the state would be included in the selector for purpose of
renaming. For every conditionallyInterceptedState, the renderer could have a method returning a <JSEvent, String> tuple specifying on what event and with
what script the pseudo-class can be emulated, but the method would return
null if the current agent can already handle it. Let make an example using
":hover".

We have two components:
- component1 that intercepts :hover
- component2 the let :hover pass though

Since :hover is a valid CSS pseudo-class, it can be found inside the
conditionally intercepted pseudo-classes list.

We have 2 skinning keys inside the skin's CSS:
- af|component1:hover
- af|component2:hover

For af|component1:hover, it's simple. Since it,s part of the intercepted
list of component1, it's intercepted.

For af|component2:hover, since :hover might pass though, the CSS generation class checks if :hover is suppoerted for the current agent. If it's, :hover
is simply written to the CSS file and is not placed in the final selector
list (since af|component2 will). However, if it is not supported on the
current agent, :hover is considered intercepted and the whole
af|component2:hover become a new selector in the selector list (and will
thus have its own short style class name). During rendering, in the writeJS method(s) a getHoverScript("af|component2:hover") method would be called. If
the specified selector cannot be found in the list, it means that the
pseudo-class passed through and the agent can handle it or it means that
af|component2:hover was just not defined at all in the skin CSS, then the
method should return null. On the other hand, if the selector is found, it
means the user's agent cannot handle :hover and the method should then
return <"onmouseover", "this.class=' " + selector.getStyleClass() + " ';"> tuple. The return value is then simply interpreted by the writeJS method to
add the good event and script to the generated markup. This pattern is, I
believe, decently clean, scalable and reusable without being too hard to
implements nor maintain.


Regards,

~ Simon


Reply via email to