Adding True Internet Explorer 9 support to Pyjamas

About two months ago, Rich Newpol added Internet Explorer 9 support to pyjamas. Before then, pyjamas tried to use old mozilla (pre-3.5 version) format whenever it detected IE9, which would result in an epic fail. One small problem, however, is that Rich’s solution was not good enough for the app I’m developing. The solution was to tell IE9 to render the website the same way previous versions of IE would render it. Since my app relies heavily on HTML5 canvas element, this means I’d be stuck with old crappy VML. Instead I have started examining pyjamas to add true IE9 support. In the end, it turned out simpler than I thought. This post talks about how I did it, as well as the quirks I had to address.

Setting up ie9 directory

To maintain at least partial support in older IE browsers, I decided to create a new __ie9__ directory inside pyjamas library. My first goal was to get pyjamas to compile a separate cache file for IE9 (*.ie9.cache.html). To do so, I had to modify home.nocache.html file inside of boilerplate to detect ie9:

20 else if (ua.indexOf('msie7.0') != -1) {
21 return 'ie6';
22 }
23 else if (ua.indexOf('msie 8.0') != -1) {
24 return 'ie6';
25 }
26 else if (ua.indexOf('msie 9.0') != -1) {
27 return 'ie9';
28 }
50 window["prop$user.agent"] = function() {
51 var v = window["provider$user.agent"]();
52 switch (v) {
53 case "ie9":
54 case "ie6":
55 case "mozilla":
56 case "oldmoz":
57 case "opera":
58 case "safari":
59 return v;
60 default:
61 parent.__pygwt_onBadProperty("%(app_name)s", "user.agent",
["ie9", "ie6", "mozilla", "oldmoz", "opera", "safari"], v);
62 throw null;
63 }
64 };

This tells the website to load *.ie9.cache.html if the browser identifies itself as ‘msie 9.0′. The next task is to modify pyjamas so it actually generates *.ie9.cache.html file for us. The script responsible for this is pyjs/src/pyjs/ Here are the changes I made to it:

21 AVAILABLE_PLATFORMS = ('IE6', 'IE9', 'Opera', 'OldMoz', 'Safari', 'Mozilla')
45 class BrowserLinker(linker.BaseLinker):
47 # parents are specified in most-specific last
48 platform_parents = {
49 'mozilla':['browser'],
50 'ie6':['browser'],
51 'ie9':['browser'],
52 'safari':['browser'],
53 'oldmoz':['browser'],
54 'opera':['browser'],
55 }

With these files modified, pyjamas should now generate *.ie9.cache.html file for us, that the *.nocache.html file will load if you visit the page in IE9. The problem is that there is nothing in our ie9 folder yet.

Populating ie9 directory

The obvious starting point would probably be to copy the contents of __ie6__ directory into __ie9__ and start tweaking it from there. However, after playing with that approach for a while, I started realizing that __ie9__ is so different from previous versions that the best approach is to actually leave __ie9__ blank and start troubleshooting from there. It turns out that if you leave __ie9__ directory empty, the compiled *.ie9.cache.html file is actually somewhat usable. After some testing, I found that the only methods that did not work as expected were DOM.eventGetButton(), DOM.getAbsoluteLeft(), DOM.getAbsoluteTop() (it’s possible I missed some, but my very complex web app seems to be working fine in IE9 now). After writing my own implementations of those, I noticed that from __mozilla__ implements all 3 of those methods similar to my personal implementation, and all 3 implementations fix IE9 as well. This is not too much of a surprise, since Opera 11 now seems to run just fine with mozilla cache file as well, as I reported on pyjamas mailing list here. Perhaps __mozilla__ should be renamed to __default__ or __compliant__? Anyway, if you’ve been following along, chances are that even with all these changes you still might have issues with your web-app layout. The next section is designed to help you troubleshoot those.

Layout and appearance issues

First of all, IE9 will automatically throw you into ‘Quirks Mode’ if you don’t define a correct DOCTYPE. Quirks mode is designed to help with rendering non-W3C-compliant webpages. Its purpose is to render pages that were designed for older browsers and are no longer compliant with today’s standards. You can find more about it on Wikipedia. Actually, all browsers have a quirks mode, and they will all throw you into it if you don’t define a valid DOCTYPE. And if you look through pyjamas examples, you’ll probably notice a consistent lack of DOCTYPE. That’s right, most of pyjamas examples actually run in quirks mode when opened inside a browser (and not just in IE). This is usually not a big deal, unless you happen to be running IE9.

It turns out IE9 does not support event handler when in quirks mode. Unfortunately, event handler is one of the most important building blocks for pyjamas, as it handles just about all user interaction. So to make your web app compatible with IE9, you will have to make it W3C-compliant, this is something that will affect all browsers, not just IE9. Most of your changes will be in your app’s main html file itself and your css stylesheet, although it’s possible that you will need some slight code changes as well (in particular if you used DOM.setStyleAttribute() method).

First of all, we need to define a valid DOCTYPE. To do so, open up your app’s main html file (should be located in your app’s public directory) and add this line at the very top (before tag):

<!DOCTYPE html>

This tells it to render your app using the latest html standard (which would be HTML5). If your app looks and works great, congratulations, you know your html and can probably stop reading now. If you’re someone like me, however, you’re probably staring at a deformed version of your app while scratching your head. First of all, let’s address the issues that are common across all browsers. To do so, read my previous post about making your app HTML5-compliant. Once done, your app should appear correctly in all browsers (except maybe some glitchtes in IE9). Here are the last few fixes for the annoyances with IE9.

If you use a text area element (pyjamas’ TextArea() class), IE9 seems to override the width and height you set in the stylesheet unless you use ‘!important’ tag. It also seemed to add a scrollbar for me, so I had to set ‘overflow’ property to auto as well. I also used this oportunity to prevent Chrome from making my text area resizable (that little corner in bottom-right corner that the user can drag) by setting ‘resize’ to none:

.gwt-TextArea {
    overflow: auto;
    resize: none;
    width: 300px !important; /* important tag needed for IE9 */
    height: 100px !important; /* important tag needed for IE9 */

The second annoyance seems to be that unlike other browsers, IE9 (when operating in strict mode) does not assume that a single value for a field should be applied to both dimensions. This means that to center a background image, for example (as I needed to do with my loading icon), you’d need to specify “center” twice in CSS stylesheet. That should be pretty much it, I have to admit that for the most part IE9 is actually more standards compliant than Safari or Chrome. There might be other quirks, which I haven’t ran into with my app. Feel free to mention them to me so I can update this post.

This entry was posted in Frameworks, How To and tagged , , by Alexander Tsepkov. Bookmark the permalink.

About Alexander Tsepkov

Founder and CEO of Pyjeon. He started out with C++, but switched to Python as his main programming language due to its clean syntax and productivity. He often uses other languages for his work as well, such as JavaScript, Perl, and RapydScript. His posts tend to cover user experience, design considerations, languages, web development, Linux environment, as well as challenges of running a start-up.

2 thoughts on “Adding True Internet Explorer 9 support to Pyjamas

  1. I never bothered to merge it (partially because I forgot, partially because my commit rights were tied to a key that I accidentally erased with my OS re-install, and I never requested new commit rights for Pyjamas), it’s possible someone else has merged this instead, however.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>