Autonomous Machine

Posts from 2008

List Ordering with a JavaScript State Machine

I've been thinking a lot about state machines recently- specifically, if the use of an event-driven state machine could be a useful pattern when creating JavaScript interfaces. I did a little poking around online, and the best resource I could find was a series of articles on IBM's developerWorks. The articles are actually quite good, and I'd recommend reading them. They include some nice background information on the hows and whys of state machine usage.

The one valid criticism I have of the articles is they spend a lot of time developing special code to deal with browser idiosyncrasies and event handling although the articles date from early 2007, well after the rise of JavaScript frameworks. I decided to see what I could to do build a lightweight state machine model using mostly framework code, in this case Prototype and Low Pro.

A Somewhat Contrived Example

Since I want to mostly show the syntax I'm using, here is a basic example for a simple widget: a web radio. Here are the states and transitions this example will be using:

State machine diagram for radio widget

States

Here are the states shown in that diagram, converted to JavaScript (I've stripped most of the functionality out for brevity, a link to the full code is below). I've stolen the idea of using functions as event handlers like this from the developerWorks articles. I like the flexibility it offers, and also that in order to transition to a new state, one of these functions simply needs to return the name of the new state. I've also added a shortcut- if a event handling function is only going to return a state name, that string can just be used in the definition in place of the function.

The state 'start' and its event 'init' are simply there so we can define a place for the machine to start.

Radio.definition = {
    start: {
        init: 'Stopped'
    },

    Stopped: {
        play: 'Playing'
    },
    
    Paused: {
        play: 'Playing',
        stop: function(event) {
            return 'Stopped';
        }
    },
    
    Playing: {
        enter: function() {
            // called when we enter this state
        },
        pause: 'Paused',
        stop: 'Stopped',
        exit: function() {
            // called when we leave this state
        }
    }
};

Events

The next thing to consider is how to map DOM events to the events defined above. I decided to define them for each state using a simple CSS selector to event name mapping. Just as with the state definitions, each CSS selector is either mapped to a string (this time an event name) or a function that will return an event name.

Radio.events = {
    Stopped: {
        'button.play:click': 'play'
    },
    Playing: {
        'button.stop:click': 'stop',
        'button.pause:click': function(event) {
            // ...
            return 'pause';
        }
    },
    Paused: {
        'button.stop:click': 'stop',
        'button.play:click': 'play'
    }
};

All Together Now

The state and event mapping definitions are brought together in a fairly standard Low Pro behavior, inheriting from another behavior containing the state machine logic. Any functions that are used as a part of the state and event definitions above are evaluated in the context of a behavior instance, so this is a convenient place for utility and helper functions.

Radio.machine = Behavior.create(State.behavior, {
    definition: Radio.definition,
    events: Radio.events,
    incrementCounter: function() {
        // ...
    },
    updateCounter: function() {
        // ...
    }
});

The complete behavior is applied using the standard Low Pro Event.addBehavior().

Event.addBehavior({
    'div.radio': Radio.machine
});

Here's a working example of the radio using the complete code.

Sort, Sort, Sort

Obviously, a state machine could be used to model a much more complicated interaction. A client application I'm working on had a need for some customizable sorting, and I decided to write the code from the ground up in order to have complete control over the sort lifecycle. After some thought, I decided to try to model the behavior of many desktop UI systems: a clone of the element being dragged would move with the mouse, and an insertion point would appear when and where a legal insertion could occur. I thought this was the best interface for most use cases as it allows the user to see both an object's new and old positions throughout the drag process. I also like the clear indication of when a valid drop can occur.

The states and events used by the ordering widget are shown in the following diagram:

State machine diagram for ordering widget

I won't paste all of the code to the sorter here, but I've posted it on GitHub as well as a working example. It worked out rather well, and I found the use of a state machine helped in keeping the code well organized and extensible, despite the fairly complicated interaction being modeled.

  • December 30, 2008
  • Article
  • JavaScript, Prototype

GIF, the PNG fallback

About a year ago I was working on the front end of one of those new fangled Web 2.0 websites, with pages full of curvy drop shadowed gradients. I stumbled into a fairly obvious technique for dealing with IE6's lack of proper PNG support- replace said PNGS with the closest possible GIF in my IE6-specific stylesheet. Yes, this means that the edges of some page elements aren't going to look as nice, but most of the time, it's close enough for such an old browser.

My typical CSS skeleton construction process is now:

  1. Semantic markup
  2. CSS and optimal background images (PNG if needed)
  3. IE Compatibility Check for layout
  4. IE Compatibility Check for PNG/GIF substitution

Step 4 is where I go through and replace any trouble PNGs with GIFs. I no longer use any of the various filter/IE specific PNG hacks; all of the ones I've tried don't work correctly with tiled background images, which something I end up needing frequently.

  • December 16, 2008
  • Article
  • CSS

Emulating :hover in IE6 with Prototype and Low Pro

A common technique for building UI items that respond to a hover, such as drop downs, is to write CSS rules that make a child UL appear when an enclosing element is moused over:

<ul>
    <li>
         <a href="/item1">Item 1</a>
         <ul>
                <li><a href="subitem1">Subitem1</a></li>
                <li><a href="subitem2">Subitem2</a></li>
                <li><a href="subitem3">Subitem3</a></li>
         </ul>
    </li>
    <li><a href="/item2">Item 2</a></li>
    <li><a href="/item3">Item 3</a></li>
</ul>
ul li ul {
  display: none;
}

ul li:hover ul {
  display: block;
}

Which works everywhere except under IE6. I've seen some posts on the web that suggest adding event listeners to the elements that need to detect hovering, and then having an event handler add a CSS class to the elements. Unfortunately, most of these posts recommend attaching listeners to the the mouseover and mouseout events, which is problematic if the elements have any children. When the child elements fire their own events, the result will be an annoying flicker.

One option is to add conditionals the event handler functions to make sure only the desired events are being responded to. But a simpler solution in this case is to use IE's non-standard mouseenter and mouseleave events. Here's an example in LowPro:

var ElementWithManualHover = Behavior.create({
    onmouseenter: function() {
        this.element.addClassName('hover');
    },
    onmouseleave: function() {
        this.element.removeClassName('hover');
    }
});

if (Prototype.Browser.IE6) {
    Event.addBehavior({
       'ul li': ElementWithManualHover 
    });
}

I'm using some extended browser detection to apply these behaviors only to IE6. You could do the same thing on your own in a few more lines of code.

This, of course, is only a good technique if you're already using Prototype. If you aren't, take a look at jQuery's hover.

  • November 24, 2008
  • Article
  • JavaScript, Prototype

Fitzgerald: a Sinatra clone in PHP

Two weeks ago I had a tiny client website that suddenly needed a login section to provide some downloads to approved users. Initially I reached for Sinatra, which I have grown to love in recent months, but sadly the client's server had no opportunity to run Ruby. A sad day for sure, but the world moves on and I decided to revisit my old friend PHP and see what could be done.

I spent about ten minutes looking through various PHP frameworks, but quickly decided that it would be faster to write the code the tiny site would need than learn the ins and outs of a full framework. I wanted something tiny anyway (preferably a single file), and most of what I found online were various fully fledged MVC Rails clones. Not going to work.

I knew I wanted a solution that would get me as close to possible to Sinatra's syntax, while making the best of the confines of PHP. Here's the final syntax I came up with:

<?php
    include('lib/fitzgerald.php');
    
    class Application extends Fitzgerald {
        
        // Basic get request
        public function get_index() {
            return $this->render('index');
        }
    }
    
    $app = new Application();
    
    $app->get('/', 'get_index');
    
    $app->run();
?>

The basic concept is to subclass Fitzgerald with controller methods, and then map them to urls using get() and post() calls on an instantiated application object.

I added some Merb-style argument passing to the mix using PHP5's Reflection API:

<?php
    include('lib/fitzgerald.php');
    
    class Application extends Fitzgerald {
        
        // $page will be one of 'about', 'contact', or 'faq' thanks to our URL mapping below
        public function get_page($page) {
            return $this->render($page);
        }
    }
    
    $app = new Application();

    // :page is a placeholder- it will match anything by default, or a regex to match can
    // be passed in using an optional third argument to get() or post()
    $app->get('/:page', 'get_page', array('page' => 'about|contact|faq'));
    
    $app->run();
?>

Like Sinatra, the return value of a method is what is returned to the browser. Fitzgerald has built in methods to render a template or redirect the browser:

<?php
    class Application extends Fitzgerald {
        
        // Renders a php file in '../views/', making variables provided to compact
        // available as local variables in the template
        public function get_page($page) {
            $var1 = 'Value to use in template';
            $var2 = 'Another value to use in template';
            return $this->render($page, compact('var1', 'var2'));
        }

        // You can also send redirect headers
        public function get_redirect {
            return $this->redirect('/url/to/redirect/to');
        }
    }
?>

You can also specify a layout with an options array passed to the application initialization:

<?php
  // This will capture the output of any render calls into a local variable $content,
  // and then render the layout provided here
  $app = new ApplicationWithLogin(array('layout' => 'shell'));
?>

And that's Fitzgerald. There is a more advanced example that shows how to build a simple authentication system in the repo on Github- look at example.php.

  • November 21, 2008
  • Article
  • PHP

Steer WebDriver from Ruby with Backseat

I've been wanting to try out WebDriver for a while now, and this week I finally had a day to devote to kicking its tires. So far, I like pretty much everything about it. Oh, except that right now you have to write your tests in Java.

Backseat is a little Ruby library that uses Rjb to wrap the WebDriver classes in a nice interface. My goal is to integrate with Rspec eventually, but for now, only the basics work.

Here's an example (you can see the original Java source at the WebDriver site):

require 'backseat'
include Backseat

Backseat.load!('/Users/jimb/src/webdriver/trunk') # path to webdriver root

driver = Backseat::Driver.new(:firefox)

driver.get('http://www.google.com/webhp?complete=1&hl=en')

element = driver.find_element input(:name => 'q')
element.send_keys('Cheese')

wait :until => lambda { driver.has_child?(table(:class => 'gac_m')) &&
                        driver.find_element(table(:class => 'gac_m')).displayed? }

driver.find_elements(td(:class=> 'gac_c')).each do |e|
  puts e.text
end

driver.close # quit Firefox

For the most part, I've stuck to the original WebDriver API, but there are a few differences. One is the usage of a set of helpers for building XPath locators (used as arguments to find_element above), and the wait method which sure beats the way it was done in Java. There will be API changes going forward as I start using this for some real testing.

I have, of course, set up a repo at Github.

  • October 17, 2008
  • Article
  • Ruby