Christian Heilmann

Author Archive

YUI 2.4.0 is out – CSS Selector engine, JSON support, dynamic CSS/script getter and lots more

Wednesday, December 5th, 2007

It is quite cool to see that your feedback is being implemented in something as big as the YUI. With every release the team excels itself building new components but also fixing and changing the existing ones.

Part of my job is to test the YUI for the European market (as we by default develop in 5 languages and encounter totally different issues) and in Asia (oh well, obvious that there are differences) and I am happy to say that all the problems we found got fixed and several of our suggestions implemented in this release.

While a lot of this is under the hood you can also see some new components in the 2.4.0 release:

  • Probably the most anticipated step is YUI getting a jQuery style CSS selector engine which allows you to quickly access the document without having how to traverse the Dom with native functions.
  • For those who need to work with numerical data a lot, the YUI now has a Flash charts component which allows you to create fancy pies and graphs easy
  • The new get utility is not the same as YAHOO.Dom.Get() but allows you to load scripts and CSS on demand after the page has been rendered by creating new nodes and having control over what has been loaded. This is quite handy in terms of page performances and I waxed lyrical over that in the past.
  • Those who love to take your Script to the garage and give them an intensive test-run will love the new Profiler which profiles JS in a browser environment
  • And last but not least we finally proclaimed our undying love to the JSON format by adding a new JSON component that allows you to stringify and validate JSON you retrieve either with dynamic script nodes or AJAX.

Again, under the hood, there are a lot of changes you cannot see but result in much better performance, especially in the DragDrop and the Rich Text Editor Control.

[tags]YUI,libraries,upgrade,news,json,selectorengine,flashcharts,charting,profiling[/tags]

It is official, I am an ELF

Thursday, November 29th, 2007

No, I am not talking about last year’s elf yourself viral pest, but about being an Excellent Learning Facilitator or ELF. This is a training for trainers which turns a lot of your beliefs about teaching and training inside out and by doing so makes you a much better trainer. I normally don’t talk about personal stuff here, so sorry if you expected another JS posts, but I really wanted to talk about this as I think a lot more people should go for it and I am proud to have pulled it off.

The ELF course is held by the UK company Matrix42 and has a lot of cool benefits:

The ELF courses are mapped to the National Occupational Standards for Learning and Development
The Bronze assessment is accepted as evidence of competence for professional membership of the Institute of IT training, as recognised by OCR at Level 3 equivalence on the National Qualifications framework
It is also one of a few qualifications to be endorsed by the British Computer Society (BSC) against their ACTT qualification which is a level 4 qualification on the National Qualifications framework

Beats me what a lot of that means but what I took away from the course is basically that it:

  • teaches you how to make learners find solutions themselves instead of listening to you (thus remembering a lot more)
  • makes you aware of the different kind of learners and how information should be conveyed to them to be easy to take in and to stick
  • teaches you to plan a full learning event and sessions in those to be as useful as possible for the participants
  • makes you aware that you can teach really complex technical courses without computers or monkeying about in front of a powerpoint.

My personal win was to get away from the speaker that I normally am and switch to trainer when I need to. Not everybody who gives public speeches and writes books is also a good trainer, actually it is quite a step from one to the other and you need to set a massive switch in your head.

In my case I messed up my first practical test exactly for that reason: I was more of a presenter than a trainer which made me rush participants. Silence is not a problem and if neither you nor participants in a training talk this does not mean nothing happens. In the heads of the participants there is a lot going on. I changed my pace and stance and voila, the second time I passed with flying colours.

Anyways, I am proud to be an ELF, and I will try my best to use this new approach and ideas as soon as I can bag another workshop or longer training session.

[tags]training,trainer,ELF,excellent learning facilitator,teaching,training,learning,BCS[/tags]

Planning JavaScript for Larger Teams – Draft & Handout version

Wednesday, November 28th, 2007

I just found my original draft of my @mediaAjax presentation. I discarded it cause it was way too long for an hour talk and I didn’t know what do ditch:

Hope it is of use somehow.

[tags]javascript,mistakes,development,bestpractice,webdevtrick,teamwork[/tags]

JavaScript shortcut notations that shouldn’t be black magic to the “average developer”

Tuesday, November 27th, 2007

When publishing articles about JavaScript development you run into many rules set by publishers and editors. This is a great thing as it keeps us authors on our toes and makes us understand more about how much work successful publishing really is. However, it can also be terribly annoying, especially when older idioms just stick. One of them is that “the average developer” does not quite understand JavaScript shortcut notations.

Now, if you are “the average developer”, please give me 5 minutes of your time to get through the following, you’ll understand a lot more code out there and also spend a lot less time writing your own scripts.

Array shortcut notation – It is hip to be square

The first bugbear I have are arrays. These are terribly useful and omnipresent in JavaScript and still I find people who write convoluted things like:

var links = new Array();
links[0] = 'http://cuteoverload.com';
links[1] = 'http://icanhascheezburger.com';
links[2] = 'http://pencilsatdawn.wordpress.com';
links[3] = 'http://apelad.blogspot.com';
// ... ad nauseam ...

This is convoluted (you have to repeat the array name for every item) and also tricky to maintain. When you change the order (granted the order is of importance) you need to change the number, too. It is not necessary, as the numbering is done automatically for you. All you need to do is use the square brackets:

var links = [
  'http://cuteoverload.com',
  'http://icanhascheezburger.com',
  'http://pencilsatdawn.wordpress.com',
  'http://apelad.blogspot.com' // <-- last one, NO COMMA!
];

This makes it more obvious from a visual point of view, too. The indentation makes it easy to spy where the array begins and where it ends. Much less line noise to take in.

Notice that you need to separate each item with a comma, but make sure you don’t have a trailing comma at the last item. You can even nest arrays that way:

var links = [
  'http://cuteoverload.com',
  'http://icanhascheezburger.com',
  [100,200,20,'foo'],
  'http://pencilsatdawn.wordpress.com',
  'http://apelad.blogspot.com' // <-- last one, NO COMMA!
];

On that note, here’s another trick: to add a new item to arrays, you can either use the push() method or use the length property:

links.push('http://dailypuppy.com');
links[links.length] = 'http://bigeyedeer.wordpress.com';

Associative Arrays – OMG! Ponies!

One myth that keeps sticking is that JavaScript has a magical thing called associative arrays. These allow you to not just number the items but give them names instead! You find examples like:

var links = new Array();
links['Cute Overload'] = 'http://cuteoverload.com';
links['I can has cheeseburger'] = 'http://icanhascheezburger.com';
links['Pencils at dawn'] = 'http://pencilsatdawn.wordpress.com';
links['Hobotopia'] = 'http://apelad.blogspot.com';

This is treachery to the highest degree. It is a confusing JavaScript trait, as what you created here is not really an array, but an object. Want proof? – Do an alert(typeof links) or try alert(links[1]).

Object shortcut (literal) notation – getting curly.

So called associative arrays are actually objects, which means you will also find other scripts that took the earlier example serious and use the following instead:

var links = new Object();
links['Cute Overload'] = 'http://cuteoverload.com';
links['I can has cheeseburger'] = 'http://icanhascheezburger.com';
links['Pencils at dawn'] = 'http://pencilsatdawn.wordpress.com';
links['Hobotopia'] = 'http://apelad.blogspot.com';

Again we have far too much repetition. For objects, you have the Object Literal Notation as a shortcut, which basically is using curly braces:

var links = {
  'Cute Overload' : 'http://cuteoverload.com',
  'I can has cheeseburger' : 'http://icanhascheezburger.com',
  'Pencils at dawn' : 'http://pencilsatdawn.wordpress.com',
  'Hobotopia' : 'http://apelad.blogspot.com' // <-- again, no comma!
}

The semicolons get replaced by commatacommas (Happy, Stuart?) (except for the last one which you need to omit) and the equal signs become colons. If the properties (the things to the left of the colon) don’t have any spaces in them, you can even get rid of the quotes:

var chris = {
  hair : 'red',
  age : 32,
  city : 'London'
}

You can access the properties with object.property when they don’t have any spaces or with object[property] when they have spaces. For example:

var links = {
  'Cute Overload' : 'http://cuteoverload.com',
  'I can has cheeseburger' : 'http://icanhascheezburger.com',
  'Pencils at dawn' : 'http://pencilsatdawn.wordpress.com',
  'Hobotopia' : 'http://apelad.blogspot.com' // <-- again, no comma!
};
alert(links['I can has cheeseburger']);
alert(links.Hobotopia);

Simple if-else statements – ask and define with the ternary notation

You can shorten simple if statements dramatically. With simple I mean an if statement that assigns one of two values like this:

  var YUIguy;
  if(city === 'London'){
    YUIguy = 'Chris';
  } else {
    YUIguy = 'Eric';
  };

Again, a lot of repetition there. The ternary notation works around that problem:

var YUIguy = city === 'London' ? 'Chris' : 'Eric';

A lot of equal signs there. Maybe some parenthesis will make it clearer:

var YUIguy = (city === 'London') ? 'Chris' : 'Eric';

What’s going on here? You define the variable YUIguy and assign it a value. Then you have a statement, in this case the comparison of the variable city and if it equals to the string London (=== tests for both the value and the type, much safer than ==).

Then you ask the question if that is true or not by using the question mark. The option on the left of the colon is the answer to the question when the condition was met and the option on the right of the colon is the answer when the condition was not met. Any condition that could be true or false can go inside the parenthesis.

var direction = (x < max) ? 'left' : 'right';

Offering a fallback option with the default operator

The last thing I wanted to quickly talk about is the double pipe (||) default operator. This one is terribly useful when you want to make sure that something is set with a default value. The following construct is something that should not show up any longer:

  var section = document.getElementById('special');
  if(!section){
    section = document.getElementById('main');
  }

Again, useless repetition, as the same can be written as:

  var section = document.getElementById('special') || document.getElementById('main');

If the first is not defined, the second gets assigned as a value to section.

Thanks for your time!

I hope this helped “the average developer” to understand how you can make your JS a lot shorter without really cutting down on readability. If you want more detailed information about all these goodies, check out Douglas Crockford’s articles on the matter:

Transcript of the Paris Web 2007 workshop on Unobtrusive JavaScript

Friday, November 23rd, 2007

This is a step-by-step description accompanied by code examples of the “Unobtrusive JavaScript” workshop at Paris Web 2007 in Paris, France.

You can download all the files used in this here: parisweb2007_workshop.zip

At the start of the workshop I gave two promises:

  • Participants who know JavaScript will find out that they do often write far too much code
  • Participants who don’t know JavaScript will learn how they can prepare and help JS developers building unobtrusive products.

First Step: Analyzing the task and the HTML

We started with an HTML template (01_template.html) and analyzing it. We pointed out that the template is not optimal as it contains embedded CSS which in a live product should be in a separate CSS file. We also pointed out that it is OK to start like this, as it keeps maintenance easier.

The template is a list of links (a table of contents) pointing to a group of headings further down the page. The idea is that visitors can click the table of contents(TOC) and move down the document. “Back to top” links allow them to go back up again. The TOC has an ID of “toc”, the back links a class of “back”.

We have a block of CSS in the head of the document and a script block at the end of the body. Having a script block at the end of the body makes sure that all the HTML we want to reach in our JavaScript is available when it gets executed.

The task we wanted to achieve in the workshop was to turn this template into a dynamic interface that hides all the content and only shows the one connected to the link in the TOC when a visitor clicks it.

Second Step: Knowing browser issues and using them to our advantage

The problem we had was to know which section to show and hide when the links are clicked. The logical connection was easy: every link inside the TOC has an href attribute that points to an ID in the heading it connects to. We can use this in our script. The problem was that we have no idea about the content that follows the heading. We needed a way to make sure we can group all the elements we need to hide into an element.

The thing that helped us there is a lesser known Internet Explorer bug if you use your keyboard to tab through links pointing to anchors inside the page the page does jump there, but the keyboard focus does not move with it. The easiest workaround is to nest the anchor element inside an element that hasLayout. In our case we added DIV elements around each heading and content section and set their widths to 100% (02_iefix.html).

Third Step: The script

We had all the HTML we needed and the page already did what we wanted to. Now we started thinking about how to override the default behaviour and make it work for us. The main changes we wanted to do was:

  • Hide all the content sections
  • Hide the back links as we don’t need them when we show only one content section
  • Show the content section connected with the link in the TOC when it is clicked

We discussed the different possibilities to do that (looping through the DOM, getting all child elements of the DIV and set their style.display value to ‘none’ and so on). I then proposed that the easiest way by far is to write a simple JavaScript that adds a class to the body of the document when JS is available and define CSS that hides the necessary elements. That way we can easily let CSS do all the heavy DOM traversing and we offer designers a hook to style the non-JavaScript and the JavaScript version differently.

The JavaScript:


document.body.className = 'js';

The CSS:


/* Scripting dependent styles */

body.js #toc{
float:left;
width:20%;
margin-right:5%;
}
body.js div{
float:right;
width:70%;
}
body.js div,body.js .back{
position:absolute;
left:-9999px;
}

We then found out that this would not be safe, as there might already be a class applied to the body element, which means we need to check for that and append the new class if needed.


document.body.className = (document.body.className +' '||'') + 'js';

This made sure all the necessary elements are initially hidden (03_hideandstyle.html). We also pointed out that we use the off-left technique instead of hiding the content with display:none as that makes sure it is still accessible for screen readers.

Event Handling

This is as far as we got with JavaScript and the DOM. Now we needed to find out how we can show the section we want to show when the appropriate link is clicked. We need to use event handling for that and apply event listeners to the different elements. Originally the participants considered adding a click event listener to every event but after going through the idea of event handling using human guinea pigs (video on dailymotion) we realized that there is only need to apply a single event handler to the TOC and use event delegation to do the rest.

We used the W3C approach to event handling, which resulted in the following code (04_events.html):

CSS:


body.js div.show{
position:relative;
left:0;
}

JavaScript:


document.body.className = (document.body.className +' '||'') + 'js';
var toc = document.getElementById('toc');
if(toc){
function toggle(e){
var t = e.target;
if(t.nodeName.toLowerCase() = 'a'){
var sectionID = t.getAttribute('href').split('#')[1];
var section = document.getElementById(sectionID);
if(section){
section.parentNode.className = 'show';
}
}
};
toc.addEventListener('click',toggle,false);
};

This made sure we can actually show the elements when we click on them but it also had the problem that we didn’t hide the previously shown section. For this, we needed to store the information and reset it when toggle() was called. I mentioned as a tip that it is always a good plan to use an object to store state of an interface as that means you can keep as many properties as you want without needing to introduce more variables. The change was only a few lines storing the section in a current object and removing the class when there is already one set (05_keepingstate.html):


document.body.className = (document.body.className +' '||'') + 'js';
var toc = document.getElementById('toc');
if(toc){
var current = {};
function toggle(e){
var t = e.target;
if(t.nodeName.toLowerCase() = ‘a’){
if(current.section){
current.section.className = ‘’;
};
var sectionID = t.getAttribute(‘href’).split(‘#’)[1];
var section = document.getElementById(sectionID);
if(section){
section.parentNode.className = ‘show’;
current.section = section.parentNode;
};
};
};
toc.addEventListener(‘click’,toggle,false);
};

This was it in terms of (very basic) functionality for the course (we only had an hour) and the last few things to remember was to make this code work with other scripts and how to make it easier to maintain.

Namespacing the script.

The easiest trick to make the script work well with others is to use the module pattern and nest it in a variable assigned to an anonymous function (06_namespaced.html):


var sectionCollapse = function(){
document.body.className = (document.body.className +' '||'') + 'js';
var toc = document.getElementById('toc');
if(toc){
var current = {};
function toggle(e){
var t = e.target;
if(t.nodeName.toLowerCase() = 'a'){
if(current.section){
current.section.className = '';
};
var sectionID = t.getAttribute('href').split('#')[1];
var section = document.getElementById(sectionID);
if(section){
section.parentNode.className = 'show';
current.section = section.parentNode;
};
};
};
toc.addEventListener('click',toggle,false);
};
}();

Making maintenance easier

In order to make it easy for the next developer taking over from us, we then agreed to not have any ID or class names in the script itself but move them out to an own config object. The last step we were able to cover was to move the CSS and JavaScript out into own documents and our example was done (07_final.html):


var sectionCollapse = function(){

// start configuration - edit here
var config = {
JSavailableClass:'js',
showClass:'show',
tocID:'toc'
}
// end configuration

document.body.className = (document.body.className +' '||'') + config.JSavailableClass;
var toc = document.getElementById(config.tocID);
if(toc){
var current = {};
function toggle(e){
var t = e.target;
if(t.nodeName.toLowerCase() = ‘a’){
if(current.section){
current.section.className = ‘’;
};
var sectionID = t.getAttribute(‘href’).split(‘#’)[1];
var section = document.getElementById(sectionID);
if(section){
section.parentNode.className =  config.showClass;
current.section = section.parentNode;
};
};
};
toc.addEventListener(‘click’,toggle,false);
};
}();

Conclusion

I hope that the participants got an insight how you can make CSS and JavaScript can work together, and learnt some ways to make their JavaScript easier to maintain. I personally wanted most of all people to start analyzing problems before starting the code :)

[tags]parisweb,parisweb2007,workshop,unobtrusive javascript,unobtrusive,coursematerial[/tags]