Tag Archives: jquery

Ups and downs

I’m stuck in my home-town because of an annoying backache, I’ll take this opportunity to write a small post.

Down

So I went to Boston and things did not go as planned.

First there was the rain: I ended up walking a quarter of an hour under a heavy rain and arrived at the venue just as if I crossed the Charles by swimming. I was so grateful for the dry jQuery T-shirt they gave us! My laptop was OK but I was still freezing. Was I going to give my first talk in wet pants? Not such an enjoyable perspective…

I was after all dry for the talk, but that did not help much. I was afraid the biggest problem would be my nervousness and my accent, but it turned out that the demo I prepared was too abstract, distracting and did not match the expectations of the audience , probably composed of intermediate/advanced jQuery developers. In the thirty minutes or so that followed the conference I realized all the mistakes I did, and yet it was too late.

I therefore asked Karl Swedberg to write a follow-up post on learningjquery.com with the content that I felt, retrospectively, appropriate for the conf.

Up

You can now read my first post, More Event Delegation with jQuery, on this official jQuery blog. I actually decided to split the original content. There will be a part 4 explaining the way non-bubbling events are made compatible with .live() in jQuery 1.4 (the sections about focus/blur and mouseenter/mouseleave are already written, but the implementation of submit/change/select is not ready yet). The fifth part is going to be shorter, discussing the performance in event delegation with jQuery.

The conference was also a good opportunity to get to meet members of the jQuery community. The few people I had a chance to chat with (mostly foreigners, what a coincidence!) were really nice people. I was thrilled with the announcement of an up-coming jQuery conf in London, I hope I’ll be able to join once again.

What’s next?

First things first, I hope I will heal quickly, staying in bed all day long really doesn’t suit me. I shouldn’t be using a computer right now… I cannot help it.

I’ll be in Praha from the second to the fifth of October for the EU MozCamp. It looks like I’ll see many of the people I met in Madrid, those two days can only be fantastic! And I’ll take two extra days to visit this wonderful city with a friend from uni.

Then it will be time to look for a job… Independence, at last!

EventSound, round 3

And here we are, the penultimate version of EventSound has been uploaded. And the only feature that is missing for 1.0 is… the sound. It looks like I’ll have to find samples on the Internet now.

I’m rather happy with the development pace of this application. It all started last Saturday and in four days we have something up and running, nice looking and maybe even useful! Altogether the application consists of one static HTML page and two scripts for a total of approx. 350 nice lines of JavaScript/jQuery.

I learned a lot writing this experiment, event delegation with jQuery is not only easy and powerful, but it feels natural. At some point you’ve got the impression to write XBL with this feature. For example there is one event listener for each kind of snippet (one by tab basically). But all of those are listening to the “update” event that can be triggered in three ways:

  • when the content of an input is modified (either by clicking on the scene or typing text)
  • when commented code is clicked
  • when removing the snippet

And then we just do event delegation:

  • once to detect the modification of an input value and triggers the update event for the parent snippet,
  • once to detect the click on commented code and trigger the update event on the parent snippet and modify the color of the code,
  • once to detect the click on the “-” to trigger the update event on the parent snippet and remove it,
  • once to detect the click on the “+” to duplicate the snippet.

And that’s basically it. Create a new tab, add a div with a class “.snippet” in it, then insert an input, a div with a class “.comment”, a link with a class “.remove”, a link with a class “.add” and all those features will work right away. The only thing left to implement is what happens when the snippet is updated. It’s like having behaviours attached to some kind of elements and you compose another element with those building blocks, you give it a specific behaviour and you can in turn duplicate this bigger building block.

Event delegation could be seen as a great advantage for the Open Web as a development platform. Which other technology offers this mechanism out of the box? Although it can be achieved with ActionScript or other technologies, it implies to rethink and reimplement strategies to broadcast events to higher levels… you end up reinventing the DOM!

Just as for the first round of EventSound, I let you find what the last two tabs are for. It should be fairly easy to figure it out.

EventSound, round2

The second iteration of EventSound has been uploaded. It doesn’t make any sound yet (I’m waiting for samples from my brother and my friend Lorenzo) but there are new nice improvements since last time.

EventSound is an application aimed at explaining how events work in the DOM and how to write code relying on events with jQuery. Not only is the interface built with jQuery and jQuery-ui, but the interface itself consists of snippets of JavaScript/jQuery code that can be used to play sounds when events occur on the scene (the left panel). You need to be familiar with the basics of the jQuery syntax to understand those snippets. Fortunately I wrote a quick introduction to jQuery for my final report (see “Dealing with the DOM”).

Illustration of event propagation

You will immediately notice that the bubbling of the events is decomposed on the scene. If you click on an element, you will see the click event being triggered on the element and then all of its ancestors.

Simple listeners

The first thing you can do with the application is to bind event listeners to scene’s elements using the snippets in the bind tab. The only thing you have to do is to fill the space reserved for the CSS selector in a snippet. To do so, there are two possibilities:

  • You look at the source of the scene to search for the classes and ids of its elements. There is no need to use ctrl+U or Firebug for that since I’ve implemented a neo mode: as long as you hold down the control key, you can see the Matrix! Be careful, you cannot dodge bullets.
  • You click in the space reserved for the selector and then click on any element on the scene. Simple, isn’t it?

The neo mode has been implemented just for fun. I read an interesting article by Atul Varma recently about Kids and the Open Web, and I tried to imagine a cool way to introduce non-programmers to the source of a Web page. I came up with this Matrix analogy: the ability to see (and later modify) what makes the Web we live in. Unfortunately it won’t take long before we see a generation of kids who don’t know about the World imagined by the brothers Wachowski.

From here, when you click on an element of the scene, as the bubbling event reaches an element that has a listener attached, the opacity of the listener changes. This is where the “Sound” of “EventSound” should make sense, because you will hear something, in the future, once the samples are ready (guys, if you’re reading me…).

Using those snippets it is also possible to cancel the bubbling of the events in the jQuery way: by returning false. Simply click on the last commented line of code… and pray for this feature to work ; )

Cloning elements and listeners

The second thing you can do in the application is to clone elements of the scene. You need to uncomment the single line of code in the snippet of the “instructions” tab. The next time you will click on an element it will be cloned and inserted gently, as the code suggest: the position and the color of the element is modified and appropriate id and class are set. Don’t take my word on that, enter the Matrix!

There are two comments in a single line of code (resulting in a CSS nightmare), the second one is a true parameter for the clone method which also clones the event listeners. When uncommented, if an event listeners is bound to an element and you clone this element, when a bubbling event reaches the clone, the event will also fire (unless there is a bug in the application, hehe).

Live events

.live() is a function introduced in jQuery 1.3 which brings event delegation to the masses: using this function, instead of binding events to individual elements (and having to clone the listeners when you add an element later), you bind a listener on a higher level and use the bubbling property of events to listen to the events occurring on a lower level.

This time you need to select both the elements on which you want to detect the event, and the higher element that you will use to bind the listener. For that I’m using a special syntax of jQuery where I do not pass only a CSS selector to jQuery, but also a context. Be careful, this syntax only works for event delegation with the upcoming jQuery 1.3.3.

[code lang="js"]
$("<selector>", $("<context>")[0])...
[/code]

Currently, to be successfully set, the context needs to be a DOM element, not a CSS selector, not a jQuery object, simply a DOM element, hence the [0] at the end of my jQuery object. I proposed a patch to be able to get rid of this [0] and thus reduce the number of function calls but it hasn’t been accepted yet.

You can now clone and add elements inside your context without worrying of attaching new listeners, great! And soon or later I hope that my bigger patch will eventually be accepted in jQuery so that you don’t have to worry about performances of event delegation.

And now…

I need your comments as I’m going to reuse this Blog post for my presentation on Saturday. What could be clarified? What could be improved? What did I do wrong? What is good, if any?

In the meantime I’ll work on the last two tabs and start to create my slides.

Busy September

My report was just handed-in, I was starting to feel relieved of all the pressure and the work… when I learned that I was going to give a talk at the jQuery conf in Boston and the MozCamp in Praha (in October actually, but in less than one month from now). I’ll be sponsored by Teesside University for Boston, and for Praha I don’t know but I’ve got good friends living over there, I’m not too worried.

No matter how great those news are, it means that I’ll have to prepare my talks and will thus have less time to work on ToDoSo. It doesn’t even mean that the project is on pause, since I will have to use a presentation software for at least one of these talks, and I’d like to use mine!

In September I’ll also have to move from Middlesbrough to Lyon and start to search for a real job!

You can expect to see new projects for the Open Web on this Blog, I’ll soon introduce the first version of “EventSound: audible jQuery events”.

New mockups and keyboard navigation

I’ve added mockups demonstrating the appearance of the presentation when an embedded one is maximized. Since it is pure HTML, it is not going to be opened in a different window unlike a Flash video, it is rather going to overlay all the page.

todosOverlay, the overlay plugin used on the intro page of ToDoSo, is now an independant project since it tends to become a full featured overlay plugin. It is now possible to use the keyboard for navigation and I got rid of some graphical glitches. I’m quite proud of its look & feel. The idea of using buttons looking like keys  is likely to be used again in ToDoSo since it seems like a great way to make keyboard shortcuts discoverable.

http://www.todoso.org/image/keyLeft.png

Unit testing with QUnit

What does reliability means for a computer program?
It means that it has to behave exactly as its designers expect it to.
One way to achieve it is to test every part of the program with a given input, against the expected results. Those tests should be automated and run regularly during the development process to make sure that no regression is introduced (what works today doesn’t break tomorrow). The rule is to break down the program into simple units and test them separately in order to identify precisely the source of a problem.
This technique is called unit testing and most languages are offering a framework to write, run and produce a visual feedback for the test (green for pass and red for fail).

Consider a function myCamelCase( sentence ) designed to turn any given string into my very own kind of camel case word. To make sure that this function is reliable, we need to be able to assert that, for each potential type of input string, its actual output will match the expected result:

input string expected output
“word” “Word”
“WORD” “Word”
“two words” “TwoWords”
“A single letter” “aSingleLetter”
“this is a letter” “ThisIsAletter”
“remove+special_chars!” “RemoveSpecialChars”
“save 123 numbers” “Save123numbers”
“+ trim me _” “TrimMe”
” + _ ! “ false

Using QUnit

The unit test framework of choice for a jQuery related piece of code is QUnit. It offers a reduced number of assertion methods, allows to group them in tests and modules and display verbose feedback in HTML.

The assertions

QUnit offers three basic assertion functions: ok, equals, same

ok( state, message );

Should be used to assert a Boolean output for a function.

test("'ok' is not only meant to be used for Boolean values", function() {
    ok(123, "123 is ok");
    ok("abc", "Any string is ok");
    ok([], "An empty array is ok");
    ok(!"", "An empty string is not ok");
    ok(!0, "0 is not ok");
    ok(!null, "null is not ok");
    ok(!undefined, "undefined is not ok");
});
equals( actual, expected, message );

Should be used for a comparison assertion.

test("Cases where 'equals' passes for two values not strictly identical", function() {
    equals(1, true, "1 equals true");
    equals([1], true, "An array with a single 1 value equals true");
    equals("1", true, "A string with only the number 1 equals true");
    equals(0, false, "0 equals false");
    equals([0], false, "An array with a single 0 value equals false");
    equals("0", false, "A string with only the number 0 equals false");
    equals("012.345", 12.345, "A number and this number turned into a string are equal");
});
same( actual, expected, message );

Should be used for strict comparison assertion, works recursively on arrays and objects.

test("The actual and expected values have to be strictly identical", function() {
    same([{a: 2}, false, null], [{a: 2}, false, null], "Same is recursive");
});

Writing tests and modules

A test is composed of an homogeneous set of assertions for one unit of the program: In our example, we should write one assertion for each potential type of input string. The first line of a test state the number of assertions that are expected to pass, it’s optional.


test("Test that each type of input string produces the expected output", function() {
    expect(9);

    equals( camelCase("word"), "Word", "First letter of a word is capitalized");
    equals( camelCase("WORD"), "Word", "Other letters are lower-case");
    equals( camelCase("two words"), "TwoWords", "Spaces between two words are removed");
    equals( camelCase("A single letter"), "aSingleLetter", "If the first letter is a single letter, it is turned to lower-case");
    equals( camelCase("this is a letter"), "ThisIsAletter", "If there is a single letter in the middle of a sentence, the following letter is turned to lower-case);
    equals( camelCase("remove+special_chars!"), "RemoveSpecialChars", "Special characters are removed");
    equals( camelCase("save 123 numbers"), "Save123numbers", "Numbers are saved and the following letter is turned to lower-case");
    equals( camelCase("+ trim me _"), "TrimMe", "Trailing spaces are always removed");
    ok( !camelCase(" + _ ! "), "Return false instead of an empty camel case word");
});

QUnit offers the module method to help you visually identify related tests:

module("Camel Case");

Every test following this module will be prefixed by the module name.

synchronizing tests

QUnit offers two other methods to pause the tests for example when an Ajax call was made and the client is waiting for the answer. It is possible to make a pause in the sequence using the stop() and the start() methods.

Making your life easier.

If you happen to write a long batch of tests, you’re likely to realise that you often write similar lines. Being, like the vast majority of us, a lazy developer, you may start copy/paste large amount of code and write additional logic in order to factorise your test code. By doing this way, you might end up chasing bug that are not in the code you are testing, but right in your tests!

On the other hand, there are several ways to write DRY tests safely.

In-line function

If your function accept a second parameter that is not supposed to change the output of the function, it’s possible to create an additional set of test with few lines of code by using an in-line function. Imagine that we add a second Boolean parameter to make the camel case algorithm go faster (I’d love to see such parameter for every algorithm): myCamelCase( sentence, faster). The code would be:

var camelCaseTest = function(faster) {
    expect(9);

    equals( camelCase("word", faster), "Word", "First letter of a word is capitalized");
    equals( camelCase("WORD", faster), "Word", "Other letters are lower-case");
    equals( camelCase("two words", faster), "TwoWords", "Spaces between two words are removed");
    ...
});

test("Test that each type of input string produces slowly the expected output", function() {
    camelCaseTest(false);
});

test("Test that each type of input string produces quickly the expected output", function() {
    camelCaseTest(true);
});

We’ve just written two tests for the same price!

Setup and Teardown

module() also offers a second parameter to register a setup and teardown callback: pieces of code that will be called respectively before and after each test of this module. For example if you want to reset a number of variables that have been modified during the test:

module("Test camel case", {
    teardown: function() {
        a = b = c = d = undefined;
    }
});

Breaking the rule

The main rule in unit testing is to test your units of code separately. The smaller the units, the easier it will be to locate the source of an assertion failure. It is actually possible to break this rule and test multiple units at the same time ONCE those units have been tested enough to appear reliable.

Limit of unit tests

The first limit of unit testing is… the writer himself. If you don’t cause any failure just by writing tests, then I’m afraid you haven’t written enough tests. The second limit of unit tests in JavaScript is the number of configuration and what is actually testable.

This has been explained in details by John Resig in JavaScript Testing Does Not Scale. In brief, there is too much browsers and OS and it’s not possible to use unit testing to check the visual appearance of a page, or the correct behaviour of an animation for example.

Going further

During this post I have written a complete test for myCamelCase(), a method that I haven’t actually implemented. The test that I’ve written can actually be seen as a specification of this method, and I will only be able to claim that its implementation is complete once it successfully pass those tests. This software design method is called Test-driven Development and is one of the best way to write code that is reliable from the very beginning throughout the entire life cycle of the project.

You know everything about cookies, don't you ?

Cookies are used on the Web for almost 15 years now, and despite their numerous flows and the emerging alternatives brought by HTML5, developers still resort to them, mainly for their ease of use and consistent implementation across browsers. For example, as you might have noticed, the background colour of this page changes over the time. To keep the colour up to date across the different pages, the colour value is stored in a cookie. When a user is offered controls to increase or decrease the font sit on a site directly from a Web page, the same mechanism is used.

So far, the best technical documentation about cookies available on the Web was the one found on QuirksMode. It still appears as the number 1 result on google for the query: cookie Javascript. The related page on Wikipedia is a good source of information concerning all the drawbacks and the alternative to cookies. Although there are suitable alternatives when it comes identifying a client from a server, there is no widespread solutions working purely on the client-side (but I urge you to use a modern web browser and the gears plugin to get yourself ready for the next generation of Web applications). Anyway this documentation and the proposed algorithms are quite old, and the purpose of this post is to give the small update it deserves, and it will stick to client side use of cookies.

Writing a cookie

Cookies are just little text files managed by the browser that can be used to store key/value pairs. The maximum size of a cookie file for a given website is 4ko, preventing it to be used for anything else than small strings (a colour code, a font-size, a preferred language are perfectly fine). And this is the basic code to write your first cookie:

var cookie = "fontsize=19px";
document.cookie = cookie;

You just append a string composed of a key and a value separated by an “=” sign to the cookie property of the document.

By default, this cookie will be stored only as long as your browser remains opened and it will be available only on the same path of the same domain. If the address of the page is http://en.wikipedia.org/wiki/HTTP_cookie for example, cookies written from this page will be only available on pages with addresses beginning by en.wikipedia.org/wiki/, everything before the first “/” being the domain, and the rest being the path.

By the way, during the celebration of the 20th anniversary of the World Wide Web, Tim Berners-Lee admitted that he regretted the way Web addresses were constructed, and that the domain should start with the more general elements. Applied to the previous example, this would have lead to: /org/wikipedia/en/wiki/… (bringing the folder/sub-folder metaphor to the Web).

It is possible to change those defaults by adding parameters at the end of your cookie String.

Expiry date

It is possible to specify explicitly the date when the cookie will be trashed by the browser, using the expires parameter and a Date object serialized by the Date.toUTCString() method (and not the deprecated toGMTString one):

var day = new Date(),
expiryDate = "expires=" + day.toUTCString();

In modern browsers, it is alternatively possible to set the max-age of a cookie in seconds, but this parameter is unfortunately unavailable in Internet Explorer (just like so many other things that would make the Web developer’s life easier).

Path and domain

It’s a good practice to set the path to the highest level:

var path = "path=/";

I can’t foresee any serious security issue resulting from this practice (considering that cookies should never be used to store critical data). And on the other hands you are likely to be unable to erase a particular cookie written by a script not specifying any path.

If there is no sub-domains for your website, the domain parameter is not useful. But in the Wikipedia example, the domain should be set as follows to be able to use the cookies across sub-domains:

var domain = "domain=wikipedia.org";

All-together

Writing a cookie with those parameters can be achieved with the following code:

var day = new Date();
document.cookie = "fontsize=19px" +";"+
"expires=" + day.toUTCString() +";"+
"domain=wikipedia.org +";"+
"path=/";

As you can notice, parameters should be separated by a “;”. Note that so far the Date used is a new, unmodified date, which represent the current date. Setting a expiry date to the current date is not gonna make your cookie last long. The solution will be provided in the scripts.

It is not possible to write two cookies at a time.

document.cookie = "fontsize=19px; fontcolor=#0000FF";

This code would actually write only the first key/value pair. You have to write the second cookie on a separated line beginning with document.cookie. Considering the parameters string to add to each cookie, the need of code factorisation is easy to understand.

Reading a cookie

Reading a particular cookie value can be achieved by reading the cookie string of the website and extracting a single value pair using a regular expression based on a key.

result = new RegExp("(?:^|; )" +key+ "=([^;]*)”).exec(document.cookie);
var value = result[1];

Special characters

In order to be able to read and write values potentially containing special characters (such as a “;” that would split your value), the value should be encoded before being written and decoded after being read.

document.cookie = encodeURIComponent("special=abc;def");
result = new RegExp("(?:^|; )" +"special"+ "=([^;]*)”).exec(document.cookie);
var value = decodeURIComponent(result[1]);

Overwrite and delete cookies

To overwrite a cookie simply write a new cookie with the same key.

document.cookie = "key=firstValue";
document.cookie = "key=secondValue";
// When reading "key", you'll find "secondValue"

The best way to erase a cookie is to overwrite it with an empty value and a past expiry date

var day = new Date();
// set the date to yesterday
day.setDate(day.getDate() -1);
document.cookie = "key=" +";"+
"expires=" + day.toUTCString();

The scripts

Using the previous pieces of code, it is possible to create a small cookie library that will handle writing/reading/erasing a cookie with a single function.

function cookieLib(key, value, expiryDay) {
  // If there is not just a key, the function is used to write a cookie
  if(arguments.length >1) {
    // But if the value is null, the function is used to erase a cookie
    if (value === null) {
      value = '';
      expiryDay = -1;
    }
    // If the date parameter is a number,
    // create a date from today + this number of days
    if (typeof expiryDay == "number") {
      var day = new Date();
      day.setDate(day.getDate() + expiryDay);
      expiryDay = day;
    }
    // Create the cookie string
    document.cookie = [
      key , '=' , encodeURIComponent(value),
      '; expires=' , expiryDay.toUTCString(),
      '; path=/'
    ].join("");
  // If there was only a key, the function is used to read a value
  } else if(result = new RegExp("(?:^|; )" +key+ "=([^;]*)")
           .exec(document.cookie))
    return decodeURIComponent(result[1]);
  return false;
};

Remember that cookies are only meant to store string values. If you want to write a number, remember to parse it back to a number after reading it.

I’ve also turned this cookie library in a plugin for the famous jQuery library, check the code of jquery.cookie on github.

Release early ? citizenColor

During the design phase of this blog, I have not only written a cross-browser implementation of border-image, but I’ve also added support of hsl colors to jQuery’s animate function.

citizenColor is not a traditionnal jQuery plugin, it’s more some kind of hack, but it does what it is intended for. It overwrites native jQuery’s animate function and allows you to use hsl colors such as hsl(272, 40%, 70%). But it also allows relative animations, like the ones you can use with dimensions in jQuery: hsl(+=54, +=20%, -=10%)

The only limitation is that you can’t use it on elements with different colors.

You can find more information about HSL colors on wikipedia, on w3c’s CSS3 draft. Check the plugin page in jQuery’s plugin repository and the code in github.

Release often, release early: borderImage.

Today I have commited the version 1.0a1 of jquery.borderImage to it’s github repository.

jquery.borderImage is a partial, cross-browser implementation of CSS3′s borderImage property, as described in the CSS3 draft proposal. It only allows to stretch slices of your image but neither to repeat it nor to round it. Anyway this is already great as it works in firefox2+, opera9+, safari3+ and IE6+!

It uses either the vendor specific implementation of the property (firefox3.1, recent webkit), canvas (firefox2/3, opera) or vml (IE).

There is few bugs in IE6, especially when using images with transparency, and IE8b2 has a major regression preventing to dynamically create vml elements (see related bug on microsoft connect). The only workaround is to use the IE7 meta-tag.

I am working on detailed explanations and “how to“s for the plugin but during this post I will assume you already know how fantastic it is, what is the syntax of the property and that you are familiar with jQuery.

  1. Make sure your element actually has border:
    #element { border: 10px solid transparent; }
  2. Draw your image
  3. Describe how you would have sliced it, with the following syntax:
    $(‘#element’).borderImage(‘url(“border.png”) 20′);

This is exactly the kind of code used to produce the border of this page. It’s not only perfect to create any kind of borders around elements, but it can also emulate rounded-corners, stretching background images as well as tabs and buttons adjusted to their contents.

Their is already built-in features to make use of images with gradient and creation of multi-state tabs/buttons a lot easier. More about that later, I need some rest.

Get the code, test it, report bugs/enhancements, port it to other popular libraries, enjoy!