Thursday, October 18, 2007

Dojo, Flash, SWFObject, Packer, IE's "Click here to activate and use this control" and Eval Contexts

Boy, that's a long title!

Solving this problem I had at hand took a good day and a half. What I discovered seems obvious in hindsight, but it wasn't obvious to me until I had solved it. So that no one ever goes through the pain, here's what happened.

There is this thing I'm working on at work that required the use of SWFObject class simply to get around the IE "Click here to activate and use this control" nuisance when inserting flash files into the page.

Now, the reason why that message comes up is pretty shitty, but the problem and solution is very well documented. SWFObject is supposed to solve this problem. So, rather than re-inventing the proverbial wheel, we decided to use SWFObject. However, needless to say, IE would still keep throwing the message.

Now, a bit about the setup we have. We are using Dojo for this particular thing. I have written a wrapper around SWFObject so that I don't have to bother passing it all the stuff it needs every time I need to use it. Also, on a test machine, we host built versions of the code, which used Packer to compress the JavaScript. We were using Packer more as a compresser than as an obfuscator, since Packer gave us a considerable improvement in the compression ratios over anything else. On my local machine, I use the unbuilt version of the code.

Irrespective of where the code ran from, we used to get the nasty message in IE.

For those who don't know yet, here's how you get around the message - it's pretty simple. Create the object/embed tag from an external JavaScript file, and insert it into the HTML document. It's that simple.

Now, going by unobtrusive principles, our JavaScript always lies in external files (unless there's very good reason to not do so). So, why was this message showing up? There were two scenarios here:

  • My dev machine: Because of the way I had layered the files in Dojo for ease of maintenance, Dojo would dynamically pull in the references on the fly. This is very convenient and makes for easy to organize code. The way Dojo does this is by making an XHR call to the server to fetch the .js file, and then evaling the code. Now, these evals are run in the context of the window, effectively making them inline scripts. IE thus thought the code was inline, and showed the error message.

  • The test machine: So, even if it doesn't run on my machine, that's fine if we can get it to run on a test machine correctly. On this test machine we always house the built version of the Dojo file. With a properly written build profile, Dojo might not have to go around and pull in references as required since they would already be baked into the built files. So, that would make the SWFObject code external, and IE shouldn't have a problem with it, right? Almost. Packer requires an eval of the code it has obfuscated to make sense of it. Again, the eval is run in the context of the browser, and IE treats the resultant code as inline, again showing the error.

So, in both the cases, the problem was the context of the eval, though in entirely different scenarios. It could also be concluded that SWFObject cannot ever be compressed using Packer. It was just painful to track down and fix this bug. I hope no one ever has to go through this pain again.

If you need to know, we had to switch to ShrinkSafe to avoid the eval that Packer does. There are definitely better ways to compress, but this should do for now. The code-size increase wasn't too significant, so we were fine with using ShrinkSafe. Ideally, I would use ShrinkSafe for SWFObject and packer for everything else, giving the best of compression and avoiding the implicit eval. This doesn't solve the problem on my local dev machine (since the code is unbuilt), but that doesn't really matter.

No comments: