@madpilot makes

Ensuring background AJAX requests have completed when leaving a page

To make things feel quicker on 88 Miles, I update the UI straight after an interaction (like punching in or out), even though in reality the AJAX request is still sitting there waiting for confirmation from the server. Generally, the AJAX request will complete correctly (and if it doesn’t a message gets popped up and the UI is restored to a pre-action state), however there is a chance that the user will close their browser or navigate away before everything completes, which may result in a project staying punched in which is less than ideal.

This little snippet of JS will allow you to check for pending AJAX requests, and throw up a warning dialog is a request is still pending.

jQuery example:

var ajaxInProgress = false;
function ajaxStart() {
  ajaxInProgress = true;
}
function ajaxStop() {
  ajaxInProgress = false;
}
$(window).bind('beforeunload', function(e) {
  if(ajaxInProgress) {
    return "There is a background process that hasn't completed yet. Reloading might result in data loss.";
  }
});

Pure XHR example:

var requests = [];
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
  if(this.readyState == 1) {
    requests.push(this);
  }
  if(this.readyState == 4) {
    var index = requests.indexOf(this);
    // Remove the completed request from the request list - handles out of order responses
    if(index != -1) {
      requests.splice(index, 1);
    }
  }
}
window.onbeforeunload = function() {
  if(requests.length != 0) {
    return "There is a background process that hasn't completed yet. Reloading might result in data loss.";
  }
}

Caveats

Tested on latest Chrome, Firefox, Safari and IE 9+.

It doesn’t work on the iPhone. Which is shit, because phones are the ones that need this the most. It works fine on Android and Windows Phone though.

Debugging JavaScript in Internet Explorer

As anyone who has ever received the dreaded Object doesn’t support this property or method error in IE can attest, debugging using everyone favourite browser is a right, royal pain in the heiny. Using Firebug in Firefox really has spoilt us as frontend developers (Hey, what am I talking? These ARE BASIC TOOLS that every other development platform has had since Ada Lovelace was in small britches, but I digress), so what is a cross-platform developer to do?

Little known fact outside of the .NET world: Visual Studio has a complete JavaScript debugger built in, which allows you to set breakpoints, add watches, mess around with variable values and more importantly, gives you better error messages, and actually highlights the line where things went wrong.

  1. Download and Install Visual Studio Express Edition (which is free as in beer).
  2. Create a new Web Site – call it what ever you like, it’s just a placeholder
  3. Hit “Run” (or F5) on the blank problem – a local server should start, and IE7 should load a blank page
  4. Change the URL to the page you want to debug. Once the page is loaded the debugger is good to go – in fact, if your page has any errors, Visual Studio will get focus, and politely tell you as such
  5. To add a break point, flick back to Visual Studio Express and open the JavaScript file you wish to add the break point to, and then refresh the browser – once context hits the point, you will be able to step through the code.

Whilst still lacking a DOM browser (Firebug Lite might be able to help out with that), this takes some of the fun out of debugging JavaScript IE, from the point of view that it is now actually possible.

Get the skinny on the Mario Brothers in Javascript

Since I’m trying to milk the Mario Brothers in JavaScript thing for all it’s worth, I’d like to announce part two of my SitePoint article, which gets into the juicy bits – collision engines and physics as well as side scrolling screens. Go forth, read and learn.

What I learnt at Web Directions South 08

First off, thank to WA government for having the foresight for ignoring the actual birthday of the Queen and making today a public holiday – my couch has been-a callin’. So what has been happening over the past couple of days?

Day 0

After getting in early morning on the Wednesday, I toddled along to Stories for one of their famous egg and bacon rolls with Simon, Lachlan and Nick.  Oh how I’ve waited for that. I could have gone home at this point a happy man, but then there was work to do! Spending the day tweaking my presentation, next it was up to the Kirk for memories of last year (Yes, they still only have five pint glasses) and then on to Port80 Sydney: Wednesday edition. We had a fantastic turnout, with over 80 people – most of which were new faces. Big ups to Clever starfish, radharc and Saasu.com for throwing dollars on the bar. I’m seeing a definate pattern here in regards to free beer.

Day 1

Waking up slightly hung over, I was off to the registration desk, and then the games began. Highlights for me was Dmitry Baranovskiy’s web vector graphics  talk. I’m about to go download raphael and build some stuff – not only if the guy a genius, but his talks are hilarious. Unfortunately, I missed the JavaScript workshop, where I hear Cameron Adams wowed the crowds with a JavaScript drum machine – with visualizations. The final keynote from August de los Reyes tied software and psycology together, something that I think is the crux of what we do. It was also a great talk, although the ads were a little too much to take.

What I learnt:

  • Seeing cool stuff is inspiring.
  • When giving a presentation, find out about the audience – it’s better to pitch a bit to high than to low.
  • Don’t try to squeeze in 2 hours of material into 55 minutes

Day 1.2

Next up was WebJam8. The one big disappointment of this trip is that I didn’t get something entered in WebJam, but having a Web Directions talk to do and a stupid amount of work took priority… Some really cool stuff was shown: Dmitry came third with a live code, that added reflections and animation to images on a web page, Diana came second with a crazy funny fast presentation about governments and bike helmets and the winners, Mr Speaker and Henry Tapia did a awesome YouTube remixer. In a moment of unlike-me-ness, I wentback to the hotel at a reasonable hour…

Day 2

…and for the first time EVER made it to the first session of the second day! So no one can joke that I missed the best talk of the conference (as happened the past couple of years) and I wasn’t dissapointed. Jeffrey Veen is a brilliant speaker, and I wanted to pull my laptop out right there and then and cut some code. This is the sort of stuff that makes these conferences. After lunch, I gave my presentation on OpenID, OAuth and webservices (Available on slideshare here), and I think it went pretty well. The backchannel was only positive, so I count that as a win. Next I headed over to Douglas Crockford for a good old fashioned Computer Science lecture, god that takes me back! Whilst a little dry, and technical (Who am I kidding – I wanted that) it generated some great discussion.

What I learnt:

  • Great talks bring in personal experience
  • You need to get the audience to think
  • Dual monitor Powerpoint never works properly when you need it to

Closing night

With all of the festivities over, it was time to let the hair down at the Shellbourne, for a quick shandy.  Had a debate about designers vs UX experts (We were actually arguing the same point, it turns out), and had many an indepth conversation, including one with Charles from Opera, about webservice brokering. So much so, my plans to build one may now be possible (Huzzah!).

What I learnt:

  • Finding random “locals” to go out with doesn’t mean they know where they are going
  • Peanuts 2u is actually a brand of salted almonds
  • There is a “No redheads” policy in NSW pubs
  • Bats are weird and scary

So that was my Web Directions experience in a nutshell! Roll on Edge of the Web – only five weeks until we get to do it all over again!

Use CSS to speed your unobtrusive JavaScript

Unobtrusive JavaScript does for JavaScript what CSS did for HTML design. Separating the design and business logic client side means better re-use and compatibility.

To make a truly unobtrusive site, you should start with a base, non-JavaScript version of the site, and then add functionality dynamically. One of the issues with this is quite often you are left with elements that are required for HTML-only functions, but not for the JS version. Obviously, it’s easy to traverse the DOM tree and hide elements that not required like this:

var elementToHide = document.getElementById('hide_me');

if(elementToHide) {
    elementToHide.style.display = 'none';
}

but this can be pretty slow if you have lot of elements to hide. Sure, you could use XPath, but it isn’t supported in many browsers.

CSS is pretty darn quick when applying styles (well, you would hope so – that’s what it is designed for), so by dynamically including a CSS file via JavaScript we can hide (and show) elements really quickly. It’s all pretty simple:

  1. Create the style sheet (We’ll call it /stylesheets/css.js)
  2. Set up the desired styles in the style sheet as you would any another CSS file
  3. Drop the following code is to a JavaScript file and include it in your header
function unobtrusiveCSS() {
    head = document.getElementsByTagName('head');
    head = head[0];
    link = document.createElement('link')
    link.href = '/stylesheets/js.css';
    link.setAttribute('media', 'screen')
    link.setAttribute('rel', 'stylesheet');
    link.setAttribute('type', 'text/css');
    head.appendChild(link);
  }

  FastInit.addOnLoad(unobtrusiveCSS);

Now, you might have noticed that I’m using the FastInit library (written by the ever so talented Andrew Tetlaw). Because we are modifying the DOM, we need to wait for it to load before we can append anything. I could have used window.onload, but that would defeat the purpose, as we would have to wait for all of the images on the page to load, negating the speed up we would get.

The FastInit library will fire the JavaScript as soon as the DOM is loaded. (Go to the site to find out how it works – it’s quite ingenious), At the end of the day, you would need to a library like this regardless of whether you use the CSS include hack.

Caveat: Another way of doing it would be to use document.write, which would eliminate the need for an external library, but hacks like that make baby jeebus cry.

Swing your hands from side to side – how to abuse JavaScript

What is a developer to do with all of that spare time between 1am and 3am? Write a JavaScript platform game of course!  I’ve been sitting on this for the last couple of months, waiting for a good time to release it, but as this guy just released his (freaking awesome) canvas element version, I didn’t want to be out done. So as a proof of concept of how far you can push semantic HTML, CSS and JavaScript, I present to you: JavaScript Mario Brothers!

  • The level is built using plain old HTML and CSS. Using absolute positioning and class names give each sprite a location and look (Yes, I know it should be in a separate CSS file – it was just easier for debugging at the time), so no cheating with the canvas element ;)
  • Sprite actions are determined by class names – so all divs with the class name koopa-sprite instantly start acting like koopas.
  • The collision engine and animation is all done via un-obtrusive JavaScript (Except for a few bits that I couldn’t get running after window.onload for various reasons).

The JavaScript is based on the Prototype JS library, and the level is a complete write from scratch (which is why it isn’t quite correct), but as a proof of concept in both game development and pushing the limits of JS, I think it’s pretty cool.

Facebook, OpenSocial – meh. Why aren’t widget useful?

Widgets are a hot topic in the world of social networks and blogs, but at the end of the day they really don’t make our lives better. I mean honestly, if all of those widgets out there stopped would we miss them? Hell, some of them are down right annoying. The IDEA of a widget is not as dumb as some of these apps, but for some reason they haven’t been embraced by those developers that are helping us to get things done.

Google has just released OpenSocial, and I was admittedly pretty excited – for about 5 and a half seconds at which point I realised it would have limited scope outside of the social networking world (hence the name). Why was I excited? Well I would love to be able to create a widget for 88 Miles – imagine being able to drop a time-tracking widget into BaseCamp or NetAccounts or ? Or, even better, into your internal intranet.

OpenSocial has so much potential, but isn’t quite there for the Software as a Service guys, so why don’t we create a an Open Widget API? What do we need? Well, not that much – if we flip the way that OpenSocial works a little and do a little work from the application side.

JavaScript, JSON and HTTP

The easiest way to drop your widget on to a third-party site would be JavaScript. Create a standard JavaScript end-point that the third-party app can retrieve. Maybe it could pass in a element id that you could use to build your DOM tree from. Because the script is hosted on YOUR server, you can make calls back to your server via AJAX. You can use this to generate HTML, make callbacks, retrieve JSON and generally interact with your database.

This is SO easy with Rails, as you can get a JSON REST API out of the box, with very little effort. PHP/Pylons/ASP.NET will do the same thing easily enough to. Extend that idea, and with a little knowlegde of the site you are embedding on, you could probably even interact – add a company to your Basecamp account and it would automatically add it to 88 Miles. You could do it by registering observers of specific types maybe – not sure, will still have to think that bit through.

Authentication

We already have a system for authentication – it’s called OpenID. If your site implements OpenID, it is pretty god-damn trivial to authenticate a user that has already authenticated on the third party site. Any OpenID provider worth it’s wait will remember your credentials once you have logged in – so the third party site can pass your OpenID URL down to the widget, then you can authenticate them from there, and because your provider has already logged you in, you won’t need to enter a username or password.

The ultimate mashup

If all of your favourite apps had these widgets, you could easily drop them in to your intranet site. How kick-arse would that be? What do you think?

JavaScript is OK!

A couple of days ago, the regular ol’ Port80 meet up was on. However, this one was a little different. Firstly, we tried out our new venue – the Velvet Lounge in Mt Lawley. We booked a room so we didn’t have weather and other punters to contend with. It just so happens that the room has a stage. And it was on this stage that the first set of Port80 mini talks took place.

The idea behind the Port80 mini-talk is simple: Two local gurus get up and talk on a (web-related) topic for 10 minutes. It is a great way to share knowledge between the tightly knit web industry and a great opportunity of Perth designers and developers to show their wares. Because of our small population and isolation from the rest of the country attending conferences is both expensive and difficult, so these mini talks are a great way to build community.

Brian Madsen started off the proceeding with a talk about the new expressions suite from Microsoft. Since most in the room would have written off Microsoft products for anything web related, it was great to see that Microsoft are now taking standards a little more seriously.

Brian Madsen. Photo by Kay Smoljak

Then it was my turn with a little talk entitled “Out of my way JSON! If CSS can be unobtrusive, so can JavaScript” where I go on to explain the benefits and techniques involved in un-obtrusive JavaScript.

Myles Eftos. Photo by Kay Smoljak

You can view the slides (S5 format) for those of you who weren’t there on the night (Brian said he will upload his soon) and I’m busy doing some post-production on the audio in preparation for some podcasty goodness. That will include transcribing too for those that want to skim read the talks.

I think the night was really successful – and we are currently looking for some more speakers! So if you are in Perth or going to be in Perth on March 8, 2007 and you have a topic you can babble on about for 10 minutes, drop me a line! Even if you don’t want to talk just yet, I hope we can see you there next month. It’ll kick off about 6 o’clock.

Photos by Kay Smoljak.

Password Generating Bookmarklet

Some how I managed to get lumped with the un-enviable task of creating email accounts for clients at Bam Creative – we currently have to use an archaic web interface and it takes forever. One of the many things that annoyed me about the system, is it can’t generate passwords for you, so I whipped up this little bookmarklet that will generate an eight character password made up of upper and lowercase letters and numbers. It adds a small div to the very top of the page you are viewing. Clicking the password makes it disappear again.

Drag the following link into you bookmarks. Click it now to see it work!

[Password generator][2]

Known issues:

  • It doesn’t play nice with frames, it will throw a JavaScript error.
  • Clicking the link in IE doesn’t make it disappear.

The raw code:

<li class="li1">
  <div class="de1">
    <span class="kw1">for</span><span class="br0">(</span>i=<span class="nu0"></span>; i < <span class="nu0">8; i++<span class="br0">)</span><span class="br0">{</span></div> </li> 
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <span class="kw1">switch</span><span class="br0">(</span>Math.<span class="me1">round</span><span class="br0">(</span>Math.<span class="me1">random</span><span class="br0">(</span><span class="br0">)</span> * <span class="nu0">2</span><span class="br0">)</span><span class="br0">)</span> <span class="br0">{</span>
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">case</span> <span class="nu0"></span>:
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> passwd += String.<span class="me1">fromCharCode</span><span class="br0">(</span>Math.<span class="me1">round</span><span class="br0">(</span>Math.<span class="me1">random</span><span class="br0">(</span><span class="br0">)</span> * <span class="nu0">25</span><span class="br0">)</span> + <span class="nu0">65</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">break</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">case</span> <span class="nu0">1</span>:
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> passwd += String.<span class="me1">fromCharCode</span><span class="br0">(</span>Math.<span class="me1">round</span><span class="br0">(</span>Math.<span class="me1">random</span><span class="br0">(</span><span class="br0">)</span> * <span class="nu0">25</span><span class="br0">)</span> + <span class="nu0">97</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">break</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">case</span> <span class="nu0">2</span>:
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> passwd += Math.<span class="me1">round</span><span class="br0">(</span>Math.<span class="me1">random</span><span class="br0">(</span><span class="br0">)</span> * <span class="nu0">9</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <ins class="in"> </ins> <ins class="in"> </ins> <span class="kw1">break</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins> <span class="br0">}</span>
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <span class="br0">}</span>
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <ins class="in"> </ins>
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        <span class="kw2">var</span> pDiv=document.<span class="me1">createElement</span><span class="br0">(</span><span class="st0">&#8216;div&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pDiv.<span class="me1">setAttribute</span><span class="br0">(</span><span class="st0">&#8216;style&#8217;</span>,<span class="st0">&#8216;postion:absolute; top:0px; left:0px; border: 1px solid black; background-color: grey; text-align: center;&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1" />
    </li>
    <li class="li1">
      <div class="de1">
        <span class="kw2">var</span> pClose=document.<span class="me1">createElement</span><span class="br0">(</span><span class="st0">&#8216;a&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pClose.<span class="me1">setAttribute</span><span class="br0">(</span><span class="st0">&#8216;href&#8217;</span>,<span class="st0">&#8216;#&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pClose.<span class="me1">setAttribute</span><span class="br0">(</span><span class="st0">&#8216;style&#8217;</span>,<span class="st0">&#8216;color: white&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pClose.<span class="me1">setAttribute</span><span class="br0">(</span><span class="st0">&#8216;onclick&#8217;</span>,<span class="st0">&#8216;this.parentNode.parentNode.removeChild(this.parentNode);&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pClose.<span class="me1">appendChild</span><span class="br0">(</span>document.<span class="me1">createTextNode</span><span class="br0">(</span>passwd<span class="br0">)</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        pDiv.<span class="me1">appendChild</span><span class="br0">(</span>pClose<span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        body = document.<span class="me1">getElementsByTagName</span><span class="br0">(</span><span class="st0">&#8216;body&#8217;</span><span class="br0">)</span>;
      </div>
    </li>
    
    <li class="li1">
      <div class="de1">
        body<span class="br0">[</span><span class="nu0"></span><span class="br0">]</span>.<span class="me1">insertBefore</span><span class="br0">(</span>pDiv,body<span class="br0">[</span><span class="nu0"></span><span class="br0">]</span>.<span class="me1">firstChild</span><span class="br0">)</span>;
      </div>
    </li></ol> </div> 
    
    <ul />

[2]: javascript:passwd=’’;for(i=0;i<8;i++){switch(Math.round(Math.random()*2)){case 0: passwd+=String.fromCharCode(Math.round(Math.random()*25)+65);break;case 1:passwd+=String.fromCharCode(Math.round(Math.random()*25)+97);break;case 2:passwd+=Math.round(Math.random() * 9);break;}}var pDiv=document.createElement(‘div’);pDiv.setAttribute(‘style’,‘postion:absolute;top:0px;left:0px;border:1px solid black;background-color:grey;text-align:center;’);var pClose=document.createElement(‘a’);pClose.setAttribute(‘href’,’#’);pClose.setAttribute(‘style’,‘color:white’);pClose.setAttribute(‘onclick’,’this.parentNode.parentNode.removeChild(this.parentNode);’);pClose.appendChild(document.createTextNode(passwd));pDiv.appendChild(pClose);body=document.getElementsByTagName(‘body’);body[0].insertBefore(pDiv,body[0].firstChild);void(null);

New JavaScript framework – Tennaxia

I just received an email a couple of days ago from one of the developers of a new JavaScript framework called Tennaxia. The point of the email was to ask permission to use my JavaScript colour picker as part of the library which is pretty cool. They also included the fabtabulous library from my mate over in Queensland, Andrew Tetlaw.

The library is a group of JavaScripts based on Prototype which provide widgets to use on web pages. Andrew’s widget, for example converts divs into panel tabs. There are a number of demos on the Tennaxia page.

It all looks pretty cool, so go and check it out.

Next