Caustic is a highly experimental JavaScript reflection-based template engine for web applications.
Caustic generates a View
simply by providing it html, no other intervention is required. It does this by "reflecting" on the node types, classes, and other attributes in order to build a meaningful and helpful object for interacting with it. This inference is powerful and dramatically reduces boilerplate template logic.
make
will build both the build targets, ./build/caustic.js and ./build/caustic.min.js for development and production use.
The examples in this section highlight some of the capabilities of Caustic, but certainly not all the features.
An extremely simple example would be building a list of pets. Instead of creating a template with Mustache, EJS, or similar, we simply add some html to our file as script tag, or simply pass a string of html.
<script type="text/template" id="pet-template">
<div class="pet">
<h2 class="name"></h2>
<p class="description"></p>
</div>
</script>
We may then want to add several pets to the following unordered list:
<ul id="pets"></ul>
To do this, we simply invoke View
(with or without new
) to create our "pet" views. By passing a non-html string (does not contain "<"), Caustic will grab the html from the element with the id name + "-template"
, so "pet-template". Caustic then provides us with many methods associated to the html provided, in this case simply some methods that allow us to set the text (or html) of the h2 and description paragraph, then appending each to the "#pets" list.
View('pet')
.name('Tobi')
.description('A small beige ferret.')
.appendTo('#pets');
View('pet')
.name('Jane')
.description('A small dark bitchy ferret.')
.appendTo('#pets');
Another example of this is a confirmation dialog, with the following logic-less html:
<script type="text/template" id="confirm-template">
<div class="confirmation dialog">
<h2 class="title"></h2>
<a href="#" class="close">Close</a>
<p class="description"></p>
<p class="buttons">
<a href="#" class="cancel">Cancel</a>
<a href="#" class="ok">Delete</a>
</p>
</div>
</script>
With the tiny follow snippet we can bring our dialog to life. By doing absolutely nothing but invoking View()
. Much like before we have auto-generated .title()
and .description()
methods to get or set values, as well as three methods bound to clicks on their associated elements. Caustic concludes from the fact that we have an "a" tag, and that we typically bind to the click event as a common behaviour, so Caustic makes this even easier for us. Likewise we could simply invoke .close()
or .cancel()
to invoke the callbacks programmatically.
View('confirm')
.title('Delete this item?')
.description('Click "cancel" to abort, "delete" otherwise.')
.close(function(){ this.remove(); })
.cancel(function(){ this.remove(); })
.ok(function(){ alert('item removed'); this.remove(); })
.appendTo('body');
Our todo list example consists of two views, the list itself and the items, each containing a checkbox and a label.
<script type="text/template" id="list-template">
<div>
<h2 class="title"></h2>
<ul class="items"></ul>
</div>
</script>
<script type="text/template" id="item-template">
<p>
<input type="checkbox" name="complete" />
<span class="label"></span>
</p>
</script>
The list and items are ease to manipulate, adding addition list items by passing a string, jQuery
object, or View
to list.items.add()
. Since Caustic is aware of "complete" being a checkbox
it allows us to toggle the value with .complete(expr)
, or get the value with .complete()
, or finally reacting to changes by providing a callback.
var list = View('list').title('Todo Items');
var item = View('item')
.label('Start caustic')
.complete(true);
list.items.add(item);
var item = View('item')
.label('Finish caustic')
.complete(function(checked){
if (checked) alert('yeah right!');
this.checked(false);
});
list.items.add(item);
list.appendTo('body');
The following sections discuss the API generated by View()
, each tag, and sometimes tags based on their type
etc are handled differently, and generate different methods for common use-cases. Wherever you see val
a View
, jQuery
, string
of html, or selector string
is valid. For example .add(val)
to append a value to a list, accepts views or anything jQuery may generate. Names are camel-cased, for example if you have a property named user-name
it becomes userName
, or user[name]
also becomes userName
.
Remove the view's element from the DOM.
Hide the view's element.
Show the view's element.
Append this view's element to val
.
Prepend this view's element to val
.
Replace val
's children with this view's element.
editForm.replace('body');
Add to a list:
user.addTo(friendsList);
<script type="text/template" id="login-template">
<form>
<input type="text" name="user[name]"/>
<input type="password" name="user[pass]"/>
</form>
</script>
.name(val)
:
var form = View('login');
form.userName('tj');
.name()
:
var form = View('login');
form.userName('tj');
console.log(form.userName());
.name.placeholder(val)
:
var form = View('login');
form.userName.placeholder('Username');
.name.isEmpty()
:
var form = View('login');
if (form.userName.isEmpty()) {
alert('enter a username!');
}
.name.clear()
:
var form = View('login');
form.userName('tj');
form.userName.clear();
<script type="text/template" id="login-template">
<form>
<input type="text" name="user[name]"/>
<input type="password" name="user[pass]"/>
<input type="checkbox" name="agree" />
</form>
</script>
.name(bool)
:
var form = View('login');
form.agree(true);
.name()
:
var form = View('login');
form.agree(true);
console.log(form.agree());
.name(fn)
:
var form = View('login');
form.agree(function(checked){
if (checked) {
...
}
});
html:
<script type="text/template" id="article-template">
<div class="article">
<h2 class="title"></h2>
</div>
</script>
.name(val)
:
var article = View('article');
article.title('Caustic view system');
.name()
:
var article = View('article');
article.title('Caustic view system');
console.log(article.title());
html:
<script type="text/template" id="dialog-template">
<div class="dialog">
<a href="#" class="close">Close</a>
</div>
</script>
.name(fn)
handles event:
var dialog = View('dialog');
dialog.close(function(){ this.hide(); });
.name()
triggers event:
var dialog = View('dialog');
dialog.close();
.name(method)
handles event, invoking method
:
var dialog = View('dialog');
dialog.close('hide');
"name" event is triggered when clicked, for example:
var dialog = View('dialog');
dialog.on('close', function(){
alert('I was closed!');
});
dialog.close();
html:
<script type="text/template" id="login-template">
<form action="/" method="post">
<input type="text" name="name" />
<input type="password" name="pass" />
<input type="submit" value="Login" />
</form>
</script>
.name
access jQuery object, defaulting the name to .form
:
var login = View('login');
console.log(login.form);
.name.values()
serialized array of values:
var login = View('login');
console.log(login.form.values());
.name.values.toString()
serialized x-www-form-urlencoded string of values:
var login = View('login');
console.log(login.form.values.toString());
.name.submit()
:
var login = View('login');
login.name('tj');
login.pass('foo');
login.submit();
.submit(fn)
:
var login = View('login');
login.name('tj');
login.pass('foo');
login.submit(function(){
console.log(login.values.toString());
});
html:
<script type="text/template" id="todo-template">
<ul class="list"></ul>
</script>
.name
to access the jQuery object:
var todo = View('todo');
todo.list.css('opacity', .5);
.name.add(val)
append a list element:
var todo = View('todo');
todo.list
.add('Buy groceries');
.add('Try out Caustic');
.add('Help out with Caustic');
``
## License
(The MIT License)
Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.