Naivete Precedes Misrepresentation

    slm

    2.0.0 • Public • Published

    Slm

    Slm is a template language for js. Port of Slim but slimmer :)

    Build Status Test Coverage Dependency Status devDependency Status NPM version Code Climate Gitter

    A little bit of history

    HAML -> Jade -> Slim -> Slm

    Short list of the features

    • Elegant syntax
      • Short syntax without closing tags (Using indentation instead)
      • HTML style mode with closing tags
      • Shortcut tags (based on css selectors)
    • Safety
      • Automatic HTML escaping by default
      • Support htmlSafe attribute on String objects
    • Highly configurable and extendable via plugins
    • High performance
    • Easy integration with hapijs
    • Embedded engines like CoffeeScript, Markdown and Textile (TBD)

    Links

    How to start?

    Install Slm with npm:

    npm install slm --save
    

    Configure to work with ExpressJS

    // in app.js
     
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'slm');
     

    Configure to work with hapijs

    var Hapi = require('hapi');
     
    var server = new Hapi.Server(3000);
    server.views({
       engines: {
          'slm': require('slm')
       },
       basePath: __dirname + '/views',
       compileOptions: {
          basePath: __dirname + '/views',
          useCache: false // disable internal cache - useful for development
       },
       isCached: false // disable hapi view cache
    });
     
    server.route({
        method: 'GET', path: '/',
        handler: function (request, reply) {
          reply.view('index', {hello: "word"});
        }
    });
     
    server.start(function () {
      console.log('Server running at:', server.info.uri);
    });

    Syntax example

    Here's a quick example to demonstrate what a Slm template looks like:

    doctype html
    html
      head
        title Slm Examples
        meta name="keywords" content="template language"
        meta name="author" content=this.author
        javascript:
          alert('Slm supports embedded javascript!')
     
      body
        h1 Markup examples
     
        #content
          p This example shows you how a basic Slm file looks.
     
        == content()
     
        - if this.items.length
          table#items
            - for item in this.items
              tr
                td.name = item.name
                td.price = item.price
        - else
          p No items found Please add some inventory.
            Thank you!
     
        div id="footer"
          == partial('footer')
          | Copyright © ${this.year} ${this.author}

    Indentation matters, but the indentation depth can be chosen as you like. If you want to first indent 2 spaces, then 5 spaces, it's your choice. To nest markup you only need to indent by one space, the rest is gravy.

    Line indicators

    Text |

    The pipe tells Slm to just copy the line. It essentially escapes any processing. Each following line that is indented greater than the pipe is copied over.

    body
      p
        |
          This is a test of the text block.

    The parsed result of the above:

    <body><p>This is a test of the text block.</p></body>

    The left margin is set at the indent of the pipe + one space. Any additional spaces will be copied over.

    body
      p
        | This line is on the left margin.
           This line will have one space in front of it.
             This line will have two spaces in front of it.
               And so on...

    You can also embed html in the text line

    - for (var a in this.articles)
      | <tr><td>${a.name}</td><td>${a.description}</td></tr>

    Text with trailing white space .

    The single dot tells Slm to copy the line (similar to |), but makes sure that a single trailing white space is appended.

    Inline html < (HTML style)

    You can write html tags directly in Slm which allows you to write your templates in a more html like style with closing tags or mix html and Slm style.

    <html>
      head
        title Example
      <body>
        - if this.articles.length
          table
            - for (var a in this.articles)
              <tr><td>${a.name}</td><td>${a.description}</td></tr>
      </body>
    </html>

    Control code -

    The dash denotes control code. Examples of control code are loops and conditionals. Blocks are defined only by indentation. If your js code needs to use multiple lines, append a backslash \ at the end of the lines. If your line ends with comma , (e.g because of a method call) you don't need the additional backslash before the linebreak. Slm inserts ( and ) for if, for, else if automatically. So you JS code is more readable.

    body
      - if !this.articles.length
        | No inventory

    Output =

    The equal sign tells Slm it's a JS call that produces output to add to the buffer. If your JS code needs to use multiple lines, append a backslash \ at the end of the lines, for example:

    = javascript_include_tag(\
       "jquery",
       "application")

    If your line ends with comma , (e.g because of a method call) you don't need the additional backslash before the linebreak. For trailing or leading whitespace the modifiers > and < are supported.

    • Output with trailing white space =>. Same as the single equal sign (=), except that it adds a trailing white space. The legacy syntax =' is also supported.
    • Output with leading white space =<. Same as the single equal sign (=), except that it adds a leading white space.

    If you use Slm as express view engine, you have to make the function available to the view render, eg:

    res.render('viewname', { items: some.result.data, foofunc: foofunc })
    

    Then in your slm file you can call foofunc:

    p = this.foofunc()
    

    Output without HTML escaping ==

    Same as the single equal sign (=), but does not go through the escapeHtml method. For trailing or leading whitespace the modifiers > and < are supported.

    • Output without HTML escaping and trailing white space ==>. Same as the double equal sign (==), except that it adds a trailing white space.
    • Output without HTML escaping and leading white space ==<. Same as the double equal sign (==), except that it adds a leading white space.

    Output in Javascript j

    To output data from the node side within Javascript there is a j function:

    javascript:
      var user = ${=j(this.user)};

    Code comment /

    Use the forward slash for code comments - anything after it won't get displayed in the final render. Use / for code comments and /! for html comments

    body
      p
        / This line won't get displayed.
          Neither does this line.
        /! This will get displayed as html comments.

    The parsed result of the above:

    <body><p><!--This will get displayed as html comments.--></p></body>

    HTML comment /!

    Use the forward slash immediately followed by an exclamation mark for html comments (<!-- ... -->).

    IE conditional comment /[...]

    /[if IE]
        p Get a better browser.

    renders as

    <!--[if IE]><p>Get a better browser.</p><![endif]-->

    HTML tags

    Doctype tag

    The doctype tag is a special tag which can be used to generate the complex doctypes in a very simple way.

    XML VERSION

    doctype xml
      <?xml version="1.0" encoding="utf-8" ?>
    
    doctype xml ISO-8859-1
      <?xml version="1.0" encoding="iso-8859-1" ?>
    

    XHTML DOCTYPES

    doctype html
      <!DOCTYPE html>
    
    doctype 5
      <!DOCTYPE html>
    
    doctype 1.1
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
        "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    
    doctype strict
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
    
    doctype frameset
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
    
    doctype basic
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN"
        "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
    
    doctype transitional
      <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    

    HTML 4 DOCTYPES

    doctype strict
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
    
    doctype frameset
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
        "http://www.w3.org/TR/html4/frameset.dtd">
    
    doctype transitional
      <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
        "http://www.w3.org/TR/html4/loose.dtd">
    

    Closed tags (trailing /)

    You can close tags explicitly by appending a trailing /.

    img src="image.png"/

    Note, that this is usually not necessary since the standard html tags (img, br, ...) are closed automatically.

    Trailing and leading whitespace (<, >)

    You can force Slm to add a trailing whitespace after a tag by adding a >.

    a> href='url1' Link1
    a> href='url2' Link2

    You can add a leading whitespace by adding <.

    a< href='url1' Link1
    a< href='url2' Link2

    You can also combine both.

    a<> href='url1' Link1

    Inline tags

    Sometimes you may want to be a little more compact and inline the tags.

    ul
      li.first: a href="/a" A link
      li: a href="/b" B link

    For readability, don't forget you can wrap the attributes.

    ul
      li.first: a[href="/a"] A link
      li: a[href="/b"] B link

    Text content

    Either start on the same line as the tag

    body
      h1 id="headline" Welcome to my site.

    Or nest it. You must use a pipe or an apostrophe to escape processing

    body
      h1 id="headline"
        | Welcome to my site.

    Dynamic content (= and ==)

    Can make the call on the same line

    body
      h1 id="headline" = this.pageHeadline

    Or nest it.

    body
      h1 id="headline"
        = this.pageHeadline

    Attributes

    You write attributes directly after the tag. For normal text attributes you must use double " or single quotes ' (Quoted attributes).

    a href="http://slm-lang.com" title='Slm Homepage' Goto the Slm homepage

    You can use text interpolation in the quoted attributes.

    Attributes wrapper

    If a delimiter makes the syntax more readable for you, you can use the characters (...), [...] to wrap the attributes. You can configure these symbols.

    body
      h1(id="logo") = this.pageLogo
      h2[id="tagline" class="small tagline"] = this.pageTagline

    If you wrap the attributes, you can spread them across multiple lines:

    h2[id="tagline"
       class="small tagline"] = this.pageTagline

    You may use spaces around the wrappers and assignments:

    h1 id = "logo" = page_logo
    h2 [ id = "tagline" ] = this.pageTagline

    Quoted attributes

    Example:

    a href="http://slm-lang.com" title='Slm Homepage' Goto the slm homepage

    You can use text interpolation in the quoted attributes:

    a href="http://${url}" Goto the ${url}

    The attribute value will be escaped by default. Use == if you want to disable escaping in the attribute.

        a href=="&amp;"

    You can break quoted attributes with backslash \

    a data-title="help" data-content="extremely long help text that goes on\
      and one and one and then starts over...."
    

    Javascript attributes

    Write the javascript code directly after the =. If the code contains spaces you have to wrap the code into parentheses (...). You can also directly write hashes {...} and arrays [...].

    body
      table
        - for var user in this.users
          td id="user-${user.id}" class=user.role
            a href=userAction(user, 'edit') Edit ${user.name}
            a href=pathToUser(user) = user.name
    

    The attribute value will be escaped by default. Use == if you want to disable escaping in the attribute.

    a href==actionPath('start')
    

    You can also break javascript attributes with backslash \ or trailing , as describe for control sections.

    Boolean attributes

    The attribute values true, false, null and undefinded are interpreted as booleans. If you use the attribute wrapper you can omit the attribute assigment.

    input type="text" disabled="disabled"
    input type="text" disabled=true
    input(type="text" disabled)
     
    input type="text"
    input type="text" disabled=false
    input type="text" disabled=null

    Attribute merging

    a.menu class="highlight" href="http://slm-lang.com/" Slm-lang.com

    This renders as

    <a class="menu highlight" href="http://slm-lang.com/">Slm-lang.com</a>

    You can also use an Array as attribute value and the array elements will be merged using the delimiter.

    a class=['menu','highlight']
    a class='menu','highlight'

    Text interpolation

    Use ES6 interpolation. The text will be html escaped by default.

    body
      h1 Welcome ${current_user.name} to the show.
      | Unescaped ${=content} is also possible.
    

    To escape the interpolation (i.e. render as is)

    body
      h1 Welcome \${current_user.name} to the show.
    

    Mixins

    Mixins allow you to create reusable blocks of Slm.

    = mixin('paragraph')
      p Hello from mixin!
     
    .say
      = mixin('paragraph')

    They are compiled to functions and can take arguments:

    = mixin('paragraph', 'name')
      p Hello from ${this.name}!
     
    .say
      = mixin('paragraph', 'me')

    Even with default values:

    = mixin('paragraph', 'name = me')
      p Hello from ${this.name}!
     
    .say
      = mixin('paragraph')

    And from partial:

    // mixins.slm
    = mixin('paragraph', 'name = me')
      p Hello from ${this.name}!
     
    // index.slm
    = partial('mixins')
    .say
      = mixin('paragraph')

    License

    Slm is released under the MIT license.

    Special Thanks

    Install

    npm i slm

    DownloadsWeekly Downloads

    2,326

    Version

    2.0.0

    License

    ISC

    Unpacked Size

    320 kB

    Total Files

    57

    Last publish

    Collaborators

    • yury
    • anjlab