November 23, 2006

A Grid in jQuery

After a disappointing start with jQuery:

  1. No clear strategy to preserve state of custom objects.
  2. No response to questions in the jQuery discuss mailing list.

As a result, I fetched the Yahoo UI Library and Jack Slocum’s Yahoo UI Extension Library. That grid worked well in Internet Explorer 6 and in Firefox. In Safari, the column resize seemed to fail.

Nice. A bit heavy. There are a lot of dependencies. A lot of features that I don’t really need. I can turn them off, but the code and the complexity are still present. In essence, I wanted a table that had a sticky headers.

I found that state is stored in jQuery fancy-pants extensions by creating a hash and attaching it to the target element. I don’t know why that couldn’t have been said on jQuery discuss.

I’d imagined that there was some limitation, that not all browsers supported “expando” properties on document elements, but it must not be the case.

Here is the simple table that I’ve created in jQuery. No resizable columns.

This works on IE 6, Firefox 1.5 and Safari 2.0.4.

It was only possible once I’d abandoned table markup, however. The table is rendered with div and span elements, rather than table, tbody, tr, td, etc.

Much easier. The implementation of tables has a lot of baggage attacted to it.

However, I’m not finding that it doesn’t scale. The rendering causes the “Unresponsive Script” warning in Firefox when the table is large.

In the course of creating this grid, I fixed the innerWidth and innerHeight methods of dimensions.js, which incorrectly named the border properites, “borderLeft” instead of “borderLeftWidth”, and neglected to deduct the padding width.

Update: I’ve addressed some of the performance issues of loading the table. The time that it takes to load this new revision is greatly reduced. Speed up is a factor of ten.

I build the cells as spans, so that I can measure the width of the text, when rendered as a span, an inline element, this is possible. A assign a class name for the span, based on it’s column position. Then I’d set the dispaly property of the span to block. In the end, I’ll define a CSS class for each column, with the width set to the maximum width for that span.

By removing the assignment of the display property of the span, I got my speed up.

I also speed up loading by measuring the border and padding for each column once, rather than calculating the inner width for each column, I keep track check the offset width, and calculate the innner width by dedcuting the total of all borders and padding of the first from form the offset width. The assumes that the styles for each column are identical in all rows (which is perfectly reasonable and all I need).

It still chokes on the large datasets that I’m using, 500+ rows. For my next trick, I’m going to load incrementally, so that the unresponsive script warning does not appear.

The grid will render much faster if I have a set width, of course. I can create an optimized rendering method that builds a large HTML string and injects it, 100 rows at a time, in the case of resorting, or in the case where I’ve assigned widths to all the columns.

Update: The grid now renders concurrently. Different browsers prefer different combinations of rows per timeout and time between timeout.

The important thing is that the page is responsive. The user can scroll the grid while it loads, the back button and other controls still work.

The key tradeoff is that the slower the grid loads, the more responsive it is.

Rendering is faster in this incarnation. Absolute positioning is much faster that relative layout. Much faster than laying out the grid as blocks that float left.



 

UniversalException

I do not like checked exceptions. I consider them harmful. They create a lot of noise. They insist on attention at every level of a program, when I’d prefer to decide for myself where I’d like to handle exceptional conditions.

To reduce the amount of noise in my Java programs, I created a class called UniversalException, and use it as the base class for all my exceptions. At the starting point of a program, I can catch UniversalException, and place my application wide error handling there.

A new trick is to add the ability to declare an exception and fill it full of useful information as a one liner.

if (!file.exsits())
    throw new StorageException("file.not.found")
             .info("file", file);

There is a method in UniversalException called info that adds exception information to a linked hash map of exception information. Thus, it’s pretty easy to throw an exception and have some meaningful reporting in the stack trace.

This only works because I’ve renounced checked exceptions. If it meant something to me to declare a method as one that throws StorageException, then I’d have a problem, because the info method would generalize the exception into a UniversalException.

How nice to not have to worry about that petty little language misfeature.



November 12, 2006

Second System Syndrome 2.0

Set out to look for a ready made grid to import information from a spread sheet. The nicest one that I came across, via the Rails Spinoffs mailing list was A Grid Component for Yahoo! UI – Part 1, the work of a fella named Jack Slocum. This introduced me to the Yahoo! UI Library, or rather, made me take notice.

I’ve just completed a real deal Prototype/Script.aculo.us application, for the neighborhood boundary project at Think New Orleans.

Prototype and Script.aculo.us are well documented, and there is enough mention of quirks between the Google Maps API and Rails Spinoffs mailing lists, that I’ve been able to navigate the incompatibilites between Protoype and Google Maps.

The Yahoo! UI Library contains parallels to the Prototype library, such as effects and event handling structures. What caught my eye, was the Ajax implementation’s acceptance of a structure of event handlers, much like in Prototype, with the addition of a field for the target of the event handlers. Assuming that this pattern is repeated elsewhere, this is more economical than saying:

this.onMouseOver.bindAsEventListener(this)

When that is repeated for every mouse action, it seems tedious. This may have more to do with my preference for short lines than any rational complaint.

One nice concept, shows that people are somewhere thinking about the lessons learned from Prototype, and other libraries that I’m not as familiar with, like Dojo. The code Jack created for his grid is crisp.

The crisp code and straight creases makes me think of Borland’s Object Windows Library, which was where I entered the world of UI programming, many years ago.

It also makes me think of Second System Syndrome, first diagnosed by Fred Brooks in the Mythical Man Month. The Yahoo! UI Library adds more structure to Prototype and Script.aculo.us, creating a library with more rigor.

In Jack’s blog he references a Zebra Table Showdown over at a blog about jQuery. Although he goes on to show that with his extension library, the Yahoo! UI Library can be just as terse, I’m already drawn to the jQuery library.

jQuery has the feel of scripting, where the Yahoo! UI Library has the feel of the Object Windows Library.

The former uses the document itself as part of the model. In Prototype derived code, the trick where you bind the “this” object to an object of your choice, is used to create a controller. This is a step just far enough away from the Document Object Model to organize one’s thoughts, but not so far away that you interact with the browser’s document as if it were a sofa-surfing paradigm that stayed longer than the weekend it promised.

jQuery makes it easier to navigate the browser’s document, and therefore, makes applications a matter of knitting together document nodes with events. That’s a fresh new look for this generation of JavaScript programmers, or a return to the practices of the days of yore. Not a second system effect.



 

Drawing Polylines

The task at hand is to create a polyline draw UI that people can use to edit their own neighborhood boundaries.

The tool that I’ve created uses the Google Geocoder to set the points. (Previously, I’d used a Geocoder based on the Perl module Geo::Coder::US.)

The UI builds a list of points. There is a box at the top where the next point is added when the goecoding resolves correctly.

There is the issue of how to resolve multiple geocode answers, when they occur. One option is to draw the possiblities, each in a different color and ask the person to choose which they want to use. If there are three addresses, say, each point can be displayed with different marker, and marker color, the Three addresses can appear at the top of the list in a style of some sort, something bulbous, that has the three addresses with color coded back grounds, the user can chose one of the three options.

Mousing over each coordinate and highlights them. An X will appear to the right, allowing you to delete the address.

I’m trying to decide how to insert.

I don’t want to reorder the list. I’d rather move the insertion point.

I’m imagining drawing a border, or moving a div to show the insertion point. Drawing a dark line above where the insert would take place.

What will I learn when this is done? I’ll have chosen a temporary icon set, or possibly it is the one to go with.

I might learn how to create the rounded edges that are found around Flicker photosets.



November 5, 2006

Quick Study

One of failure points is that once I get too familiar with something, I loose interest in it. I assume the because I have an understanding of something, that everyone else does. It must be time to move on. More likely, continue to have a perception that is uncommon, the difference is that I have explored beyond the point where it’s novel, to the point where I can act on it. Perhaps it is not as earth shattering as spaghetti you can eat with a spoon, but maybe it is. The implementation and marketing of idea make the difference. This is true of software programming especially, where an idea gets implemented, and it doesn’t seem so slick anymore. At that point it falls victim to refactoring, so it can be really truly elegant, and perhaps even read email. It doesn’t ever seem to make it over the wall, however.