Kidomi - a JSON-based templating library
Posted on 05 January 2014 in articles
Certainly, ClojureScript plays a major role in why the templating syntax seems so natural and pleasant, e.g.:
1 2 3 4 5 6 | (node
[:span
{:style
{:color "#aaa"
:text-decoration "line-through"}}
"hello world!"])
|
But with JavaScript arrays and objects, there is a way to create something similar
1 2 3 4 5 | kidomi(['span',
{'style':
{'color': '#aaa',
'text-decoration': 'line-through'}},
"hello world!"])
|
Which outputs a HTMLElement with the following nested structure:
1 2 3 | <span style="color:#aaa; text-decoration:line-through">
hello world!
</span>
|
Kidomi is written in CoffeeScript. It is covered by unit tests via QUnit and can be used by a Google Closure compiler in an ADVANCED_MODE compilation or separately (e.g. to produce a minified output).
Usage
The kidomi(data) function returns a HTMLNode constructed from a data, for example:
1 2 3 4 5 6 7 8 9 10 | elem = kidomi(
['div#main.content',
['span', {'style': {'color': 'blue'}}, 'Select file'],
['form', {
'name': 'inputName',
'action': 'getform.php',
'method': 'get'},
'Username: ',
['input', {'type': 'text', 'name': 'user'}],
['input', {'type': 'submit', 'value': 'Submit'}]]])
|
The generated HTML element is:
1 2 3 4 5 6 7 8 | <div id="main" class="content">
<span style="color: blue;">Select file</span>
<form name="inputName" action="getform.php" method="get">
Username:
<input type="text" name="user"></input>
<input type="submit" value="Submit"></input>
</form>
</div>
|
Syntax
The general syntax of kidomi is: node = kidomi(parsableObject). Here, node is a HTMLElement or in a more generic case a DOM node.
The parsableObject is:
- A string. The returned object is a Text node.
- A number. It is automatically converted to string and the returned object is a Text node.
- A node. The returned object is the same node.
- An array. This should be discussed a bit thoroughly:
The syntax of the parsableObject array is simple and very flexible. It consists of at least one item, which is:
1 | ['element#id.class1.class2.classN']
|
Here, id - is the id attribute of the node, class1.class2.classN - CSS classes of the node, i.e. class="class1 class2 classN".
For example:
1 2 3 4 5 6 | ['div'] // <div></div>
['div#content'] // <div id="content"></div>
['span#user.username'] // <span id="user" class="username"></span>
['span.password'] // <span class="passwordd"></span>
['div.main.dialog'] // <div class="main dialog"></div>
// etc.
|
The second item is either an attributes object, or a sub-parsableObject. The attributes object has the following syntax:
1 2 3 4 | {'class': ['class1', 'classN'],
'style': {'prop1': 'val1', 'propN': 'valN'},
'attribute1': 'value1',
'attributeN': 'valueN'}
|
or
1 2 3 4 | {'class': 'class1 classN',
'style': 'prop1:val1; propN:valN;',
'attribute1': 'value1',
'attributeN': 'valueN'}
|
The class and style key-value pairs or strings are optional.
- The class key-value pair is an array or a string with CSS classes' names applied to the node. It is appended to the classes found in the first item of the parsableObject array.
- The style key-value pair is an object or a string of CSS style properties of the node.
The attributeX key-value pairs are the attributes of the node.
For example:
1 2 3 4 5 | ['a', {'class': ['biglink'],
'style': {'color': 'red'},
'href': 'http://github.com'}]
// <a href="http://github.com" class="biglink" style="color:red;"></a>
|
The rest of the array items are nested parsableObjects or in a special case - an array of arrays with parsableObjects. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | // Nested elements
['div', ['div', ['span.name', 'Name: '], ['span.lastname', 'Last name: ']]]
/*
<div>
<div>
<span class="name">Name: </span>
<span class="lastname">Last name: </span>
</div>
</div>
*/
// Expandable nested array
['tr', [['td', 'First'], ['td', 'Second'], ['td', 'Third']]]
/*
<tr>
<td>First</td>
<td>Second</td>
<td>Third</td>
</tr>
*/
|
Building and testing
You will need the following tools to build and test kidomi:
- GNU Make. This is used to run the Makefile script.
- CoffeeScript compiler. This is enough to build the library.
- Google Closure compiler. This is used to build the optimized version of the library. The CoffeeScript code is written with the Closure restrictions in mind.
- PhantomJS is used to run the unit tests from a shell. You can as well run them in a normal browser.
Advanced usage
Referencing elements
One of the patterns where kidomi might be especially handy is when you have to create certain HTML elements before adding them in a DOM structure. For example:
1 2 3 4 5 6 7 8 9 | button = kidomi(['button']);
button.onclick = function(){ alert('Hello world'); };
myDiv = kidomi(
['div',
['span', 'Click me:'],
button]);
document.body.appendChild(myDiv);
|
List comprehensions in CoffeeScript
List (array) comprehensions are very handy to use as the expandable array elements, for example:
1 2 3 4 5 | ['tr', [['td', '1'], ['td', '2'], ['td', '3']]]
# can be written as:
['tr', (['td', "#{i}"] for i in [1..3])]
|