web-dev-qa-db-ja.com

Moustache Templatesはテンプレートの拡張を行うことができますか?

Moustacheは初めてです。

多くのテンプレート言語(例:Django/Jinja)では、「親」テンプレートを次のように拡張できます。

base.html

<html><head></head>
    <body>
    {% block content %}{% endblock %}
    </body>
</html>

frontpage.html

{% extends "base.html" %}
{% block content %}<h1>Foobar!</h1>{% endblock %}

レンダリングされたfrontpage.html

<html><head></head>
    <body>
    <h1>Foobar!</h1>
    </body>
</html>

Moustacheのpartialsを知っています(例:{{>content}})、しかしそれらはちょうどincludesのようです。

Moustache用のテンプレート拡張機能はありますか?または、それに失敗すると、includesをテンプレート拡張の同等物に効果的に変える設計パターンが少なくともあります。

52
Chris W.

私は最近、マコのバックグラウンドから来たことを除いて、同じボートに乗っていました。

Moustacheはテンプレートの拡張/継承を許可しませんが、私が知っている利用可能なオプションがいくつかあります。

  1. パーシャルを使用できます:

    {{>header}}
        Hello {{name}}
    {{>footer}}
    
  2. 他のページから継承する必要がある各テンプレートのコンテキストに、テンプレートの前処理関数を挿入できます。

    {{#extendBase}}      
        Hello {{name}}
    {{/extendBase}} 
    

    ハッシュ:

    {
       "name": "Walden",
       "extendBase": function() {
           return function(text) {
               return "<html><head></head>" + render(text) + "</body></html>"
           }
       }
    }
    
  3. 目的のHTMLをプリペンドして、コントローラーの関連ページに追加します。

  4. レイアウトテンプレートalaを使用します。

    {{>header}}
        {{{body}}}
    {{>footer}}
    

    コントローラーで本体をレンダリングし、bodyという名前の変数としてレイアウトテンプレートに渡します。

  5. テンプレートをロードするコードに、テンプレート継承、事前口ひげを実装します。

ただし、エスケープされていないHTMLをどこにも表示したくないため、トリプルヒゲを使用しません。

他の誰かがこの問題に対するより良い解決策を持っているなら、私はこれらの方向のいずれにもまだ思い切っていないので、私もそれを聞きたいです。

61
Walden

ここで、Mustacheの仕様にこれを提案しました。

https://github.com/mustache/spec/issues/38

現在、mustache.Java、hogan.js、phly_mustacheはテンプレートの継承をサポートしています。

12
Sam Pullara

口ひげphpでは、バージョン2.7.0以降、テンプレートの継承がサポートされています。

https://github.com/bobthecow/mustache.php/wiki/BLOCKS-pragma

ファイルMustache/Engine.phpから現在のバージョンを把握し、以下を含む行を検索できます。

class Mustache_Engine
{
    const VERSION        = '2.8.0';
    ...
3
Basil Musa

Moustacheはテンプレートの拡張を行いません。

テンプレートの拡張が本当に必要な場合は、選択した言語/フレームワークに対して、この機能で構築されたライブラリ目的を使用することができます。


参考までに、Node.js/Expressを使用しているため、おそらく https://github.com/fat/stache を使用することになります。

3
Chris W.

HTMLを含む変数を使用できます。 {{{variable}}}のような「トリプルヒゲ」はエスケープされていないHTMLを返します。テンプレートの拡張機能とまったく同じではありませんが、frontpage-content.htmlをレンダリングし、その出力をbase.htmlに渡されるcontent変数に入れることができます

(私は-contentfrontpage.htmlファイル名に追加しました。このような命名パターンはファイル名を管理しやすくすることを期待しています。)

3
Kurt McKee

私はこれをPython(私はMakoの作成者です)で遊んでいます)、セクションをキャプチャする動的なコンテキストに追加することは正しいことをしているようですが、これをさらにテストする必要があります。

基本的には、「<」プレフィックスが「このテンプレートから継承する」ことを示すラムダを使用しています( https://github.com/mustache/spec/issues/38 で説明されている構文と同様)。 「$」プレフィックスは、「これは継承されたセクションです」を示します。

import pystache

class NameSpace(object):
    def __init__(self, renderer, vars_={}):
        self.renderer = renderer
        self._content = {}
        self.vars = vars_

    def add_content(self, name, value):
        self._content[name] = value

    def __getattr__(self, key):
        if key in self.vars:
            # regular symbol in the vars dictionary
            return self.vars[key]
        Elif key.startswith("<"):
            # an "inherit from this template" directive
            name = key[1:]
            return inheritor(self, name)
        Elif key.startswith("$"):
            # a "here's a replaceable section" directive
            name = key[1:]
            if name in self._content:
                # if we have this section collected, return the rendered
                # version
                return sub_renderer(self, name)
            else:
                # else render it here and collect it
                return collector(self, name)
        else:
            # unknown key.
            raise AttributeError(key)

def sub_renderer(namespace, key):
    def go():
        def render(nested):
            return namespace._content[key]
        return render
    return go


def collector(namespace, key):
    def go():
        def render(nested):
            content = namespace.renderer.render(nested, namespace)
            namespace.add_content(key, content)
            return content
        return render
    return go


def inheritor(namespace, name):
    def go():
        def render(nested):
            namespace.renderer.render(nested, namespace)
            return namespace.renderer.render_name(name, namespace)
        return render
    return go

ここにいくつかのテンプレートがあります。 base.mustache:

<html>

{{#$header}}
    default header
{{/$header}}

{{#$body}}
    default body
{{/$body}}

{{#$footer}}
    default footer, using {{local key}}
{{/$footer}}


</html>

hello.mustache:

{{#<base}}

{{#$header}}
    new header
{{/$header}}

{{#$body}}
    new body, with {{local key}}
{{/$body}}

{{/<base}}

そして、3レベルの深さで遊ぶには、subhello.mustache:

{{#<hello}}

{{#$footer}}
    im some new footer
{{/$footer}}

{{/<hello}}

このようなhello.mustacheのレンダリング:

renderer = pystache.Renderer(search_dirs=["./templates/"])

print renderer.render_name("hello",
                    NameSpace(renderer, {"local key": "some local key"}))

出力:

<html>

    new header

    new body, with some local key

    default footer, using some local key


</html>

Subhello.mustacheのレンダリング:

print renderer.render_name("subhello",
                    NameSpace(renderer, {"local key": "some local key"}))

出力:

<html>

    new header

    new body, with some local key

    im some new footer


</html>

私はこれを20分で書きましたが、過去にhandlebars.jsを少しだけ使用し、今は初めてpystacheを使用したので、「口ひげ」のアイデア全体はまだ深くありません。しかし、これはうまくいくようですか?

1
zzzeek

サーバーサイドのみのコードに満足している場合は、 Nunは「テンプレートのオーバーライド」機能を介して機能を拡張する口ひげのようなテンプレートシステムです -Djangoでモデル化されています。ただし、動作している間は、作成者によって保守されなくなります。

0
mikemaccana

Node.jsでは、 express-handlebars または hogan-express を使用して、Inna Moustacheテンプレートをレイアウトできますが、設定方法は異なります。テンプレート自体のレイアウト、レイアウトはアプリコードに登録されます。

0
Alfgaar