• Stars
    star
    900
  • Rank 50,742 (Top 1.0 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 15 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Haml ported to server-side Javascript. This is a traditional server-side templating language. Tested with node-js

haml-js - Server side templating language for JavaScript

Ever wanted to use the excellent HAML syntax on a javascript project? Me too, so I made one!. This has most of the same functionality as the traditional haml.

About the language

Here is the first example(with a little extra added) from the haml site converted to haml-js:

haml-js

!!! XML
!!! strict
%html{ xmlns: "http://www.w3.org/1999/xhtml" }
  %head
    %title Sample haml template
  %body
    .profile
      .left.column
        #date= print_date()
        #address= current_user.address
      .right.column
        #email= current_user.email
        #bio= current_user.bio

html

<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"><head><title>Sample haml template
</title></head><body><div class="profile"><div class="left column"><div id="date">January 1, 2009
</div><div id="address">Richardson, TX
</div></div><div class="right column"><div id="email">[email protected]
</div><div id="bio">Experienced software professional...
</div></div></div></body></html>

Note that this works almost the same as ruby's haml, but doesn't pretty print the html. This would greatly slow down and complicate the code. If you really want pretty printed html, then I suggest writing one using the xml parser library and process the resulting html..

API

Haml(haml) -> template(locals) -> html

This is the new (as of 0.2.0) way to generate haml templates. A haml template is a live function that takes in "this" context and a "locals" variable. This compile step takes a few milliseconds to complete so it should be done at startup and the resulting function should be cached. Then to use the template function you simply call it with the desired local variables and it will output html at blazing speeds (we're talking millions per second on my 13" MBP)

Compile and store a template:

var main = Haml(main_haml);

Then use it whenever you need a new version:

main({name: "Tim", age: 28});

That's it. Haml templating made easy!

If you want to store the generated javascript to a file to skip the compile step later on you can either decompile the template function or use the compile and optimize advanced functions directly.

Haml.compile(text) -> JavaScript compiled template

Given a haml template as raw text, this compiles it to a javascript expression that can later be eval'ed to get the final HTML.

The following input:

#home
  = title
  %ul.menu
    %li Go Home
    %li Go Back

Produces the following JavaScript expression:

"<div id=\"home\">" + 
title +
"\n" + 
"<ul class=\"menu\">" + 
"<li>" + 
"Go Home\n" + 
"</li>" + 
"<li>" + 
"Go Back\n" + 
"</li>" + 
"</ul>" + 
"</div>"

Haml.optimize(js) -> optimized JavaScript expression

Takes the output of compile and optimizes it to run faster with the tradeoff of longer compile time. This is useful for framework developers wanting to use haml in their framework and want to cache the compiled templates for performance.

With the previous input it outputs:

"<div id=\"home\">" + 
title +
"\n<ul class=\"menu\"><li>Go Home\n</li><li>Go Back\n</li></ul></div>"

Notice how congruent static strings are merged into a single string literal when possible.

Haml.execute(js, context, locals) -> Executes a compiled template

Context is the value of this in the template, and locals is a hash of local variables.

Haml.render(text, options) -> html text

This is a convenience function that compiles and executes to html in one shot. Most casual users will want to use this function exclusively.

The text parameter is the haml source already read from a file.

The three recognized options are:

  • context: This is the this context within the haml template.
  • locals: This is an object that's used in the with scope. Basically it creates local variables and function accessible to the haml template.
  • optimize: This is a flag to tell the compiler to use the extra optimizations.

See test.js for an example usage of Haml.render

Executable JavaScript (not output)

New in version 0.2.6 is the ability to embed javascript in your template function. This lets you do variable assignments, if/else, switch statements, and even define functions. In Haml.js, execution blocks begin with a - and define a raw js block. This behaves slightly differently from Ruby's Haml. The advantage is that you can easily have multi-line executable blocks and comments, but the downside is that that you have to "outdent" the haml if you want to output from within a javascript block.

Simple example:

- var area = 0.5 * length * height
.area= area

Multi-line example:

- var obj = {
    area: 0.5 * b * h,
    r: opposite / adjacent
  }
.triangle-details Area is: #{area} and the ratio is: #{r}

"Outdent" the haml in a javascript block (the "goodbye" div is not rendered!)

.conditional
  - var a = "strings are truthy"
  - if(a){
  .hello
  -  } else{
  .goodbye
  - }

You can even define functions:

- function b(item){
.item
  %b= item
  %span.length= item.length
- }
- b("Hi")
- b("World")

This outputs:

<div class="item"><b>Hi</b><span class="length">2</span></div><div class="item"><b>World</b><span class="length">5</span></div>

Please see test/raw_complex.haml for more details and examples.

Comments

Comments that will not appear in the compiled JS function nor the output begin with -#

-# This is a comment
- # This is a syntax error because of the extraneous space between the - and #.

If you want to have comments that will be in the compiled JS function but NOT the final HTML output:

- /*
  here we can have a comment that will not be output. Since executable-JS is block-level,
  we can have as much comment as we want, and it will not be output to html */

If you want an HTML comment that WILL be in the final HTML, begin with /

Whitespace

By default, Haml.js has no whitespace between tags. In this way, Haml.js is the opposite of Haml in Ruby. You can insert whitespace around or inside tags with > and <, respectively.

Most commonly, you want to have an a or span with whitespace around it:

Download the file
%a(href="/home")> here
now.

Will produce:

Download the file <a href="/home">here</a> now.

You can also combine them if you want to have whitespace around and inside your tag.

%span<> This will have space in and around it.
%span>< This will, too.
%span><= "also works with code".toUpperCase()

Please see test/whitespace.haml for more examples.

Code interpolation

As of version 0.2.0 there is string interpolation throughout. This means that the body of regular text areas can have embedded code. This is true for attributes and the contents of plugins like javascript and markdown also. If you notice an area that doesn't support interpolation and it should then send me a note and I'll add it.

For interpolation, you may use #{} for escaped interpolation or !{} for unsafe interpolation.

Html Escaping / Sanitizer

You probably don't want to put unescaped user input right into your html. http://xkcd.com/327/ HTML/XSS sanitization is the new "Bobby Tables."

Let's assume we have a malicious username: name = "<script>...</script>"

Always unsafe:

  %span!= name
  
  <span><script>...</script></span>

Always safe:

  %span&= name
  <span>&lt;script&gt;...&lt;/script&gt;</span>

Sometimes safe:

  %span= name

The behavior of = depends on the setting of the escapeHtmlByDefault configuration variable. To make = safe, call Haml like this:

  Haml(src, {escapeHtmlByDefault: true})

Plugins

There are plugins in the parser for things like inline script tags, css blocks, and support for if statements and for loops.

:if/:else statements

if statements evaluate a condition for truthiness (as opposed to a strict comparison to true) and includes the content inside the block if it's truthy. An optional else is also supported.

:if todolist.length > 20
  %p Oh my, you are a busy fellow!

:if val == selectedVal
  %option{value: val, selected: true}= val
:else
  %option{value: val}= val

:each loops

:each loops allow you to loop over a collection including a block of content once for each item. You need to what variable to pull the data from and where to put the index and value. The index variable is optional and defaults to __key__.

Here is an example over a simple array.

%ul.todolist
  :each item in todolist
    %li= item.description

You can loop over the keys and values of objects too (Note the inner :each loop)

:each item in data
  :if item.age < 100
    %dl
      :each name, value in item
        %dt&= name
        %dd&= value

:css and :script helpers.

It's easy to embed script and css tags in an haml document. Note that both :script and :javascript will work.

%head
  :javascript
    function greet(message) {
      alert("Message from MCP: " + message);
    }
  %title Script and Css test
  :css
    body {
      color: pink;
    }
%body{ onload: "greet(\"I'm Pink\")" } COLOR ME PINK

This compiles to the following HTML:

<head>
<script type="text/javascript">
//<![CDATA[
  function greet(message) {
    alert("Message from MCP: " + message);
  }
//]]>
</script>
<title>Script and Css test
</title>
<style type="text/css">
  body {
    color: pink;
  }
</style>
</head><body onload="greet(&quot;I'm Pink&quot;)"> COLOR ME PINK
</body>

Custom Escaper

By default, Haml(src) returns a completely self-sufficient function, including a nested html_escape function. However, repeating the html_escape function definition in each of your templates is going to use more size than necessary. So, you may pass the name of a custom escaper in an optional config variable.

  Haml(src, {customEscape: "MyApp.esc"})

Then, the output template function definition will call MyApp.esc(string) and will omit the html_escape function definition. Haml.html_escape exposes the default escape function. If you are going to render your templates in the same context where you compile them (for instance, if you are only rendering them on the server side,) it might make sense to use Haml(src, {customEscape: "Haml.html_escape"})

Get Involved

If you want to use this project and something is missing then send me a message. I'm very busy and have several open source projects I manage. I'll contribute to this project as I have time, but if there is more interest for some particular aspect, I'll work on it a lot faster. Also you're welcome to fork this project and send me patches/pull-requests.

About Performance

The haml compiler isn't built for speed, it's built for maintainability. The actual generated templates, however are blazing fast. I benchmarked them with over 65 million renders per second on a small (20 line) template with some dynamic data on my laptop. Compare this to the 629 compiles per second I got out of the compiler. The idea is that you pre-compile your templates and reuse them on every request. While 629 per second is nothing compared to 65 million, that still means that your server with over 600 different views can boot up in about a second. I think that's fine for something that only happens every few weeks.

License

Haml-js is licensed under the MIT license.

More Repositories

1

js-git

A JavaScript implementation of Git.
JavaScript
3,815
star
2

step

An async control-flow library that makes stepping through logic easy.
JavaScript
2,214
star
3

wheat

Wheat is a blog engine for coders written in node.JS
JavaScript
1,364
star
4

howtonode.org

This repo contains the actual articles for HowToNode.org
JavaScript
887
star
5

topcube

Webkit Bindings for node
JavaScript
403
star
6

nstore

nStore is a simple, in-process key/value database for node.js
JavaScript
393
star
7

jsonparse

A streaming JSON parser written in pure JavaScript for node.js
JavaScript
349
star
8

do

Do is a simple library for managing async actions in node.JS.
JavaScript
294
star
9

dukluv

LibUV bindings for duktape JS engine
C
265
star
10

msgpack-js

The msgpack protocol implemented in pure javascript.
JavaScript
252
star
11

http-parser-js

A pure JS HTTP parser for node.
JavaScript
237
star
12

node-gir

Node bindings to libgirepository
C++
231
star
13

node-git

Node.JS library to read git repositories.
JavaScript
205
star
14

node-persistence

A high level persistance/database system for node.js
JavaScript
193
star
15

tedit

Chrome app for tedit
JavaScript
188
star
16

node-sdl

Minimal sdl bindings for maximum fun
C++
180
star
17

brozula

VM that runs in the browser and interprets luajit bytecode.
JavaScript
168
star
18

node-router

A simple http server for node.js that has sinatra like qualities. Ideal for generating web services via node.
JavaScript
166
star
19

js-github

An implementation of the js-git interface that mounts a live github repo.
JavaScript
162
star
20

node-webgl

OpenGLES 2.0 bindings for nodeJS with a webGL API
JavaScript
161
star
21

postgres-js

The postgres backend protocol implemented in pure JS for use with node.js
JavaScript
121
star
22

jsgit

A command-line git client powered by js-git and node.js
JavaScript
114
star
23

node-leveldb

NodeJS bindings to levelDB - a fast and lightweight key/value database library
C++
113
star
24

jquery-haml

jQuery-haml is a haml like language written in JSON. This allows for easy dom building so that web apps can do more work independent of the server for a better user experience.
JavaScript
111
star
25

jack

Another new language. The name will probably change.
JavaScript
109
star
26

gen-run

Generator Async Runner. Makes it possible to yield and wait for callbacks and continuables.
JavaScript
105
star
27

stack

Stack is a minimal http module system for node.js
JavaScript
103
star
28

couch-client

A minimal CouchDB client that easy and powerful
JavaScript
101
star
29

weblit

A web framework for luvit 2.0 and lit
Lua
101
star
30

node-gamepad

node.js bindings for Alex Diener's cross-platform gamepad code
C
95
star
31

msgpack-js-browser

A browser port of msgpack-js using DataView and ArrayBuffer.
JavaScript
92
star
32

git-browser

Browse Git Repos offline.
JavaScript
88
star
33

js-git-app

A js-git packaged app for chrome and chromebooks.
JavaScript
77
star
34

node-blog

This repo is the code behind the blog HowToNode.org
JavaScript
76
star
35

domchanger

dombuilder that applies diffs only to the real dom
JavaScript
70
star
36

nuv

N-API bindings to libuv with async/await friendly JS wrapping on top.
JavaScript
66
star
37

ivy

Ivy is Tim Caswell's personal node.js distribution, fork and customize!
Shell
59
star
38

conductor

Conducts async functions into orchestrated masterpieces
JavaScript
52
star
39

lua-git

Git implementation in pure lua for luvit.
Lua
51
star
40

nstore-session

This is a connect session store using nStore
JavaScript
51
star
41

libco

Mirror of http://byuu.org/library/libco/
C
51
star
42

rack-php

A php 5.3 framework with built in rack support. You can serve the php site using thin, mongrel, webrick, passenger, mod_php, or mod_fcgid.
JavaScript
51
star
43

jack-old

A new programming language that sits on top of JavaScript in order to iron out the rough spots and please the programmer
JavaScript
47
star
44

wheaty

JS-Git based application hosting platform
JavaScript
45
star
45

sousaball

social networking game project using html5 canvas for the front end and node.js/V8 for the backend.
JavaScript
45
star
46

adventure

Adventure is the start of a real-time RPG world using node.js and Websockets.
JavaScript
41
star
47

movies

The server I use to stream my kids dvd backups over http using node.js from a mac mini running linux.
JavaScript
40
star
48

luvmonkey

Spidermonkey shell with libuv bindings built-in.
C
39
star
49

moonslice-luv

A port of moonslice running on top of luv and lhttp_parser
Lua
38
star
50

safereturn

Functional helpers for callback based code.
JavaScript
38
star
51

seaduk

An implementation of nucleus-js using duktape and libuv implemented in C
C
35
star
52

dombuilder

An easy dombuilder using json-ml style syntax
JavaScript
35
star
53

min-stream

A meta-package for min-stream helper modules.
JavaScript
33
star
54

node-web

A small and fast web/http library for nodejs. (replaces the built-in http module)
JavaScript
33
star
55

refresh

Refreshing REST/Webdav for node
JavaScript
33
star
56

proto

Adds nice utilities to Object.prototype for JavaScript using Object.defineProperty
JavaScript
32
star
57

creationix

My personal sandbox for growing packages.
JavaScript
31
star
58

pattern

An experiment with my new prototypal style programming
JavaScript
30
star
59

rec

A tool for recording CLI programs and posting their output.
JavaScript
29
star
60

uscript

μScript is a simple programming language for μControllers co-designed by a 9-year-old.
C
29
star
61

simple-mime

A small, simple mime database for node.js
JavaScript
29
star
62

grain

Grain is an async framework for node-js templating languages.
JavaScript
28
star
63

fastqueue

A fast push/shift sync queue
JavaScript
28
star
64

sftp-server

sftp-server implemented in pure JS using node
JavaScript
28
star
65

websocket

A simple drop-in replacement for node's TCP server that supports the WebSocket protocol.
JavaScript
26
star
66

nodemcu-webide

A websocket based IDE for nodemcu devices.
JavaScript
25
star
67

LESS.tmbundle

a textmate bundle for less css using the node version of the library at http://github.com/cloudhead/less.js
25
star
68

nibs

Lua
23
star
69

boxcode

A tiling code editor
JavaScript
23
star
70

firmata-chrome

Firmata driver for chrome.serial
JavaScript
23
star
71

topcloud

High level application framework for Javascript (built on top of jquery-haml and modeled somewhat after SproutCore)
JavaScript
21
star
72

basic-games

An archive of the best games I wrote for Q-Basic over a 10 year span.
C++
21
star
73

experiments

Random collection of my experiments
JavaScript
20
star
74

drop-dat

A quick file sharing mechanism using dat libraries.
JavaScript
20
star
75

uvrun

Tiny node module to expose uv_run and uv_run_once to JavaScript
C++
19
star
76

candor.io

candor.io is a server framework that uses the candor language combined with libuv to make fast scripted network servers.
C++
19
star
77

chrome-app-module-loader

A module loader that lets you load npm modules from a chrome app.
JavaScript
19
star
78

nodeconf2012

My slides and content from nodeconf 2012
Lua
18
star
79

world-db

A specialized database for massive tilemaps
JavaScript
18
star
80

git-node-fs

A node adapter for the fs-db mixin for js-git.
JavaScript
18
star
81

mine

Miner digs into a javascript file looking for require calls. Used to statically extract common js dependencies.
JavaScript
17
star
82

lshell

A remote shell using luvit, websockets, and term.js
JavaScript
17
star
83

coffeepot

A compiler for coffee-script written in coffee-script.
JavaScript
17
star
84

git-node

A convenience wrapper for js-git preconfigured for node.js
JavaScript
17
star
85

moonslice

A fast web framework for luvit
JavaScript
16
star
86

git-sha1

A pure js SHA1 implementation created for js-git.
JavaScript
16
star
87

bench-suite

A benchmark skeleton for something better than static hello world http servers.
C
15
star
88

candor.js

An alternate vm for candor that runs in your browser!
JavaScript
14
star
89

staff

A port of the excellent Backbone.JS with minor API style changes and no dependencies. ES5 support only.
JavaScript
14
star
90

revision

TypeScript
14
star
91

ujkl

Micro Jack Lisp - For ESP8266 and Raspberry PI
C
14
star
92

msgpack-es

Msgpack implemented in pure ecmascript.
JavaScript
14
star
93

git-repo

A local git repository using any pluggable backend.
JavaScript
14
star
94

dukcurl

libcurl bindings for duktape
JavaScript
13
star
95

redis-luvit

A redis client for luvit
Lua
12
star
96

jack-lang

C VM for Jack Language
C
12
star
97

wscat

A netcat like client for websockets
Lua
12
star
98

ts-git

TypeScript re-implementation of js-git (aka js-git 2.0)
TypeScript
12
star
99

git-tree

Create a composite tree of js-git repos and work via paths.
JavaScript
11
star
100

luvit-quest

An interactive workshop that teaches network programming with luvit.
JavaScript
11
star