Code Monkey home page Code Monkey logo

haml-js's Introduction

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.

haml-js's People

Contributors

aaronblohowiak avatar aeosynth avatar andrewschaaf avatar codemonkeysteve avatar creationix avatar evilstreak avatar fjakobs avatar frob avatar kuma avatar maciek416 avatar maritz avatar nex3 avatar paulyoung avatar raganwald avatar redsquirrel avatar reid avatar soyuka avatar stevenharman avatar ttp avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

haml-js's Issues

Unexpected token >

%div{:style => "position: relative; margin: 0 auto; width: 500px; height: 300px"}
  .wrapper
    .navigation
      %ul.navigationList
        %li.navigationItem
          %a{:href => "a"} aha
        %li.navigationItem.itemActive
          %a{:href => "b"} b
        %li.navigationItem
          %a{:href => "b"} c
    #content.content

I'm trying to parse this haml, and it throws the error: Syntax error: Unexpected token >
Additional: haml.js:637

Multiple templates as a single input (your feedback?)

I have done some work RE integrating hamljs as a first citizen for Rails 3.1 Assets Pipeline.

And one of the suggestions I received is that templates are too small to have them in separate files.
So I thought putting multiple templates into one would be useful.

But not sure how to better approach it. I probably can split it manually and compile as separate ones, but just wondering if there are better ways.

Also any feedback that would help to solve most common problem is greatly appreciated.

In two words what it does:

Precompiled HAML templates (Rails 3.1 Assets Pipeline)

Assuming you have a file app/assets/javascripts/comment.js.hamljs on the server with the content:

.comment
  .text= text
  .author= author  

When this asset is require-d, it will give you access to plain Templates.comment function allowing you to write JavaScript like:

var html = Templates.comment({author: 'Dima', text: 'Awesome'});
$("#commit").append(html)

The name of the template function is derrived from the file name. If the file name is weird, you still can access it via Templates['what ever it is!'].

probs with interpolation in attributes

Thanks for putting this together--perfect timing for us :)

I'm trying to find the easiest way to conditionally include an attribute, and running into the following. E.g.,:

    - var target = thumbnail_url ? "target=\\"_blank\\"" : null
    %a( href="#{id}" #{target} )= name

This seems really awkward and so I am thinking of hacking the attribute parser to add some sort of conditional interpolation. Any thoughts on this? But, unfortunately, even the above does not work as expected and instead produces:

   var _$output="";var target = thumbnail_url ? "target=\"_blank\"" : null; _$output = _$output  +
"<a href=\"" +
html_escape(id) +
"\">" + 
name + 
"</a>";

which clearly (note the lack of interpolation of #{target} and the dangling quote ") seems like a bug, no?

Thanks!
tv/

cli.js needs a #!

Please either remove the bin from the package.json, or add a #!/usr/bin/env node or something to it, so that it can work ever.

Plugins lose scope

I believe this should work but when I try to use a local variable inside a :foreach loop the parsing fails with:

ReferenceError: mystring is not defined
    at eval at <anonymous> (/Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.j                                 s:83:55)
    at /Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.js:83:62
    at instance_eval (/Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.js:84:1                                 8)
    at /Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.js:205:21
    at parse_content (/Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.js:206:                                 9)
    at /Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.js:377:23
    at process_plugins (/Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.js:32                                 1:35)
    at /Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.js:383:25
    at Object.render (/Users/snoe/dev/teamating/lib/express/lib/support/haml/haml.js:402:                                 25)
    at [object Object].<anonymous> (/Users/snoe/dev/teamating/lib/express/lib/support/ham                                 l/what.js:18:17)

Here's the test code (works if I remove the loop):
= myarray
= mystring
:foreach{array: myarray, value: 'item'}
= item
= mystring

Run with:
// Set up a scope for our view to render in
var scope = {
myarray : [1,2,3],
mystring : "hello there"
};
file.read('what.haml').addCallback(function (source) {
sys.puts(Haml.render(source, {
locals: scope
}));
});

inconsistent handling of indent

Not sure about this, but I didn't expect it. Two space indent is handled differently than one space indent or tab.

a=haml.compile('%table\n\t%tr')
'"

" + \n"
" +\n"" + \n""'
a=haml.compile('%table\n %tr')
'"" + \n"
" +\n"" + \n""'
a=haml.compile('%table\n %tr')
'"" + \n"" + \n"" + \n"
"'

%script doesn't close properly

haml-js treats script tags as self closing, but <script /> does not work; script tags need to be closed with </script>.

I wrote a simple test app, which displays a link at '/', but nowhere else.

app.js
var haml = require('./lib/haml');
var file = require('file');
var http = require('http');

http.createServer(function (req, res) {
  file.read('app.haml').addCallback(function (source) {
    var body = haml.render(source, {
        locals: {
          url: req.url
        }
    });
    res.sendHeader(200, {'Content-Type': 'text/html'});
    res.sendBody(body);
    res.finish();
  });
}).listen(8000);

app.haml
%html
%head
:if url !='/'
%script
%body
%a{ href: 'link' }
link

$ node -v; git branch -v

0.1.25

  • master 53fad8e Rename the :script plugin to :javascript to conform more closely with ruby haml. :script is still allowed however.

edit: I tried this on Chrome and it works fine, but Opera/Firefox don't display.

:else block rendering unexpected results

Here is my haml template:

.handle drag
:each plannedTime in plannedTimes
  .duration= plannedTime

Here is what is being generated

<div class="handle">
  drag
  <div class="duration">1 day</div>
  <div class="duration">2 days</div>
  <div class="duration">3 days</div>
</div>

This is what I was expecting:

<div class="handle">
  drag
</div>
<div class="duration">1 days</div>
<div class="duration">2 days</div>
<div class="duration">3 days</div>

:plain filter

Please add a :plain filter to the haml-js implementation.

I find the :plain filter does not work and is not documented, is it just not implemented? It would come in handy for my purpose of writing code examples using the haml template language in https://github.com/bevry/docpad/

e.g. i would like to write a codeblock like this:

%pre
  :plain
     this is my sample code.
     syntax-highlighting will be done on the client-side
     i want newlines and spaces to be preserved.

how can enable filters

i'd like to enable a markdown filter a la haml:

%root %child :markdown * item 1 * item 2 * item 3

how can i do this?

rendering a hrefs doesn't work

How does one render a hrefs?

%a{:href => "about.html"} 
  About 

renders to:

"<a =\"" + html_escape(href => "about.html") + "\">" + 
"About" +
"</a>"

Thanks.

Problems with 0.4.0

Love haml-js but am having some problems with 0.4.0. I had been using 0.2.5 for a while and was able to write the following code in nodejs:

fs = require('fs');
haml = require('haml');
content = fs.readFileSync('test.haml','utf-8');
console.log(haml.render(content));

This used to work completely fine. Now it does not.

Here is the content of test.haml:

.class1
.class2#testid

All i get back from haml is 'undefined'.

Sass support

Haml comes bundled with Sass.
It would be great to see it in Picard.

Attribute splats

I've had a JS object with some key-value pairs I wanted to put as attributes on tags, but it seemed that only way to do so is to manually maintain attributes for all the k-v pairs I have, which I thought was pretty inelegant and dumb maintenance-wise, so I went ahead and implemented splat syntax for attributes in my fork of ruby-haml-js.

It works like this:

%p{ attr: 'val', *splat }
    hurr durr

Which given splat: { sattr: 1, sattr2: 'derp' } as the argument to the template renders as such:

<p attr="val" sattr="1", sattr2="derp">
    hurr durr
</p>

I'm not sure if there is any need for such functionality and if it is a safe thing to do - I mean I use the escape func, but since the rendering of the splats has to be done client-side it may be can be tampered with somehow?
But if it feels lik a good addition, I can try to clean it up and port it back to the main library.

Parse error when tags are in a certain order

I have the following template:

.component.video-player
  :if !useHtml5Player
    .play-button{ dojoAttachPoint : 'playButton' }
    %img.poster{ src : poster, dojoAttachPoint : "videoPlaceholder" }

  .backdrop{ dojoAttachPoint : 'backdrop' }

And it results in the following error:

with(locals || {}) {
  try {
   var _$output="<div class=\"component video-player\">" + 
(function () { if (!useHtml5Player) { return (
"<div dojoAttachPoint=\"" + html_escape('playButton') + "\" class=\"play-button\">" + 
"</div>"
"<img src=\"" + html_escape(poster) + "\" dojoAttachPoint=\"videoPlaceholder\" class=\"poster\" />"
);} else { return ""; } }).call(this) +
"<div dojoAttachPoint=\"" + html_escape('backdrop') + "\" class=\"backdrop\">" + 
"</div></div>";
 return _$output;  } catch (e) {
    return "\n<pre class='error'>" + html_escape(e.stack) + "</pre>\n";
  }
}

The issue is that there is no "+" after the play-button div string; however, if I put the img before that div, then everything works fine. I'm having a hard time tracking down where in the code this is getting assembled, any help would be welcome :)

not liking the spacing trimming

it seems if i want spacing inbetween any of my tags, i have to explicitly define that, like so:

%p
  Getting started is easy. Watch our
  =' '
  %a(href="#") demo video
  =' '
  to learn more.

This approach is artificially inflating the size of my Haml templates, and reducing readability.

Why can't it assume that items on a new line have a space between them, unless you specify %p>< similar to how Ruby Haml does?

see also:
http://haml-lang.com/docs/yardoc/file.HAML_REFERENCE.html#whitespace_removal__and_

:if etc cannot access context

for example if an instance of Request is the "context",
and my haml is:
:if this.flash('info')
%ul.messages.info
:each msg in this.flash('info')
%li= msg

fails due to "this" no longer being the given context

TypeError: Object #<an Object> has no method 'flash'
at eval at <anonymous> (lib/support/haml/lib/haml.js:473:11)
at IncomingMessage.<anonymous> (eval at <anonymous> (lib/support/haml/lib/haml.js:473:11))
at IncomingMessage.<anonymous> (lib/support/haml/lib/haml.js:473:18)
at Object.execute (lib/support/haml/lib/haml.js:479:8)
at Object.render (lib/support/haml/lib/haml.js:466:17)
at render (lib/express/plugins/view.js:74:36)
at [object Object].<anonymous> (lib/express/plugins/view.js:91:19)
at [object Object].emitSuccess (node.js:244:15)
at [object Object].<anonymous> (node.js:658:21)
at [object Object].emitSuccess (node.js:244:15)

putting inline javascript under :each breaks

example:

:each question in questions

  • var temp = 'hello'

Browser reports: missing ) after argument list

And the following is logged to the console

with (locals || {}) {
    try {
        var _$output = (function () {
            var __result__ = [], __key__, question;
            for (__key__ in questions) {
                if (questions.hasOwnProperty(__key__)) {
                    question = questions[__key__];
                    __result__.push("";
                    var temp = 'hello';
                    _$output = _$output
                )
                    ;
                }
            }
            return __result__.join("");
        }).call(this);
        return _$output;
    } catch (e) {
        return "\n<pre class='error'>" + html_escape(e.stack) + "</pre>\n";
    }
}

doesn't work on ie8

Is this on purpose? I'm trying to use haml-js on the client but it's not compatible to ie 8 <

Cryptic error message if trying to render 'undefined'

If we pass an undefined value as the first argument to haml.render, we get the following error:

TypeError: (Haml): Cannot call method 'trim' of undefined
at tokenize (/Users/redsquirrel/Projects/apprentice.us.com/vendor/haml/0.4.0/lib/haml.js:177:17)
at <error: TypeError: Cannot read property '0' of undefined>
at /Users/redsquirrel/Projects/apprentice.us.com/vendor/haml/0.4.0/lib/haml.js:624:18

Obviously, we shouldn't be passing an undefined value there, but a more revealing error would make debugging easier. :)

Making Haml.js work on the client-side

Recently my team decided to use Haml for our templates on the client-side. Out of the box the Haml.js library works for non-ie browsers, but of course we must support Internet Explorer. I was able to make a version for my team's purposes that uses underscore.js as a dependency. If I get some extra time I'll fork and make a version that doesn't depend on underscore.js. If someone else happens to get around to it before I do, below is a list of the exact changes that need to take place to get the current version of Haml.js to play nicely with IE.

  1. The primary signature for Haml needs to be "Haml = function(haml, config) {", not "Haml = function Haml(haml, config) {"
  2. Replace String.trim()
  3. Replace Array.forEach, Array.filter, Array.indexOf, and Array.map

Thanks

haml-js works in Safari and Firefox, but breaks in IE8

I know that the mandate is for haml-js to work in server-side JS only, but it is extremely useful when writing client-side JS applications as well. The minor issues are some missing methods on core prototypes like Array. These are easily worked around in a separate JS file. The more major issue is that the syntax matcher.regexp(line) is not supported in IE at all, and this requires an actual patch to transform it into matcher.regexp.exec(line).

equivalent for content_for :head and/or blocks like Ruby do

is there an easy way to do include code in the layout HEAD tag from within a haml template / partial with Haml.js and/or Picard?

- content_for :head do
  = css_include 'groups/list'

%section.left
  - unless true # unless you have pending invitations
    %h1 Recommended Groups

i can see that templates are processed before their layout files are, and I imagine i could write some sort of helper, but wondering if this has already been thought of and provided for.

notice how haml is able to be rendered by nesting within the Do block

Tabs in place of spaces break things

It took me a few minutes to realize that when I tried to use tabs instead of spaces that everything broke. So copy and paste your examples... it worked, but use tabs instead results in all sorts of broken javascript being generated.

When indenting - if blocks it generates invalid JS

Hey Aaron,

I don't know if this is an issue, or I'm doing something wrong. But if you indent an if block it does generates invalid JS:

- if (true) {
  %h1 Wont Work
- }

This is what I get:

return "";if (error !== undefined) {
- if (true) {
  %h1 Wont Work
- };
_$output = _$output  +
"";}; _$output = _$output ; }};

BTW I'm using haml.compile

Also, it would be nice to have a :elsif or :else ifplugin ;)

Nested tags can cause parent tag not to close

A problem I came across is that if you have a tag as the last element of a block, then the parent tag will not properly close.

%div   
  Does not close properly
  %div Nested same level as next div
%div   
  Will be nested, but should be top level

expressjs 2.0 support

I used haml-js to render .haml templates within my expressjs routes. This functionality is broken with the new expressjs 2.0 train.

HTML Tags don't nest properly with extra whitespace before haml

I have a template embedded in a script tag in my html file. Using DOM selectors (jquery in specfic) I pull in the 'text' of the script node.

To keep the html file clean, I use pretty spacing (i have similar results using 'tabs') like this:

  </body>
  <script type="text/haml" id="template">
    %h2 title
    %ul
      %li Text Item
  </script>
</html>

called via:

Haml( $("#template").text() );

or:

Haml( $("#template").html() );

results in:

<h2>title
  <ul>
    <li>Text item</li>
  </ul>
</h2>

however if the content of the script tag is 'normalize' like this:

  </body>
  <script type="text/haml" id="template">
%h2 title
%ul
  %li Text Item
  </script>
</html>

the resulting html is nested correctly:

<h2>title
<ul>
  <li>Text item</li>
</ul>

Using the command-line haml interpreter, it seems that this kind of nesting is 'illegal'. Still not sure if this is a bug to be fixed or not, however the command-line version throws an error when it encounters this formatting instead of silently converting incorrectly.

Conditional `selected` at runtime

So how do you generate (or not) selected attribute with HAML similar to this:

#something{selected: visible}

When I do:
Haml.compile('#something{selected: visible}')

I get the code generated:

"<div selected=\"" + undefined(visible) + "\" id=\"something\">" + 
"</div>"

This includes undefined(visible) which is invalid JavaScript.
Am I doing something wrong here?

IE problems

Seems like haml.js is using some JS methods that dont exist in IE

[].forEach

and matcher.regexp

probably others. I'm working through them 1 by 1. Am i missing a required compatibility library?

haml.js broken in firefox due to regexp regression

Fix in the following patch

diff --git a/vendor/assets/javascripts/haml.js b/vendor/assets/javascripts/haml.js
index e5fe217..d586a96 100755
--- a/vendor/assets/javascripts/haml.js
+++ b/vendor/assets/javascripts/haml.js
@@ -387,7 +387,7 @@ var Haml;

       // Collect all text as raw until outdent
       if (block) {
-        match = block.check_indent(line);
+        match = block.check_indent.exec(line);
         if (match) {
           block.contents.push(match[1] || "");
           return;
@@ -399,7 +399,7 @@ var Haml;

       matchers.forEach(function (matcher) {
         if (!found) {
-          match = matcher.regexp(line);
+          match = matcher.regexp.exec(line);
           if (match) {
             block = {
               contents: [],

`:each` and `:if` syntax consistency

Is it possible to provide each and if blocks that are consistent with the original haml? I'm trying to share haml templates between the client and server in a rails app, so syntax must be compatible between the two in order for that to work.

:each blah in collection = fail

I am currently using haml.js on the client side, as the templating solution for sammy - and a core aspect of it simply isn't working.

When I do :each var in collection, and then try and use var, it always comes up undefined. Always.

:script plugin

haml already has a :javascript filter. IMO, haml-js should conform as closely as possible with the reference, so that we can actually use it as a reference.

inline locals don't work?

I'm new to using Haml but judging from the examples on the Haml site it seems the following should work:

locals: {
  me: "Aaron"
}

#test1 Hello = me`

The following is what renders: <div id="test1">Hello = me</div>

But shouldn't it render <div id="test1">Hello Aaron</div>

BTW, if I put the = me on a new line then it renders properly but I don't want a line break to be output between Hello and Aaron.

Thanks

Verbose plugin syntax

Hi, I understand that using JSON syntax makes the parser's job easier, but the resulting code looks awkward for humans. If I may be so bold, I'd like to propose the following syntax changes:

Instead of
:if{ condition : todolist.length > 20 }
use
:if{ todolist.length > 20 }

instead of
:foreach{ array : todolist, value : "item" }
use
:foreach{ item in todolist }

Auto-call objects with #toHTML()

Would be cool if for example a collection of flash messages could just:
= flash

instead of the regular ul, for each message li etc

non-unix line endings

Haml-js breaks when using non-unix (LF) line endings in templates. For example, if you're writing on windows you'll end up with either CR or CRLF, resulting in \r or \r\n in the template. Currently, Haml-js is splitting the templates on \n, so only the very last line of a template is evaluated.

A fix is to replace all \r or \r\n with \n BEFORE splitting.

Support :if, :else statements

I encountered a couple of unexpected behaviors in the :if plugin.

:if foo
  %p This
:else
  %p That

would be a great feature. I understand if it's difficult to implement this in the current parsing logic.

Also :if foo will yield an error if foo is not defined on the object. You need to type something like :if typeof foo != 'undefined' now which is kind of meh.

Thanks for a great template engine.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.