|
![]() |
Revenge of CookbooXULNOTE: None of this code is available. It was stolen by Ninjas. Sorry. I did a very simple little Ruby On Rails application a while back using the XPFE (Cross Platform Front End). For those people out there with TLA overload the XPFE is what Firefox, Thunderbird, Mozilla and many other products sits upon. It has the XUL (XML UI Language) as well as many other components which make doing clients so rich they make Bill Gates look like a Calcutta leper. To most people this is a “XUL Application” since they don’t realize the full extent of the XPFE platform. This is a lot like saying that you wrote a “Ruby Application” when really you used Ruby On Rails and lots of other libraries. The original CookbooXUL was nothing more than a XUL face put onto Curt Hibbs’ article Rolling With Ruby On Rails a while back. It didn’t do very many fancy things but did demonstrate that you can easily do a XUL interface with Rails. This new version of CookbooXUL is significantly different. First off it is still a Rails application, but the Rails part is very thin—really nothing more than a REST backend if that. The remaining functionality for the application is all held on the client side. Don’t worry though, there’s nothing required besides an XPFE/Gecko based browser such as Firefox, Mozilla, or Epiphany. Just load your browser and check the application out. One of the main detractors that you get from people who rant on Rails applications is
that- On the client side I’ve implemented a small JavaScript Finite State Machine (FSM) library which really makes writing asynchronous interactive applications a snap. I’m still refining the application, but I threw in enough demo code that it should get people interested in the technique. Now With Fresh Odeum FlavorThe main backend feature of CookbooXUL is its use of Ruby/Odeum to search through 10,000+ recipes in RecipeML format. This provides fast as hell access to the entire catalog and demonstrates an application that isn’t really a CRUD application. If you wanted to do the same kind of searching within a CRUD application you would have to troll through tons of records and compare all the fields. It would take forever, and there wouldn’t be any relevance ratings included. In the Java and Python world there is Lucene for full-text indexing. Lucene is a great library and does nearly the same things as Ruby/Odeum but is more mature right now. One of the things Lucene does not do is support Ruby so for now Ruby/Odeum is the only game in town. If you were to use Lucene you could easily do this application in a simple little Java servlet. Again, the point isn’t to say that Java or other languages couldn’t do an application like this, but rather to demonstrate that a Rails application does not have to be “just another CRUD application.” Other FeaturesThere’s lots of other weird features that came out from me trying out new ideas and playing with the frontend code. The main features you should check out are:
Checking Out The AppBefore you get into how the application is built you should go and play with it. I have a temporary setup running which you can play with. If you want to check out a screenshot of the application then try this one as an example. If you want to get the code then you can download the source and extract it. You’ll then need to do the following:
That should get you started no problem, but let me know if you have issues. The main thing is getting the files indexed, and making sure they are in the public/xml directory. The other key point is to get rid of any files with # in the name. ArchitectureCookbooXUL is kind of an experiment in pushing all of the logic out to the client and keeping the backend as simple as possible without losing features. One major disadvantage of doing fatter clients is that you have to struggle with deploying them to clients and doing a controlled roll-out. This is a huge pain in the ass and is the major driving force behind HTML only interfaces. With XUL and XPFE you can do a completely “thick client” application that uses a ridiculously simple backend to get the data it needs, but still get the deployment heaven of an HTML application. In many cases it isn’t necessary to use a XUL application since HTML user interfaces these days can handle most situations just fine. A XUL interface with a fat XPFE based client though has a lot of advantages including a wider range of client side technologies available, and an application that looks like it’s a desktop application. For CookbooXUL I went with all of the logic sitting on the client in the web browser, and then had the backend provide all of the services needed. These services simply return XML results which are converted into UI elements and alter the client’s interaction. It turns out that this was pretty darn simple, and I even wrote a full framework to support the application at the same time. Rails BackgroundYou should have a Rails understanding before you dive into this little article. I’m not going to go over Rails at all, but take a look at the recipes_controller.rb file for the code. It’s pretty simple and completely documented. There are three things you should realize about the controller which are specific to XUL interfaces, and particular to the FSM Framework:
Once you get this and how the Ruby/Odeum library is being used then you should be ready to get into the actual CookbooXUL code. The Frontend ClientThe CookbooXUL consists of a simplified Rails backend and a much fatter frontend client that uses XUL, JavaScript, XmlHttpRequest, and XSLT to create the UI. As I wrote the CookbooXUL interface I also wrote a small framework that simplifies creating an FSM based logic controller that handles asynchronous events from the user and the server at the same time. The framework simplifies doing a lot of things, but you’re probably better off reading the documentation and playing with the functions. Here’s a quick list of what it does:
The framework doesn’t deal with fancy stuff like faders, drag-n-drop, or other stuff. It’s purpose is to make it easier to hook the logic of the client into the backend and make the interactions consistent. It wouldn’t be hard at all to use another framework, but you might run into function clashes since I made many of the functions first level for convenience. Finally, the framework isn’t cross browser. I only care about doing XUL applications with it, so that’s all I worked on. If you want IE you should look at some of the Ajax libraries out there as they have much better support for this stuff under that platform. The Client FSMIf you take a look at the recipes.js file you can see the FSM
definition right at the top. All you need to use the FSM framework is to specify
the states, events, and the code to run for each. The states are implemented as
a hash map that is passed into the Here’s an example from the recipes.js file:
start: {
INIT: function(fsm, data) {
find("query").focus()
fsm.request('/recipe-transform.xml', 'processing', 'READY')
fsm.logShowing = false // keep this around for the log toggle
}
},
In this code we’re saying the following:
That’s basically how the entire system works. You create a collection of states and events, and then use either XUL tag handlers (onload, oncommand, onclick, etc.) or asynchronous request/response calls to transition the FSM and handle events. Other Important StatesYou should also review these other state:EVENT functions as they have interesting functionality in them:
You should be able to figure out how the rest of the FSM works from this. The main thing is to play with it then use the ’?’ button to look at the log. I’ve setup a bunch of the event handlers at the end to log transitions and unknown states/events so you can see what’s going on. Supporting CodeAfter the FSM you’ll find a bit of supporting code. This code is typical JavaScript that is used to turn buttons on, disable them, alter DOM objects, etc. After this code are a set of handlers that I’ve setup for which log various events. Normally you wouldn’t put code like this in production, it’s just there for demonstration. You should also take a look at the app.js file to see the rest of the available functions. There’s a lot of handy stuff, but not much of it is required. If you prefer to torture yourself with the DOM API then you can skip the simplifying functions I’ve got. Using The FSM FrameworkTo actually use the app.js code you need to of course include it prior to your own FSM definition. Otherwise you won’t have any of these functions. You may use the FSM Framework under the LGPL license for now. Nothing too formal, just please send me back any bug fixes or enhancements you may have done. I’m interested in doing a small chat client with this so if someone wants to beat me to it then let me know. Driving Home Drunk With A 6’8” TransvestiteI wanted to include a small blurb about my thoughts on this little XUL experiment. These are totally my opinion, so take them as you want. One thing I found about XUL applications is that they are stuck between being “web apps” and being “desktop apps”. I realized this when someone commented, “The text in your lower panel is too wide for my 1600×1200 pixel screen.” Turns out he had his browser completely maximized and it just didn’t dawn on him that he should probably try shrinking the window down before he used the application. For whatever reason, he thought that since the application is in a web browser it should try to defend against all possible window-maximize-stupidity and give him a nice printed page layout. But it’s more like a desktop app and is meant to be used in a thin configuration, which is hard and annoying to control since it’s a web browser really. Damn. Now, imagine this same fellow has accidentally maximized the tools panel in his Adobe™ Photoshop™ application. He’d see it was huge and ugly, realize this isn’t normal, and then shrink it down. He wouldn’t complain about the ugly typography of the menus, the weird striped background of his OSX panels, or the strange window organizations. He’d just deal with it and move on since he’s using the application to get something done. Desktop applications are held to different standards of usage and appearance than web applications. I’m not sure why. People will use ugly ass Vim or Emacs and not shed a single tear, but show them anything other than a Zen Garden layout on a web site and they instantly are experts on how much your site sucks. I see now that XUL has a distinct disadvantage as people don’t know whether to think of it as a desktop application or a web application. It looks like a desktop application. It feels like a desktop application. But wait, it sizes like a web application. Oh, and look it has web browser controls on top. It’s like people are checking out CookbooXUL’s ass, roaming their eyes over its nice rack, then bam! They see facial hair and an adam’s apple. They suddenly become confused and don’t know how to evaluate it. “Oh no, am I using a web application? Does that make me gay? Holy crap, this thing is suddenly ugly for a web application. I mean sure, it’s got a sexy simple fast as hell body, but damn that’s one ugly mug. Could I switch over? What’s the point really? I’ll just stick to HTML I guess.” Oh well, it was fun. |