Christian Heilmann

You are currently browsing the Christian Heilmann blog archives for August, 2007.

Archive for August, 2007

Talking about unobtrusive, publisher-friendly badges at ebay UK\’s webwatch

Friday, August 31st, 2007

Presenting at ebay

I just came back from giving a presentation on how to cater content distribution via badges and widgets to the right audience and how we fail at it.

See it on slideshare.net:

Enhancing YUI grids with equal height columns

Thursday, August 30th, 2007

One of the biggest issues of CSS layouts is that not all columns are the same height which makes it hard to style them in a traditional manner. You can embrace this change as a designer, but that seldomly happens.

Having played with YUI grids lately I realized this shortcoming, too. Nested grids don’t have the same height. I am sure you can tweak the CSS to do that (Ed Eliot showed a lot of options how to achieve equal height columns in the past) but I don’t get much fun out of CSS hacking.

What I like is JavaScript and as equal column heights are not really a vital part of a web site functionality, I am happy to use it to fix these issues.

As the YUI grids come with a defined set of CSS classes I have my hooks to apply JS functionality to and the script was easy to do using YUI Dom and YUI Dom Region.

Check out the demo page for equal height nested grids and download the script to use it in your own grid solutions.

All you need to do is to add YAHOO, YAHOO Dom and YAHOO Event (easiest with the collated yahoo-dom-event package) and the script in the bottom of your document’s body. The script automatically equals all columns in nested grids. If you don’t want all of them to be equal, define only those that need fixing by adding a “columnfix”CSS class.

Monitoring element size and position with the YUI

Tuesday, August 28th, 2007

One of the lesser known gems of the Yahoo User Interface library is the Region utility which is part of the Dom utility. The documentation only mentions it and what it gives you but doesn’t quite live up to how powerful it can be in day to day interface development.

Please refer to the accompanying demo page about YUI Region to see the examples in this post in action.

Retrieving an element’s region

The Region utility returns you the region occupied by a certain element in the browser. You use it by sending the ID, a reference to an element or an array of elements to the getRegion() method:


var region = YAHOO.util.Dom.getRegion(‘reg1’);

The method returns an object with several properties and some methods. The properties are:

top

the amount of pixels between the top side of the element and the top left of the window.

bottom

the amount of pixels between the bottom side of the element and the top left of the window.

right

the amount of pixels between the right side of the element and the top left of the window.

left

the amount of pixels between the left side of the element and the top left of the window.

0,1

Shortcuts for the left and top property (added for compatibility with YAHOO.util.Dom.setXY()

The really cool thing about Region is that it gives you that information regardless of the positioning of the element (static,relative,absolute,fixed). A possible result would be:


Region {top: 109, right: 571, bottom: 177, left: 371};

Check the “Get occupied space of #1” link on the demo page to try it out.

Determining element overlap

Furthermore the object has several methods:

getArea()

returns the total amount of pixels occupied by the region.

contains()

returns a Boolean if a region fully contains another region

union()

returns the union region of two regions, which is the screen estate containing both of them

intersect()

returns the region that two regions have in common

The contains() method is pretty useful as it can tell you when and if an element is visually inside the other one. This can help immensely for drag and drop interfaces. You use it by defining the two regions and it returns a Boolean.


reg1 = YAHOO.util.Dom.getRegion(‘reg1’);
reg2 = YAHOO.util.Dom.getRegion(‘reg2’);
var contains = reg1.contains(reg2);

If the element with the id reg2 is visually completely inside the element with the id reg1 contains will be true, otherwise it is false.
You can try this out by clicking the “Is #2 fully inside #1?” link on the demo page to this post. Also resize the element with the “Resize#2” to see the change when you click the test link again and reset the element with “Undo Resize #2”.

The union() method returns the screen region that encompasses both the elements. This is very useful if you want to cover both regardless of their positioning.


reg1 = YAHOO.util.Dom.getRegion(‘reg1’);
reg2 = YAHOO.util.Dom.getRegion(‘reg2’);
var contains = reg1.union(reg2);

The result is another region object.

The intersect() method returns the screen region that is covered by both the elements. This is very useful to determine to what percentage two elements overlap or highlight the overlapping section.


reg1 = YAHOO.util.Dom.getRegion(‘reg1’);
reg2 = YAHOO.util.Dom.getRegion(‘reg2’);
var contains = reg1.intersect(reg2);

The result is another region object.

You can test both methods by clicking the “Show section containing both” and “Show section occupied by both” links on the accompanying demo page about YUI Region.

Calculating element dimensions

You can use the region information for a lot of different things. Probably one of the most useful is to get the width and height of the element in a reliable fashion. All you need to do to calculate them is to substract left from right for the width and top from bottom for the height:


var region = YAHOO.util.Dom.getRegion(‘reg1’);
var elmHeight = region.bottom – region.top;
var elmWidth = region.right – region.left;

Check the “Get dimensions of #2” link on the demo page to try it out.

You can use this to for example read out the size of form elements and fix tooltips to their correct size. Say you have a DIV with the ID reg2 and a select box with the ID selectbox. The following script would position the DIV under and make it as wide as the selectbox.


var sel = YAHOO.util.Dom.get(‘selectbox’);
var elm = YAHOO.util.Dom.get(‘reg2’);
var size = YAHOO.util.Dom.getRegion(sel);
YAHOO.util.Dom.setXY(elm,[size.left,size.bottom]);
YAHOO.util.Dom.setStyle(elm,’width’,(size.right-size.left-20)+’px’);

You can try this out by clicking the “Resize #2 to the size of the select” link on the demo page to this post.

Notice the -20 in the last line, this is a fix as the element has a padding of 10 pixels. This is neccesary as you cannot easily and reliably read out the padding of the element automatically unless you also set it with JavaScript.

This is just a teaser on what you can use Region for. Widgets like the YUI menu or container use it constantly to determine if certain functionality can be displayed or not.

Being humbled talking about JavaScript – and more to come at @media Ajax

Wednesday, August 22nd, 2007

I am currently in [tag]Hongkong[/tag] training colleagues from Asia on how we do things in Europe. Or so I thought. I came here with [tag]Douglas Crockford[/tag] and [tag]Nate Koechley[/tag] to show what we’ve done in the US and the UK to make life easier for developers to create web sites and applications.

When we asked around for each team to show us what they work on and what things they needed input on we were in for a big surprise. It is pretty amazing what kind of implementations you see around Asian web sites and how naturally the developers here used the recommended technologies without ever asking or telling us about it. I can’t wait to bring back the findings the teams here documented to share with the folks back home.

That said, I am also learning about problems us latin font users don’t get and only come up when you use Mandarin or Korean. All in all this is a great experience, both in terms of sharing information and realizing how much of your work for the web standards movement gets used without you ever being the wiser. For example I found a translated PDF of one of my articles I didn’t know before.

Talking about being humbled talking about JavaScript, things are happening on the [tag]@mediaAjax[/tag] web site. The sessions are mostly defined and the already impressive list of speakers got some more interesting additions. Specifically the [tag]Ajaxian[/tag] folk [tag]Dion Almaer[/tag] & [tag]Ben Galbraith[/tag] and [tag]Alex Russell[/tag] of [tag]Dojo[/tag] join well-known JS speakers and scarcely seen people on the European speaker circuit. If you want to talk JS and Ajax, I am quite sure there is hardly any better summit to go to this year.

Again with the Module Pattern – reveal something to the world

Wednesday, August 22nd, 2007

Not too long ago I was raving about the beauty of the Module Pattern in JavaScript and the annoyance I felt with it when it comes to repetition of long namespaces when calling or reading public methods and properties from other public methods and properties.

To recap, the “classic” Module Pattern means you define a variable as an anonymous function that gets immediately called with (). You define private functions and variables and return your public variables and functions as properties and methods of an anonymous object:

var classicModulePattern = function(){
  var privateVar = 1;
  function privateFunction(){
    alert('private');
  }
  return {
    publicVar:2,
    publicFunction:function(){
      classicModulePattern.anotherPublicFunction();   
    },
    anotherPublicFunction:function(){
      privateFunction();
    }
  }
}();
classicModulePattern.publicFunction();

The beef I had with that is that you need to repeat the name of the main object when you want to call one public method from another or access public variables. The other bit I was annoyed about is having to switch to object literal notation for the things you want to make public.

Inspired by the comments on the blog post on the YUI about the module pattern and pubstandards, I started advocating using a named object called pub to append methods and properties to before returning it. That way you can call public methods via the pub.methodName shortcut notation instead of repeating the main name:

var namedObjectModulePattern = function(){
  var pub = {};
  var privateVar = 1;
  function privateFunction(){
    alert('private');
  };
  pub.publicVar = 2;
  pub.publicFunction = function(){
  pub.anotherPublicFunction();    
  };
  pub.anotherPublicFunction = function(){
    privateFunction();
  };
  return pub;
}();
namedObjectModulePattern.publicFunction();

During a Q&A session in a training in Hongkong yesterday I showed this to Douglas Crockford and asked him what he thinks of it. He didn’t mind the idea, but considered even the pub object redundant.

There is another option which I am hereby calling the Revealing Module Pattern. In this permutation you simply define all your functions and variables in the private scope and return an anonymous object at the end of the module with pointers to the private variables and functions you want to reveal as public:

var revealingModulePattern = function(){
  var privateVar = 1;
  function privateFunction(){
    alert('private');
  };
  var publicVar = 2;
  function publicFunction(){
    anotherPublicFunction();    
  };
  function anotherPublicFunction(){
    privateFunction();
  };
  // reveal all things private by assigning public pointers
  return {
    publicFunction:publicFunction,
    publicVar:publicVar,
    anotherPublicFunction:anotherPublicFunction
  }
}();
revealingModulePattern.publicFunction();

This keeps the syntax of the whole script consistent and makes it obvious at the end which of the functions and variables can be accessed publicly. The other benefit is that you can reveal private functions with other, more specific names if you wanted to.

var revealingModulePattern = function(){
  var privateVar = 1;
  function privateFunction(){
    alert('private');
  };
  var publicVar = 2;
  function publicFunction(){
    anotherPublicFunction();    
  };
  function anotherPublicFunction(){
    privateFunction();
  };
  // reveal all things private by assigning public pointers
  return {
    init:publicFunction,
    count:publicVar,
    increase:anotherPublicFunction
  }
}();
revealingModulePattern.init();

You can even return values as the public properties by calling the functions in the anonymous object:

var revealingModulePattern = function(){
  var privateVar = 1;
  function privateFunction(){
    alert('private');
  };
  var publicVar = 2;
  function publicFunction(){
    anotherPublicFunction();    
  };
  function anotherPublicFunction(){
    privateFunction();
  };
  function getCurrentState(){
    return 2;
  };
  // reveal all things private by assigning public pointers
  return {
    init:publicFunction,
    count:publicVar,
    increase:anotherPublicFunction,
    current:getCurrentState()
  }
}();
alert(revealingModulePattern.current) 
// => 2
revealingModulePattern.init();

Of course the example names here are far from what I would use in a real script, but it shows the power of this pattern.