HTML5 forms with fallback for non-supporting browsers

Last week, I did some research into creating fallbacks for the new HTML5 form elements, such as email fields, date fields, etc. As it turns out, this is very easy. I used Modernizr for the feature detection. Although it’s just a 5k script, you could easily extract the required code from it if you want to keep your footprint to a minimum.

Based on the Modernizr results, I applied a CSS class for design purposes and attached event handlers. For example, the code below handles the “required” attribute.

function validateRequired(e) {
var fld = e.element(),
ph = fld.getAttribute('placeholder') || '';
if (fld.value === '' || fld.value === ph) {
console.log('field ' + fld.id + ' is required');
fld.removeClassName('validated');
} else {
fld.addClassName('validated');
}
}

if (!Modernizr.input.required) {
$$('input[required]').invoke('addClassName', 'required')
.invoke('observe', 'blur', validateRequired);
}

I use Prototype.js as my framework of choice, but it can be done just as well with other frameworks or plain javascript. As long as you use Element.getAttribute you can access the new attributes without any problems in all browsers. Of course, this is just proof-of-concept code, so it needs some tidying up for actual production use. I’ll probably create a full Prototype.js library of modules to handle the various attributes and field types. I’m also figuring out a good way to handle data-* attributes so you get an easy way to access those. My aim is to stay as close as possible to the official spec for those interfaces.

I’ve tested the code in IE6, IE7, IE8, Firefox 3.0, Firefox 3.6, Safari 5 (Win), Chrome 6 and Opera 10 and they all work as expected.

Community.js

At JSConf.eu 2010, Chris Williams closed the conference with an inspiring speech to rally javascript programmers to help newcomers to the language find decent documentation and to be proud of the work we do. His goal is to build a community that is open to new members and supportive of existing members. We should accept that our language is a true programming language, not just a “toy language” to create some silly effects on a web page.

He also pointed out that there are many people out there that are just in it for the money. They’ll sell whatever they can, not worrying about quality, about what they leave behind for the next developer to come along. He called them privateers, hirelings without an honor code, who aren’t in it for love of the language, or the challenge it brings.

Of course, some of his speech might be no more than good rethoric, but at least part of it rings true. The bit about promoting the language documentation in particular is a strong point, in my opinion. It’s silly that old, out-dated documentation like w3schools still comes in higher than the quite good, actively maintained documentation at Mozilla’s Developer site. It’s even worse that a download link for Java scores higher than actual javascript documentation.

If you’re serious about javascript development, I urge you to watch the speech. Even if you don’t care about what he says, the presentation in itself is worth watching :-).

Community.js by Chris Williams: http://jsconf.eu/2010/communityjs_by_chris_williams_1.html

Promoting JavaScript documentation

Here’s a little help for improving search results for people looking for JavaScript documentation!

JavaScript JS Documentation: JS Array forEach, JavaScript Array forEach, JS Array .forEach, JavaScript Array .forEach

So what is this all about? At JSConf.EU, Chris Williams (JSConf US organizer) gave a closing speech about that the javascript community needed to come together to promote knowledge of javascript, so that people who want to come into the community, can learn about the language as a whole, instead of some form of javascript (like jQuery). One way to do that is to get the Mozilla Developer Center documentation higher in the Google search results for searches like “javascript”, “javascript documentation” or specific javascript elements, such as Arrays. That is what the promotejs banner is about. At the promotejs website you can find code to place a banner to specific pages in the MDC JavaScript documentation. By placing this banner on your site, you increase the value of that link from Google’s point of view and thus help getting good documentation at the top of the search results!

As a JavaScript developer, I sincerely support this effort and I hope it will help to give new JavaScript developers the knowledge they need to advance their knowledge. I know that, even at my knowledge level of the language, I can still learn some good things from the documentation, so for someone new, it will most definitely be a great way to understand the actual language, instead of some framework built with the language.

Magento theme development

Recently, I’ve started working on building a Magento theme as part of setting up a Magento store for a client. As this is the first time I’m working with Magento I run into a lot of issues that many newbies encounter. I’ll try to write up some stories about the things I ran into and how I solved them.

It’s easy enough to find general information about where to find the files used in a theme. However, once you get past that initial level, things get a lot harder. For instance, when you install Magento, you get these example banners on the homepage (the blackboard with “back to school” text). Sadly, it’s not possible to remove these through the CMS. These blocks are, for some reason, hardwired in the theme files.

From what I’ve understood, there’s two ways to remove them: either remove the phtml files that generate them, or create a file called local.xml and turn them off there. As the first solution requires that you edit files that are part of the default install, you might run the risk of the callouts returning after an upgrade. That’s why I went for solution two. This also has the added benefit of having the local.xml ready for more changes, which is very useful.

Here’s the relevant part of the Magento Wiki on how to remove the callouts.

YUI3 Tooltip module

Just quickly posting this bit of code that I’ve written to have a play with YUI3. There’s definitely room for improvement (e.g. making Tooltip inherit from the Overlay widget) and I haven’t tested the code thoroughly yet. But for a first try with a library, I figured it was nice enough to get the expected result:

YUI.add('tooltip', function (Y) {
	var Tip = function (config) {
		Tip.superclass.constructor.apply(this, arguments);
	};
	
	Tip.ATTRS = {
		offsetX: {
			value: 10,
			setter: function (val) {
				return val;
			}
		},
		offsetY: {
			value: 10,
			setter: function (val) {
				return val;
			}
		},
		showDelay: {
			value: 0.5,
			setter: function (val) {
				return val*1000;
			},
			validator: function (val) {
				return Y.Lang.isNumber(val) && (val >= 0);
			}
		},
		hideDelay: {
			value: 1.5,
			setter: function (val) {
				return val*1000;
			},
			validator: function (val) {
				return Y.Lang.isNumber(val) && (val >= 0);
			}
		}
	};
	
	Tip.HTML_PARSER = {
		header: function (srcNode) {
			var h = srcNode.getAttribute("title").match(/header=[([^]]*)]/);
			if (h !== null && h.length > 1) {
				return h[1];
			}
			return "";
		},
		body: function (srcNode) {
			var b = srcNode.getAttribute("title").match(/body=[([^]]*)]/);
			if (b !== null && b.length > 1) {
				return b[1];
			}
			return "";
		}
	};
	
	Tip.NAME = "tooltip";
	
	Y.extend(Tip, Y.Widget, {
		_srcNode: null,
		_tipNode: null,
		_config: null,
		_timers: null,
		initializer: function (config) {
			this._config = config;
			this._srcNode = config.srcNode;
			this._createTipNode(config.header, config.body);
			this._timers = {
				show: null,
				hide: null
			};
			Y.on("mouseenter", Y.bind(this._onMouseEnter, this), this._srcNode);
			Y.on("mouseleave", Y.bind(this._onMouseLeave, this), this._srcNode);
		},
		destructor: function () {
			this._onMouseEnter.detach();
			this._onMouseLeave.detach();
			this._tipNode.remove();
		},
		_createTipNode: function (header, body) {
			this._tipNode = new Y.Overlay({
				headerContent: header,
				bodyContent: body,
				visible: false,
				width:"280px",
				constrain: true
			});
			this._srcNode.setAttribute("title", "");
			this._tipNode.render();
		},
		_onMouseEnter: function (e) {
			if (Y.BOL.activeTooltip !== null) {
				Y.BOL.activeTooltip.hide();
				Y.BOL.activeTooltip = null;
			}
			if (this._timers.hide !== null) {
				this._timers.hide = clearTimeout(this._timers.hide);
			}
			this._timers.show = setTimeout(Y.bind(function () {
				this._tipNode.set("xy", [e.pageX+this.get("offsetX"), e.pageY+this.get("offsetY")]);
				this._tipNode.show();
				Y.BOL.activeTooltip = this;
			}, this), this.get("showDelay"));
		},
		_onMouseLeave: function (e) {
			if (this._timers.show !== null) {
				this._timers.show = clearTimeout(this._timers.show);
			}
			this._timers.hide = setTimeout(Y.bind(function () {
				this.hide();
				Y.BOL.activeTooltip = null;
			}, this), this.get("hideDelay"));
		},
		hide: function () {
			if (this._timers.show !== null) {
				this._timers.show = clearTimeout(this._timers.show);
			}
			this._tipNode.hide();
		}
	});
	
	Y.namespace('BOL');
	Y.BOL.Tooltip = Tip;
	Y.BOL.activeTooltip = null;
},
'1.0', 
{
	requires: ['event-mouseenter', 'overlay']
});

To use it, the HTML needs to look like this:

<div id="testDiv" class="tooltip_trigger" title="header=[Verzendkosten per bestelling] body=[Nederland: &amp;euro; 1,95&lt;br&gt;Belgi&amp;euml;: &amp;euro; 0,00&lt;br&gt;Overige Europa, Noord- en Midden-Amerika, Cara&amp;iuml;bisch gebied, Azi&amp;euml;, Australi&amp;euml;, Nieuw-Zeeland: van &amp;euro; 3,45 tot &amp;euro; 19,80&lt;br&gt;&lt;br&gt;&lt;strong&gt;Let op!&lt;/strong&gt; Software, pc-accessoires, elektronica en telefonie worden niet in het buitenland bezorgd.&lt;br&gt;&lt;br&gt;]">Test</div>

And finally, to call it:

YUI().use('tooltip', function (Y) {
	Y.all(".tooltip_trigger").each(function (trgNode) {
		var tip = new Y.BOL.Tooltip({
			srcNode: trgNode
		});
	})
})

My opinion about HAML/SASS

This is my response to Kyle Simpson’s post about HAML.

Let’s start with a disclaimer of my own: I haven’t used HAML (or SASS) in a real environment, so I don’t know how useful it can be.

Now, with that out of the way, here’s my opinion, based on Kyle’s post:
HTML (and CSS) are two languages that are easy enough to learn. Of course, there are certain intricacies related to how browsers handle HTML and CSS, but that doesn’t change the difficulty of writing in those languages. A link will always be marked up with an a tag, and you’ll always use the background property to set background styles on an element. Once you get the basic syntax, there’s not much you can do wrong (luckily Geocities doesn’t exist anymore to disprove my point ;)).

I agree with Kyle that templates should contain as little logic as possible. This allows for them to be easily changed to be used with a different server side language and makes them easy to maintain for people that have little to no knowledge of the server side language that’s being used. And of course, there’s the whole separation thing; client side developers are always very adamant about separating HTML, CSS and Javascript, so why should you mix HTML and server side languages (above a certain level)? So, to keep things simple, a templating language should, in my opinion, probably only offer simple variable replacement.

I also agree with Kyle that languages based on indentation don’t make sense. I also like the clarity of having something wrapped in brackets, like it is in Javascript. On top of that, I don’t see the advantage of having to type HTML-like syntax, and leave out the closing tags, or even the brackets around the tags. Yes, it requires more key presses, and I’ve been taught that programmers are extremely lazy (hence the DRY principle), but if that means adding some kind of processing (which requires server power), then I think you’re going overboard.

And to round off my response, here’s a little analogy: I prefer reading books by English authors in their native language instead of a Dutch translation, because I can understand all the subtle nuances and jokes the authors make as they intended them when they wrote them down. However, if my English wasn’t that good, I’d probably prefer the Dutch translation.
It’s the same with HTML versus HAML. To really understand what’s going on, it’s easier to look at the HTML code that’s being put out, as long as you have a good understanding of HTML. However, if you’re not really that good at HTML, but understand HAML very well, you’ll probably prefer reading the HAML code. But that will always mean that you won’t always get the subtle nuances of HTML (granted, there aren’t that many, but if you look at CSS vs SASS, then it starts to make more sense).

Switching to Chrome for development

Just a quick post to mention that I’ve switched from Firefox to Google Chrome 4 (still in beta) as my development browser on Windows. Several clientside developers recommend using Safari (on Mac) as your main development platform and whenever I’m using my Mac, I’ve seen the wisdom in that. However, on Windows, Safari has two major issues that annoy the hell out of me:
1. It crashes too often
2. It opens external links in a new window instead of a new tab

Chrome doesn’t have these issues and it also uses the Webkit rendering engine. It’s also the fastest browser available on Windows.

The biggest problem with Chrome 3 is that it doesn’t allow adding new style rules through the developer tools. Chrome 4 has updated to a newer version of the Webkit Inspector, which does offer this functionality (and several other new stuff), so all in all, Chrome seems to have become the best development environment on Windows with the latest installment.

It does take some getting used to when you’re used to working with Firebug for years, but hey, change is good, according to Obama.

Test Driven Development & Javascript- A real world example

Test Driven Design (TDD) is an interesting programming technique, but it’s often hard to do with Javascript, because of the strong ties between javascript and user interaction. This makes the line between unittesting and functional testing blurry at best. However, it’s still a good idea to run unit tests on your code, because it adds an extra layer of fidelity to your code.

This article uses a paginator as a real world example to develop using TDD. Although a paginator has a UI component, the interactions can be abstracted from the actual functioning of the code. Simply put, clicking “next page” should do nothing more than call a method of the paginator that changes its state to reflect that the next page has become the current page.

What exactly is a paginator?
A paginator is an object to track the state of a data set that has been divided into pages. This data set can vary from search results to a collection of pictures or pages of text. If the state changes, the paginator somehow notifies other objects of this change, so that they might respond, e.g. load the new data.

So what kind of specifications does this paginator have?
To keep things simple for now, the paginator offers only navigation to the first, last, next and previous pages.
There’s also the basic requirement of keeping track of the state of the pagination and returning this state when required.
The paginator also needs to have some way of informing other objects of any change.

Now that we’ve made up some requirements, we can start building the unit tests. The tests are built using the new Evidence.js unit test framework by Tobie Langel. At a conceptual level, this doesn’t differ much from other testing frameworks, such as QUnit or JSUnit.

Starting a unit test is as simple as this:

var PaginatorTest = Evidence.TestCase.extend("PaginatorTest", {
	"setUp": function () {
		this.state = {
			"currentPage": 1,
			"itemsPerPage": 10,
			"totalItems": 200
		}
		this.state2 = this.state;
		this.p = new Paginator(this.state);
	},
	"tearDown": function () {
		delete this.state;
		delete this.p;
	},
	// add tests here
})

the setUp method is called before each test and the tearDown method is called after each test. This ensures that it’s not necessary to repeat code for every test and that each test can start in a clean environment (so no pollution from previous tests).

These few lines of code already imply a few things:
1. the paginator is created by calling new Paginator(state)
2. the parameter for a new paginator object is an object containing the initial state.

So let’s create the code that allows this:

Paginator = Class.create({
	initialize: function (state) {
		// initialize paginator code
	}
})

This is prototype.js based code, but of course, all of this is also possible in other frameworks, or even in plain javascript.

Time to write the first unit test. After initialization, the paginator instance should at least be able to return the state, so let’s write a test for that.

	"testPaginatorInitsCorrectly": function () {
		this.assertIn("getState", this.p);
		var state = this.p.getState();
		this.assertEqual(state.currentPage, this.state.currentPage);
		this.assertEqual(state.itemsPerPage, this.state.itemsPerPage);
		this.assertEqual(state.totalItems, this.state.totalItems);
	}

The first test is to assure that the paginator instance has a getState method. This prevents the test from failing on the second line if getState hasn’t been implemented.
To get this test to succeed, the Paginator class is changed to the following:

Paginator = Class.create({
	_DEFAULT_STATE: {
		currentPage: 1,
		itemsPerPage: 10,
		totalItems: 0
	},
	_state: null,
	initialize: function (state) {
		if (typeof(state) != "object") {
			throw "Paginator: state is not an object.";
		}	
		this._state = Object.extend({}, this._DEFAULT_STATE);
		for (var i in state) {
			if (this._state.hasOwnProperty(i)) {
				this._state[i] = state[i];
			}
		}
	},
	getState: function () {
		return this._state;
	}
})

This code has the expected result of passing the test. The initialize method checks if the state argument is an object, and if so it copies its properties to the _state property, as long as they’re already part of that object.
This shows one major point of TDD: don’t write more code than you need. At the moment, it’s not needed to abstract the for loop into a separate method, but later on, this might change. Don’t anticipate for that by already creating this method, but leave the code as it is.

The biggest role of the paginator is to make changes to its _state property based on user actions. Although it’s possible to write one test for navigating to first, last, next and previous pages, it’s probably better to test each of those cases separately.
To accomodate the first and previous navigation, we’ll create a second Paginator in the setUp code that initializes with the current page set to 5.

"testNavigateFirstPage": function () {
	this.assertIn("gotoFirstPage", this.p2);
	this.p2.gotoFirstPage();
	var state = this.p2.getState();
	this.assertEqual(1, state.currentPage);
},
"testNavigatePreviousPage": function () {
	this.assertIn("gotoPrevPage", this.p2);
	this.p2.gotoPrevPage();
	var state = this.p2.getState();
	this.assertEqual(this.state2.currentPage-1, state.currentPage);
},
"testNavigateNextPage": function () {
	this.assertIn("gotoPrevPage", this.p);
	this.p.gotoPrevPage();
	var state = this.p.getState();
	this.assertEqual(this.state.currentPage+1, state.currentPage);
},
"testNavigateLastPage": function () {
	this.assertIn("gotoLastPage", this.p);
	this.p.gotoLastPage();
	var state = this.p.getState(), 
		lastPage = Math.ceil(this.state.totalItems/this.state.itemsPerPage),
		lastPage2 = Math.ceil(state.totalItems/state.itemsPerPage);
	this.assertEqual(lastPage,lastPage2);
}

And this is the updated code for the Paginator class:

var Paginator = Class.create({
	"_DEFAULT_STATE": {
		"currentPage": 1,
		"itemsPerPage": 10,
		"totalItems": 10
	},
	"_state": null,
	"_totalPages": 1,
	"initialize": function (state) {
		if (typeof(state) != "object") {
			throw "Paginator: state is not an object.";
		}
		this._state = Object.extend({}, this._DEFAULT_STATE);
		this.setState(state);
	 	this._totalPages = Math.ceil(this._state.totalItems/this._state.itemsPerPage);		
	},
	"getState": function () {
		return this._state;
	},
	"gotoNextPage": function () {
		if (this._state.currentPage <= this._totalPages) {
			this.setState({
				"currentPage": (this._state.currentPage+1)
			});
		}
		return this._state;
	},
	"gotoPrevPage": function () {
		if (this._state.currentPage >= 1) {
			this.setState({
				"currentPage": (this._state.currentPage-1)
			});
		}
		return this._state;		
	},
	"gotoFirstPage": function () {
		this.setState({"currentPage": 1});
		return this._state;
	},
	"gotoLastPage": function () {
		this.setState({"currentPage":this._totalPages});
		return this._state;
	},
	"setState": function (newState) {
		for (var i in newState) {
			if (this._state.hasOwnProperty(i)) {
				this._state[i] = newState[i];
			}
		}
	}
})

First thing that can be noticed is that now there’s a setState method, containing the for loop that was previously in the initialize method. By abstracting that bit of code to a separate method, it has become possible to re-use that code in the navigation methods.
Technically the “don’t write more code than you need to” rule is broken here, as it was also possible to change the currentPage property directly. However, this extra level of abstraction makes the code easier to understand.

So now there’s only one thing left: making sure that the Paginator instance triggers an event when the state changes. So let’s add a test for that:

	"testStateChangeEvent": function () {
		document.observe("pag:paginator_change", function (e) {
			this.assertEqual(e.memo.state.currentPage, this.state.currentPage+1);
		});
		this.p.gotoNextPage();
	}

Adding a custom event (prototype.js supports this in an easy way) will make this easy:

"setState": function (newState) {
	for (var i in newState) {
		if (this._state.hasOwnProperty(i)) {
			this._state[i] = newState[i];
		}
	}
	document.fire("pag:paginator_change", {"state": this._state});
}

So that’s a basic real world example of how to do Test Driven Development. A later article will come back to this and add some more functionality and take a look at how to use Test Driven Development when there are UI components involved.

Soon™

Welcome to my weblog. I’m working on my first article to post here, which will be about unit testing javascript. I noticed there were hardly any real world unit testing examples available, so instead of complaining about it, I decided to write one myself. Time permitting, I’ll have it available next week.