Ups and downs

September 27th, 2009

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 4: now with sounds!

September 10th, 2009

I’ve finally found some samples and I didn’t had to search really far: I took sounds from World of Goo.

So go test the latest version of SoundEvents. You need a browser compatible with HTML5’s audio tag, preferably Firefox. Chrome introduces a delay before playing the sound even though it is cached when you open the page. And I haven’t tested Safari.

The only problem is that I cannot redistribute those sounds since they are not liberally licensed. I tried to use the sounds of Wormux as an alternative but for some reason the sound is not playing in my application even though they do play when I drag & drop them in the browser. It’s too late now, I’ll search for alternatives tomorrow.

Do you know any Open game with interesting samples?

EventSound, round 3

September 9th, 2009

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

September 7th, 2009

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.

$("<selector>", $("<context>")[0])...

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.

EventSound, round 1

September 6th, 2009

I’m so happy to be done with my report that I don’t even want to bother about explaining anything about my new projects ; )

This is the best I came up with:
There is now a quite usable version of EventSound online. It is not finished but it shouldn’t be too buggy, it doesn’t make any sound but it does look nice, and I won’t even tell what it actually does. One beer to the one who finds what it is for.

I hope to have the sound and the last three tabs working by Tuesday.

Busy September

September 3rd, 2009

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”.

And now…

August 27th, 2009

Let’s get some rest.

Improvements to ActiveJS

August 27th, 2009

The ability to create relations between the different objects of the application (a user has many articles, a section has one HTML content) was believed to be implemented in ActiveJS as it is implemented in Ruby on Rails.

An attempt to define the relations between articles and sections was implemented as follows:

Section = ActiveRecord.create('sections', {});

Article = ActiveRecord.create('articles', {
	created_at: '',
	updated_at: ''
});

Section.belongsTo( Article );

And when relations were to be set between instances of the User and Article class:

article1 = Article.create({
	created_at: now(),
	updated_at: now()
});
section1 = Section.create({ });
section1.createArticle( article1 );

It appeared however that those two assumptions were false. ActiveJS in its official implementation requires the following to be written:

Section = ActiveRecord.create('sections', {
	article_id: ''
});

Article = ActiveRecord.create('articles', {
	created_at: '',
	updated_at: ''
});
Section.belongsTo( Article );
section1 = Section.create({ });
section1.createArticle({
	created_at: now(),
	updated_at: now()
});

The fact that it was not possible to use pre-existing objects when creating a relation between two objects penalising problem, as it was actually impossible in the application to create a presentation once all of its slides were created.

Instead of working around those two issues, it was decided to spend some time implementing the missing features. The first two snippets of code can now successfully be used with the improved version of ActiveJS and additional unit tests were added to the existing one to ensure that those change will still work with future versions of the framework.

Improvements to jQuery

August 26th, 2009

As advised in Yahoo’s best practices, an extensive use of event delegation has been made in ToDoSo while access to the DOM have been reduced as much as possible.

However, upon careful inspection of jQuery’s internals, it appears that those two rules are contradictory with this library. Indeed, in the case of a document composed of nested <div>s of different colours such as illustrated in the following figures:

Structure of the document

actual document

If event delegation is to be used at the div.grey level to change a class of a div.red to .yellow, the following code would be used:

$("div.grey").find("div.red").live("click", function( event ) {
// event.currentTarget is the clicked red.div
$(event.currentTarget).removeClass("red").addClass("yellow");
});

In the current implementation of jQuery, this is what happens when div.white is clicked, before the class can be changed:

  1. the event is captured at the div.grey level, but the event target is the clicked div.white
    1. the DOM is accessed to retrieve all div.red inside the div.grey
    2. a function loops through all the retrieved div.red to check if the event target is one of them, and fails.
  2. the ancestor of the event target (the top left div.black) needs to be checked in the same way
    1. the DOM is accessed to retrieve all div.red
    2. a function loops through them, searching for the parent div.black, without success
  3. finally, the ancestor of the div.black (the top left div.red)  is checked
    1. once again the DOM is accessed to retrieve all div.red
    2. a function loops through them and the top left div.red is one of them
  4. as of jQuery 1.3.3, the currentTarget property of the event object is set to the found div.red

The complexity of this algorithm is O(n * m) or 0(n²):

  • n being the number of level of elements between the initial event target and the element to which the listener is bound,
  • m being the number of elements corresponding to the delegation selector, “div.red” in this case.

However, it appears that, in the case of a delegation selector of the form “div”, “.red” or “div.red”, it is unnecessary to access the DOM and loop through the elements corresponding selector. Instead, it is possible to:

  1. check if the event target is a div and has a class “red”: its class is white
  2. check if the ancestor is a div and has a class “red”: its class is black
  3. check if the ancestor’s ancestor is a div and has a class “red”: the currentTarget has been found.

Although checking the class and type of an element requires an access to the DOM, it does not require to retrieve elements from the document, which is far more expensive, and effectively reduces the complexity of the algorithm to 0(n).

A new implementation of the jQuery.filter() function (used by .live()) yielded the following results for the previous document:

Action Original implementation New implementation
function calls exec. time function calls exec. time
Click in div.grey 75 2.2ms 33 0.8ms
Click in a div.red 46 1.4ms 24 0.6ms
Click in a div.black 78 2.3ms 34 0.8ms
Click in a div.white 94 2.7ms 39 0.9ms

Those results make the reduced complexity obvious and show a decent performance improvement. The test has been run on a simple document with a high end machine and the latest version of Firefox (3.5). The performance gain is expected to be significant when run on less powerful hardware with older browser.

Moreover, click events occur rather rarely on the document, but mouseover, mouseout and mousemove events occur much more frequently as the user moves the cursor within a page. Dealing with those event is far more efficient with the new implementation, as long as the delegation selector conforms the previously specified pattern. This limited choice of “efficient selectors” proved to be sufficient when developing ToDoSo.

An advantage of improving the jQuery.filter() function rather than the .live() function directly is that it benefits all function of jQuery using the former: .filter(), .is(), .hasClass(), .closest() and .live().

designing ToDoSo

August 26th, 2009

The navigation in ToDoSo will occur on three different levels:

  • The folder level allows the user to view all the presentations that he/she has created in the application. Although there are no folders in ToDoSo, this term is used in analogy with the file system explorer that is to be found on the desktop.
  • The presentation level allows the user to navigate within a presentation, through the slides that it is composed of.
  • The slide level is the one at which the player and the editor of the presentation operate: the slide is displayed in full-screen.

Those levels are detailed in a different order to clarify the rational behind their design.

Presentation level

In current presentation software, navigating in a set of slides generally requires to scroll through the thumbnail view. In desktop applications, additional ways of navigation might be provided but they are neither the default choice nor obvious alternatives.

This way of navigation is obviously convenient to navigate to the previous and next slides, however, this could also be achieved by providing two buttons labelled as “previous” and “next”. What is the real value of the thumbnails for those two slides when they could be accessed in full screen by a simple click? The visual consistency of the presentation should be guaranteed by the “theme” and “layout” features of the application, it does not require for the user to remember (or see) how the other slides look like. Likewise, the thumbnail is generally too small to have a readable content. A slide has to be in the main view for its content to be readable.

The usefulness of the thumbnail view resides in the possibility for the user to quickly search for a particular slide, which is likely to be easily identified visually. It requires, that the user points at the thumbnail view with its mouse, then scroll until he/she finds the slide and finally click on it. If it is a long presentation, this can be a rather long process with those slides stacked on top of the others in a single dimension.

The solution that will be explored in ToDoSo is to remove the thumbnail view from the interface and to create a zoomable bi-dimensional map of the slides.

When a presentation is opened, this map is displayed to the user who can simply double-click on a slide or point at it ans use the mouse’s wheel to zoom in. Once a slide is zoomed in, controls appear to let the user access directly the next and previous slides, and to zoom out to search for a particular slide in the map.

This way of navigation can be compared to the one used in Google Maps and which is generaly referred to as Zooming interface (Cockburn et al., 2008) or Zooming Interface Paradigm (ZIP) (Raskin, 2000).

Folder level

It would be tempting to apply the Zooming Interface concept to the folder level to provide a coherent way of navigation throughout the application. However, this would require to display all the slides of all presentations at this level which in turn requires to have very tiny thumbnails to be able to fit multiple presentations on the same view. Instead, it has been decided to present only the first slide of a presentation at this level.

A visual clue should be provided to differentiate this level from the presentation level in addition to the different menus and toolbars, such as a a different background colour.

To switch to the presentation level, the user would simply double click on a presentation to reveal its full content while other presentations are hidden.

Slide level – the player

The player is designed to let the user access to the next and previous slides as well as playing the possible animations of the slide and switch back to the presentation level.

In this mockup of the player, the buttons have been given the look of keys. This emphasise the possibility to use the keyboard as an alternative to control the display of the presentation. Indeed, when the presentation is played during a lecture, the buttons should be hidden and a keyboard or a remote control could be used instead of the mouse. Those buttons actually fade out when the pointer of the mouse is moved away from the slides.

The button with the bigger arrow corresponds to the “play” button: the main control that either triggers an animation or the display of the following slide if all the animations have been played.

Slide level – the editor

This part requires further research before a valuable design could be produced.