Skip to content
highly experimental JavaScript reflection-based template/view system for web applications
JavaScript
Pull request Compare This branch is 10 commits ahead of matschaffer:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.
build
examples
lib
.gitignore
History.md
Makefile
Readme.md
head
tail

Readme.md

Caustic

Caustic is a highly experimental JavaScript reflection-based template engine for web applications.

About

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.

Build

make will build both the build targets, ./build/caustic.js and ./build/caustic.min.js for development and production use.

Examples

The examples in this section highlight some of the capabilities of Caustic, but certainly not all the features.

Lists

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');

Confirmation Dialog

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');

TODO List

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');

API

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.

View#remove()

Remove the view's element from the DOM.

View#hide()

Hide the view's element.

View#show()

Show the view's element.

View#appendTo(val)

Append this view's element to val.

View#prependTo(val)

Prepend this view's element to val.

View#replace(val)

Replace val's children with this view's element.

editForm.replace('body');

View#addTo(list)

Add to a list:

user.addTo(friendsList);

Input tag

text / password

<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();

checkbox

<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) {
    ...
  }
});

Heading tags

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());

A tags

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();

Form tags

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());
});

UL / OL tags

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.

Something went wrong with that request. Please try again.