shannonmoeller / handlebars-layouts

Handlebars helpers which implement layout blocks similar to Jinja, Nunjucks (Swig), Pug (Jade), and Twig.
http://npm.im/handlebars-layouts
MIT License
361 stars 29 forks source link

Possible 'ifBlock' helper #16

Closed spacedawwwg closed 9 years ago

spacedawwwg commented 9 years ago

Basically, I'd like to include extra HTML in my layout conditionally, based on whether a particular {{#content}} has been included on a page.

I wrote a little helper that extends your helpers:

// Include Assemble & Helpers
var assemble = require('assemble');
var handlebars = require('handlebars');
var layouts = require('handlebars-layouts')(handlebars);

handlebars.registerHelper('ifBlock', function (names, options) {
  actions = this._layoutActions || {};
  names = names.split('||');
  for (var i=0; i < names.length; i++) {
    var name = names[i].trim();
    var action = actions[name];
    if (action) {
      return options.fn(this);
    }
  }
});

a use example would be:

layout--a.hbs


---
title: layout--a

---
{{#extend "master"}}
  {{#content "master__head" mode="append"}}
    {{#block "head"}}{{/block}}
  {{/content}}
  {{#content "master__body"}}
    <main role="main" class="layout layout--a">
      <div class="row">
        {{#ifBlock "region--a"}}
        <div class="region region--a">
        {{#block "region--a"}}{{/block}}
        </div>
        {{/ifBlock}}
        {{#ifBlock "region--b"}}
        <div class="region region--b">
        {{#block "region--b"}}{{/block}}
        </div>
        {{/ifBlock}}
      </div>
    </main>
  {{/content}}
  {{#content "master__foot" mode="append"}}
    {{#block "foot"}}{{/block}}
  {{/content}}
{{/extend}}

page.hbs


---
title: Page

---
{{#extend "layout--a"}}
  {{#content "region--a"}}
  <p>content</p>
  {{/content}}
{{/extend}}

...The output of page.hbs would not include the <div class="region region--b"> markup as I did not use {{#content "region--b"}}

I wondered if this might be worth including as part of your helpers?

shannonmoeller commented 9 years ago

As discussed in #17, I've added support for {{#if @content.main}} into the develop branch. It will be released as soon as I have time to update the documentation.

https://github.com/shannonmoeller/handlebars-layouts/blob/develop/test/fixtures/partials/layout.hbs#L12

shannonmoeller commented 9 years ago

Released as 2.0.

spacedawwwg commented 9 years ago

All seems to be working great with this code:

---
layout: layout--a
---
{{#extend "master"}}
  {{#content "master__head" mode="append"}}
    {{#block "head"}}{{/block}}
  {{/content}}
  {{#content "master__body"}}
    <main role="main" class="layout layout--a">
      {{!-- {{#or @content.region--a @content.region--b @content.region--c}} --}}
      {{#or @content.region--a @content.region--b}}
      <div class="row">
        {{#if @content.region--a}}
          <div class="region region--a row__col row__col--sm-12 row__col--md-12">
            {{#block "region--a"}}{{/block}}
          </div>
        {{/if}}
        {{#if @content.region--b}}
          <div class="region region--b row__col row__col--sm-7 row__col--md-8">
            {{#block "region--b"}}{{/block}}
          </div>
        {{/if}}
        {{#if @content.region--c}}
          <div class="region region--c row__col row__col--sm-5 row__col--md-4">
            {{#block "region--c"}}{{/block}}
          </div>
        {{/if}}
      </div>
      {{/or}}
    </main>
  {{/content}}
  {{#content "master__foot" mode="append"}}
    {{#block "foot"}}{{/block}}
  {{/content}}
{{/extend}}

I just need to find a helper that allows me to use {{#or}} on more the two items

any suggestions @shannonmoeller ?

shannonmoeller commented 9 years ago

@spacedawwwg The syntax is a little gross, but you can actually nest helpers using subexpressions.

{{#or @content.region--a (or @content.region--b @content.region--c) }}
    ...
{{/or}}
spacedawwwg commented 9 years ago

Seems or is not playing nicely with subexpressions. I'll keep looking, but thanks again!

screen shot 2015-04-22 at 16 41 06

shannonmoeller commented 9 years ago

Oh, right. The and and or helpers return block content, so they wouldn't work with subexpressions. Just found ifAny though!

{{#ifAny @content.region--a @content.region--b @content.region--c}}
    ...
{{/ifAny}}

https://github.com/assemble/handlebars-helpers/blob/v0.6.0/lib/helpers/comparisons.js#L282

spacedawwwg commented 9 years ago

Thanks @shannonmoeller , that is exactly what I needed!!

...Though, seems to be broken in Assemble.

BUT, this guy sorted it: https://github.com/assemble/handlebars-helpers/pull/165

so for now I'm simply using:

handlebars.registerHelper('eitherOr', function () {
  var options = arguments[arguments.length - 1];
  for (var i = 0; i < arguments.length - 1; i++) {
    if (arguments[i]) {
      return options.fn(this);
    }
  }
  return options.inverse(this);
});

Which will get me by. Thank you again though!!

shannonmoeller commented 9 years ago

Awesome!

shannonmoeller commented 9 years ago

@spacedawwwg An issue was submitted related to the @content variable. The resolution was to switch back to a helper-based solution. As such, the content helper is now a boolean getter when used as a subexpression. So the above ifAny example becomes:

{{#ifAny (content "region--a") (content "region--b") (content "region--c")}}
    ...
{{/ifAny}}

It's a breaking change that I released as 3.0. Since you're one of the two people I know are using this feature, just wanted to give you (and any googler's of this thread) a heads up.