OO templates for Node.js
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Failed to load latest commit information.



Coffee Views was inspired by coffee-templates and coffeekup to add template inheritance to CoffeeScript templating.


npm i --save coffee-views


# views/layout.coffee

{Html} = require 'coffee-views'

module.exports = class Layout extends Html
  # The #render() method is automatically called when rendering the view in express.
  render: (options)->
    @doctype 5
    @html {lang:'en'}, ->

      @head ->
        @title options.title

      @body ->
        @h1 options.title

  stylesheetBlock: ->
    @link rel:'stylesheet', href:'/css/main.css'
  contentBlock: ->
# views/myview.coffee

Layout = require './layout'

module.exports = class MyView extends Layout
  contentBlock: ->
    @div ->
      @p 'This is my view'
View = require './views/myview'
view = new View()
console.log view.compile 'render', title: 'My Site'

... will produce ...

<!doctype html>
<html lang="en">
    <title>My Site</title>
    <link rel="stylesheet" href="/css/main.css"/>
    <h1>My Site</h1>
      <p>This is my view</p>

Example 2 - in Express.js

# app.coffee
# using the templates in the previous example

# ...

app = express()

app.configure ->
  app.engine 'coffee', require('coffee-views').engine
  app.set 'view engine', 'coffee'
  app.set 'views', path.join(__dirname, 'views')

# ...

app.get '/', (req, res)->
  res.render 'myview',
    title: 'My Site'

Inheriting methods

Just use CoffeeScript's native super() method to return a rendered parent method.

class MyExtendedView extends MyView
  contentBlock: ->
    @div ->
      @p 'This is an extension to "MyView"'

view = new MyExtendedView() 
console.log view.compile 'render', title: 'My extended view'
<!doctype html>
    <title>My extended view</title>
    <h1>My extended view</h1>
      <p>This is my view</p>
      <p>This is an extension to "MyView"</p>

Plain ol' JavaScript

There's a possibility you may want to use plain JavaScript instead of CoffeeScript. In this case, just use Node's util module to extend your classes:

// layout.js
var Html = require('coffee-views').Html,
    util = require('util');

function Layout(){}
module.exports = Layout;
util.inherits(Layout, Html);

Layout.prototype.render = function(options){

Layout.prototype.stylesheetBlock = function(){};
Layout.prototype.contentBlock = function(){};
// myview.js
var Layout = require('./layout'),
    util = require('util');

function MyExtendedView(){}
module.exports = MyExtendedView;
util.inherits(MyExtendedView, Layout);

MyView.prototype.contentBlock = function(){
    this.p('My content');
// extendedview.js
var MyView = require('./myview'),
    util = require('util');

function ExtendedView(){}
module.exports = ExtendedView;
util.inherits(ExtendedView, MyView);

ExtendedView.prototype.contentBlock = function(){
    this.p('Native extensions');

Registering XML Tags

When creating your own XML tags you can register them like so:

# my-xml.coffee

{Xml} = require 'coffee-views'

class MyXml extends Xml
MyXml.registerTag 'mung'
MyXml.registerTag 'face'
MyXml.registerOpenTag 'this-is-always-open'
MyXml.registerClosedTag 'this-is-always-closed'
# your-xml.coffee

MyXml = require './my-xml'

class YourXml extends MyXml
  render: ->
    @mung ->
      @face 'yay, custom tags'

# <mung><face>yay custom tags</face></mung>
# <this-is-always-open></this-is-always-open>
# <this-is-always-closed/>

Registered HTML Tags

Apart from the obvious HTML5 compliant tags, here are a few extras.

The JavaScript Tag

Using the #javascript() function will create a <script> tag with the passed function as a string.

class MyView extends Html
  javascriptBlock: ->
    @javascript ->
      alert 'Yay! CoffeeScript'

view = new MyView()
console.log view.compile 'javascriptBlock'
(function () {
  alert('Yay! CoffeeScript!');

You can also pass server variables through to your client code:

class MyView extends Html
  javascriptBlock: (options)->

    # Assuming "options" is {username:'Craig David'}

    @javascript [options.username], (username)->
      alert "Your name is #{username}. Lucky you. *snigger*"

    @javascript [options], (options)->
      alert "Name: #{options.name}"

    @javascript [-> 'Craig David'], (getName)->
      alert "getting name... #{getName()}"

... will produce ...

  alert('Your name is ' + username + '. Lucky you. *snigger*');
}).call(this, 'Craig David')

  alert('Name: ' + options.name);
}).call(this, {username:'Craig David'});

  alert('getting name... ' + getName());
}).call(this, function(){ return 'Craig David'; })


The #css() method renders as CCSS. Pass an object and it will create a <style> tag.

class MyView extends Html
  stylesheetBlock: ->
          padding: '5px'
          border: '1px solid'

view = new MyView()
console.log view.compile 'stylesheetBlock'
<style>form input {
  padding: 5px;
  border: 1px solid;

The Literal Tag

Using the #lit() method will just add any content to the output string:

class MyView extends Html
  contentBlock: ->
    @lit '<wierdtag/> Mung'

view = new MyView()
console.log view.compile 'contentBlock'
<wierdtag/> Mung

The Unliteral Tag

Using the #unlit() method will escape content if #safeOutput is set to true (which it is by default).

class MyView extends Html
  contentBlock: ->
    @unlit '<wierdtag/> Mung'

view = new MyView()
console.log view.compile 'contentBlock'
&lt;wierdtag/&gt; Mung

Escaping content on the fly

If you want to make sure something is escaped, go ahead and use the #escape() method:

escapedContent = @escape '<mung>' # => '&lt;mung&gt;'


HTML comments.

@comment 'Here\'a a comment'
@comment ->
  @p 'I\'ve been a commented out'

IE Specific comments

@ie ->
  @link rel:'stylesheet', href:'ie.css'
@ie 7, ->
  @link rel:'stylesheet', href:'ie7.css'
@ie 'lte', 8, ->
  @link rel:'stylesheet', href:'ie8.css'