Detalhes do pacote

handlebars-layouts

shannonmoeller374.7kMIT3.1.4

Handlebars helpers which implement layout blocks similar to Jade, Jinja, Nunjucks, Swig, and Twig.

blocks, dust, express, handlebars

readme (leia-me)

handlebars-layouts

NPM version Downloads Build Status Coverage Status Tip

Handlebars helpers which implement layout blocks similar to Jade, Jinja, Nunjucks, Swig, and Twig.

Install

With Node.js:

$ npm install handlebars-layouts

With Bower:

$ bower install shannonmoeller/handlebars-layouts

API

Helpers are generated by passing in your instance of Handlebars. This allows you to selectively register the helpers on various instances of Handlebars.

layouts(handlebars) : Object

  • handlebars Handlebars - An instance of Handlebars.

Generates an object containing the layout helpers suitible for passing into registerHelper.

var handlebars = require('handlebars'),
    layouts = require('handlebars-layouts');

handlebars.registerHelper(layouts(handlebars));

layouts.register(handlebars) : Object

  • handlebars Handlebars - An instance of Handlebars.

Both generates an object containing the layout helpers and registers them with Handlebars automatically.

var handlebars = require('handlebars'),
    layouts = require('handlebars-layouts');

layouts.register(handlebars);

Helpers

{{#extend [partial] [context] [key=value ...]}}

  • partial String - Name of partial to render.
  • context Object (Optional) - A custom context for the partial.
  • attributes Object (Optional) - Arbitrary values that will be added to the partial data context.

Loads a layout partial of a given name and defines block content.

{{#extend "layout" foo="bar"}}
    {{#content "title" mode="prepend"}}Example - {{/content}}
{{/extend}}

The {{#extend}} helper allows you to reason about your layouts as you would class extension where the above is equivalent to the following psuedo code:

class Page extends Layout {
    constructor() {
        this.foo = 'bar';
    }

    title() {
        return 'Example - ' + super();
    }
}

{{#embed [partial] [context] [key=value ...]}}

  • partial String - Name of partial to render.
  • context Object (Optional) - A custom context for the partial.
  • attributes Object (Optional) - Arbitrary values that will be added to the partial data context.

Allows you to load a partial which itself extends from a layout. Blocks defined in embedded partials will not conflict with those in the primary layout.

{{#extend "layout"}}

    {{#content "body"}}
        {{#embed "gallery"}}
            {{#content "body"}}
                <img src="1.png" alt="" />
                <img src="2.png" alt="" />
            {{/content}}
        {{/embed}}

        {{#embed "modal" foo="bar" name=user.fullName}}
            {{#content "title" mode="prepend"}}Image 1 - {{/content}}
            {{#content "body"}}<img src="1.png" alt="" />{{/content}}
        {{/embed}}
    {{/content}}

{{/extend}}

The {{#embed}} helper allows you to reason about your partials as you would class instantiation where the above is equivalent to the following psuedo code:

class Page extends Layout {
    body() {
        var gallery = new Gallery();

        gallery.replaceBody('<img src="1.png" alt="" />\n<img src="2.png" alt="" />');

        var modal = new Modal({
            foo: 'bar',
            name: this.user.fullName
        });

        modal.prependTitle('Image 1 - ');
        modal.replaceBody('<img src="1.png" alt="" />');

        return gallery.toString() + modal.toString();
    }
}

{{#block [name]}}

  • name String - Block identifier.

Defines a named block, with optional default content. Blocks may have content appended, prepended, or replaced entirely when extending or embedding. You may append and prepend to the same block multiple times.

{{#block "header"}}
    <h1>Hello World</h1>
{{/block}}

{{#block "main"}}
    <p>Lorem ipsum...</p>
{{/block}}

{{#block "footer"}}
    <p>&copy; 1970</p>
{{/block}}

{{#content [name] mode="(append|prepend|replace)"}}

  • name String - Identifier of the block to modify.
  • mode String (Optional) - Means of providing block content. Default: replace.

Sets block content, optionally appending or prepending using the mode attribute.

Layout:

<html>
    ...
    <body>
        {{#block "header"}}
            <h1>Hello World</h1>
        {{/block}}

        {{#block "main"}}
            <p>Lorem ipsum.</p>
        {{/block}}

        {{#block "footer"}}
            <p>&copy; 1999</p>
        {{/block}}
    </body>
</html>

Page:

{{#extend "layout"}}

    {{#content "header"}}
        <h1>Goodnight Moon</h1>
    {{/content}}

    {{#content "main" mode="append"}}
        <p>Dolor sit amet.</p>
    {{/content}}

    {{#content "footer" mode="prepend"}}
        <p>MIT License</p>
    {{/content}}

{{/extend}}

Output:

<html>
    ...
    <body>
        <h1>Goodnight Moon</h1>

        <p>Lorem ipsum.</p>
        <p>Dolor sit amet.</p>

        <p>MIT License</p>
        <p>&copy; 1999</p>
    </body>
</html>

Conditional Blocks

There are times where you need to wrap a block with an element or use a different class depending on whether content has been provided for a block. For this purpose, the content helper may be called as a subexpression to check whether content has been provided for a block.

For example, you may wish to have an optional column in a grid layout:

{{!-- layout.hbs --}}
<div class="grid">
    <div class="grid-col {{#if (content "right")}}grid-col_2of3{{else}}grid-col_full{{/if}}">
        {{{block "left"}}}
    </div>
    {{#if (content "right")}}
        <div class="grid-col grid-col_1of3">
            {{{block "right"}}}
        </div>
    {{/if}}
</div>

For a page that only needs a left column, you may omit defining content for the right block:

{{!-- page.html --}}
{{#extend "layout"}}

    {{#content "left"}}
        <p>Left</p>
    {{/content}}

{{/extend}}

Resulting in:

<div class="grid">
    <div class="grid-col grid-col_full">
        <p>Left</p>
    </div>
</div>

For a page with two columns, simply define content for both blocks:

{{!-- page.html --}}
{{#extend "layout"}}

    {{#content "left"}}
        <p>Left</p>
    {{/content}}

    {{#content "right"}}
        <p>Right</p>
    {{/content}}

{{/extend}}

Resulting in:

<div class="grid">
    <div class="grid-col grid-col_2of3">
        <p>Left</p>
    </div>
    <div class="grid-col grid-col_1of3">
        <p>Right</p>
    </div>
</div>

Example

layout.hbs

<!doctype html>
<html lang="en-us">
<head>
    {{#block "head"}}
        <title>{{title}}</title>

        <link rel="stylesheet" href="assets/css/screen.css" />
    {{/block}}
</head>
<body>
    <div class="site">
        <div class="site-hd" role="banner">
            {{#block "header"}}
                <h1>{{title}}</h1>
            {{/block}}
        </div>

        <div class="site-bd" role="main">
            {{#block "body"}}
                <h2>Hello World</h2>
            {{/block}}
        </div>

        <div class="site-ft" role="contentinfo">
            {{#block "footer"}}
                <small>&copy; 2013</small>
            {{/block}}
        </div>
    </div>

    {{#block "foot"}}
        <script src="assets/js/controllers/home.js"></script>
    {{/block}}
</body>
</html>

page.html

{{#extend "layout"}}
    {{#content "head" mode="append"}}
        <link rel="stylesheet" href="assets/css/home.css" />
    {{/content}}

    {{#content "body"}}
        <h2>Welcome Home</h2>

        <ul>
            {{#items}}
                <li>{{.}}</li>
            {{/items}}
        </ul>
    {{/content}}

    {{#content "foot" mode="prepend"}}
        <script src="assets/js/analytics.js"></script>
    {{/content}}
{{/extend}}

Putting Them Together

var handlebars = require('handlebars');
var layouts = require('handlebars-layouts');

// Register helpers
handlebars.registerHelper(layouts(handlebars));

// Register partials
handlebars.registerPartial('layout', fs.readFileSync('layout.hbs', 'utf8'));

// Compile template
var template = handlebars.compile(fs.readFileSync('page.html', 'utf8'));

// Render template
var output = template({
    title: 'Layout Test',
    items: [
        'apple',
        'orange',
        'banana'
    ]
});

console.log(output);

Output (prettified for readability)

<!doctype html>
<html lang="en-us">
<head>
    <title>Layout Test</title>

    <link rel="stylesheet" href="assets/css/screen.css" />
    <link rel="stylesheet" href="assets/css/home.css" />
</head>
<body>
    <div class="site">
        <div class="site-hd" role="banner">
            <h1>Layout Test</h1>
        </div>

        <div class="site-bd" role="main">
            <h2>Welcome Home</h2>
            <ul>
                <li>apple</li>
                <li>orange</li>
                <li>banana</li>
            </ul>
        </div>

        <div class="site-ft" role="contentinfo">
            <small>&copy; 2013</small>
        </div>
    </div>

    <script src="assets/js/analytics.js"></script>
    <script src="assets/js/controllers/home.js"></script>
</body>
</html>

Contribute

Tasks

Standards for this project, including tests, code coverage, and semantics are enforced with a build tool. Pull requests must include passing tests with 100% code coverage and no linting errors.

Test

$ npm test

© 2015 Shannon Moeller me@shannonmoeller.com

Licensed under MIT

changelog (log de mudanças)

3.1.3

Bugfixes:

  • Added support for objects with a null prototype. (#27, #28)

3.1.2

Bugfixes:

  • Handlebars wasn't playing nice with Object.create, so all cases have been removed in favor of property copying.
  • Now using handlebars.createFrame with options.data and using the result with partials.

3.1.1

Bugfixes:

  • Corrected handling of partial context when the native syntax is used inside of an embed. (#25)

3.1.0

Features:

  • The extend and embed helpers now support a custom context to match the signature and features of the default partials syntax: {{> partialName contextObject foo=bar }}. (#21)

3.0.0

Breaking Changes:

  • The @content value has been removed in favor of the updated content helper.

Features:

  • The content helper may now be used as a subexpression to check for the existance of block content. (#22)
Before: {{#if @content.foo}}    {{{block "foo"}}} {{/if}}
After:  {{#if (content "foo")}} {{{block "foo"}}} {{/if}}

2.0.2

Bugfixes:

  • Fixed a regression in the order of content rendering. (#18)

2.0.1

Bugfixes:

  • Added files missing from a bad commit.

2.0.0

Breaking changes:

  • The handlebarsLayouts(handlebars) function no longer automatically registers helpers. Instead it returns an object which is compatible with the Handlebars.registerHelper method. If you want the helpers to automatically be registered, use handlebarsLayouts.register(handlebars) instead. The return value of both functions has been changed to be the object of helpers rather than the passed-in handlebars instance. (#15)

Features:

  • Exposed @content variable to facilitate conditional blocks. (#16)

1.1.0

Features:

  • Arbitrary attributes may now be given to extend and embed and are added to the partial's data context.

1.0.0

Breaking changes:

  • Consolidated append, prepend, and replace helpers into a single content helper that accepts a mode attribute. (Thank you Assemble contributors).

Features:

  • Deep inheritance.
  • Added an embed helper to insert a partial that extends from its own layout.
  • Added test server for use with Express.

Bugfixes:

  • Browserify build was not properly wrapping module with UMD due to missing standalone option. Fixes AMD issues.

0.3.3

Bugfixes:

  • Corrected git paths in package.json.

0.3.2

Features:

  • Added support for Assemble-style registration by exposing a register method.

0.3.0 - 0.3.1

Features:

  • Refactor.
  • Switched from Grunt to Gulp.
  • Improved tests including coverage.

0.2.0

Features:

  • Blocks may now be appended to, prepended to, and replaced multiple times.

0.1.4

Bugfixes:

  • Support precompiled templates.