Monday, May 23, 2011

SmartGWT IE7, IE8 Support

Version 4.0.1 of the RHQ project adds IE7 and IE8 support. It took a bit of wrangling to figure out how best to support IE with our spiffy new SmartGWT interface. There are a few parts in play:
  • IE version (7,8,9...).
  • IE Mode (quirks, standards7, standards8, standards9...)
  • SmartGWT version
  • GWT build user.agent values (ie6, ie8)
Our goal is to function with IE7, IE8 and going forward, IE9 and onwards.

One big blocker we ran into is that if you don't quite get things lined up in the build you can get a situation where IE simply will not load. The behavior basically looks like a GET request, usually with high CPU, hanging while waiting for a response for either CSS or JavaScript. Very hard to do much when you hit this.

I'm not going to go into the details too much, here's pretty much the end-game:

Use a recent version of SmartGWT: Version 2.2 or later. We're on 2.4.
This in itself solves an older issue with IE not being able to handle larger chunks of JavaScript. Later versions of SmartGWT chunk the generated JS.

Stick with Quirks Mode: This is recommended by SmartGWT because they already code for the quirks of the browser vendors. That's pretty much what you're getting with your permutations you ask for in the build.

Don't use DOCTYPE in your bootstrap HTML: This is also recommended by SmartGWT because the presence of a DOCTYPE decl will send IE into standards mode for that version of IE. It also affects other vendor's behavior so really, it changes quite a lot. We were initially lured to DOCTYPE because it solved the hanging load issue, but it caused several rendering issues later on.

Do use the meta tag to declare IE7 emulation: This avoids the DOCTYPE problem, will be used by IE8 onwards, and will be ignored by other browser vendors. So basically, if your GUI is working well for IE7 you have a pretty good chance of forward compatibility. It's placed right at the top, just inside the head tag, like this:

<html>
<head>
<meta http-equiv="X-UA-Compatible"
content="IE=EmulateIE7" />
...
</head>
</html>


The content="IE=7" will give you standards mode, which causes other rendering issues as mentioned above. Also, any attempt to use IE8 modes resulted (at least with SmartGWT 2.4) in issues with TreeGrid rendering; unindented child nodes and excessive vertical spacing. This was true even with the SmartGWT showcase. There is definitely an issue between SmartGWT and IE8 for trees.

Use the IE6 GWT user agent: You must include the "ie6" GWT user agent in your build. We're emulating IE7 and that requires the "ie6" userAgent. If you don't include this you will get the hanging loading issue mentioned above.

Tip: Starting with IE8 (I was using IE9) you get a nice feature by hitting the F12 key. This console allows you to easily see and modify the browser mode and standards/quirks mode settings currently in use.

Hope this helps...

Friday, February 18, 2011

SmartGWT Tip - Regex Evaluation

The RHQ project is building a new user interface using GWT (actually, SmartGWT). There is a definite learning curve to SmartGWT but overall I think this is a great technology for UI building. It offers a rich set of GUI Widgets, a strong architecture, an active community, and responsive developers. But maybe best of all, since you can write your GUI in Java, it can quickly enable a historically non-GUI Java programmer (like me) to contribute to a GUI implementation. As we move forward I'll try and share some tips about things we've stumbled over.

Tip: Remember that hosted mode (i.e. dev mode) is driven by Java, but your standard runtime environment is JavaScript.

GWT takes your Java code and generates vendor-specific JavaScript. This is great in that it frees the Java developer from having to, for the most part, deal with JavaScript or certain vendor-specific browser differences. But, during development you'll be running in hosted mode in order to run with a JPDA debugger, and to evaluate code changes quickly. As you learn quickly in GWT, not everything in Java is available in GWT, because it needs to be able to be supported in the resulting JavaScript. But even the things that are supported may not behave exactly the same way. One example is regular expression (regex) evaluation.

In most cases the evaluation will be the same. But, you may want to test patterns you're using in both a Java regex evaluator and a JavaScript regex evaluator, ensuring they behave the same way.

I ran into this sort of regex problem recently. Here is a slightly contrived example:


(foo|foo/bar)/[^/]*

I wanted to match path segments like: foo/1234 or foo/bar/1234

In Java (i.e when running in dev mode for GWT) this worked just fine, both of the sample paths matched just fine.

The match went like this:

"foo/1234"
(foo|foo/bar) matched "foo"
/[^/]* matched "/1234"

"foo/bar/1234"
(foo|foo/bar) matched "foo/bar"
/[^/]* matched "/1234"


But in JavaScript the second example did not work as I expected.

"foo/1234"
(foo|foo/bar) matched "foo"
/[^/]* matched "/1234"

"foo/bar/1234"
(foo|foo/bar) matched "foo"
/[^/]* failed "/bar/1234"


After matching the first OR option, it did not try the second one, despite the fact that the overall match failed.

The solution was to order the OR options from most complex to least complex, avoiding the subtle issue created by option 1 being a substring of option 2:

(foo/bar|foo)/[^/]*

The left to right evaluation now gave us the desired result.

This is not a blog about regex handling, there are probably several ways to do what we wanted, and we're not encountering a bug here. This is to point out a fundamental design point in GWT development, keep in mind that dev mode and production mode have different runtime environments that can produce subtle differences in behavior. For the same reason you're sure to encounter entire Java classes that work in dev mode and are not available in production mode, because they aren't supported in the JavaScript environment.