Archive for the ‘JavaScript’ Category

Under jQuery’s bonnet

Posted in 'Cool Stuff, JavaScript' by James on January 31st, 2010

If there’s one thing all library users should be doing more, it’s peeling back the layer of abstraction and seeing what’s really happening underneath. This is the only way to gain a true understanding of what the library provides, and who knows, maybe you’ll find some gems that you didn’t know existed.

Libraries like jQuery aren’t very small when uncompressed. Traversing a long source file trying to look for a specific method’s implementation is far from ideal. I have frequently found myself in this situation with jQuery, so today I decided to do something about it, and the result is viewable at http://james.padolsey.com/jquery.

Preview of the jQuery Source Viewer

It allows you to study specific parts of jQuery’s source. You can type in a method name and you’ll see its implementation straight away, in all its syntax-highlighted glory! It will also link’ify all function names within the presented source:

The css method's source, with certain function names as links

You can link directly to a method using the following URL pattern:

http://james.padolsey.com/jquery/[version/]methodName
 
E.g.
http://james.padolsey.com/jquery/css
http://james.padolsey.com/jquery/1.3.2/attr
http://james.padolsey.com/jquery/jQuery.proxy
 
-OR-
http://james.padolsey.com/jquery/#v=version&fn=methodName

If you don’t specify a version then 1.4 is assumed.

JavaScript’s Dark Alley

Posted in 'JavaScript' by James on January 30th, 2010

So, I happened upon an interesting thread this morning, concerning the recently released jQuery Lint. For those of you who have not dared to look, the comp.lang.javascript newsgroup is truly the proverbial dark alley of JavaScript and DOM development. I can picture it vividly, a dingy dusty cobbled walkway blackened by the thick fog of regressive opinion and unprovoked flame wars, riddled with the unquestioned prerequisite of a newsgroup’s slow death — spam on every corner!

If you have a read through that thread you’ll notice none other than the infamous David Mark. This is the same person that slammed jQuery (oh, and MooTools) for not being able to “do *anything* right” and then, not too long ago, threatened the jQuery project with legal action over some DOM attributes tests.

David had the following to say about jQuery Lint:

Well, sort of. It’s not so much the Johnny-come-lastly advisor plug- in, but the fact that it is just another horrible plug-in for an equally bad pile of JS [he means jQuery]. Anyone who would use jQuery enough to want to write a plug-in is not going to be the best candidate to wtite a browser scripting “lint.” I can’t see it.

He continues:

The idea (which is sound) is to warn developers when they are doing something incorrect (or ill-advised). I haven’t looked at the code for it (and I’m sure I never will). I find I don’t have to do that anymore as the basic rules always apply. :)

David doesn’t stop! He still continues:

[Scott Sauyet]
> It seems to be a tool to help new users learn things like that although this code is legal:

$("selector").css("color", "red").css("margin", 0);
> This would be more efficient:
$("selector").css({color: "red", margin: 0});
[David Mark]
You dump it and replace it with something better (and faster). In this case, something like:
el.style.color = "red"; 
el.style.margin = '0';
That’s smaller, faster, more readable, makes no function calls, creates no new objects and is impervious to upgrades to jQuery (typically poison). And, as we all know, jQuery doesn’t work worth a shit anyway as the “logic” in the script is mostly a diary of confused browser watchers. Get the picture?
> That doesn’t indicate anything wrong with the library any more than > any lint program indicates problems with its target environment.
Of course, you don’t need a lint to see what is wrong with the library. It’s as obviously unsuitable as a dissertation written in crayon.

According to David we should be sparing ourselves the obvious folly of abstraction and spend more time writing “smaller, faster, more readable” JavaScript:

jQuery Lint

Posted in 'JavaScript' by James on January 18th, 2010

jQuery Lint is a simple script you can download and use with jQuery. It works over the top of jQuery and diligently reports errors and any incorrect usage of jQuery. It will also, to some extent, offer guidance on best practices and performance concerns.

Unlike JSLint, jQuery Lint is a runtime reporter. To use it, you need to include it, after jQuery, in your document:

<script src="jquery.js"></script>
<script src="jquery.lint.js"></script>

jQuery lint’s main objective is to notify you of incorrect usages of jQuery’s API. So, if you pass incorrect arguments to any method then jQuery Lint will let you know. It compares your arguments to the argument signatures in jQuery’s API. It reports via Firebug, although you can quite easily plug-in your own console mechanism.

It has four different error-reporting levels (accessible via jQuery.LINT.level), zero reports nothing, three will report everything, including small things like using css().css().css() instead of css({...}). It’s quite configurable too. You can add your own checks. E.g.

jQuery.LINT.special[1].jQuery = jQuery.LINT.special[1].jQuery || [];
 
// Add check on error-reporting level one.
// Check jQuery method.
jQuery.LINT.special[1].jQuery.push(function(selector, context) {
 
    if (selector === '*') {
        return "Don't use the universal selector!";
    }
 
});

jQuery Lint tries to help you in determining where the problem occurred in your code. It’s not much help to you if it just says, “Err, you called css() incorrectly!”. If it occurred as a result of an event then Lint will say so, and if you’re using a browser that provides a stack-trace as part of its Error object (like Firefox) then Lint will also provide you with the file-name and line number. E.g.

jquery Lint - Reporting line number and file name where problem occured.

You can read more about jQuery Lint and download it at Github:

jQuery Lint @ Github

The idea of a lint-like script for jQuery has been floating around for some time. I want to thank Dave Methvin in particular, for it was his idea that sparked my interest originally.

This is quite a young project, so there will be bugs. Please report them!

Cross-domain requests with jQuery

Posted in 'Code Snippets, JavaScript' by James on January 12th, 2010

Chris Heilmann recently posted on how to use YQL to make cross-domain requests, which would usually be prohibited due to the same-domain-policy. I already knew about YQL, but I had no idea that it allowed retrieval of HTML from other sites, via JSON, returned as a single string!

Instead of asking for JSON format, ask for XML, but also add a callback parameter to your query. Voila!

So, in short, YQL allows us to make cross-domain GET requests!

Chris also posted a demo!

With a bit of hacking, we can make jQuery work with YQL for all cross-domain GET requests. UPDATE: I’ve decided to put this in my “jQuery Plugins” repo at Github:

Cross-Domain Ajax mod @ Github

With this mod, any GET request made via jQuery.ajax to another domain will work!

$('#container').load('http://google.com'); // SERIOUSLY!
 
$.ajax({
    url: 'http://news.bbc.co.uk',
    type: 'GET',
    success: function(res) {
        var headline = $(res.responseText).find('a.tsh').text();
        alert(headline);
    }
});
 
// Works with $.get too!

Have fun!

Encapsulation in JavaScript

Posted in 'JavaScript' by James on January 9th, 2010

Encapsulation is a useful technique in programming which allows you to separate an abstraction’s implementation from its interface, thus enabling future changes to the implementation without affecting the interface. There are other benefits of encapsulation, such as:

  • Being able to screen (validate) new properties, via setter methods.
  • Being able to process properties before their “release”, via getter methods.
  • Making your abstraction less prone to abuse by other developers — specifically, to protect private variables and states that could compromise the effectiveness of the abstraction.

Grady Booch (author of “Object Oriented Analysis and Design”) describes encapsulation as:

“The process of compartmentalizing the elements of an abstraction that constitute its structure and behavior; encapsulation serves to separate the contractual interface of an abstraction and its implementation.”

JavaScript is often considered a toy that doesn’t know of complex design patterns or have the capacity to support techniques such as encapsulation, but, contrary to misinformed belief, JavaScript does have capacity for encapsulation. It’s just quite tricky, that’s all!

Hiding your variables in closures

It’s possible to hide variables in JavaScript. To make this happen we take advantage of the closure:

function Person(name, age) {
 
    this.toString = function() {
        return 'Name: ' + name + ', Age: ' + age;
    };
 
}

If you’re not sure what a closure is just think of it as a function defined within another function. The “child” function has access to the “parent” function’s scope.

You can see that we’re defining the toString method within the constructor.

The only reason to define a constructor’s methods anywhere other than its prototype, is in the situation where that method needs access to variables defined in the constructor’s scope. Above, the toString method needs access to the variables, name and age.

Setters (and getters)

Once we instantiate this constructor (new Person('Jim', 88);), there’s no way to change the name or age — they’re “hard-coded” in the inaccessible “parent” scope.

We can make it possible to change these values by adding a couple of setter (AKA, mutator) methods:

jQuery code smells

Posted in 'JavaScript' by James on January 5th, 2010
jQuery code smells

Here’s a quick line-up of some smelly jQuery code! “Code smells” are pieces of code that do for your eyes what bad smells do for your nostrils, and usually result in erroneous or harder-to-maintain code. I have no doubt that at least half of you will think that I’m wrong about at least half of these.

Before you stop paying attention, I’d like to wish everyone a Happy New Year! I hope you find the new design more consistent and cleaner.

May the flaming commence…

Prefixxing all jQuery objects with “$”

It’s ugly, and my text editor doesn’t like it! But mainly, it’s ugly, and is only useful for beginners. Hungarian notation is a hotly debated technique — like Marmite (and Jade Goody?), you either love it or hate it!

var $body = $('body');
$body.click(function(){
    $this = $(this);
});

I won’t say much more; I appreciate that it’s a sensitive topic for some and is mostly about personal preference.

Concatenating a bunch of things together to make a selector

I see a lot of this! It looks dirty, and just screams, “I’m succumbing to the API because I don’t know what else to do!”

$('.' + className + '[' + attrLookup + '^=' + attrPrefix ']:not(.' + notClass + ')');

This is why I think jQuery needs some other way of filtering DOM elements (possibly something like my filter hack). For now, seperating out our selectors will have to suffice:

$('.' + blah.className)
    .filter('[' + attrLookup + '^=' + attrPrefix ']')
    .not('.' + notClassName);

To be truthful, I’m on the fence with this… Maybe I’m just against string concatenation!

Macros in jQuery

Posted in 'JavaScript' by James on December 26th, 2009
Macros in jQuery

Creating a plugin for jQuery is incredibly simple and is a very useful way to abstract complex behaviours so that they can be used repeatedly as part of your jQuery “chains”.

But, when the time comes, and you’re faced with the decision to either create a jQuery plugin or to simply create a regular function, everything suddenly becomes quite complicated. First, you’ll wonder whether the piece of behaviour you want to abstract is best kept under the jQuery namespace, and then you’ll doubt its applicability to the DOM-centred jQuery chain, and then sometimes you’ll recede to something you’re much more comfortable with, a regular ol’ JavaScript function.

If we forget about the plugins available online, and we simply focus on your plugins, made and used within a specific project, then the question of whether a plugin is really the right route becomes all the more difficult to answer. Are you going to benefit from extending jQuery’s API? Will the readability of your code benefit?

For example:

function applyColors(elems) {
    $(elems).css({
        color: config.color,
        backgroundColor: config.bgColor,
        borderColor: config.bdColor
    });
}
 
// Call it:
var myElems = $('div.something');
applyColors(myElems);

applyColors encapsulates some behaviour that is needed frequently, and that’s why it’s been abstracted into a function. To some, this approach is lacking in that it doesn’t harness the full power of jQuery, and more specifically, jQuery’s plugin mechanism. How about this:

jQuery.fn.applyColors = function( {
    return this.css({
        color: config.color,
        backgroundColor: config.bgColor,
        borderColor: config.bdColor
    });
};
 
// Call it:
$('div.something').applyColors();

Cleaner? More readable? I think so.

Many developers are not prepared to extend jQuery’s API with their own simple abstractions. I don’t know why. But, I hope, that jQuery macros can help in lowering the barrier to extending jQuery.

Gapless wall of images

Posted in 'JavaScript' by James on December 20th, 2009
Gapless wall of images

Given a set of arbitrarily sized images and a container with fixed dimensions, fit as many of the images within the container as you can, without leaving any big gaps in between images. How would you do it?

Well, I had a go, and this is a brief overview of how it works.

Obviously, it wasn’t possible to simply line the images up as a grid, because they all have varying (and unpredictable) widths and heights. Considering this, I only saw one logical way of doing it… progressively!

Place an image — determine the remaining space and use it to place the next image, and so on. Placing the first image is easy; just stick it up in the top left corner and go from there!

Diagram of placement mechanism

A single placement will open up, potentially, three new positions. Out of them, the top-most one could be used for next placement, or the left-most, whichever you fancy.

I chose to track the availability of pixels using a basic two-dimensional array:

// Nine occupied pixels:
[
    [1,1,1,0,0,0,0,0,0,0],
    [1,1,1,0,0,0,0,0,0,0],
    [1,1,1,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0],
    [0,0,0,0,0,0,0,0,0,0]
];

The width given to any image upon placement is defined by the amount of pixels free to the right of that image and the height is calculated similarly. There’s a configurable maximum width and height so that the first image doesn’t take up the entire space. Eventually, there is no space left, and the procedure halts.

You can find the code at Github, under “PhotoWall”.

I’ve also put a pretty boring demo online, and yes, I know it’s a bit messed up at the bottom edge — like everything, it’s a work in progress :) .

Easing in jQuery 1.4a2

Posted in 'Cool Stuff, JavaScript' by James on December 19th, 2009
Easing in jQuery 1.4a2

I’m happy to write that my proposed change has been accepted into the jQuery “fx” core. I thought it worth explaining how this feature works and how you can make it work in your code.

Currently, jQuery (1.3) only allows you to specify one easing function per animation. This is perfectly fine in most situations but in some unique cases there is a need for a different easing function for each animated CSS property. I mentioned, in my previous post on the topic, that such a thing could be emulated by initiating two separate animations and disabling the default animation queueing on the first one. It does work, but it’s a bit of a hack, and I felt that the API could be easily extended to serve these types of use cases.

So, as of jQuery 1.4 alpha version 2, jQuery provides you with the possibility of defining an easing function (or rather, the name of an easing function) for each property that you’re animating. It’s done in the following manner:

jQuery(myElement).animate({
    left: [500, 'swing'],
    top: [200, 'easeOutBounce']
});

Another possibility is to define the per-property easing functions within the optional options object, passed as the second argument to animate:

jQuery(myElement).animate({
    left: 500,
    top: 200
}, {
    specialEasing: {
        left: 'swing',
        top: 'easeOutBounce'
    }
});

See a demo!

The conventional easing argument can still be used to set a default easing function for those properties that don’t already specify a “special” easing function:

Simple pulse plugin for jQuery

Posted in 'Code Snippets, JavaScript' by James on December 16th, 2009

A while ago I wrote a little “pulse” plugin for jQuery which would make an element pulse between two or more states. I won’t bother linking to it because it’s offline. I decided to have another go at developing it, this time with a more refined and intuitive API.

I’ve tried to emulate the characteristics of jQuery’s animate() method as much as possible. There are only a few slight differences. Here’s a typical call to the new “pulse” plugin:

jQuery(element).pulse({
    opacity: [0, 1],
    backgroundColor: ['red', 'yellow']
}, 1000, 5, 'linear', function(){
    alert("I'm done pulsing!");    
});

It’s almost exactly the same parameter pattern as animate(), except that you have to specify an array of values for each CSS property, and also an additional numerical parameter, after the duration, which signifies how many times you want the pulse to run (the above code will run the pulse five times).

It also works with an “options” object, just like animate():

jQuery(element).pulse({
    opacity: [0,1]
}, {
    duration: 100, // duration of EACH individual animation
    times: 3, // Will go three times through the pulse array [0,1]
    easing: 'linear', // easing function for each individual animation
    complete: function() {
        alert("I'm done pulsing!");
    }
});

You should note that the duration option only defines how long each individual animation will run, not the entire pulse. To dictate the length of the entire pulse you need to use the times option. Also note that the times option refers to an entire run-through of the largest array found in the properties option.

You can “pulse” through as many values as you want:

jQuery(element).pulse({
    backgroundColor: ['red', 'yellow', 'green', 'blue'],
    opacity: [0, 1],
});

The arrays don’t all have to be of equal length – with the above code, the opacity would keep changing as is defined by its array.

The plugin itself is quite small. I’ve decided to start a new repo at Github, just for small and useful jQuery plugins like this.

Pulse plugin on Github

I haven’t tested it extensively yet, so, as usual please notify me of any bugs/issues. Thanks!