Preloading images with sexy anonymous recursive functions

[2009-06-27]

I don't do a lot of Javascript, and I used to dislike Javascript. But nowadays, with frameworks like jQuery and Prototpe, Javascript is fun. And has some really sexy properties. Like recursive anonymous functions.

It's very common to update the document with HTML that is returned by an AJAX call. That works pretty well, except for the fact that the HTML is updated while the images are not fully loaded yet. And that looks ugly, especially when using effects to show or transform that HTML bit that you update.

So, I wanted to extract all the images from a piece of HTML and preload them, check if they are loaded, and update the page when all images are loaded.

So here's a very simple function that checks if an image is loaded.

// checks if an image is loaded
function isLoaded(im) {
  if (im.complete) { return true; }
  if (im.naturalWidth > 0) { return true; }
  return false;
}

And a recursive anonymous function, that receives an array of images. We check if these images are all loaded using the function 'isLoaded()', and update the HTML if so, or call itself anothertime if the images aren't loaded yet.

// anonymous recursive function that checks if images are loaded
// and updates html when all images are loaded.
var f = function(imgs) {
  // loop images
  var notCompleteYet = $A(imgs).reject(function(im) {
    return true == isLoaded(im);
  });
  if ($A(notCompleteYet).size() == 0) {
    // and update content when all images are loaded.
  }
  else {
    // or recurse
    setTimeout(arguments.callee, 100, imgs);
  }
}

And here is the tiny bit that does the Prototype AJAX call.

try {
  new Ajax.Request(url, {
    method: 'get',
    parameters: args,
    onSuccess: function(transport) {

      // create an element node form response text
      var html = transport.responseText;
      var node = new Element('div',
			     {id:'tmp-content',
                              style:'display: none;'},
			     ' ');
      node.update(html);

      // populate array with images to be preloaded
      var images = new Array();
      $A(node.select('img')).each( function(el) {
        im = new Image(84, 48);
        im.src = el.src;
        images.push(im);
      });

      // and check if all images are loaded, 
      // and update the HTML when they are all loaded.
      setTimeout(f, 500, images);
      node = null;
    },
    onFailure: function() {
      throw('Ajax call failed');      
    }
  });
}
catch(e) {
  // error handling
}

Enjoy playing with it ;-)

-> more

 

Drawblog

[2009-06-21]

Gosh, had a look at the PHP code I wrote to get my drawblog online a couple of years ago. Was not too impressed with it, so decided to do a quick rewrite using the Zend Framework. And in a few lines of code and about 2 or 3 hours later, it's up. Looks almost the same, but it's a total rewrite. Much cleaner and a lot safer than the old code. Feels much better...

-> more

 

IE6 support

[2009-06-20]

It was about time to add some IE6 support. Visitors still surfing with the 8 year old browser IE6 are redirected to a nice surprise party page. This is how this site looks like in IE6 and IE5.5.

I don't like IE6 because it so standards uncompliant and buggy. Ie6 is retarding the future of the internet. As a wedevelopper it costs a lot of time and effort to work around those IE6 issues. It's about time to upgrade to Firefox or another browser. ;-)

I'm very lucky though, with this months stats. It turns out that quite a lot of visitors use Linux, and that Firefox beats IE. Check it out:

Windows        65   %
Linux          13.1 %
Macintosh       8.5 %
linuxubuntu     0.8 %
linuxfedora     0.3 %
linuxdebian     0.3 %
linuxsuse       0.2 %


Firefox        45.3 %
MS IE          35.3 %
Safari          6.2 %
Mozilla         5.1 %
LibWWW          1.1 %
Opera           1   %
Netscape        0.8 %

That said, my site is still best viewed in Firefox with the Vimperator plugin.

-> more

 

Transport endpoint is not connected

[2009-06-20]

I received this "Transport endpoint is not connected" error in a little UDP server I wrote. The lines that raised the error are these:

if ((len = recvfrom(s, buf, BUFSIZ, 0, (struct sockaddr *)&remote_addr,
                    &sin_size)) < 0)
{
    perror("recvfrom");
    return 1;
}

I happened to make my socket a connection-oriented socket, as for a TCP server. UDP makes uses a connectionless socket, so that there is much less overhead involved in sending the data. Instead of a SOCK_STREAM socket type, I had to specify the SOCK_DGRAM socket type.

--- a/udpserver.c
+++ b/udpserver.c
@@ -17,7 +17,7 @@ int main(int argc, char *argv[])
     my_addr.sin_addr.s_addr = INADDR_ANY;
     my_addr.sin_port = htons(8000);
 
-    if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
+    if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
     {
         perror("socket");
         return 1;
lines 1-26/26 (END) 

-> more

 

A new version

[2009-06-19]

Just now I did a deployment and a brand new version of my site is online. Polished the design a bit, and made it possible for passers-by to leave a comment. Comments need to be moderated first, so it takes some time before they appear on the site. That's to prevent SPAM SPAM SPAM.

And sorry about it, but you can only leave one message (for a given IP address) in the moderation queue. You can post again once it's approved.

And please feel free to leave me comments or to notify me if you encounter a bug.

-> more

 

Testing file uploads in Cucumber and Webrat

[2009-06-18]

You can easily test file uploads in Cucumber with Webrat. But I encountered the problem that all my uploaded files had a text/plain mime-type. It turned out that you can give an optional parameter to specify the mime-type of an uploaded file.

So, now my step goes like this

attach_file file_input_field, file_path, mime_type

and it works ;-)

-> more

 

Get the anchor of an URL in Javascript

[2009-06-17]

If you think about it, it does make sense. But it might not be the first thing to come up with when you need to solve the problem. But you can get the anchor of an url like this:

window.location.hash

So, to scroll to and open a hidden div in Prototype, try this

Event.observe(window, 'load', function() {
  if (window.location.hash) {
    try { $$(window.location.hash).first().show(); } catch(e) { }
  }
});

-> more