Categories
Javascript Optimization Programming Projects startup web-design

Javascript Element Creator

Some time ago I was working on optimizing the client side code of my website, plnnr.com, an online trip planner.
This website does automatic trip planning, and the problem was that recalculating trips was slow. After profiling, I found out that most of the time wasn’t actually taken up by the algorithm, but by the UI. Rendering the trip to html was the costly part. The process was like so:

Client-side Javascript code generates new trip prefs -> application calculates new trip -> Client-side Javascript gets the new trip, and creates new html.

It’s important to note that the app is “ajax based”, so the actual trip html was generated by the Javascript code, and not the server. At the time I was using Mochikit to generate the new html. Mochikit has a pretty nifty API for generating html, but it’s quite a bit on the slow side. Basically, this API is a wrapper around createElement.

Well, first I did a little test, and found out that generating html with cloneNode and innerHTML is much faster than createElement. Still, there was a problem – I needed to generate many similar elements – similar but not identical. Consider entries on a trip itinerary – they all look the same, yet each one has a different name, a different time string, and a different onclick event.

What I needed was a Javascript based html template library. My requirements:
1. Speed. Html had to be generated quickly.
2. Expressiveness. It had to be able to create pretty arbitrary html with a given context. For example, an anchor element (<a> tag) with a given href property, and a given text content.
3. References to inner elements: Many elements inside the generated html need various events attached to them, or various code processing. This should be easy to achieve.
4. The library has to allow the template html to be written as html, and not only as javascript strings.

So, I sat down with Benny, and we wrote the Javascript Element Creator, which we are now releasing under the BSD license. I originally wrote it to work with Mochikit and the Sizzle library, and Benny changed his version to worked with jquery.

After adding the code to my project, I got two things: first, everything worked much, much faster. Second, it was much easier changing the generated html when it was generated according to a template, and not directly in code.

Instructions

1. Write your html somewhere visible to the javascript code. Add the “template” class to the upper node, and the id will be the name of the template. For example:

<body>
    <div id="some_div" class="template">
    </div>
</body>

2. Similarly to other template engines, add double brackets to signify where text should be inserted:

<body>
    <div id="some_div" class="template">
        <a href="[[link_url]]">[[link_text]]</a>
    </div>
</body>

3. Create a creator object. It will “collect” your template, and will make it available to your code.

var creator = new ElementCreator();

4. Generate your DOM object, and add it to the document;

var obj = creator.generate("some_div",
                           {link_url: '/url/',
                            link_text: 'hello world'});
appendChildNodes(foo, obj);

The code

We decided to publish for now only the jquery version. I might publish the mochikit version as well at a later date. Since Benny wrote the jquery version, he also wrote the tests for that version.

All in all, the final code is pretty short, and could probably be even shorter. Still, it’s good enough, and gave me a very real performance boost.

Here is the code, have fun with it.

Categories
Javascript Optimization

Javascript Optimization Tricks

Profiling, Profiling, Profiling

This seems obvious, but still merits a mention. Don’t optimize your code before profiling it. If you need a profiler, just use firebug’s. Having tests to make sure that your post-profiling code is equivalent to the original is also nice.

Later is better than now

As is well known, it is usually useful to have some of the page content to be fetched in the original http get, but have non-essential content fetched using ajax after page-load.

In some cases, user interaction with your website does not require fetching new content, but doing some processing. Generating html is especially slow. In that case, the user will have to wait until the processing is done. Unless of course, you can also ‘postpone it for later’: simply use setTimeout to do the work outside of the even handler.
For example, I used Bill Chadwick’s ArrowLine, which redraws on zoom-in/out. Since the redraw isn’t quick, this makes zooming in pretty slow, especially when quickly zooming more than once.
My solution: since what takes time is drawing the arrows themselves, I put arrow drawing code in a timeout callback, which means the interface doesn’t get unresponsive.

(Of course, this might misbehave, and I had to make sure my code still works if multiple timeouts are enqueued, etc..)

A single div is all you need!

I had to write a dropdown widget for UI, one which could show arbitrary html inside the dropdown box. Problem is, I had to to have a lot of similar dropdowns. This in itself is pretty easy, as we all know how to use a for-loop.
It gets complicated when you find out that adding these dropdowns takes a lot of time. What’s worse, the part that takes time is adding the div that gets displayed when you show it, but is otherwise hidden.

To solve this, first you may apply “Later is better than now”, and create each dropdown only when it’s needed. This will work. In some cases, a different approach is warranted: all of these dropdowns share the same design of the ‘dropdown div’, and only one of these divs will be shown at any time (I had to write code to make sure of it). So, instead of making a new drop-down div for each dropdown, create just one, and let them share it. This might complicate your code, but the rewards may be great.

To make it work, you may use an object factory, or a function that creates widget classes, or any other pattern that works for you.

Categories
Javascript Programming rants

Debugging in IE.

I did something I shouldn’t have done: from JavaScript, I appendChildNodes()-ed some text and an img to an existing img. I apologize. Firefox told me it was OK. To put it more accurately, Firefox didn’t tell me anything, and just didn’t show the text and the img, which was what I wanted it to do. IE really didn’t like it.

Finding out what IE was so upset about wasn’t fun, as I didn’t have a debugger for IE. So I started looking for one. Not wanting to install visual studio just for that, I installed(*) “Microsoft Script Debugger”, which is one old piece of software. It’s so old that its readme states that it works with IE 4. At least it works. It lacks watches and some other features you’d expect from a debugger (which Firebug has!), but it got the job done. Mostly.

I wasted about 40 minutes on that issue.

* Installing “Microsoft Script Debugger”, contrary to what some my tell you, does not require installing old office versions. I followed a download link on Microsoft’s website, and got it. It does require some voodoo if you’re running Vista, but nothing too hard to handle.

Categories
Javascript Programming startup web-design

Mochikit Drag&Drop Corner Case

I found myself working again on the UI for my startup. As my Javascript library, I use Mochikit. One of the reasons for that is that it’s the Turbogears builtin, and I came to like it. The other is that it’s really easy to create DOM objects with it.

In any case, Mochikit has really easy support for good looking drag&drop. However, as usual, my requirements were strange enough to fall upon the following corner case:
I wanted to add a “tool tip popup” for some text, where I would display pertinent information to said text. To make the tool tip popup thingy work, I used the following css “on mouse over” visibility trick:
[css]
.tooltip {
display: none;
}

.parent_object_class:hover .tooltip {
display: block;
}
[/css]

This works beautifully, and with a little bit of positioning, and maybe an event here and there, you can make it appear where you want.

Cue the drag&drop. I wanted to add some drag&drop based slider to that tool tip. Since I wanted to limit the “draggability” of the slider’s selector, I used the snap argument for Mochikit’s Draggable object so that if you move the mouse too far, the dragged selector stays at the limit of a predefined area.
This was all very well, and both of the tricks described worked pretty fine separately, until I tried to put them together.
When dragging and leaving the allowed area for the drag, because of the snap argument, the dragged object stays back, and mouse is no longer over a child element of the original tooltip and tooltipped text. This means that the css trick no longer applies, and the tooltip loses visibility. This would have been fine if the drag ended there. However, the drag was not ended, and at each move of the mouse, the coordinates would grow more. Since I use the drag coordinates to compute the result of the drag, I got some pretty strange results.

To work around this behavior, I used Draggable’s starteffect and endeffect optional arguments to make sure the tooltip remained visible, thus avoiding this issue.

Still, there were many other issues with all this drag&drop going around, and I decided to go for a simpler design, and not put in more time on this.
Issue sealed with a Keep It Simple Stupid.

Categories
CSS Javascript startup web-design

Website development and not supporting Internet Explorer 6

My partner and I started to work on a website a few months ago. We have a working prototype, and we are always improving it. My work is mostly concentrated on a smart Python backend, and on a Javascript front-end, while a thin controller acts as a messenger between the two.
Lately, I’ve worked on improving the UI. As expected, I rely heavily on CSS. I generate a lot of html elements using Mochikit and format them with CSS classes. While obviously better than the old alternatives, I still don’t like CSS. Maybe it’s because I don’t understand it deeply enough, but for me, there is still a lot of voodoo involved. An example I found, which luckily I didn’t run into yet, is collapsing margins.

Still, even with all its voodoo, CSS is bearable. At least until you get to IE. My latest run in with it was a scrolling bug, and I ran into many other issues. However, as much as I complain, I’m probably getting it easy, as when we started work, we decided not to support IE 6, at least until required.
Our reasoning was:

  • Developing for IE6 both independently and consistently with other browsers has a high cost attached to it.
  • IE6’s use rates are declining, and will decline even more by the time we launch (See these statistics for example).
  • Our first versions were mostly required as a prototype to prove our technology to potential investors.
  • As a two-men team, and a one man programming team, we are very low on development resources.

Given my latest bout of UI programming, this choice made me just a little bit happier.