Sunday, March 29, 2009

Internet Explorer fun and games

This is a kind of mixed bag posting on a few IE issues I came across recently:

IE 8 Released
So, IE 8 was released recently. At the SXSW CSS3 wars talk, Sylvain Galineau of Microsoft spoke about the ~7000 w3c CSS2 tests MS have passed as part of their standards push for IE 8. Internet Explorer gets a lot of bad press (man, I'm sick of basing IE), but hopefully this will be a turning point for future releases of Internet Explorer. Cool to hear that IE 8 is now the most CSS 2.1 compliant browser on the market. Wonder when it'll be pushed as an automatic update.

IE 8 Released - my pages look like sh1t
Buy yourself some time with the IE 7 meta-tag:

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

So, dynamically creating checkboxes in IE 6 is a little different to every other browser I develop for. For whatever reason, I couldn't get my checkbox to be checked by default. That is until I found out about the defaultChecked property.

Apparently, if you try to set the checked property of a checkbox before you add it to the DOM in IE 6, IE6 drops the checked property and sets the checkbox as unchecked by default. But, if you use the defaultChecked property, it'll heed your intentions and hey presto, your checkbox is checked.

Web SuperPreview
Speaking of IE, Web Super Preview looks like a good tool. Kinda like IE on steroids.

Friday, March 13, 2009

Running Wireshark on MAC OSX

If I have to open Wireshark at all, I know I'm in trouble. Its a fantastic tool, but as a web developer, I default to Firebug. I've only ever really needed Wireshark for debugging IE network issues.

I've been taking a look at Adobe AIR recently which has a very similar Firebug like console called AIRIntrospector. However, when attempting to execute Jsonp requests in Adobe AIR, my timeout callbacks were being invoked and the requests weren't showing up in the "XHR" tab in AIRIntrospector. This was despite the fact that I could see the apache logs filling up with requests on the API server I was trying to hit.

So, I tried firing up Wireshark to listen and inspect the response from the API server only to be greeted with:

The capture session could not be initiated ((no devices found) /dev/bpf0: Permission denied).

After a few quick Googles, I found this helpful post. Apparently, you need to start Wireshark as root. So,

$cd /Applications/
$sudo ./Wireshark

After that quick sudo, I could listen for API responses without needing to rely on the AIRIntrospector.

Listening for pasted input

A lot of the input forms I work on defaults the "Submit" button to disabled. Added to client side validation, this default usually prevents the user from submitting forms without required fields. I usually attach onkeyup events to each of the form fields to see whether I should enable the "Submit" button for a particular form.

However, onkeyup doesn't catch everything. If the user pastes input into a field using their mouse, onkeyup doesn't catch that event. So, the user is left with an input field which appears filled, but the "Submit" button remains disabled.

The solution is pretty simple. You can attach something like this to your input fields:

<input type="text" dojoAttachEvent="onkeyup: checkSubmitButton, oninput: checkSubmitButton, onpaste: checkSubmitButton">

More on oninput and onpaste

Friday, March 6, 2009

dojo builds and regexp

Just saw a tweet fly by which made me think of a possible blog entry.

I'm more inclined to use Firebug and console.* statements to debug my client side dojo code. I find it easier than rebuilding my code base every time I want to make a change. The one downside to this is my client side code has console statements scattered throughout the code, thus making my the download heavier.

So, as part of my build process, I use the following code to strip out all console.* statements and replace them with a semi-colon.

my @generated_files = (
foreach my $generatedFileName (@generated_files) {
my $in_file = $generatedFileName;
my $out_file = $generatedFileName . ".stripped.js";
open DATA, "$in_file" or die "can't open $in_file $!";
my @file_lines = ;
close (DATA);
open DATAOUT, ">$out_file" or die "can't open $out_file $!";
foreach my $line (@file_lines) {
$line =~ s/(?<!:)console\.(?:warn|log|error|con|info)(\((?:(?>[^()]+)|(?{1}))*\));/;/gi;
print DATAOUT "$line";
close (DATAOUT);

The good people over at helped me out with that expression and saved me ~5KB after GZIP compression - not too shabby.

This regular expression does not filter every console.* statement out of your code. For example if the regexp parser encounters:

test ? console.warn("Success") : console.warn("Failure");

it will not strip it down to:

test ? ; : ; ;

As that isn't valid JavaScript.

I'm pretty sure this problem could be fixed for the latest and greatest versions of dojo with a new parameter which you can pass automatically to the build script, but I'm still on 1.0.2 so I'll continue with this until I upgrade to 1.3.

Monday, March 2, 2009

Catching dijit's Dialog close event

I tend to use dijit Dialogs whenever I need the user to make a decision before proceeding with any other actions. They're especially useful for server error conditions and asking the user how they'd like to react to something like an API failure.

However, popping up dialogs can be annoying to users. I know I'm guilty of scanning dialog text and just hitting the 'x' button and ignoring the message. There are two ways you can prevent the user from doing this with dojo.

1. The most obvious solution: Hide the 'x' button. This is easily done with some simple CSS:

#myDialog .dijitDialogTitleBar .dijitDialogCloseIcon {

The one drawback to this is that the user can hit the escape button and that'll close the dialog.

2. Attach the following two callbacks to your dialog:

this._userClosedDialogHandle = dojo.connect(dijit.byId("myDialog"), "hide", this, "_handleCloseDialog");
this._userClosedEscDialogHandle = dojo.connect(dijit.byId("myDialog").containerNode, 'onkeypress', function (evt) {
key = evt.keyCode;
if(key == dojo.keys.ESCAPE) {

The one caveat with this method is that you need to disconnect both handles in the _handleCloseDialog method. Otherwise, you'll find yourself in an infinite loop pretty quickly.