/haikujs

Haiku makes DOM trees / so simple to generate / we think you'll love it.

Primary LanguageJavaScriptMIT LicenseMIT

haiku.js

Haiku makes DOM trees
so simple to generate,
I think you'll like it.

Wha...?

There are plenty of libraries for making it easier to create arbitrary DOM nodes, but I couldn't find one that used Zen Coding syntax, which I've kinda fallen in love with lately. It can generate single element nodes, DOM Fragments, or even a raw string of HTML, suitable for insertion via innerHTML.

It's intended to be a lightweight replacement for the standard DOM method of creating new HTML structures, without the overhead of a full-blown templating system like Mustache or Dust.js or the like.

Installation

Haiku is packaged as an AMD module, but it's dependency-free, so it's simple to install: just drop it in your root JavaScript folder, and require away:

require(["haiku"], function(haiku) {
    document.body.appendChild( haiku.expand("section#main+aside#related") );
});

Format

ID operator (“#”)

Specifies the ID for an element (ignores multiple operands; an element can only have one ID):

div#main produces ⇒ <div id="main"></div>

Class operator (“.”)

Specifies the CSS class for an element (multiple operands allowed):

blockquote.fancy.gothic <blockquote class="fancy gothic"></blockquote>

Template value operators (“$…;”)

Provides simple Supplant-style templating based on a caller-provided data object (just basic parameter substitution right now):

a[href=http://me.com?id=$link;]>{$label;} <a href="http://me.com?id=9001">Goku's power level</a>
{ "link":9001, "label":"Goku's power level }

Child operator (“>”)

Makes the following element a child of the preceding one:

ul>li <ul> <li></li> </ul>

Sibling operator (“+”)

Makes the following element a sibling of the preceding one:

div>p#intro+p#main <div> <p id="intro"></p> <p id="main"></p> </div>

Parent operator (“<”)

Makes the following element a sibling of the preceding one's parent (i.e goes up one level in the tree):

header>h1<section.main <header><h1></h1></header> <section class="main"></section>

Text delimiters (“{ }”)

Specifies the contents of a text node:

p>{A }+em{simple}+{ example} <p>A <em>simple</em> example</p>

Attribute delimiters (“[ ]”)

Specifies attributes other than class and id (comma-separated if more than one):

a#myId.myClass[href=http://foo.com,data-type=permalink] <a href="foo.com" data-type="permalink" id="myId" class="myClass" />

Usage

Multiple Nodes

Let's say you've got a piece of code that needs to create a handful of new DOM nodes and apply a bunch of atributes to them. You could do this the Vanilla JavaScript way, like so:

function createPerson(dataObject) {
	var item, link;

	item = document.createElement('li');
	item.className = 'person';
	item.setAttribute('data-item-key', dataObject.id);
	link = document.createElement('a');
	link.href = 'http://foo.com?personid=' + dataObject.id;
	link.className = 'external';
	link.innerText = dataObject.name
	item.appendChild(link);
	
	return item;
}

Or you can use Haiku's expand method. By default, Haiku appends all of the nodes it interprets from your provided string to a new DOM document fragment, which it hands back to you for placement in your document tree:

function createPerson(dataObject) {
	var tmpl = "li.person[data-item-key=$id;]>a.external[href=http://foo.com?personid=$id;>{$name;}";
	return haiku.expand(tmpl, dataObject);
	// returns a DOM document fragment
}

Maybe you prefer to hand-jam HTML and use something like jQuery to inject it via innerHTML:

function createPerson(dataObject) {
	var html;

	html = "<li class='person' data-item-key='" + dataObject.id + "'>";
	html += "<a class='external' href='http://foo.com?personid='" + dataObject.id + "'>" + dataObject.name + "</a>";
	html += "</li>";
	
	return html;
}

Haiku supports this as well, if you pass a truthy value as the optional third argument to expand:

function createPerson(dataObject) {
	var tmpl = "li.person[data-item-key=$id;]>a.external[href=http://foo.com?personid=$id;>{$name;}";
	return haiku.expand(tmpl, dataObject, true);
	// returns a string of serialized HTML
}

Single Node

In the above case, where your created DOM tree has a single root node, you could instead use Haiku's create method to get back an actual reference to the root DOM Element node instead. This is helpful if you need to do any further manipulation of the node (say, add an event handler or two) prior to insertion into the tree:

function createPerson(dataObject) {
	var tmpl = "li.person[data-item-key=$id;]>a.external[href=http://foo.com?personid=$id;>{$name;}";
	return haiku.create(tmpl, dataObject);
	// returns the DOM Element for the <li>
}

Credits

Minified version generated via UglifyJS, using Marijn Haverbeke's online tool.

Disclaimer

So far, this is more or less a subset of Zen Coding's power — I haven't yet added support for abbreviation groups (body>(header>h1)+(div#main)+(footer>span)), element multiplication (li*5>a), or item numbering (li#item$*3).

I expect if this project proves useful, I'll probably add those features (and maybe expand the templating capability a bit more) at some point in the future.