-
Get a monthly update on best practices for delivering successful software.

One thing missing from the DOM class in GWT is the ability to set element opacity in a browser independent way. You do have DOM.setStyleAttribute, but in IE you set the opacity by squeezing a alpha(opacity=val) into the filter, where in most other browsers you set the opacity style attribute directly.
If you take a peek into the prototype library, you'll see all sorts of cruft around setting opacity, such as supporting Konquerer, etc., but in the world of GWT, we just have to support a few browsers (IE6+, Mozilla, Safari, Opera). I had a need for a kinder, gentler opacity when I started developing GWTaculous, my pure GWT port of the Scriptaculous effects library. I implemented my own DOMX class to support those extended DOM operations I needed.
The module def file looks like this:
<module>
<inherits name='com.google.gwt.user.User'/>
<replace-with class="org.puregwt.gwtaculous.client.dom.impl.DOMXImplStandard">
<when-type-is class="org.puregwt.gwtaculous.client.dom.impl.DOMXImpl"/>
</replace-with>
<replace-with class="org.puregwt.gwtaculous.client.dom.impl.DOMXImplOpera">
<when-type-is class="org.puregwt.gwtaculous.client.dom.impl.DOMXImpl"/>
<when-property-is name="user.agent" value="opera"/>
</replace-with>
<replace-with class="org.puregwt.gwtaculous.client.dom.impl.DOMXImplSafari">
<when-type-is class="org.puregwt.gwtaculous.client.dom.impl.DOMXImpl"/>
<when-property-is name="user.agent" value="safari"/>
</replace-with>
<replace-with class="org.puregwt.gwtaculous.client.dom.impl.DOMXImplIE6">
<when-type-is class="org.puregwt.gwtaculous.client.dom.impl.DOMXImpl"/>
<when-property-is name="user.agent" value="ie6"/>
</replace-with>
<replace-with class="org.puregwt.gwtaculous.client.dom.impl.DOMXImplMozilla">
<when-type-is class="org.puregwt.gwtaculous.client.dom.impl.DOMXImpl"/>
<when-property-is name="user.agent" value="gecko1_8"/>
</replace-with>
<replace-with class="org.puregwt.gwtaculous.client.dom.impl.DOMXImplMozillaOld">
<when-type-is class="org.puregwt.gwtaculous.client.dom.impl.DOMXImpl"/>
<when-property-is name="user.agent" value="gecko"/>
</replace-with>
<entry-point class='org.puregwt.gwtaculous.client.GWTaculous'/>
</module>
So, GWT identifies the user agent and subs in the appropriate subclass to handle calls to DOMX. The code for DOMX looks like this:
public class DOMX {
private static DOMXImpl impl;
static {
impl = (DOMXImpl) GWT.create(DOMXImpl.class);
}
public static void setOpacity(Element e, double opacity) {
if (opacity < 0.00001) {
opacity = 0.0;
}
if (opacity > 1.0) {
opacity = 1.0;
}
impl.setOpacity(e, opacity);
}
public static double getOpacity(Element e) {
return impl.getOpacity(e);
}
public static void clearOpacity(Element e) {
impl.clearOpacity(e);
}
}
The
bounds checking for opacity is so that we don't get any non-sense
value, plus we don't want scientific notation, so we zero out values
that are too small.
The DOMXImpl class looks something like this:
public abstract class DOMXImpl {
public void setOpacity(Element e, double opacity) {
DOM.setStyleAttribute(e, "opacity", Double.toString(opacity));
}
public double getOpacity(Element e) {
// get the current opacity
String opacity = DOM.getStyleAttribute(e, "opacity");
if ((opacity == null) || (opacity.trim().equals(""))) {
return 1;
} else {
try {
return Double.parseDouble(opacity);
} catch (NumberFormatException ex) {
return 0;
}
}
}
public void clearOpacity(Element e) {
DOM.setStyleAttribute(e, "opacity", "");
}
}
Really
pretty self explanatory. We set the opacity attribute in the usual way.
The one place we really have to override this is in the IE6 class, DOMXImplIE6:
public class DOMXImplIE6 extends DOMXImpl {
public native void setOpacity(Element e, double opacity) /*-{
if (opacity == 1) {
e.style.filter = (e.style.filter || '').replace(/alpha\([^\)]*\)/gi,'');
} else {
e.style.filter = (e.style.filter || '').replace(/alpha\([^\)]*\)/gi,'') +
'alpha(opacity='+opacity*100+')';
}
}-*/;
public native double getOpacity(Element e) /*-{
var value;
if(value = (e.style.filter || '').match(/alpha\(opacity=(.*)\)/))
if(value[1]) return parseFloat(value[1]) / 100;
return 1.0;
}-*/;
public native void clearOpacity(Element e) /*-{
e.style.filter = (e.style.filter ||
'').replace(/alpha\([^\)]*\)/gi,'');
}-*/;
}
This overrides the
behavior for IE. The code is lifted almost straight out of Prototype.
At some point I'll bundles this up as a patch for GWT's DOM class. My
actual DOMX implementation has a bunch more utility methods, but this
is it as far as opacity is concerned (sorry, Opera needs something
special to enable opacity in certain elements). In the meantime, if
anyone has suggestions, I'm open to hearing them.
Technorati Tags: ajax, gwt, scriptaculous, styles, css, opacity, DOM, gwtaculous
Related posts:
Topics: Ajax Frameworks, CSS, GWT