JWPlayer and Firefox hunting

Greetings m’chums! Welcome to this week’s big adventure: trapping and shooting an old bug in a very popular tool.

In the course of my everyday tinkering, I encountered a curious flaw in JWPlayer under Firefox which I think has plagued fellow adventurers of this fine Flash movie player for years, but which none seem to have sussed the essential nature of. Until today.

It all started when I found the player was firing no events. Initial investigation showed that I was never subscribing the events, because I was waiting for the event attaching method jwAddEventListener to arrive on the scene:

var player = $('#myplayer');
$.doWhen(function(){
  return !!player.jwAddEventListener;
}, function(){
  //attach events
});

(doWhen is a nifty little utility I wrote that runs one function once after another function returns true)

A full investigation of the matter revealed that, in Firefox, the entire Javascript API for the embed was never being created! This was quite curious, as I’ve had many players fully functional in Firefox before.

I set about identifying what was different, and at last deduced that in all the previous cases, I had been instantiating the player after an ajax call (for content). In this case, however, the player was being created immediately after jQuery(document).ready.

Pausing briefly to brew up another cup of brown joy strong enough that the spoon stood rigid, I continued the experiment by delaying the player instantiation by two seconds with setTimeout. Lo and behold, the missing API was rumbled!

This was far from an ideal solution, of course. I wondered at what critical juncture Firefox would be in a position to correctly instantiate JWPlayer. Time to dust off an old friend: window.onload. A quick test showed that yes, indeed, once the load event had fired off, the player’s entire API reappeared like Manchurians at a near-dead pub advertising half-off pints of Brown!

Naturally, I didn’t want to slow other browsers down unnecessarily, so I knew that the final solution would have to narrow its sights on Mozilla, and only if the load had not yet fired. The way to determine the latter is document.readyState: “interactive” means the page is still in its initial rendering phase, but the DOM is available; “complete” is the word we’re looking for, the readyState when load has fired.

if ($.browser.mozilla
      && document.readyState !== 'complete') {
  $(window).bind('load', function(){
    //write your embed code here
  });
} else {
  //write your embed code here
}

There you have it! Clearly, this should not be necessary; JWPlayer should do all of this internally. For now, it’s a workaround that seems 100% successful.

And with that, another successful week tromping through the deepest woods of my trade draws to a close. I bid your weekend be filled with lakes of Earl Grey and barrels of gorgeous Somerset gold. Tata!

More on Randomness of Arrays

A few months ago, I posted about how the classic method most JS programmers would use to randomise an array completely fails. I proposed a quick solution to it, but that solution had flaws of its own.

So, for those of you who need to shuffle decks of cards, scramble virtual eggs or just want to toss a little confusion into your applications, here’s a fully working array randomiser:

Array.randomiseArray = function(arr){
  var i, v;
  for (i=0; i<arr.length; i++) {
    v = arr[i];
    arr[i] = {
      v: v,
      sort: Math.random()
    };
  }
  arr.sort(function(a, b){
      return a.sort - b.sort;
  });
  for (i=0; i<arr.length; i++) {
    arr[i] = arr[i].v;
  }
  return arr;
};