Thursday, March 10, 2011

100% - 30px: Mixed-unit calculation in Firefox 4

Firefox 4 (see release notes, or dev edition thereof) adds some pretty cool new features. I love the tab candy.

A fairly big one that almost slipped under my radar is that they shipped an initial implementation of CSS calc: "Support for -moz-calc has been added. This lets you specify  values as mathematical expressions." (see https://developer.mozilla.org/en/CSS/-moz-calc).

Support for calc is kind of a big deal as it allows you to do things that are annoying as hell to accomplish today. For example, perhaps you'd like to have three columns, left and right fixed width and center resized to fill available space:

[200px][100% - 400px, minimum 250px][200px]

The problematic bit is the middle column - it's actually fairly arcane to setup mixed unit calculations presently. calc makes it easy:
<!DOCTYPE html> 
<html>
 <head>
  <title>-moz-calc</title>
  <style type="text/css">
   body { margin: 0px }
   #container {
    min-width: 650px;
    width: 100%;
   }
   #left {
    width: 200px;
    background-color: #F0F0F0; 
    float: left;
   }
   #center {
    min-width: 250px;
    width: -moz-calc(100% - 400px);
    background-color: #A0A0A0;
    float: left; 
   }
   #right {
    width: 200px;
    background-color: #F0F0F0;
    float: left; 
   }
  </style>
 </head>
 <body>
  <div id="container">
   <div id="left">left!</div>
   <div id="center">center!!</div>
   <div id="right">righter!</div>
  </div> 
 </body>
</html>
This snippet produces fixed-width left and right columns with a center column whose width is dynamically calculated using a mixture (% and px) of length units. The container div is used to prevent the left/center/right divs from dropping to the next line if the browser is sized down far enough the min-width on the center kicks in (we don't want it infinitely narrow!). Images below show the result before/after resizing the browser window:


The ability to easily (the ease being the key here; it was possible to pull off similar results before but not easily) create page structures using mixed-unit calculated sizes is an AWESOME improvement. Now all we need is a full implementation in Firefox and the other browsers :) Oh and user adoption sufficient to justify use on significant sites.

Monday, March 7, 2011

C# using is the loan pattern in Scala

One of the remarkably handy little features of C# is the using statement (http://msdn.microsoft.com/en-us/library/yh598w02.aspx). I miss it so in Java! However, Scala will let me make my own, complete with some nice additions. Using relies on IDisposeable for cleanup; for example purposes we'll use Java's Closeable. Our goal is to be able to write code similar to:
...
using(new FileWriter(file)) { fw => fw append code }
...
Simple but pretty cool. Our FileWriter could be any Closeable. This code breaks down like this:
using is just a Scala function:
package com.active.scala.util

import java.io.Closeable

object Loans {
 def using[T <: Closeable, R](c: T)(action: T => R): R = {
  try {
   action(c)
  } finally {
   if (null != c) c.close
  }
 }
}
And again with some notes:
Note that we can return a value from the Scala using if we wish. This is a simple example of the loan pattern in Scala. We can apply this to any resource we would typically have to use in a try { ... } finally { cleanup my resource } structure in Java.

How jQuery.ready works

For some time I have been meaning to poke a little at how jQuery works. Line references and code samples are from the dev version of jQuery 1.5.1 - http://code.jquery.com/jquery-1.5.1.js.

First up, the ready function (http://api.jquery.com/ready/).
<!DOCTYPE html> 
<html>
 <head>
  <title>How the heck does jQuery work?</title>
  <script type="text/javascript" src="http://code.jquery.com/jquery-1.5.1.js" ></script>
  <script type="text/javascript">
   $(onStart); //short-hand for $(document).ready(onStart);
   
   function onStart($) {
    alert('hello');
   }
  </script> 
 </head>
 <body>
  
 </body>
</html>

The $(onStart) call requests that our function be run when the DOM is available; normally if we just called onStart here the DOM probably wouldn't be loaded and we thus be unable to do cool stuff like attach event handlers or manipulate our page here because none of the objects have been created yet. The stack at time of loading is very short: We are at the very bottom!

Somewhat later our onStart function will be run via callback from jQuery. Presumably jQuery runs the ready function(s) we submit in response to some event so it seems natural to wonder what the callstack looks like when our onStart function actually runs. It turns out we are called from a stack of jQuery functions, rooted on DOMContentLoaded():
The handler function for DOMContentLoaded is setup differently depending on what browser capabilities are available:

jQuery uses the presence of addEventListener as a signal that DOMContentLoaded event is available (line 1052 above). In the past it has been fairly normal to use addEventListener as a way to detect a Mozilla based browser (eg http://dean.edwards.name/weblog/2005/09/busted/). DOMContentLoaded is ideal for ready() as it fires after the DOM is loaded but before things like large images have necessarily downloaded (M$ demo of this: http://ie.microsoft.com/testdrive/HTML5/DOMContentLoaded/Default.html). The "load" event on the other hand may wait for resources to load. Unfortunately, IE8 and lower don't support addEventListener (or DOMContentLoaded) so the failover to attachEvent is required.

IE9 will support addEventListener (http://www.davidflanagan.com/2010/03/ie9-will-have-a.html) and DOMContentLoaded (http://blogs.msdn.com/b/ie/archive/2010/03/26/dom-level-3-events-support-in-ie9.aspx) ... Yay!

The code at line ~1050 (above) merely sets up a DOMContentLoaded function based on the capabilities that appear to be available; something still needs to actually call it. The callbacks are attached to events by bindReady, at line 429.

Multiple events are setup to callback (eg both DOMContentLoaded and load) to jQuery.ready to ensure that something actually runs it; exactly which ones are setup varies based on the browser capabilities available. Taking this type of nonsense away from most developers and having it "just work" across browsers is a large part of why jQuery is awesome - it takes FOREVER to figure out how to make this stuff work reliably.

When DOMContentLoaded ultimately fires it calls jQuery.ready. Ready does some work to try to confirm it's really time to run, double-checks the document is actually ready (line 407, again shielding us from browser weirdness), then executes the list of functions that have been listed to run on ready via resolveWith:

resolveWith does some gymnastics to try to avoid running repeatedly, then runs each of our callbacks:

That was kind of cool but it is sort of hard to understand merged into all the other jQuery code. Perhaps what is called for is to build our own :) Let us suppose we wanted our library to focus on running functions when something happened. We want usage to be something like this:
//SAMPLE USE OF OUR LIBRARY
when.DOMLoaded(onDomLoad);

function onDomLoad() {
 alert('hello');
}
For this to work we'll need to declare 'when' and expose DOMLoaded. Something basic should suffice:
//OUR LIBRARY
function When() {
 this.DOMLoaded = function(userFn) {
 }
}
var when = new When();
Spiffy! All we have to do now is implement it. Luckily jQuery already did so we can rip off much of the relevant part of their implementation (simplified somewhat to try to keep the example clear):
//OUR LIBRARY
function When() {
 var domLoadedHandlers = [];
 var handleReady = function() {
  while (domLoadedHandlers.length > 0) {
   domLoadedHandlers.shift()();
  }
 }
   
 // Mozilla, Opera and webkit nightlies currently support this event
 if ( document.addEventListener ) {
  // Use the handy event callback
  document.addEventListener( "DOMContentLoaded", handleReady, false );

  // A fallback to window.onload, that will always work
  window.addEventListener( "load", handleReady, false ); 
 } //else IE event model is used ... etc
    
   
 this.DOMLoaded = function(userFn) {
  domLoadedHandlers.push(userFn);
 }
}
var when = new When();

//SAMPLE USE OF OUR LIBRARY
when.DOMLoaded(onDomLoad);

The implementation above has plenty of limitations: It only works on some browsers, it doesn't handle submission of a ready function after the loaded event has fired, errors from a ready function abort all processing, and so on.

At this point we can start to really appreciate the hard work jQuery is doing for us. Even seemingly trivial scripts - do something when the page is ready - are fairly ugly, with excitingly frequent browser-specific corner cases and hacks (IE-specific ready detection with special casing based on whether or not we are in a frame...). To make matters worse, just when you think you have it all correct a new version of the browser comes out and muddles everything up again. Thank god for jQuery!