Christian Heilmann

You are currently browsing the archives for the General category.

Archive for the ‘General’ Category

Big companies are like marching bands

Friday, June 20th, 2008

I just read another amazing novel by Douglas Coupland on my 5 hour flight to Ankara called “Eleanor Rigby”. This is a quote I really enjoyed:


Jeremy asked if I liked my job.
“I think big companies are like marching bands. You know the big secret about marching bands, don’t you?”
“No, what is it?”
“Even if half the band is playing random notes, it still sounds kind of like music. The concealment of failure is built right into them. It’s like the piano – as long as you play only the black keys, not the white ones, it’ll sound okay, but on the other hand it’ll never sound like real music either.

Now this sounds negative, but I also like the idea that big companies can have failure without totally vanishing. That’s where research departments and incubators come in.

How to stop event delegation(obvious fact #12132)

Monday, June 9th, 2008

This was a question I got in the office today and there is no shame in asking it:

I am using Event Delegation on one of my products and I need to stop the main handler on the body from firing when I click a certain button. How do I do that?

The answer is of course to use stopPropagation() or cancelBubble(), both nicely wrapped in YAHOO.util.Event.stopPropagation():

HTML:

JavaScript:

YAHOO.util.Event.onContentReady('buttons',function(){
YAHOO.util.Event.on(document.body,'click',function(e){
var t = YAHOO.util.Event.getTarget(e);
snitch('

It was the ' + t + ' that was clicked

'); }); YAHOO.util.Event.on('tease','click',function(e){ snitch('

that was the first button

'); YAHOO.util.Event.stopPropagation(e); }); YAHOO.util.Event.on('tease2','click',function(e){ snitch('

that was the second button

'); }); function snitch(msg){ document.getElementById('littlesnitch').innerHTML += msg; } });

Try it out here: Overriding Event Delegation with stopPropagation

[tags]events,javascript,eventdelegation,webdevtrick[/tags]

@media2008 report live on YDN

Friday, May 30th, 2008

It is 1.14am after the first day of @media2008 and I just finished my report over on the YDN blog:

See you there tomorrow morning for day two, I am off to bed.

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]