Christian Heilmann

You are currently browsing the archives for the General category.

Archive for the ‘General’ Category

Yay, Yahoo UK finally looks for some junior developers!

Friday, April 4th, 2008

Ever since I started working for Yahoo in England I’ve been lucky enough to recommend a lot of developers I wanted to work with for ages and get them hired to work here. One thing that annoyed me a bit is that we only took on very skilled and experienced developers. I consider a good team not to be people that are very very good but also a team where new developers can come in and grow with the rest of the team, learn from the others working on real projects and thus having a steady, maintainable, healthy flow of talent coming in replacing those that leave or want to move into other positions.

Now we get the chance to do so. If you are a web developer and you want to work with the very skilled people here in the west-end of London, check out the official job description below and send me a CV. Just comment here and I’ll mail you directly or send a mail to onlinetoolsorg@gmail.com.

Here’s the official job description:

Yahoo! Junior Web Developer – Job Description

As the world’s number one Internet brand Yahoo! delivers news, entertainment, information and fun to over a half billion people every day. Our European web development team, based in London, is seeking standards-savvy front-end developers to work on Europe’s busiest sites.
You should be able to provide examples of your work showing use of progressive enhancement techniques (e.g. unobtrusive scripting), and clear separation of structure, presentation and behaviour layers.

Required Skills

  • Hand-coded (X)HTML, CSS, and JavaScript
  • Solid knowledge of standards-based, accessible, cross-browser web development
  • PHP programming skills
  • User-level experience with BSD/Linux
  • Experience using version control systems such as CVS & Subversion

Desirable Skills

  • Client- and server?side performance optimisation techniques
  • Search engine optimisation
  • Experience in developing web applications with rich client interfaces using AJAX, drag and drop, and other DOM Scripting techniques.
  • Experience with JavaScript libraries, especially the YUI
  • Experience of Web Services (eg REST, SOAP, XML-RPC)
  • Knowledge of web site internationalisation issues and experience developing web sites in multiple languages particularly in Europe.
  • Use of the following technologies: XML/XSLT, Perl, Microformats, JSON, Flash/Flex
  • Experience developing functionality/applications by assembling existing code modules

Responsibilities

You will work closely with Information Architects, Visual Designers, User Researchers, Software Engineers, and Product Managers to ensure that our web based products in Europe provide the best possible experience for our users.

Video captioning made easy with the YouTube JavaScript API

Wednesday, March 12th, 2008

One thing that has been annoying me for ages is that no video player on the web allows you to write comments for a specific time in the video that get displayed as plain text. Viddler allows you to comment at a certain time and it appears in the video, but the benefits of time based captioning both in terms of accessibility and SEO didn’t quite transpire to any video site maintainers yet. Edit: Darn, I hadn’t looked at Viddler for a long time, it actually does this now, well done!

Google just released a JavaScript API for YouTube which makes it dead easy to control a video with JavaScript. You can start, stop and jump to a certain time of the video but more importantly – you have events firing when something happens to the player. This made it easy for me to whip up a proof of concept how time-based captioning might work as an interface. Click the screenshot to see it in action.

Screenshot of video with timed captions created with a small JavaScript

Start the video and hit the pause button to add a new caption. You can delete captions by hitting the x links and you can jump back to the section of the video by clicking the time stamp.

Check the source for how it is done. In order to make this a service, all you need to do is have a backend script that gets all the form fields and store it in a DB.

[tags]accessibility,captioning,video,youtube,api,javascript[/tags]

Step by Step – create feature walkthroughs for your web sites

Sunday, February 17th, 2008

There is a lot of software out there that allow you to create screencasts by recording what is happening on the screen. Some programs even allow you to annotate each step and tell people what needs to be done. The issue with most of this software is that the outcome are large video files and that users cannot interact with the system while the explanations are given.

Step by Step in action - a highlighted page element with an explanation in a panel

Step by Step is a JavaScript solution based on the YUI that allows you to script an annotated walk-trough of your web applications that happens directly on the application and does not require any video editing skills or large downloads.

What do you think?

Five things to do to a script before handing it over to the next developer

Thursday, February 7th, 2008

Let’s face fact folks: not too many developers plan their JavaScripts. Instead we quickly write something that works, and submit it. We come up with variable and function names as we go along and in the end know that we’ll never have to see this little bit of script ever again.

The problems start when we do see our script again, or we get scripts from other developers, that were built the same way. That’s why it is good to keep a few extra steps in mind when it comes to saying “this is done, I can go on”.

Let’s say the job was to add small link to every DIV in a document with the class collapsible that would show and hide the DIV. The first thing to do would be to use a library to get around the issues of cross-browser event handling. Let’s not concentrate on that for the moment but go for oldschool onevent handlers as we’re talking about different things here. Using a module pattern we can create functionality like that with a few lines of code:

collapser = function(){
  var secs = document.getElementsByTagName('div');
  for(var i=0;i<secs.length;i++){
    if(secs[i].className.indexOf('collapsible')!==-1){
      var p = document.createElement('p');
      var a = document.createElement('a');
      a.setAttribute('href','#');
      a.onclick = function(){
        var sec = this.parentNode.nextSibling;
        if(sec.style.display === 'none'){
          sec.style.display = 'block';
          this.firstChild.nodeValue = 'collapse'
        } else {
          sec.style.display = 'none';
          this.firstChild.nodeValue = 'expand'
        }
        return false;
      };
      a.appendChild(document.createTextNode('expand'));
      p.appendChild(a);
      secs[i].style.display = 'none';
      secs[i].parentNode.insertBefore(p,secs[i]);
    }
  }
}();

This is already rather clean (I am sure you’ve seen innerHTML solutions with javascript: links) and unobtrusive, but there are some things that should not be there.

Step 1: Remove look and feel

The first thing to do is not to manipulate the style collection in JavaScript but leave the look and feel to where it belongs: the CSS. This allows for ease of skinning and changing the way of hiding the sections without having to mess around in the JavaScript. We can do this by assigning a CSS class and removing it:

collapser = function(){
  var secs = document.getElementsByTagName('div');
  for(var i=0;i<secs.length;i++){
    if(secs[i].className.indexOf('collapsible')!==-1){
      secs[i].className += ' ' + 'collapsed';
      var p = document.createElement('p');
      var a = document.createElement('a');
      a.setAttribute('href','#');
      a.onclick = function(){
        var sec = this.parentNode.nextSibling;
        if(sec.className.indexOf('collapsed')!==-1){
          sec.className = sec.className.replace(' collapsed','');
          this.firstChild.nodeValue = 'collapse'
        } else {
          sec.className += ' ' + 'collapsed';
          this.firstChild.nodeValue = 'expand'
        }
        return false;
      }
      a.appendChild(document.createTextNode('expand'));
      p.appendChild(a);
      secs[i].parentNode.insertBefore(p,secs[i]);
    }
  }
}();

Step 2: Remove obvious speed issues

There are not many issues in this script, but two things are obvious: the for loop reads out the length attribute of the secs collection on every iteration and we create the same anonymous function for each link to show and hide the section. Caching the length in another variable and creating a named function that gets re-used makes more sense:

collapser = function(){
  var secs = document.getElementsByTagName('div');
  for(var i=0,j=secs.length;i<j;i++){
    if(secs[i].className.indexOf('collapsible')!==-1){
      secs[i].className += ' ' + 'collapsed';
      var p = document.createElement('p');
      var a = document.createElement('a');
      a.setAttribute('href','#');
      a.onclick = toggle;
      a.appendChild(document.createTextNode('expand'));
      p.appendChild(a);
      secs[i].parentNode.insertBefore(p,secs[i]);
    }
  }
  function toggle(){
    var sec = this.parentNode.nextSibling;
    if(sec.className.indexOf('collapsed')!==-1){
      sec.className = sec.className.replace(' collapsed','');
      this.firstChild.nodeValue = 'collapse'
    } else {
      sec.className += ' ' + 'collapsed';
      this.firstChild.nodeValue = 'expand'
    }
    return false;
  }
}();

Step 3: Removing every label and name from the functional code

This makes a lot of sense in terms of maintenance. Of course it is easy to do a quick search + replace when the label names or class names have to change, but it is not really necessary. By moving everything human readable into an own config object you won’t have to hunt through the code and suffer search + replace errors, but instead keep all the changing bits and bobs in one place:

collapser = function(){
  var config = {
    indicatorClass : 'collapsible',
    collapsedClass : 'collapsed',
    collapseLabel : 'collapse',
    expandLabel : 'expand'
  }
  var secs = document.getElementsByTagName('div');
  for(var i=0,j=secs.length;i<j;i++){
    if(secs[i].className.indexOf(config.indicatorClass)!==-1){
      secs[i].className += ' ' + config.collapsedClass;
      var p = document.createElement('p');
      var a = document.createElement('a');
      a.setAttribute('href','#');
      a.onclick = toggle;
      a.appendChild(document.createTextNode(config.expandLabel));
      p.appendChild(a);
      secs[i].parentNode.insertBefore(p,secs[i]);
    }
  }
  function toggle(){
    var sec = this.parentNode.nextSibling;
    if(sec.className.indexOf(config.collapsedClass)!==-1){
      sec.className = sec.className.replace(' ' + config.collapsedClass,'');
      this.firstChild.nodeValue = config.collapseLabel
    } else {
      sec.className += ' ' + config.collapsedClass;
      this.firstChild.nodeValue = config.expandLabel
    }
    return false;
  }
}();

Step 4: Use human-readable variable and method names

This is probably the most useful step when it comes to increasing the maintainability of your code. Sure, during development sec made a lot of sense, but doesn’t section make it easier to grasp what is going on? What about a, and especially when it needs to be changed to a button later on? Will the maintainer rename it to button?

collapser = function(){
  var config = {
    indicatorClass : 'collapsible',
    collapsedClass : 'collapsed',
    collapseLabel : 'collapse',
    expandLabel : 'expand'
  }
  var sections = document.getElementsByTagName('div');
  for(var i=0,j=sections.length;i<j;i++){
    if(sections[i].className.indexOf(config.indicatorClass) !== -1){
      sections[i].className += ' ' + config.collapsedClass;
      var paragraph = document.createElement('p');
      var trigger = document.createElement('a');
      trigger.setAttribute('href','#');
      trigger.onclick = toggleSection;
      trigger.appendChild(document.createTextNode(config.expandLabel));
      paragraph.appendChild(trigger);
      sections[i].parentNode.insertBefore(paragraph,sections[i]);
    }
  }
  function toggleSection(){
    var section = this.parentNode.nextSibling;
    if(section.className.indexOf(config.collapsedClass) !== -1){
      section.className = section.className.replace(' ' + config.collapsedClass,'');
      this.firstChild.nodeValue = config.collapseLabel
    } else {
      section.className += ' ' + config.collapsedClass;
      this.firstChild.nodeValue = config.expandLabel
    }
    return false;
  }
}();

Step 5: Comment, sign and possibly eliminate the last remaining clash with other scripts

The last step is to add comments where they are really needed, give your name and date (so people can ask questions and know when this was done), and to be really safe we can even get rid of the name of the script and keep it an anonymous pattern.

//  Collapse and expand section of the page with a certain class
//  written by Christian Heilmann, 07/01/08
(function(){
 
  // Configuration, change CSS class names and labels here
  var config = {
    indicatorClass : 'collapsible',
    collapsedClass : 'collapsed',
    collapseLabel : 'collapse',
    expandLabel : 'expand'
  }
 
  var sections = document.getElementsByTagName('div');
  for(var i=0,j=sections.length;i<j;i++){
    if(sections[i].className.indexOf(config.indicatorClass)!==-1){
      sections[i].className += ' ' + config.collapsedClass;
      var paragraph = document.createElement('p');
      var triggerLink = document.createElement('a');
      triggerLink.setAttribute('href','#');
      triggerLink.onclick = toggleSection;
      triggerLink.appendChild(document.createTextNode(config.expandLabel));
      paragraph.appendChild(triggerLink);
      sections[i].parentNode.insertBefore(paragraph,sections[i]);
    }
  }
  function toggleSection(){
    var section = this.parentNode.nextSibling;
    if(section.className.indexOf(config.collapsedClass)!==-1){
      section.className = section.className.replace(' ' + config.collapsedClass,'');
      this.firstChild.nodeValue = config.collapseLabel
    } else {
      section.className += ' ' + config.collapsedClass;
      this.firstChild.nodeValue = config.expandLabel
    }
    return false;
  }
})();

All very obvious things, and I am sure we’ve all done them before, but let’s be honest: how often do we forget them and how often do you have to alter code where it’d have been nice if someone had taken these steps?

Code tutorials for lazy people with Ajax Code Display

Monday, January 28th, 2008

Currently I am writing a lot of tutorials for an online self-training course about web standards and I ran into the annoyance of having to maintain example code in two places: the code itself and the HTML document with the explanations. Therefore I took jQuery and wrote a small script that automatically turns links to HTML code examples with HTML entities and line numbers. You can define which lines to display, which lines should be highlighted and you can add a live preview in an IFRAME when the link is clicked.

[tags]annoyances,codehighlighting,code,tutorials,javascript,ajax[/tags]