Skip to content

Repository files navigation

Fest Build Status

Fest — это шаблонизатор общего назначения, компилирующий XML шаблоны в самодостаточные JavaScript функции. Для установки требуется Node.js >= 0.8.

Установка

npm install fest

Введение

Шаблоны представляют собой XML документы, содержащие HTML, текстовые данные и управляющие конструкции. Шаблон задается парным элементом <fest:template> (с указанием пространства имен http://fest.mail.ru). Например:

<fest:templatexmlns:fest="http://fest.mail.ru">
Hello!
</fest:template>

Данные передаваемые в шаблон, доступны через переменную с именем, указанным в атрибуте context_name элемента fest:template:

<fest:templatexmlns:fest="http://fest.mail.ru"context_name="json">
Hello, <fest:value>json.name</fest:value>!
</fest:template>

Чтобы посмотреть результат работы, приведенных выше шаблонов, необходимо воспользоваться встроенной утилитой fest-render или API библиотеки.

fest-render

Утилита fest-render используется для компиляции и последующего запуска скомпилированного шаблона из командной строки. В таком случае, для передачи данных в шаблон используется JSON-файл.

hello.json

{"name": "John"}

hello.xml

<fest:templatexmlns:fest="http://fest.mail.ru"context_name="json">
Hello, <fest:value>json.name</fest:value>!
</fest:template>
$ ./node_modules/.bin/fest-render --json=hello.json hello.xml
Hello,John!

Замечание: начальные и конечные пробелы в текстовых узлах удаляются при компиляции. Если необходимо вывести символ пробела, можно вопспользоваться fest:space.

render()

Функция render() API компилирует и исполняет шаблон с заданными параметрами.

hello.js

varfest=require('fest');console.log(fest.render('hello.xml'),{name: 'John'});
$ node ./hello.js
Hello,John!

Данные и вывод

fest:value

Служит для вывода значения JavaScript выражения. Поддерживаем 4 режима вывода: html (по умолчанию), text, js и json.

<fest:script><![CDATA[ var value = '"<script/>"';]]></fest:script>
<fest:value>value</fest:value><!-- &quot;&lt;script/&gt;&quot; -->
<fest:valueoutput="text">value</fest:value><!-- "<script/>" -->
<fest:valueoutput="js">value</fest:value><!-- \"\u003Cscript\/\u003E\" -->
<fest:valueoutput="json">value</fest:value><!-- "\"\u003Cscript/\u003E\"" -->

fest:var

Устаналивает локальную JavaScript переменную.

<fest:varname="question">Ultimate Question of Life, The Universe, and Everything</fest:var>
<fest:value>question</fest:value><!-- Ultimate Question of Life, The Universe, and Everything -->
<fest:varname="answer"select="question.length - 13" />
<fest:value>answer</fest:value><!-- 42 -->

fest:text

Выводит неформатированный текст.

<fest:text>"Hello"</fest:text><!-- "Hello" -->

fest:space

Служит для вывода пробела. Необходим в тех случаях, когда пробел в тектовом узле удаляется при компиляции, например:

Hello,<fest:space/><fest:value>json.name</fest:value>!<!-- Hello, John! -->

fest:set

Объявляет именованный подшаблон. Содержимое fest:set не будет выполнено до тех пор, пока не будет вызван блок с таким же имененем с помощью fest:get.

<fest:setname="name">John</fest:set>
<fest:setname="full_name">
<fest:getname="name"/><fest:space/>F. Kennedy
</fest:set>

Для fest:set можно использовать атрибут test. Операция выполнится, если его значение (JavaScript выражение) истинно.

<fest:setname="name"test="false">should not be set</fest:set>

Внутри fest:set доступен контекст params, передаваемый через fest:get.

<fest:setname="line">
Hello,<fest:space/><fest:value>params.username</fest:value>!
</fest:set>
<fest:getname="line">{username: "John"}</fest:get><!-- Hello, John! -->

fest:get

Выводит содержимое блока, объявленного через fest:set.

<fest:getname="name"/>
<fest:getname="name">{'some': 'data'}</fest:get>

С помощью fest:param можно передавать в блок XML-данные.

<fest:getname="page">
<fest:paramname="doctype">html</fest:param>
<fest:params>
{
title: json.title
}
</fest:params>
<fest:paramname="content">
<article>
<fest:iftest="json.title">
<h1><fest:value>json.title</fest:value></h1>
</fest:if>
</article>
</fest:param>
</fest:get>
<fest:setname="page">
<fest:doctype><fest:value>params.doctype</fest:value></fest:doctype>
<title><fest:value>params.title</fest:value></title>
<body>
<fest:valueoutput="text">params.content</fest:value>
</body>
</fest:set>

Внутри атрибута name можно использовать JavaScript выражения для вычисления имени блока во время выполнения. Значения выражений, заключенных в фигурные скобки, объединяются с примыкающим текстом. Помимо этого, можно использовать атрибут select.

<fest:script>
var name = 'foo'
</fest:script>
<fest:getselect="name"/><!-- foo -->
<fest:setname="foo">foo</fest:set>
<fest:setname="bar">bar</fest:set>
<fest:getname="b{true?'a':''}r"/><!-- bar -->

fest:element

Выводит HTML элемент с переменным именем.

<fest:elementname="div" />
<fest:script>
var variable = 'table';
</fest:script>
<fest:elementselect="variable">
fest code
</fest:element>
<fest:elementname="{variable2}">
fest code
</fest:element>

Результат:

<div></div><table>fest code</table><div>fest code</div>

fest:attributes, fest:attribute

Добавляет атрибуты к родительскому элементы. Все fest:attribute должны быть внутри блока fest:attributes, который должен идти первым внутри элемента.

<a>
<fest:attributes>
<fest:attributename="href"><fest:value>json.href</fest:value></fest:attribute>
</fest:attributes>
Some link
</a>

Существует быстрый способ вывести значение в атрибут:

<ahref="{json.href}">Some link</a>

Имена атрибутов можно вычислять в момент исполнения шаблона:

<div>
<fest:attributes>
<fest:attributename="data-{json.name}"value="{json.value}" />
</fest:attributes>
</div>

Управляющие конструкции

fest:each

Предоставляет механизм итерации по объекту.

<fest:script>var obj = {"foo": "bar"}</fest:script>
<fest:eachiterate="obj"index="i">
<fest:value>i</fest:value>=<fest:value>obj[i]</fest:value><!-- foo=bar -->
</fest:each>
<fest:eachiterate="obj"index="i"value="v">
<fest:value>i</fest:value>=<fest:value>v</fest:value><!-- foo=bar -->
</fest:each>

fest:for

Выполняет итерацию по массиву или числовому ряду.

<fest:script>json.items = ['a', 'b', 'c']</fest:script>
<fest:foriterate="json.items"index="i">
<fest:value>json.items[i]</fest:value><!-- abc -->
</fest:for>
<fest:foriterate="json.items"index="i"value="v">
<fest:value>v</fest:value><!-- abc -->
</fest:for>
<fest:forfrom="1"to="5"index="i">
<fest:value>i</fest:value><!-- 12345 -->
</fest:for>

fest:if

Условный оператор.

<fest:iftest="true">
It's true!
</fest:if>

fest:choose, fest:when, fest:otherwise

Ветвление. Если ни у одного fest:when условие не выполнено, будет выбрана ветвь fest:otherwise.

<fest:choose>
<fest:whentest="1">
<fest:text>one</fest:text>
</fest:when>
<fest:whentest="2">
<fest:text>two</fest:text>
</fest:when>
<fest:otherwise>
<fest:text>More than 2</fest:text>
</fest:otherwise>
</fest:choose>

Остальные конструкции

fest:cdata

Служит для вывода блока CDATA.

<script>
<fest:cdata>
<![CDATA[alert ("2" < 3);]]>
</fest:cdata>
</script>

fest:comment

Выводит HTML комментарий.

<fest:comment>comment</fest:comment>

fest:doctype

Задает DOCTYPE генерируемой страницы.

<fest:doctype>html</fest:doctype>

fest:script

Служит для выполнения произвольного JavaScript.

<fest:script>
<![CDATA[ json.script = 2 < 3;]]>
</fest:script>

Содержимое fest:script можно загрузить из файла, указав в атрибуте src путь к нему.

<fest:scriptsrc="script.js"/>

fest:include

Вставляет содержимое другого шаблона с заданным контекстом.

<fest:script>json.list = ['a', 'b', 'c'];</fest:script>
<fest:includecontext="json.list"src="./include_foreach.xml"/>

fest:insert

Выводит содержимое файла:

<styletype="text/css">
<fest:insertsrc="style.css"/>
<style>

Примеры

Использование

Компиляция с помощью compile():

varfest=require('fest');vardata={name: 'Jack "The Ripper"'},template='./templates/basic.xml';varcompiled=fest.compile(template,{beautify: false}),template=(newFunction('return '+compiled))();console.log(template(data));

Компиляция с последующей отрисовкой с помощью render():

varfest=require('fest');vardata={name: 'Jack "The Ripper"'},template='./templates/basic.xml';console.log(fest.render(template,data,{beautify: false}));

basic.xml

<?xml version="1.0"?>
<fest:templatexmlns:fest="http://fest.mail.ru"context_name="json">
<h1>Hello,<fest:space/><fest:valueoutput="text">json.name</fest:value></h1>
<!-- По умолчанию все значения fest:value экранируются --><!-- Необходимо использовать fest:space или fest:text для явного указания строк с пробелами-->
</fest:template>

Результат:

<h1>Hello, Jack "The Ripper"</h1>

Вложенные шаблоны

Данные на вход:

vardata={people: [{name: 'John',age: 20},{name: 'Mary',age: 21},{name: 'Gary',age: 55}],append: '>>'}

foreach.xml (основной шаблон):

<?xml version="1.0"?>
<fest:templatexmlns:fest="http://fest.mail.ru"context_name="json">
<!-- Контекст можно передавать во вложенные шаблоны -->
<fest:includecontext_name="json"src="./person.xml"/>
<!-- Значением iterate может быть любое js-выражение -->
<fest:foriterate="json.people.reverse()"index="i">
<!-- Передаваемые значения будут доступны в контексте params -->
<fest:getname="person">json.people[i]</fest:get>
</fest:for>
</fest:template>

person.xml:

<?xml version="1.0"?>
<fest:templatexmlns:fest="http://fest.mail.ru"context_name="json">
<!-- Используем set для объявления блока, который используем в родительском шаблоне-->
<fest:setname="person">
<p>
<fest:script><![CDATA[ var first = params.name[0], other = params.name.slice(1);]]></fest:script>
<fest:value>json.append</fest:value>
<strong>
<fest:value>first</fest:value>
</strong>
<fest:value>other</fest:value>
</p>
</fest:set>
</fest:template>

Результат:

<p>&gt;&gt;<strong>G</strong>ary</p><p>&gt;&gt;<strong>M</strong>ary</p><p>&gt;&gt;<strong>J</strong>ohn</p>

Использование set и get

<?xml version="1.0"?>
<fest:templatexmlns:fest="http://fest.mail.ru"context_name="json">
<fest:setname="host">http://e.mail.ru</fest:set>
<fest:setname="all">msglist</fest:set>
<fest:setname="new">sentmsg?compose</fest:set>
<fest:setname="all_link">
<fest:getname="host"/>/<fest:getname="all"/>
</fest:set>
<fest:setname="new_link">
<fest:getname="host"/>/<fest:getname="new"/>
</fest:set>
<ul>
<!-- fest:attribute добавляет параметр к родительскому тегу -->
<li><a>
<fest:attributes>
<fest:attributename="href"><fest:getname="all_link"/></fest:attribute>
</fest:attributes>
Все сообщения
</a></li>
<li><a>
<fest:attributes>
<fest:attributename="href"><fest:getname="new_link"/></fest:attribute>
</fest:attributes>
Написать письмо
</a></li>
</ul>
</fest:template>

Результат:

<ul><li><ahref="http://e.mail.ru/msglist">Все сообщения</a></li><li><ahref="http://e.mail.ru/sentmsg?compose">Написать письмо</a></li></ul>

Интернационализация

fest:plural

По умолчанию доступна поддержка плюрализации для русского и английского языка. В параметрах fest.compile можно передать любую другую функцию плюрализации.

<fest:pluralselect="json.n">один рубль|%s рубля|%s рублей</fest:plural>

Или англоязычный вариант:

<fest:pluralselect="json.n">one ruble|%s rubles</fest:plural>

Чтобы вывести символ “%” внутри тега fest:plural используйте “%%”:

<fest:pluralselect="json.n">…1%%…|…%s%%…|…%s%%…</fest:plural>

fest:message и fest:msg

Позволяет указать границы фразы для перевода и контекст для снятия многозначности. Например,

<fest:messagecontext="растение">Лук</fest:message>
<fest:messagecontext="оружие">Лук</fest:message>

Для каждого fest:message, fest:msg, обычного текста, заключенного между XML тегами (опция auto_message), или текстового значения некоторых атрибутов компилятор вызывает функцию events.message (если такая была указана в параметрах). Данный механизм используется в fest-build утилите для построения оригинального PO-файла.

Пример вызова fest-build для создания PO-файла:

$ fest-build --dir=fest --po=ru_RU.po --compile.auto_message=true

Пример компиляции локализованных шаблонов:

$ fest-build --dir=fest --translate=en_US.po

Пример компиляции одного шаблона:

$ fest-compile path/to/template.xml
$ fest-compile --out=path/to/compiled.js path/to/template.xml
$ fest-compile --out=path/to/compiled.js --translate=path/to/en_US.po path/to/template.xml

Contribution

Необходимо установить Grunt:

$ git clone git@github.com:mailru/fest.git
$ cd fest
$ sudo npm install -g grunt-cli
$ npm install
$ grunt

Grunt используется для валидации JS (тестов) и запуска тестов. Перед отправкой пулл-риквеста убедись, что успешно выполнены git rebase master и grunt.

Если необходимо пересобрать шаблоны spec/expected, то выполните:

$ ./bin/fest-build --dir=spec/templates --exclude='*error*' --compile.beautify=true --out=spec/expected/build/initial
$ ./bin/fest-build --dir=spec/templates --exclude='*error*' --compile.beautify=true --out=spec/expected/build/translated --translate=spec/templates/en_US.po

About

javascript templates

Resources

Stars

129 stars

Watchers

33 watching

Forks

Releases

Packages

Used by

Contributors

Languages