Archive for the 'javascript' Category

Checkbox Range Selection Update

Just a little update to my checkbox range selection jQuery plugin to allow chaining.  I'd forgotten to return 'this' at the end of the function.  Here's the full source, including the mod:

(function($) {
  $.fn.enableCheckboxRangeSelection = function() {
    var lastCheckbox = null;
    var $spec = this;
    $spec.bind("click", function(e) {
      if (lastCheckbox != null && e.shiftKey) {
        $spec.slice(
          Math.min($spec.index(lastCheckbox), $spec.index(e.target)),
          Math.max($spec.index(lastCheckbox), $spec.index(e.target)) + 1
        ).attr({checked: e.target.checked ? "checked" : ""});
      }
      lastCheckbox = e.target;
    });
    return $spec;
  };
})(jQuery);

You can check the project page as well, for full history and updates.

Prototype's Array.any/all with jQuery

I needed to convert a couple Array.any() and Array.all() calls (from Prototype) to jQuery syntax. Since jQuery doesn't extend the built-in objects with nice functionality like this, you have to fake it. Here's what I came up with. Old version ('images' is an array):

images.all(function(o){return o.status == "ready";})

and the new version:

jQuery.inArray(false,
  jQuery.map(images, function(o){return o.status == "ready";})
) < 0

Array.any()'s equivalent is the reverse:

jQuery.inArray(true,
  jQuery.map(images, function(o){return o.status == "ready";})
) >= 0

Might have to rip the Enumerable and Array extensions out of Prototype for standalone use as well.

Prototype and jQuery

Since I discovered it a few years ago, I've been a big Prototype fan.  It's simple, and gets the job done with a minimum of fuss.  It's not without warts, of course.  I still occasionally forget to put 'new' in front of Ajax.Request, and some of the Ruby-like methods share their lineage's arcane naming.  When it was new, it was the best thing around, and while it now has competitors, it's certainly not lagging behind.

At work, however, jQuery has been adopted as the standard (and I've no power to change it).  The lack of the $() function is annoying; several times I've debated adding this function (or one of various similar ones) to our library:

function $(id) {
  return jQuery("#" + id)[0];
}

I haven't, of course, as it's not the jQuery way.  jQuery also lacks any sort of class assistance, so we still use the Prototype class framework for our class-based JS.  That seems to work fairly well, except for the fact that we have to use two frameworks where one could suffice.

jQuery is not without it's benefits, of course.  The plugin architecture is a nice aspect that Prototype didn't really offer an equivalent of.  It means the core stays lighter (good), but if you want additional functionality you're stuck managing files from a bunch of different projects (annoying).  Event handling is a bit more straightforward, in some ways.  "Magically" acting on collections of elements with a single call (i.e. no .each(function(o){…}) garbage) definitely makes for more readable code as well.

Because of this shift at work, I've been porting some of my personal apps over to jQuery as well.  I've actually been using a couple jQuery plugins (both self-written and external) for specific tasks for a while now, but not the core framework.  What I've found, however, is that jQuery can be prone to slow code.  To avoid a huge amount of extra work on the part of the JS interpreter, using temporary variables for jQuery objects is essential.  If you do strictly id-based queries, the degradation isn't huge, but if you do CSS-based queries, it can be significant.  With Prototype's focus on id-based queries (at least until $$() came about in 1.5), that was less of an issue.

This need to query a minimum number of times can provide a fair amount of complexity when you have more than a handful of closures hanging about and/or a dynamic DOM.  You end up doing a lot of state management work because you're, in effect, caching DOM lookups and have to ensure you never have stale cache.

Other than that issue and the lack of an equivalent to document.viewport, porting has been relatively painless.  Still very id heavy, so not leveraging jQuery as much as could be, but most of what I'm doing wouldn't benefit from other selectors.

Which one is better?  Hard to say.  jQuery seems to make you work harder to type less code, while Prototype seems to cost you a few more characters for a bit less density.  With the exception of Prototype's class support, their feature sets are fairly equivalent, especially with jQuery UI now available to "compete" with Scriptaculous.  For the moment, I'm choosing to use jQuery on new stuff, but wishing for Prototype every few minutes.  Until I come up against some sort of significant wall, it'll probably stay that way, just to stick with the same tooling professionally and personally.  And over time it'll probably get better as the Prototype-ness fades from apps.

Ajaxian on Prototype vs JQuery

Ajaxian posted a little blurb on benchmarking Prototype and jQuery today. I've been a Prototype guy for years, but at the office we've gone from all-Prototype to all-jQuery, and performance degredation was one of the things I noticed. I never did any actual benchmarking, just went by feel, but it's interesting to see that my perceptions were well founded.

Whether performance of JS libraries should be a huge determinant in picking one to use is up for grabs. Unless the client-side is doing a hell of a lot of work, these days' computers have plenty of CPU hanging about unused.  However, in the past couple months we've spent a lot of time working around JS performance issues at the office. I can't say that using Prototype instead of jQuery would have eliminated the bottlenecks, but clearly performance matters.

Checkbox Range Selection (a la GMail)

If any of you use GMail, you'll know that you can shift click the checkboxes on the conversation list to select a range of conversations (i.e. click the second conversation's checkbox and then shift-click the tenth conversation's checkbox). You can also deselect the same way (click the seventh, and then shift-click the fourth). Finally, you can shift-click a second time (third click total) to extend the range. I wanted that functionality in one of my apps, and here it is.

Update: I've repackaged the code as a jQuery plugin based on Dan Switzer's suggestion. I've left the original code in place, just struck it out.

function configureCheckboxesForRangeSelection(spec) {
  var lastCheckbox = null;
  jQuery(function($) { // for Prototype protection
    var $spec = $(spec);
    $spec.bind("click", function(e) {
      if (lastCheckbox != null && e.shiftKey) {
        $spec.slice(
          Math.min($spec.index(lastCheckbox), $spec.index(e.target)),
          Math.max($spec.index(lastCheckbox), $spec.index(e.target)) + 1
        ).attr({checked: e.target.checked ? "checked" : ""});
      }
      lastCheckbox = e.target;
    });
  }); // for Prototype protection
};

(function($) {
  $.fn.enableCheckboxRangeSelection = function() {
    var lastCheckbox = null;
    var $spec = this;
    $spec.bind("click", function(e) {
      if (lastCheckbox != null && e.shiftKey) {
        $spec.slice(
          Math.min($spec.index(lastCheckbox), $spec.index(e.target)),
          Math.max($spec.index(lastCheckbox), $spec.index(e.target)) + 1
        ).attr({checked: e.target.checked ? "checked" : ""});
      }
      lastCheckbox = e.target;
    });
  };
})(jQuery);

It requires jQuery to be available (I used 1.2.1 and 1.2.3), and is safe to use with Prototype also in-scope (regardless of which owns the $ function). Call that function passing in a jQuery expression (NOT a jQuery object) that describes the checkboxes you want to be range-selectable:

configureCheckboxesForRangeSelection("input.image-checkbox");
$("input.image-checkbox").enableCheckboxRangeSelection();

Thanks to Matt Wood (a coworker) for the slice/index suggestion. My initial implementation had used an each with a conditional and a status variable - definitely less elegant.  Check the project page for any additional updates.

E4X and Prototype Goodness

I got around to trying the E4X-based query structure this morning, and it works like a charm.  It's now possible to write your queries like this:

Query.execute(
  <query>
    update contact set
      name = :name,
      email = :email
    where id = :id
  </query>,
  {
    id: new QueryParam(id, "integer"),
    name: new QueryParam(name),
    email: new QueryParam(email)
  }
);

There's still an extra layer in there (i.e. the Query type and the <query> element), but the SQL is far more cleanly differentiated from the javascript, which is a big plus.  I've updated the core and sample application in Subversion with the changes to allow this syntax (the string-based syntax is still supported), along with various other little changes, including a full import of the browser-agnostic portions of Prototype (Object, Array, Hash, String, Template, etc.).

I also tried the "add the execute method to the XML class" route that I wrote about, and that doesn't work.  It seems that the E4X class (XML, XMLList, etc.) are sealed and can't have additional stuff added to them.  That's a bummer, but such is life.

More Thoughts on Server-Side JS

I got a lot of great comments (along with some not-so-great ones) regarding my server-side JS implementation. As expected, quite a few people were very excited about using AS3 on the server instead of JS, and I agree. It got me thinking about how much code reuse you could get within an application. At the very least, you can share libraries, which is handy. But you can also very likely share VO's, and quite possibly entity objects as well. If you're using AIR, and you're building your server-side in the appropriate ECMAScript, then you could theoretically port your server-side to the client side for use in standalone mode (i.e. persisting to SQLite), and then the "occasionally connected client" model becomes nothing more than two databases that you have to sync. No need to implement everything twice, because you're using the same technology in both tiers.

One big gripe (which I share) with script notation is the lack of tag bodies. CFQUERY and CFMAIL are wonderfully simple to use because their main textual parameter is just the tag's body. Having to synthesize that with string literals as you do in script is cumbersome to say the least. What I realized tonight, however, is that E4X (or ECMAScript for XML) isn't actually tied to ECMAScript 4, it's standalone, so it can be used with ECMAScript 3 implementations (such as Rhino). And that means that you can actually embed XML snippets directly in your code. I haven't tested it (had to work on other stuff this evening), but you should be able to take what I've got today for querying:

var get = new Query("select * from user where email is not null", "mydsn").execute();

and replace it with something like this:

var get = new Query(<query datasource="mydsn"><![CDATA[
select *
from user
where email is not null
]]></query>).execute();

While it's not quite as clean as the CFML version, it's a big step towards it. Better yet, Rhino supports E4X today, so this should work immediately. Not sure about WebKit (AIR's HTML/JS implementation), though a quick Googling indicates that as of this time last year there was nothing available, nor anything in the works. If only they'd used Gecko, which has supported it for a while. Now that I think about it, depending on the E4X implementation, it's entirely possible that you might be able to do this:

var get = <query datasource="mydsn"><![CDATA[
select *
from user
where email is not null
]]></query>.execute();

Doing that would depend on being able to extend the core E4X classes in the style of Prototype's extensions to Object and Array. Just throw an execute method on there that checks the root node of the doc it's called on as a selector for the desired action, and than hands off processing to the right subsystem, and you're done.

So much cool stuff…

Why JavaScript (or really, ECMAScript)?

After my last post on CF and JS integration (via Rhino), I got several comments that can be summarized as "why?". I addressed the issue in a rather oblique manner in my last post; here's a more full treatment.

Before I start, I want to make incredibly clear that I'm not talking about a new JS-based application server built on Rhino. I'm talking about using JS as an alternate/supplemental syntax for your CFML applications, which still run on the ColdFusion application server, with all the niceties that the CF server provides.

The first reason is that CFML is incredibly verbose for a lot of common tasks. Consider a function definition in CFML:

<cffunction name="doIt" output="false">
  <cfargument name="param1" />
  <cfargument name="param2" />
</cffunction>

Now the same definition in JS:

function doIt(param1, param2) {
}

The CFML is a lot more verbose, which is both more typing, and more characters to visually parse when you're trying to read the code. Of course, this isn't without downsides. Consider running a parameterized query in CFML:

<cfquery datasource="myDsn" name="get">
  select *
  from my_table
  where id = <cfqueryparam cfsqltype="cf_sql_integer" value="#id#" />
</cfquery>

And now in JS:

var q = new Query("myDsn", "select * from my_table where id = :id");
var get = q.execute({
  id: new QueryParam(id, "integer")
});

The CFML implementation definitely highlights the SQL as a standalone language embedded within the markup, while with the JS implementation, the SQL is just a string; there's nothing SQL-y about it. Is the more concise nature of the JS worth it in this specific case? I'd say it's close to a wash: less SQL delineation, but more concise code, more easily reusable SQL, semantically relevant (instead of positionally anchored) parameters, and reusable parameters. Note that in either case, I'm running my parameterized SQL against a datasource configured in the CF Administrator, and the 'get' variable will be a native CF query object (a 'coldfusion.sql.Table' instance).

Now where I really think JS (really ECMAScript, in general) has a lot to offer over CFML is in the language constructs itself. Nested functions, function literals (and their extension: closures) are a singularly fantastic language constructs. Rather than show a single example implemented in both CFML and JS, I'm going to just illustrate the concepts in JS, and contrast them with CFML. Nesting first:

function doSomething(param) {
  function f(o) {
    // do something ...
  }
  var result = f(param);
  for (var i in result) {
    if (typeof i == "object") {
      result[i] = f(result[i]);
    }
  }
}

So what's happening? I'm packaging up some reusable functionality into a function (named 'f'), but it's an implementation detail of the 'doSomething' function, and is therefore internal to the 'doSomething' function. Do do this same sort of "subpackaging" of functionality in CFML, you'd have to put the 'f' function outside as a peer of the 'doSomething' function (probably named 'doSomething_f' or whatever). That's a leak in encapsulation, as well as unnecessarily crowding the external namespace.

Function literals implicitly require function variables, the latter of which CF already has. A function variable just means you can pass around a function as a variable, and then call it later. A function literal, however, means you can define a function without declaring it. A simple example:

function declaredFunction() {
}
literalFunction = function() {
};

In the former case, there is an actual declaration of the function. It is it's own statement, and is compiled (or interpreted) as such. The latter, however, is a literal. It's an expression, and can be placed anywhere you might want to use an expression. Here's another example of doing something with declarations and then literals:

// declarations
function optionOne(){}
function optionTwo(){}
return (x == y) ? optionOne : optionTwo;

// literals
return (x == y) ? function(){} : function(){};

Assuming this is within another function, the declared functions in the first section could be nested, thereby minimizing their effect on namespace crowding. The second section, of course, doesn't have any extra declarations, though if the functions have any substantial size to them, it can get unreadable very quickly. As such, the latter syntax isn't always the right one, but it is nice to have the option. With CFML, you're again forced to explicitly declare the functions as peers.

And now closures. Closures are nested functions (declared or literal), which execute in the context of their definition location, even if they're executed after that context has gone away. Here's a (somewhat contrived) example:

function getFilter(name, value) {
  return function(item) {
    return item[name] == value;
  }
}
function conditionallyDoSomething(collection, filter) {
  for (var i = 0; i < collection.length; i++) {
    if (filter(collection[i]) {
      // do something …
    }
  }
}
conditionallyDoSomething(people, getFilter("age", 27));

This is a fairly contrived example, as I said, but it illustrates the concept. By the time the function returned from 'getFilter' is executed, the 'getFilter' function has terminated. However, it (the function literal) still has access to the context it was defined in - namely the 'getFilter' function's context, and therefore it's parameters. Closures are really the crown jewel of ECMAScript, in my opinion. With CFML, the closure is totally undoable, unless you use some sort of synthesis framework like Sean's.

The final advantage, like the querying example above, cuts both ways. JS-based implementations can't use any existing CFML tools (Fusebox, ColdSpring, etc.), but they can use all the myriad JS tools that are available. I happen to be a big fan of Prototype, and I can use the UI-agnostic pieces (like the Object and Array extensions) of Prototype on the server-side. Similarly, if you write some wicked-cool routine for your server-side processing, you can immediately and directly reuse it in your client-side JS (or quite possibly AS).

So between the enormously lighter language syntax and the additional language functionality, I think there's a compelling case for using JavaScript (or ECMAScript) as a language for building apps on the ColdFusion server. In an ideal world, it's be ECMAScript 4th Edition (what ActionScript 3 is based on), but there isn't a mature, Java-based interpreter for it anywhere. Aside from just generally being more modern, the 4th Edition provides strong typing (using colon-postfix notation), real packages and classes, interfaces, object member access levels, and a few other neat things.

One very interesting aspect of all this is that Adobe happens to own an ECMAScript 4 compiler (the AS3 compiler from the Flex SDK), an ECMAScript 4 runtime (the Tamarin project that underlies Flash Player 9 and is now hosted by the Mozilla Foundation), and ColdFusion.  So it seems like using ECMAScript 4 as an alternative to CFML for the CF Server is really not that outlandish.  The pieces are all done, it's just the integration that is lacking, and CF is all about integration.  Rather to rich of a project for me to undertake on my own (hence ECMAScript 2 and Rhino), and the closed nature of CF makes it rather hard as well, but for an entity like Adobe, quite a reasonable undertaking, I'd think.  Here's hoping for CF9!

The Rhino Is Coming … to fix CFML

Show of hands, how many people like CFML? Ok, how many like the ColdFusion Platform? What's the difference, you ask? CFML is a markup language that you do most CF Platform development in. You can use CFSCRIPT (which is ECMAScript-like) for certain things, but CFML is the Platform workhorse. The Platform, on the other hand, is all the stuff that your applications (written in CFML, usually) get because they run on the CF server. Things like datasources, PDF generation, easy file access, etc. That's the platform, not the CFML language.

What if I said you could build applications on the CF Platform but weren't required to use the often-cumbersome CFML? What if it were a language that you already new? What it it was JavaScript? And what does that have to do with rhinos?

Rhino is a free JavaScript implementation from Mozilla. It's what drives Firefox, and is also the base implementation of the new Java scripting framework that is available in Java 6 (the javax.script package). It's entirely implemented in Java, and since ColdFusion is as well, that means that CFML within CF and JS within Rhino can execute in the same context, intermingled with each other.

Here's a simple proof-of-concept contact manager that I build over the weekend (running on my underpowered server). You can download the source as a ZIP archive, or via anonymous SVN (with SVN always being current, of course).  Of perhaps more general interest is the class explorer mini-app, which is included in the distribution. As you might imagine, getting everything wired up took some digging around in the Java internals, and this provides a window to the classes that are actually executing inside the JVM. Helpful for both exploration and troubleshooting classpath issues.

The app is in two parts: the integration core within the 'rhino' subdirectory, and the sample app itself. I'll discuss them separately (and very briefly) below.

The basic architecture of the app is to use JS for the business logic and backend processing, and use CFML only for the view layer (where it excels). 'Application.cfm' and 'index.cfm' can be considered "framework" files; there is no application logic in there, just wiring stuff. The views are all in the 'views' subdirectory, and the backend is in the 'scripts' subdirectory.

The architecture of the Rhino integration is centered around 'rhino.cfc' and it's 'runScript' method. You pass that method a JS file to execute, and before evaluation, it will marshal some CF objects into the JS runtime. Following execution, it will unmarshal the top-level 'model' object back to CF for use in rendering your views. More simply, you pass in your parameters and your JS script, it executes, and you get a 'model' structure back to do something with. There is a special global function named 'loadScript' that can be used at runtime to pull in additional scripts, rather like CFINCLUDE.

As you'd expect, JS files are "precompiled" into in-memory script objects and cached until they update on disk, just like CF does with CFM templates. Unlike CF, however, this doesn't seem to offer a particularly significant performance improvement. I don't have a trusted-cache option at the moment, so there is still the filesystem check per-file, per-request, which is probably part of the reason. This actually happens in two places, once to bootstrap the environment (in 'rhino.cfc') and one for the actual runtime (in 'core/bootstrap.js'). The dichotomy annoys me, but such is life.

So why did I spend 15 or 20 hours putting this together? Because I'd love to be able to write my server-side with ECMAScript (though I'd prefer ActionScript 3 to JavaScript 1.6), and wanted to do a little proof of concept for that. I quite like the CF platform, but I'm not a huge fan of CFML itself. How supremely excellent would it be for CF9 to natively support scripting in ActionScript as well as CFML/CFScript, with equal access to the same underlying platform?

More on Prototype Templates

So it turns out I'm a a bit silly (duh).  My previous post on Templates was all well and good, but it didn't consider IE6.  IE6 loudly complains if you have substitution strings in 'id' attributes, so if you need to do that (usually the case), you have to use the TEXTAREA hack I listed.  Which is a bummer, but such is life.