Coding Javascript as Javascript

One of the most common questions that I hear at companies I’ve worked at and classes I’ve taught is, “Why don’t you write Javascript as if it’s ____ language?” Fill in the blank as you like.

The question I immediately ask is: “do you enjoy writing Javascript? Is it a fun language to code in?” The answer is invariably a strong “no!”

Javascript, for all its flaws (which are not few), is one of the most flexible programming languages ever created. It is a new type of language which is neither procedural nor class-based OOP, but can mimic both if you work hard at it. I don’t mean that it’s prototypal; that’s just one feature, and quite possibly the most misused one. I mean that it’s expressive.

Any object can be extended with any behaviour at any time, and that behaviour can be called at any time. You can write objects which aren’t classes, but groups of behaviours, and extend any other object with them when you need. Even JSON data coming in from a server can instantly be embedded with such behaviour.

Mimicking another language with Javascript is not only hard work, but will cause the author to lose the advantages of the new type of language (which, frankly, are fun when you get the hang of them!) There’s no need in Javascript for complicated class hierarchies to create a stable, maintainable body of behaviour in even the largest applications. Javascript, used properly and not as if it were another language, can create libraries and applications written in a tiny fraction of the number of lines that a classical OOP model requires. Fewer lines means less code to maintain, and less code for new team members to learn.

Do note that, due to the newness and, ironically, the flexibility of the language, these different patterns are still being developed. It’s hard for all of us to let go of old ideas and fully embrace the new ones, and deadlines often mean not doing that new feature in the way you’ve been learning (or brainstorming). Ultimately, you and the developers who follow after you (and ultimately the company) will pay the price for such shortcuts.

Caveats of the JS Module Pattern

Javascript modules are a nifty construct which I was lucky enough to learn firsthand from Douglas Crockford in his (then) small classes at Yahoo c2005. He didn’t use the term “module pattern” then — I expect he hadn’t thought of the phrase yet. It was just a way to have private variables and methods.

I still love them, but I have some caveats with regards to using them for non-singleton objects.

First, what is a module?

var counter = function(){
    var my = {
        count: 0,
        max: 5,
        isPastMax: function(){
            return this.count > this.max;
        }
    };
    //This is what gets assigned to the variable "counter"
    return {
        getCount: function(){
            return my.count;
        },
        reset: function(){
            my.count = 0;
        },
        increment: function(){
            my.count++;
            if (my.isPastMax()) {
                this.reset();
            }
        }
    };
}(); //NOTE the (). That makes the outer function run and return immediately

A module is nothing more than a function which returns a public API object which, through the magic of closure, has access to truly private methods and variables. Here I’ve put them all as properties of private variable my.

counter is now a singleton object that maintains a counter state privately. No more methods can be added to it which reach anything in my that we haven’t explicitly allowed.

This is all well and good. But what if we want more than one counter? Let’s take off the trailing () so that we have a factory that produces counters:

var Counter = function(){
   //just as above
}; //NOTE the absence of ()!
var instances = [];
for (var i=0; i<100; i++) {
    instances.push(Counter());
}

Now we have 100 instances of the Counter module!

Unfortunately, the encapsulation has come with a price in this case. Every function we defined within Counter has to be created again and occupy more memory!

Sometimes this is acceptable, if the number to be created is low and the module is small. If you’ve got a module that goes on for a few pages and you intend to make a few dozen instances, expect to be eating up substantially more memory than a similar feature using a non-encapsulated object, like so:

var Counter = {
    _count: 0,
    _max: 5,
    _isPastMax: function(){
        return this._count > this._max;
    },
    reset: function(){
        this._count = 0;
    },
    increment: function(){
        this._count++;
    },
    getCount: function(){
        return this._count;
    }
};
Object.extend = Object.extend || function(a, b){
    for (var k in b) {
        if (b.hasOwnProperty(k)) { a[k] = b[k]; }
    }
    return a;
};
var instances = [];
for (var i=0; i<100; i++) {
    instances.push(
        Object.extend({}, Counter)
    );
}

All of the functions exist only once in memory, referenced by the individual instance objects.

Make no doubt: the module pattern is a tool that every good Javascript developer should understand. It provides excellent encapsulation that can’t be externally broken. It’s not without its drawbacks, however.

Resize-to-window web apps

One of the things Flash designers have had which web developers have not is the ability to retarget an application to any viewport size desired. I’ve been saddled with implementing a by such a Flash designer for deployment in HTML/CSS/JS on QTwebkit.

What’s amazing is that I’ve had some degree of success with it. I can’t show a demo yet, but imagine that a fully animated, complicated application smoothly scales, centres, and otherwise behaves more or less like you’d expect Flash to.

To be sure, there are some sketchy areas. Webkit’s positioning math can be very sloppy if you need precision (my design does). Any container that’s affected by font size is going to change a little (not always bad).

Watch here for a demonstration of this soon, along with a bit of how-to.

HTML5 cache manifest, or an experiment using unfinished and undocumented technology

I’m on a project right now that needs to work on or offline (no, not for mobile, but still confined to webkit), so HTML5′s manifest attribute is the obvious choice. Unfortunately, the implementation even on Safari is spotty at best, and the documentation of precisely what is necessary to make it work (or troubleshoot what went wrong) is nearly nonexistent. That which has been written is largely incomplete or inaccurate, not because of laziness or incompetency but due to the fact that the specification itself is still in flux!

The bits I’m having trouble with at the moment:

  • There’s some HTTP header other than the mime type which (I think) is preventing a simple test page from working on one server. I think it’s “Accept-Ranges: bytes”, but I’m not sure.
  • Safari (4.0.5) handles loading new versions of the cached files in a way that I suspect is a design flaw rather than a bug. Safari isn’t my target platform (QTwebkit is), but I’m attempting to use it as a reference for how things are supposed to work so I can verify how good or bad QT’s implementation is.

On the latter issue, a little background explanation is required. A cache manifest file is (mainly) just a short list of files that may or may be not used by your html5 page. The page itself is listed in there as well:

CACHE MANIFEST
#version: 1
offline.html

When you navigate to offline.html (whose html element has the manifest attribute pointing to the file above) the first time, the browser behaves more or less as normal. But when you go the second time, instead of checking with the server to see if offline.html has changed, it only checks to see if the manifest file has changed. If it has, then it should check for updates to all the files listed within it.

That’s the expected behaviour. What Safari seems to do requires a third loading to describe, however.

Let’s say that after the first loading, you make a change to offline.html, and update the version number in your manifest to prompt the update. If you reload the page, offline.html will not appear to have changed. Reload once more, however, and you’ll see the change.

This is where it gets weird: with the first reload, the Apache access log shows offline.html being requested, and delivered in full with a 200 (and not a 304). The second reload shows only the manifest being requested (with a 200). This means that Safari is getting the updated html file but not using it.

If you think about it, this might be the intended behaviour. Here’s what happens on the first reload:

  1. Safari checks its list of manifests to see if any mention offline.html.
  2. They do, so Safari loads up the cached version of it.
  3. The html element references a manifest, so it checks the manifest to see if it’s changed.
  4. It has, so it checks all the files within to see if they’ve changed, and updates the cache.
  5. The page continues rendering. Since the old version of offline.html was already loaded (which is how Safari knew to check the manifest at all), we don’t see the new version.

Obviously, this isn’t very intuitive, and it’s easy to think you’re seeing a bug. My thinking on the matter is that the manifest might not belong on the page it’s caching, but on another page which redirects or otherwise brings up that page. Alternatively (and for my project this is probably the best solution), the core page would almost never change, and all files would be brought in by the initial JS.

jQuery 1.4 has landed!

I’ve been using jQuery for most of a year now, having been a YUI man for years. I absolutely love it.

I have had a few gripes about jQuery, however, but I’m pleased to say that as of yesterday, many of them were addressed.

One of the gripes I’ve had with jQuery is the messiness of building an element string:

jQuery('a href="' + url + '" class="' + classes.join(" ") + '">' +
  '' + linkText + '');

This can get quite big in some cases, spanning multiple lines.

jQuery 1.4 lets you create elements with a second “attributes” argument:

jQuery('', {
    href: url,
    className: classes.join(" "),
    html: '' + linkText + ''
});

Note the “html” attribute. That’s the same as writing:

jQuery('')
  .html('' + linkText + '');

Obviously, there are times when you’ll want to use one or the other… but for many situations, this will fit very well into jQuery’s “configuration-based” theory of expressive programming.

Here’s a rundown on 15 new features.

Improved jquery ajax error reporting

jQuery is a great library, and I highly recommend it after 6 months of use. One of the problems I’ve had with it, however, is its poor error reporting on ajax requests. While you can subscribe to the global event ajaxError, there’s nothing to tell you what went wrong. Specifically, I’ve wanted a way to report when the json parse fails.

Looking through the jQuery core, I found that the problem is that “status” field isn’t sent to the handler. A simple intervention on jQuery.handleError will close the gap:

jQuery.handleErrorOriginal = $.handleError;
jQuery.handleError = function( s, xhr, status, e ){
  if (s.global) {
    xhr.error_status = status;
  }
  jQuery.handleErrorOriginal.apply(this, arguments);
};

The “e” object is the original ajax configuration object. Since it reaches the global ajaxError listener, we can pull the status out of that.

Notice that I don’t replace the original functionality, I just do something before calling it with the same scope and arguments. The reason here is forwards-compatibility. Assuming that the name and api of jQuery.handleError doesn’t change, any changes to its internal functionality in future updates will likely be preserved without refactoring effort on your part.

To catch the errors:

$("html").ajaxError(function(xhr, s, e){
    var msg;
    switch (s.error_status) {
      case "parsererror":
        msg = "A JSON parsing error occurred.";
        break;
      case "timeout":
        msg = "An ajax request timed out.";
        break;
      default:
        msg = "An ajax error occurred.";
        break;
    }
    alert(msg + "\n\n" + e.url);
});

Why do I set xhr.error_status and then read s.error_status? Because, somewhere in the jumble of handleError and trigger, xhr becomes s. I love jQuery, but some of its core code can be quite difficult to read through.

jQuery(document).ready() bug with Google Chrome 4.0 beta

I came across a major issue with jQuery (1.3.2) and Google Chrome 4.0 beta today. I’d been testing my company’s web application (for which I’m the primary frontend developer) with Chrome 3.0x, and it was working fine. After a sudden influx of chrome bug reports from someone using 4, I updated to that. And suddenly, nearly nothing worked.

After a fair bit of futzing around in my code and the jQuery core library, I discovered that in chrome 4 in certain cases (probably in large apps), the DOMContentLoaded event was never sent to the core jQuery library. To test this, I inserted a couple of lines into the file you saw above:

3052  if ( document.addEventListener ) {
3053      // Use the handy event callback
[ins]     alert("jQ adding listener for DOMContentLoaded");
3054      document.addEventListener( "DOMContentLoaded", function(){
[ins]         alert("jQ received DOMContentLoaded event");
3055          document.removeEventListener( "DOMContentLoaded", arguments.callee, false );
3056          jQuery.ready();
3057      }, false );

Both alerts show in FF, but only the first does in chrome. However, I found I could add my own and have them called.

Now, since the chances are you’re on this page because you googled for a workaround, here it is:

Google Chrome 4 beta jQuery document ready fix plugin

What this plugin does is first test to see if the browser is chrome 4, and if it is, then it adds another event listener for DOMContentLoaded, which will run even though the main jQuery one mysteriously does not. This calls jQuery.ready function (which is what is used to run through jQuery.readyList, the queued functions array).

We now have two chances for jQuery.ready to be called, therefore a potential race condition. To avoid this, I rewrote jQuery.ready() to null out  jQuery.readyList before cycling through the queued functions.

I still have no idea what’s causing Chrome 4 to fail on this. A test of document.readyState right after I added $(document).ready() shows that it is “loading”, so the problem isn’t that it finishes before adding the event handler or enqueueing the function.

IE and newlines from innerHTML

I ran into a problem today that I’m surprised I haven’t run into before. Internet Explorer loses newlines when pulling text from an HTML element.

In short, if you use innerHTML, innerText or outerHTML on most elements, IE will convert newlines to spaces. Checking the charCodes of newlines (whether unix or ascii) shows them as 32s.

On the other hand, if I output (in a template) the text inside a PRE element, IE will keep the newlines. An element styled with white-space:pre won’t do the trick.

In my case, I have a TD and inner DIV which contain a text string. I need to show the full text string, with line breaks, in a popup dialog. (The CSS property white-space:pre isn’t useful, since long lines can’t wrap at all.) My two realistic options are to copy the data into a JS variable or put the text initially inside a PRE element.

Got to love Microsoft. They keep us webdevs in a job.

Chrome Quarters: a lightweight alternative to sliding doors.

In an ideal world, HTML would mark up a document in a completely semantic way, with no extra nesting or non-semantic elements. There’s a very big stigma against use of “chrome-only” chunks of markup. I’d like to make the case that sometimes, such markup is, if not ideal, at least better than more popular alternatives.

Say you wanted a dynamically sized box to have nice borders with beveled or rounded 3D corners. Here’s the lightweight markup you start with (39 chars without content):

<div id="mybox">
  <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
 doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore
 veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>
  <p>Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit.</p>
</div>

You want to have that look something like this:

Box with rounded corners, beveling and a gradient

Box with rounded corners, beveling and a gradient

Unfortunately, CSS doesn’t give us any way to do that without specifying an exact height and width for the box — a major accessibility block. We need a nested container and a fake header (I’ll use the Yahoo! standard container model) in order to use the sliding doors technique in 147 chars without content:

<div id="mybox">
  <div class="hd"><h4></h4></div>
  <div class="bd">
    <div class="wrap">
      <div class="wrap">
        <p>...</p>
        <p>...</p>
      </div>
    </div>
  </div>
</div>

Now we can reach that style (with an appropriately large image). I won’t go into details on how to make CSS sliding doors, as that’s well documented elsewhere. Here’s what the CSS for that might look like:

#mybox {
  max-width: 250px;
}
#mybox .hd, #mybox .hd h4, #mybox .bd, #mybox .bd .wrap {
  background: url(roundedCornerBoxBg1.png) no-repeat;
}
#mybox .hd {
  padding-left: 10px;
  margin-right: 10px;
}
#mybox .hd h4 {
  background-position: top right;
  height: 31px;
  margin: 0 -10px 0 0;
}
#mybox .bd {
  background-position: bottom left;
  padding-left: 10px;
  margin-right: 10px;
}
#mybox .bd .wrap {
  background-position: bottom right;
  margin-right: -10px;
}
#mybox .bd .wrap .wrap {
  background: none;
  position: relative;
  top: -24px;
  padding: 1px 0 0 1px;
  margin-right: 0;
}

There are two markup problems with this: one, we’ve created non-semantic markup that looks semantic, and we’ve had to add three layers of nesting! How is this better than tables?

Even with all that, due to the 31px height that the chrome image has for the top gradient, we have to resort to negative margins for the innermost content wrapper to achieve centering of the content. Our content formatting CSS and chrome CSS are heavily intertwined. Even with that, we still have a large amount of padding on top and bottom that cannot be eliminated.

Nested markup rendered - lots of padding at top and bottom

Nested markup rendered - lots of padding at top and bottom

Another way: Chrome Quarters

Consider this markup instead (142 characters without content, and chrome whitespace removed):

<div id="mybox">
  <p>Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium
doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore
veritatis et quasi architecto beatae vitae dicta sunt explicabo.</p>
  <p>Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit.</p>
  <b class="chr4c chrome">
    <b class="ul"></b>
    <b class="ur"></b>
    <b class="lr"></b>
    <b class="ll"></b>
  </b>
</div>

Here, we’ve got a separate heirarchy just to hold the chrome, clearly marked as such. The chrome and content markup don’t interfere with one another. Here’s the CSS:

.chr4c {
  display: none;
}
.chr4c * {
  display: block;
  position: absolute;
}
.chr4c .ul {
  background-position: left top;
  top: 0;
  right: 50%;
  bottom: 50%;
  left: 0;
}
.chr4c .ur {
  background-position: right top;
  top: 0;
  right: 0;
  bottom: 50%;
  left: 49%;
}
.chr4c .lr {
  background-position: right bottom;
  top: 49%;
  right: 0;
  bottom: 0;
  left: 49%;
}
.chr4c .ll {
  background-position: left bottom;
  top: 49%;
  right: 50%;
  bottom: 0;
  left: 0;
}
#mybox {
  max-width: 230px;
  min-height: 62px;
  position: relative;
  padding: 1px 10px;
}
#mybox .chr4c {
  display: block;
}
#mybox .chr4c * {
  z-index: -1;
  background-image: url(roundedCornerBoxBg1.png);
}
@media audio, speech {
  .chrome {
    display: none !important;
  }
}

Here, our content formatting CSS is limited to a single rule, almost entirely separate from the chrome styling. A slate of generic rules sets up most of the styling for re-use in many rounded-corner type situations. The four corner pieces are positioned absolutely to occupy 1/4 of the box each (a small amount of overlap allows for IEEE floating point math oddities). The main container is set to position:relative to constrain the absolutely positioned elements.

Finished box with chrome divided into four more-or-less equal quarters of the container.

Finished box with chrome divided into four more-or-less equal quarters of the container. Borders drawn for clarity.

The last rule hides all chrome-only elements from audio browsers, just to be on the safe side. They generally wouldn’t report empty spans, but this assures as much. The b tag is used for brevity, and shouldn’t cause any more trouble than a span.

Browser bugs

The one caveat I must offer: browsers sometimes have some odd rendering differences when it comes to the use of positioning within certain elements. divs will generally work flawlessly, but you’ll find that browser differences abound when it comes to positioning inside buttons and lis. In those cases, know that you’ll likely need to deliver different styles to various browsers.

Despite those limitations, I think you’ll agree that our finished markup and CSS is far more readable, maintainable and reusable than the first. Thoughts?