And Again! (ComboBox)

Based on some user feedback and some more of my own use, I've made a
couple more little tweaks to the script.  In a nutshell, orm
submission blocking now works in a far less intrusive way, hitting TAB
will select the active item before changing focus, and ESCAPE will
close the dropdown if it's open.

I've also been looking for a javadocesque
tool for generating documentation from JavaScript files.  The only
one I found was NaturalDocs, which is similar to javadoc, but uses a
different syntax.  Anyone know of anything that uses standard
javadoc sytax?

ComboBox Update

Yeah, I know it's only been a few hours, but after implementing a few different instances, I quickly decided that async processing was basically required for a performant UI. Your callback function no longer has to return an array of items (it still can, of course), but now it will be passed a second argument, which is a reference to the ComboBox object itself. There is a new setItems method on the object, which simply takes an array of items and rerenders the dropdown with them.

This makes using asynchronous JS remoting very easy to use for popuplating the dropdown with a simple closure (leveraging the Neuromancer JS remoting libraries):

function nameCallback(name, cb) {
  getGateway(true).doGetRequest(
    pathToFacade + "getNames&name=" + name,
    function(s) {
      var result;
      if (s == "")
        result = new Array();
      else
        result = s.split("|");
      cb.setItems(result);
    }
  );
}

I also added a config framework for functional flexibility, and used it to implement multi-item processing. So instead of only being able to enter a single item, you can configure the widget to allow multiple items, and as you enter each one, it will give you completion options for just that single item. I used it for tagging objects in a CMS, where I needed to assign multiple tags to an object, but also be able to create new tags on the fly. So I just type them all in, using completion for the existing tags, and then the backend sorts out what it needs to create before assigning.

The demo, downloads, and project page are still available in their original locations, just they now have updated code.

DHTML ComboBox Widget

With the wife and kid out of town, I didn't have much to do, so I spent the afternoon building a simple DHTML combobox widget. Yes, I'm that much of a geek. I haven't done a lot of testing, but I built it exclusively in FireFox, aiming for compatibility, and IE6 behaved exactly as expected on the first try, so I'm hoping other browsers will behave as well.

It's available for download at widgets.zip, a demo is available at /web/widgets/ (try entering the letter 'a'), and there is a project page as well. The demo is included in the zip file as well.

The architecture will likely seem a bit odd at first, but it's built the way it is for good reason. In a nutshell, you put an INPUT in your document, and pass it's ID and a callback function to the ComboBox constructor, and the rest happens by magic. You'll notice that you don't pass in any options, but that's where the callback function comes in. That function will be called any time the value entered in the field changes and the field has focus, and will be passed the current value. It's responsibility is to return an array of strings that should be displayed.

The demo just uses a simple array of names for the values, but I set it up in the seemingly overflexible way specifically to allow for JS remoting calls to be used for generating the dropdown list. Currently, you only get synchronous processing (since the callback has to return the values), but I might add async capabilities (so your can pass in an array of options at any time).

As always, download and run with it, and give me any feedback you have along the way.

TreeManager CFC Released

I put together this component a while back, intending to eventually
release it, and it's now time.  Basically it manages a tree of
records in a databas table using the nested set model.  It acts
independantly of your existing persistance operations, and only
requires the addition of two fields to your table for it's use. 
You continue to manage your rows as you do right now, completely
ignoring the two extra fields, and then when you need to do tree-based
operations, you call the tree manager, and it takes care of all the
wizardry.

Included
in the zip (link below) is a very simple
application that creates a table, populates it with a bunch of data,
and then uses the tree manager to create a hierarchy out of the
records.  It doesn't really illustrate any of the action methods
in the component, but I wanted to get it out while I was on a role, and
didn't figure I'd ever finish if I tried to write a complete
example.  However, complete documentation is included, and the CFC
itself is fully commented.

So enough boring chit-chat, here's the code: 

http://www.barneyb.com/web/static/treemanager.zip

I've
only tested it on CFMX 6.1 and MySQL 4.1.  I know it won't work on
database other than MySQL 4.1 and higher (because there are a few LIMIT
clauses), but porting it to other DBs should be relatively
trivial.  I don't have access to anything else, so I can't do it,
but if you feel so inclined, please send me a patch so that I can
integrate it into the distributed version.  And you needn't
understand the nested set model to hack the SQL, most of the queries
are pretty simple, it's just the amalgamation of operations that does
the magic.

There is no license, so do what you will, though I'd
appreciate credit of some sort if that's appropriate for your
application. 

More J2EE Goodness

I recently needed to capture output for a page to email, as well as
actually output it to the page.  No big deal with CFSAVECONTENT,
of course, but there was one little glitch: occasionally, the core code
needed to use CFFLUSH, and in those cases, the email wasn't needed,
just the screen output.  Rather than screw around with separate
page rendering mechanisms for the two different approaches, a quick
look at the JSP spec yielded this little gem:

getPageContext().getOut().getString()

This returns the contents of the current buffer.  Note that
it's context sensitive (i.e. if you call it within a tag, it'll return
the contents of the buffer for the tag's body), and there's the
potential for the getString method not to exist, since
it's defined in the BodyContent subclass of JspWriter (what getOut actually returns) that is
used for tag-body buffers.  However, CFMX 6.1 seems to treat the
top-level page as a tag body, so it seems safe to use.

So to
solve my problem, I render my page just as normal, and then if an email
is needed, use that mechanism to pull the contents of the buffer and
send it off. 

The MySpace.com Cowboys

I've been at CFUNITED all week, and based
on the amount of blog coverage that's occurred without my help, I
didn't feel compelled to post.  However, the day three New Atlanta
/ MySpace.com keynote was an amazing talk that couldn't go without my
opinions being expressed to the world.

First, some background.  MySpace.com is a huge
CFML site that has recently moved from CF5 to BlueDragon.NET. 
They seem to be the centerpoint of New Atlanta's marketing efforts, at
least for the CFUNITED crowd. 
They get about a bazillion hits a day, and have had lots of problems
scaling their infrastructure and codebase over the crazy growth curve
they're on.

However, after listening to one of the
Directors of Something Techical speak at the keynote, it's not hard to
see why they have this problem.  He said several times that they
often push code two, three, four times a day.  They don't have
separate development, staging, QA, and production server
infrastructures.  They don't scale their server architecture, they
just increase it's size (which sounds similar, but is quite different).

One of the specific problems he
mentioned was unsufficient throughput of their database drivers on CF,
specifically that the database servers couldn't handle more than X
connections, and that if you have Y server, you're necessarily limiting
each server to X / Y connetions.  With a huge web farm, that might
mean X / Y is only 5 or so connections, which greatly cripples the
throughput of the web server.  So how do they solve it?  Not
build a more scalable database infrastructure that can handle more
connections (something that I understand MS SQL Server can do easily
with replication and distributed servers, though I've never actually
done it).  They switch to ADO.NET native drivers, rather than the
JDBC drivers that CF uses.

I don't want to rail MySpace.com too much, but I couldn't pass up the chance to share my amazement such that a huge
site does things in such a ridiculous way, and then complains when they
have problems, and looks for a solution to the symptoms, rather than a
solution to the problems.  The moral of the story, of course, is
that your infrastructure (both server, and development processes) is vitally
important.  And unfortunately, that kind of cowboy attitude
reflects rather poorly on New Atlanta, since they seem to consider
MySpace.com to be such a core part of their marketing efforts.

And
to round out some context, I originally had no intention of going to
the keynote, because I figured it'd be an hour of New Atlanta doing
MS's marketing for them.  However, I was pleasantly surprised to
see a truly legit case study from a real client, solving real-world
problems, and it wasn't overtly sales-pitchy.

Couple MT Changes

I installed MT-Blacklist,
a comment and trackback spam filter a couple weeks ago.  Man does
it do it's job well.  Took a little training to get it catching
all the usual suspects, but just in the past few days it's caught over
a thousand spam comments.  So much nicer than having to delete
them manually.

Last night, I also installed MT-Notifier,
which is a plugin to allow you to subscribe to an entry's
comments.  I'd been wanting to do that for a while, but since I'm
still running MT 2.6x (the free version), I had some troubles finding
an older version to install.  Much thanks to Chad (the author) for
helping out on that quest.  So far it seems to be a very nice
little plugin. 

Fink for Tiger

Last night I finally got Fink
installed on my newly Tiger-ed PowerBook.  Opted for the binary
install this time, and it worked like a charm.  Less than 40
minutes to go from noticing that a 10.4-specific release had been made
to having it all set up with X, Gnucash, the GImP, and the GNU
FileUtils package (for the color-aware ls command) all installed.

Naming CFC Instance Variables

I was working on a little app of mine over the weekend that uses a
closed-source (encrypted) CFC for some of it's functionality.  The
CFC (which will go unnamed to protect the innocent), does a number of
things, but it's functionality wasn't quite "complete" enough for my
application, so I extended it to add a couple more features.  No
problem, until I started having this really weird error about an
invalid method return type for a private method that I didn't even know
existed.

After a quick dump of the 'variables' scope, I
discovered the problem was nothing more than a variable
collision.  One of the instance variable from the encrypted CFC
happened to be the same as what I wanted to call one of the methods I
was adding.  Needless to say, I was a little bothered by this; now
my method wouldn't be able to conform to same naming conventions as the
rest of the CFC's methods.  However, being the [relatively] mature
adult that I am, I quickly got over it, did a quick search and replace, and went on with my business.

The reason I'm writing is that I want to restate the point that you should never put anything
directly into the 'variables' scope in a CFC except public data fields
that are clearly documented with CFPROPERTY.  Instance variables
should always go into a substruct (I prefer 'my', but 'instance' seems
to be a more common name), both to keep them nicely packaged, and to
avoid this kind of variable collision.  This is particularly
important if you're going to be distributing your CFCs for other
developers to use and possibly extend.

Another CFML w/ Java Trick

I just wrote a script that would check for orphaned files in an
uploads directory.  Orphan meaning the file still exists, but the
database doesn't have record of it.  Those files needed to either
be reclaimed or deleted, but finding them is cumbersome (and slow!)
process.

What I discovered is that CFDIRECTORY ACTION="list" is really slow if you just need a list of filenames without any of the extra metadata.  Using the list() method of the java.io.File
class turned out to be more than a order of magnitude faster.  The
one caveat is that you can't do a filter without writing some Java (an
implementation of java.io.FileFilter or java.io.FilenameFilter).  But for the performance gain, it's hard to beat.

Here's the CFML code:

<cfdirectory action="list" directory="#LOCAL_DIRECTORY#" name="files" />

And here's the Java code:

<cfset fileList = createObject("java", "java.util.Arrays").asList(
createObject("java", "java.io.File").init(LOCAL_DIRECTORY).list()
) />

With the Java, you get an instance of java.util.List, which can be treated just like a normal CF array.