Christian Heilmann

You are currently browsing the archives for the General category.

Archive for the ‘General’ Category

Providing script configuration in-line and programatically

Friday, May 23rd, 2008

One of the things I’ve been quite consistent and pushy about when writing code is to separate out all the things that should be customizable into an own configuration object.

A normal script I write these days would look like this:

var module = function(){
  // configuration, change things here
  var config = {
    CSS:{
     classes:{
       hover:'hover',
       active:'current',
       jsEnabled:'js'
     },
     ids:{
       container:'maincontainer'
     } 
    },
    timeout:2000,
    userID:'chrisheilmann'
  };
 
  // start of main code 
  function init(){
 
  };
  // ... more methods and other code ...
 
  // make init a public method
  return {
    init:init
  };
}();
module.init();

The benefits should be quite obvious:

  • Implementers don’t need to hunt through the whole script to find what they need to change
  • There’s a clear separation of “change what you need to change here” and “only touch this if you know what you are doing” – allowing more developers to use your code.
  • You show implementers in a single location where you overlap with other development layers, for example by defining IDs of HTML elements you use and CSS class names you apply to generated elements.
  • Having all the strings in one place makes for easier localisation and also speeds up the script (IE6 creates a string object for every string – even in conditions inside loops for example!)

I was quite OK with that until Ara Pehlivanian asked for an option to programatically override the configuration files, much like the YUI allows you to do with the YAHOO.util.Config utility. He is right of course, sometimes you’d want to change the config and re-initiate the script (the other way of course is to write a module with instantiation).

The easiest way to approach that is to make the config object public:

var module = function(){
  // configuration, change things here
  var config = {
    CSS:{
     classes:{
       hover:'hover',
       active:'current',
       jsEnabled:'js'
     },
     ids:{
       container:'maincontainer'
     } 
    },
    timeout:2000,
    userID:'chrisheilmann'
  };
 
  // start of main code 
  function init(){
 
  };
  // ... more methods and other code ...
 
  // make init and config a public method
  return {
    init:init,
    config:config
  };
}();

That way you can override the properties you need before you call init():

module.config.CSS.ids.container = 'header';
module.config.userID = 'alanwhite';  
module.init();

However, Ara thought it more convenient to be able to provide an object as a parameter to init() that overrides certain properties. You can do that by checking for this object, looping through its properties and recursively trying to find and match a property of the config object:

var module = function(){
  // configuration, change things here
  var config = {
    CSS:{
     classes:{
       hover:'hover',
       active:'current',
       jsEnabled:'js'
     },
     ids:{
       container:'maincontainer'
     } 
    },
    timeout:2000,
    userID:'chrisheilmann'
  };
 
  // start of main code 
  function init(){
    // check if the first argument is an object
    var a = arguments;
    if(isObj(a[ 0 ])){
      var cfg = a[ 0 ];
 
      // loop through arguments and alter the configuration
      for(var i in cfg){
        setConfig(config,i,cfg[i]);
      }
    }
  };
 
  function setConfig(o,p,v){
    // loop through all the properties of he object
    for(var i in o){
      // when the value is an object call this function recursively
      if(isObj(o[i])){
        setConfig(o[i],p,v);
 
      // otherwise compare properties and set their value accordingly
      } else {
        if(i === p){o[p] = v;};
      }
    }
  };
 
  // tests if a parameter is an object (and not an array)
  function isObj(o){
    return (typeof o === 'object' && typeof o.splice !== 'function');
  }
  // ... more methods and other code ...
  // make init a public method
  return {
    init:init
  };
}();
module.init({
  container:'header',
  'timeout':1000
});

This works swimmingly when all the configuration properties are unique. It fails though when a property in a nested object has the same name as another one on a higher level. In order to allow for this, we can offer the option to send a string with the path to the property as the property name. Then it gets messy as we need to eval() that string and make sure we return the value in the right format. All in all it could look like this:

var module = function(){
  // configuration, change things here
  var config = {
    CSS:{
     classes:{
       hover:'hover',
       active:'current',
       jsEnabled:'js'
     },
     ids:{
       container:'maincontainer'
     } 
    },
    timeout:2000,
    userID:'chrisheilmann'
  };
 
  // start of main code 
  function init(){
    if(isObj(arguments[ 0 ])){
      var cfg = arguments[ 0 ];
      for(var i in cfg){
        if(i.indexOf('.')!== -1){
          var str = '["' + i.replace(/\./g,'"]["') + '"]';
          var val = getValue(cfg[i]);
          eval('config' + str + '=' + val);
        } else {
          setConfig(config,i,cfg[i]);
        }
      }
    }
  };
  function setConfig(o,p,v){
    for(var i in o){
      if(isObj(o[i])){
        setConfig(o[i],p,v);
      } else {
        if(i === p){o[p] = v;};
      }
    }
  };
  function isObj(o){
    return (typeof o === 'object' && typeof o.splice !== 'function');
  };
  function getValue(v){
    switch(typeof v){
      case 'string':
        return "'" + v + "'";
      break;
      case 'number':
        return v;
      break;
      case 'object':
        if(typeof v.splice === 'function'){
          return '[' + v + ']';
        } else {
          return '{' + v + '}';
        }
      break;
      case NaN:
      break;
    };
  };
 
  // ... more methods and other code ...
  // make init a public method
  return {
    init:init
  };
}();
module.init({
  'container':'header',
  'CSS.classes.active':'now',
  'timeout':1000
});

In order to make that readable, let’s encapsulate all the configuration alteration code in an own module:

var module = function(){
  // configuration, change things here
  var config = {
    CSS:{
     classes:{
       hover:'hover',
       active:'current',
       jsEnabled:'js'
     },
     ids:{
       container:'maincontainer'
     } 
    },
    timeout:2000,
    userID:'chrisheilmann'
  };
 
  // start of main code 
  function init(){
    console.log(config);
  };
 
  // ... more methods and other code ...
 
  // Configuration changes 
  var changeConfig = function(){
    function set(o){
      var reg = /\./g;
      if(isObj(o)){
        for(var i in o){
          if(i.indexOf('.')!== -1){
            var str = '["' + i.replace(reg,'"]["') + '"]';
            var val = getValue(o[i]);
            eval('config' + str + '=' + val);
          } else {
            findProperty(config,i,o[i]);
          }
        }
      }
    };
    function findProperty(o,p,v){
      for(var i in o){
        if(isObj(o[i])){
          findProperty(o[i],p,v);
        } else {
          if(i === p){o[p] = v;};
        }
      }
    };
    function isObj(o){
      return (typeof o === 'object' && typeof o.splice !== 'function');
    };
    function getValue(v){
      switch(typeof v){
        case 'string': return "'"+v+"'"; break;
        case 'number': return v; break;
        case 'object':
          if(typeof v.splice === 'function'){
            return '['+v+']';
          } else {
            return '{'+v+'}';
          }
        break;
        case NaN: break;
      };
    };
    return{set:set};
  }();
  // make init a public method
  return {
    init:init
  };
}();
module.init({
    'container':'header',
    'CSS.classes.active':'now',
    'timeout':1000
});

And that is one way to provide a configuration object and make it possible to change it programatically in the init() method. Can you think of a better one?

Adobe onAir show in London

Thursday, April 10th, 2008

I almost didn’t hear about Adobe’s on Air conference until it was upon us and the list of attendees was full. Luckily I got hold of one of the organizers and got a ticket that way (thanks Mike !).

I have to admit that I was dreading the whole thing to be a terrible marketing-driven show and tell of out-of-the-box solutions that solve every problem web development throws at you. This was my experience with a lot of large product company shows in the past – I was proven wrong.

The onAir tour was a great experience, both in terms of organization and content. For a whole day (doors opening at 9.15am and the event closing at 6pm) several speakers told us all about Air – from low level command line building via using different IDEs all the way to deployment, automated update and security of your applications.

The schedule was very tight with a few breaks in between and a larger lunch break. There was no feeling of boredom ever as all speakers kept their presentations snappy and hands-on. If you got in a lull, the rock-steady wireless could keep you busy (although I realized that live-twittering what is going on angers folk though).

People already versed in the “Flash/Flex scene” that came to the conference said that for them a lot was not news, but I think the idea of the onAir tour was not to preach to the Flash crowd but to expand the developer community for the product. Talking to several “Adobe virgins” I got the impression they met their goal. Sam Clark for example told me he came with very low expectations but very strongly considers getting into Air development now.

Of course all of this is post-show enthusiasm, but there are a lot of things Air does that really makes it interesting for web developers:

  • you can use the technologies you are already using (HTML/CSS/JS)
  • you don’t have to worry about cross-browser and cross-platform incompatibilities (you work with WebKit, which also gives you alpha transparency, rounded corners and all the other CSS goodies we so crave to have cross-browser)
  • as a JavaScript developer you have reach you never had before – you can access the file system, create and access SQLite Databases or access 10MB of encrypted storage for your application (I remember messing around with .hta and COM objects to do this in JS once, not fun)
  • You have full access to the native windows and menus of the operating system, thus being able to write applications that look and feel exactly like any other the user is already familiar with.
  • The security model is much more sophisticated than what we have to deal with in JavaScript and browsers. That said, the option to be able to re-assign file associations for your application does sound potentially dangerous.

Of course not all is rosy about Air and the only presentation that showed the issues when implementing it on a large scale was the one by the BBC.

  • Air applications need to be installed, which is something that does spook out users paranoid about viruses. Ironically this is the only way to keep them secure – but it is a hurdle. The web installer badges are a nice way to ease this process.
  • The accessibility support is bad, this needs to get fixed, starting with proper keyboard support
  • Air applications seem to take up a lot of RAM when they run for a long time. According to Jonathan Snook this is largely caused by the library that creates growl windows and once this is fixed we’ll have less problems.
  • The installer is only available in English and needs to be i18n ready.

It is very interesting to see how all the web technologies seem to merge sooner or later with the common denominator being JavaScript. Seeing what Flash developers do with almost the same language I’ve used for years but unhindered by browser restrictions is pretty interesting and looks like a good challenge to marry the best practice quality ideas we found in the hostile browser world with this “let’s try if we can do it” attitude.

I also very much like the fact that Adobe promised to release all the presentation videos on their site after the road show and that they even provide an API to access all the media accumulated during the ride.

Of course there was schwag to go, in this case T-shirts and some goodies that were given out using raffle tickets. There was a tad of an embarrassing moment when I won twice, once with my own ticket and secondly with Steve Webster’s (who had to finish a project and couldn’t come). Hence I drew another winner and gave my prize away.

Good job, I am looking forward to the next event.

[tags]onairtour,onair2008london,conference,adobe,air,javascript,css[/tags]

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?