A couple of days ago I was talking with my friend Karsten at work about one small but relevant issue we face when building websites: our beautiful MooTools classes cannot interact with elements on the DOM until the DOM has fully loaded. This, which is obvious, sometimes has some impact.
For example, the typical case we face is with tabs. Usually you will see code that hides all tab panels but the first one with CSS classes. But what if your visitor has Javascript disabled? With no Javascript, all tabs should be visible. So we need to hide the tabs with Javascript, but now we face the problem: we cannot alter the elements until the DOM is ready. And that is to late for some browsers like IE6 & IE7 which are not very fast processing Javascript. If we hide the tabs on the initialize method of our class, you will see them on the screen for a split of a second. That is not good.
The solution is simple: Use document.write to create the styles needed to hide the tabs as soon as the javascript is processed, this is, before the DOM is loaded. The problem is that we are not creating our classes until the DOM is loaded, so this code has to be placed somewhere else, breaking the encapsulation that object oriented programming gives us.
So we came up with an idea, more or less at the same time: Instantiate our classes with a ‘Smart Start’. This is, our objects will be created before the DOM is ready but will be smart enough to hold the interaction with the elements until that point. This will allow us to do other stuff if we want to, like hiding the tabs other than the first one.
As an example, I have modified this cool CountDown class that David Walsh has just published.
Here is the new code:
-
var CountDown = new Class({
-
-
Implements: [Options,Events],
-
-
domReady: false,
-
startOnDomReady: false,
-
fx: null,
-
-
options: {
-
element: null,
-
start: 10,
-
finish: 0,
-
startFont: '36px',
-
finishFont: '12px',
-
onComplete: $$empty,
-
duration: 1000
-
},
-
-
initialize: function(options) {
-
this.setOptions(options);
-
-
// Smart objects can listen to domready
-
window.addEvent('domready',function() {
-
this.domReady = true;
-
this.options.element = $(this.options.element); // Hook element
-
if (this.startOnDomReady) this.start();
-
}.bind(this));
-
},
-
-
start: function() {
-
// If DOM is not ready, wait
-
if (!this.domReady) {
-
this.startOnDomReady = true;
-
return;
-
}
-
-
// Create FX object only once
-
this.fx = new Fx.Tween(this.options.element, {
-
duration: this.options.duration,
-
link: 'ignore',
-
onComplete: function() {
-
if(this.options.start >= this.options.finish) {
-
this.anim();
-
} else {
-
this.fireEvent('complete');
-
}
-
}.bind(this)
-
});
-
-
this.anim();
-
},
-
-
anim: function() {
-
this.options.element.set('text',this.options.start–);
-
this.fx.start('font-size',this.options.startFont,this.options.finishFont);
-
}
-
});
-
-
var cd = new CountDown({
-
element: 'countdown',
-
start: 12,
-
finish: 0,
-
onComplete: function() {
-
this.options.element.set('text','Done! Your special code is: 4065').setStyle('color','#090');
-
}
-
}).start();
As you can see, the object is instantiated as soon as the Javascript is processed but, even with the function start() being called, the object doesn’t start processing until the DOM is ready.
Demo: http://dev.enekoalonso.com/research/moo-countdown-smartstart.php