Comparing version 0.7.3 to 0.8.0
@@ -134,2 +134,21 @@ var compile = (function(){ | ||
function compileExpr(attr, _getExpr){ | ||
var i = 0, attrValue = '', result = {containsExpr: false, text: []} ; | ||
attrValue = attr.value.replace(/{{/g, "__DOUBLE_LEFT_CURLY_BRACES__").replace(/}}/g, "__DOUBLE_RIGHT_CURLY_BRACES__"); | ||
attrValue.match(/{[^}]*}|[^{}]*/g).forEach(function (str) { | ||
if (str !== '') { | ||
if (str[0] === '{') { | ||
i++; | ||
result.text.push('(' + str.slice(1, -1).replace(/__DOUBLE_LEFT_CURLY_BRACES__/g, "{").replace(/__DOUBLE_RIGHT_CURLY_BRACES__/g, "}") + ')'); | ||
_getExpr(result.text[result.text.length-1], 'expression #' + (i) + ' in attribute "' + attr.name + '"'); | ||
result.containsExpr = true; | ||
} else{ | ||
result.text.push('"' + escapeJS(escapeHTML(str)).replace(/__DOUBLE_LEFT_CURLY_BRACES__/g, "{").replace(/__DOUBLE_RIGHT_CURLY_BRACES__/g, "}") + '"'); | ||
} | ||
} | ||
}); | ||
result.text = result.text.join('+'); | ||
return result; | ||
} | ||
function errorMessage(msg, badLine, file) { | ||
@@ -343,3 +362,7 @@ function zeroPadding(s, len) { | ||
opentag = true; | ||
section.source += 'try{__fest_element=' + _getAttr(node, 'select', 'expr') + ';'; | ||
if (node.attributes.select) { | ||
section.source += 'try{__fest_element=' + _getAttr(node, 'select', 'expr') + ';'; | ||
} else{ | ||
section.source += 'try{__fest_element=' + compileExpr(node.attributes.name, _getExpr).text + ';'; | ||
} | ||
section.source += 'if(typeof __fest_element !== "string"){__fest_log_error("Element name must be a string");__fest_element="div"}'; | ||
@@ -360,3 +383,20 @@ section.source += '}catch(e){__fest_element="div";__fest_log_error(e.message);}'; | ||
case 'attribute': | ||
section.source += '__fest_pushstr(__fest_context," ' + escapeJS(_getAttr(node, 'name')) + '=\\"");'; | ||
expression = compileExpr(node.attributes.name, _getExpr); | ||
if (expression.containsExpr){ | ||
section.source += 'try{__fest_select=' + expression.text + '}catch(e){__fest_select="";__fest_log_error(e.message)}'; | ||
section.source += 'if(__fest_select!==""){'; | ||
node.conditional = true; | ||
section.source += '__fest_pushstr(__fest_context," " + __fest_select + "=\\"");' ; | ||
} else{ | ||
section.source += '__fest_pushstr(__fest_context," ' + escapeJS(_getAttr(node, 'name')) + '=\\"");'; | ||
} | ||
if(node.attributes.value){ | ||
expression = compileExpr(node.attributes.value, _getExpr); | ||
if (expression.containsExpr){ | ||
section.source += 'try{__fest_select=' + expression.text + '}catch(e){__fest_select="";__fest_log_error(e.message)}'; | ||
section.source += '__fest_pushstr(__fest_context,__fest_select);'; | ||
} else{ | ||
section.source += '__fest_pushstr(__fest_context,"' + escapeJS(_getAttr(node, 'value')) + '");'; | ||
} | ||
} | ||
return; | ||
@@ -471,5 +511,11 @@ case 'comment': | ||
output.disable_sgo = true; | ||
} else { | ||
section.source += '__fest_select="' + escapeJS(_getAttr(node, 'name')) + '";'; | ||
output.uses[_getAttr(node, 'name')] = true; | ||
} else{ | ||
var expression = compileExpr(node.attributes.name, _getExpr); | ||
if (expression.containsExpr){ | ||
section.source += 'try{__fest_select=' + expression.text + '}catch(e){__fest_select="";__fest_log_error(e.message)}'; | ||
output.disable_sgo = true; | ||
} else{ | ||
section.source += '__fest_select="' + escapeJS(_getAttr(node, 'name')) + '";'; | ||
output.uses[_getAttr(node, 'name')] = true; | ||
} | ||
} | ||
@@ -548,2 +594,5 @@ section.source += '__fest_params={};'; | ||
section.source += '__fest_pushstr(__fest_context,"\\"");'; | ||
if(node.conditional){ | ||
section.source += '}'; | ||
} | ||
return; | ||
@@ -550,0 +599,0 @@ case 'cdata': |
@@ -5,3 +5,3 @@ { | ||
"keywords": ["template", "templating", "html", "xml"], | ||
"version": "0.7.3", | ||
"version": "0.8.0", | ||
"repository": { | ||
@@ -8,0 +8,0 @@ "type": "git", |
446
README.md
@@ -1,8 +0,114 @@ | ||
# Fest [](https://travis-ci.org/eprev/fest) | ||
# Fest [](https://travis-ci.org/mailru/fest) | ||
Fest — это шаблонизатор общего назначения, компилирующий XML шаблоны в самодостаточные JavaScript функции. Для установки требуется Node.js >= 0.8. | ||
## Установка | ||
``` | ||
npm install fest | ||
``` | ||
## Введение | ||
Шаблоны представляют собой XML документы, содержащие HTML, текстовые данные и управляющие конструкции. Шаблон задается парным элементом `<fest:template>` (с указанием пространства имен `http://fest.mail.ru`). Например: | ||
```xml | ||
<fest:template xmlns:fest="http://fest.mail.ru"> | ||
Hello! | ||
</fest:template> | ||
``` | ||
Данные передаваемые в шаблон, доступны через переменную с именем, указанным в атрибуте `context_name` элемента `fest:template`: | ||
```xml | ||
<fest:template xmlns: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 | ||
```json | ||
{"name": "John"} | ||
``` | ||
hello.xml | ||
```xml | ||
<fest:template xmlns: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 | ||
```javascript | ||
var fest = require('fest'); | ||
console.log(fest.render('hello.xml'), {name: 'John'}); | ||
``` | ||
``` | ||
$ node ./hello.js | ||
Hello,John! | ||
``` | ||
## Данные и вывод | ||
### fest:value | ||
Служит для вывода значения JavaScript выражения. Поддерживаем 4 режима вывода: html (по умолчанию), text, js и json. | ||
```xml | ||
<fest:script><![CDATA[ | ||
var value = '"<script/>"'; | ||
]]></fest:script> | ||
<fest:value>value</fest:value><!-- "<script/>" --> | ||
<fest:value output="text">value</fest:value><!-- "<script/>" --> | ||
<fest:value output="js">value</fest:value><!-- \"\u003Cscript\/\u003E\" --> | ||
<fest:value output="json">value</fest:value><!-- "\"\u003Cscript/\u003E\"" --> | ||
``` | ||
### fest:var | ||
Устаналивает локальную JavaScript переменную. | ||
```xml | ||
<fest:var name="question">Ultimate Question of Life, The Universe, and Everything</fest:value> | ||
<fest:value>question</fest:value><!-- Ultimate Question of Life, The Universe, and Everything --> | ||
<fest:var name="answer" select="question.length - 13" /> | ||
<fest:value>answer</fest:value><!-- 42 --> | ||
``` | ||
### fest:text | ||
Выводит неформатированный текст. | ||
```xml | ||
<fest:text>"Hello"</fest:text><!-- "Hello" --> | ||
``` | ||
### fest:space | ||
Служит для вывода пробела. Необходим в тех случаях, когда пробел в тектовом узле удаляется при компиляции, например: | ||
```xml | ||
Hello,<fest:space/><fest:value>json.name</fest:value>!<!-- Hello, John! --> | ||
``` | ||
### fest:set | ||
Объявить внутреннюю переменную | ||
Объявляет именованный подшаблон. Содержимое `fest:set` не будет выполнено до тех пор, пока не будет вызван блок с таким же имененем с помощью `fest:get`. | ||
@@ -15,7 +121,7 @@ ```xml | ||
<fest:set name="full_name"> | ||
<fest:get name="name"/><fest:space/>F. Kennedy | ||
<fest:get name="name"/><fest:space/>F. Kennedy | ||
</fest:set> | ||
``` | ||
Для ```fest:set``` можно использовать атрибут ```test```. Операция выполнится, если его значение (js-выражение) истинно. | ||
Для `fest:set` можно использовать атрибут `test`. Операция выполнится, если его значение (JavaScript выражение) истинно. | ||
@@ -26,9 +132,9 @@ ```xml | ||
Внутри ```fest:set``` доступен контекст ```params```, передаваемый через ```fest:get```. | ||
Внутри `fest:set` доступен контекст `params`, передаваемый через `fest:get`. | ||
```xml | ||
<fest:set name="line"> | ||
Hello,<fest:space/><fest:value>params.username</fest:value> | ||
Hello,<fest:space/><fest:value>params.username</fest:value>! | ||
</fest:set> | ||
<fest:get name="line">{username: "John"}</fest:get> | ||
<fest:get name="line">{username: "John"}</fest:get><!-- Hello, John! --> | ||
``` | ||
@@ -38,3 +144,3 @@ | ||
Получить переменную, объявленную через ```fest:set``` | ||
Выводит содержимое блока, объявленного через `fest:set`. | ||
@@ -49,29 +155,31 @@ ```xml | ||
Через `fest:param` можно передавать в блок XML-данные: | ||
С помощью `fest:param` можно передавать в блок XML-данные. | ||
```xml | ||
<fest:get name="page"> | ||
<fest:param name="doctype">html</fest:param> | ||
<fest:params> | ||
{ | ||
title: json.title | ||
} | ||
</fest:params> | ||
<fest:param name="content"> | ||
<article> | ||
<fest:if test="json.title"> | ||
<h1><fest:value>json.title</fest:value></h1> | ||
</fest:if> | ||
</article> | ||
</fest:param> | ||
<fest:param name="doctype">html</fest:param> | ||
<fest:params> | ||
{ | ||
title: json.title | ||
} | ||
</fest:params> | ||
<fest:param name="content"> | ||
<article> | ||
<fest:if test="json.title"> | ||
<h1><fest:value>json.title</fest:value></h1> | ||
</fest:if> | ||
</article> | ||
</fest:param> | ||
</fest:get> | ||
<fest:set name="page"> | ||
<fest:doctype><fest:value>params.doctype</fest:value></fest:doctype> | ||
<title><fest:value>params.title</fest:value></title> | ||
<body> | ||
<fest:value output="text">params.content</fest:value> | ||
</body> | ||
<fest:doctype><fest:value>params.doctype</fest:value></fest:doctype> | ||
<title><fest:value>params.title</fest:value></title> | ||
<body> | ||
<fest:value output="text">params.content</fest:value> | ||
</body> | ||
</fest:set> | ||
``` | ||
Если указать тег select, то выражение внутри выполнится и результирующая строка будет именем блока set. | ||
Внутри атрибута `name` можно использовать JavaScript выражения для вычисления имени блока во время выполнения. Значения выражений, заключенных в фигурные скобки, объединяются с примыкающим текстом. Помимо этого, можно использовать атрибут `select`. | ||
```xml | ||
@@ -81,5 +189,6 @@ <fest:script> | ||
</fest:srcipt> | ||
<fest:get select="name"/> | ||
<fest:get select="name"/><!-- foo --> | ||
<fest:set name="foo">foo</fest:set> | ||
<fest:set name="bar">bar</fest:set> | ||
<fest:get name="b{true?'a':''}r"/><!-- bar --> | ||
``` | ||
@@ -89,5 +198,6 @@ | ||
Вывод ноды с переменным именем | ||
Выводит HTML элемент с переменным именем. | ||
```xml | ||
<fest:element name="div" /> | ||
<fest:script> | ||
@@ -99,3 +209,3 @@ var variable = 'table'; | ||
</fest:element> | ||
<fest:element select="variable2"> | ||
<fest:element name="{variable2}"> | ||
fest code | ||
@@ -105,6 +215,6 @@ </fest:element> | ||
Выведет | ||
Результат: | ||
```xml | ||
<table>fest code</table><div>fest code</div> | ||
<div></div><table>fest code</table><div>fest code</div> | ||
``` | ||
@@ -114,14 +224,14 @@ | ||
Добавить атрибуты к родительскому тегу. Все ```fest:attribute``` должны быть внутри блока ```fest:attributes```, который должен быть первым внутри тега. | ||
Добавляет атрибуты к родительскому элементы. Все `fest:attribute` должны быть внутри блока `fest:attributes`, который должен идти первым внутри элемента. | ||
```xml | ||
<a> | ||
<fest:attributes> | ||
<fest:attribute name="href"><fest:value>json.href</fest:value></fest:attribute> | ||
</fest:attributes> | ||
Some link | ||
<fest:attributes> | ||
<fest:attribute name="href"><fest:value>json.href</fest:value></fest:attribute> | ||
</fest:attributes> | ||
Some link | ||
</a> | ||
``` | ||
Быстрый способ вставить значение в атрибут | ||
Существует быстрый способ вывести значение в атрибут: | ||
@@ -132,36 +242,12 @@ ```xml | ||
### fest:value | ||
Имена атрибутов можно вычислять в момент исполнения шаблона: | ||
Вывести значение js-выражения | ||
```xml | ||
<fest:value>json.value</fest:value> | ||
<fest:value output="text"><![CDATA["<script/>"]]></fest:value> | ||
<fest:value output="js">'"'</fest:value> | ||
<div> | ||
<fest:attributes> | ||
<fest:attribute name="data-{json.name}" value="{json.value}" /> | ||
</fest:attributes> | ||
</div> | ||
``` | ||
### fest:var | ||
Установить js-переменную | ||
```xml | ||
<fest:var name="question">Ultimate Question of Life, The Universe, and Everything</fest:value> | ||
<fest:value>question</fest:value> | ||
<fest:var name="answer" select="question.length - 13" /> | ||
<fest:value>answer</fest:value> | ||
``` | ||
### fest:text | ||
Вывод неформатированного текста | ||
```xml | ||
<fest:text>"Bla bla bla"</fest:text> | ||
``` | ||
### fest:space | ||
Пробел | ||
## Управляющие конструкции | ||
@@ -171,3 +257,3 @@ | ||
Итерация по объекту | ||
Предоставляет механизм итерации по объекту. | ||
@@ -177,6 +263,6 @@ ```xml | ||
<fest:each iterate="obj" index="i"> | ||
<fest:value>i</fest:value>=<fest:value>obj[i]</fest:value> | ||
<fest:value>i</fest:value>=<fest:value>obj[i]</fest:value><!-- foo=bar --> | ||
</fest:each> | ||
<fest:each iterate="obj" index="i" value="v"> | ||
<fest:value>i</fest:value>=<fest:value>v</fest:value> | ||
<fest:value>i</fest:value>=<fest:value>v</fest:value><!-- foo=bar --> | ||
</fest:each> | ||
@@ -187,3 +273,3 @@ ``` | ||
Итерация по массиву или по числовому ряду | ||
Выполняет итерацию по массиву или числовому ряду. | ||
@@ -193,9 +279,9 @@ ```xml | ||
<fest:for iterate="json.items" index="i"> | ||
<fest:value>json.items[i]</fest:value> | ||
<fest:value>json.items[i]</fest:value><!-- abc --> | ||
</fest:for> | ||
<fest:for iterate="json.items" index="i" value="v"> | ||
<fest:value>v</fest:value> | ||
<fest:value>v</fest:value><!-- abc --> | ||
</fest:for> | ||
<fest:for from="1" to="5" index="i"> | ||
<fest:value>i</fest:value> | ||
<fest:value>i</fest:value><!-- 12345 --> | ||
</fest:for> | ||
@@ -206,7 +292,7 @@ ``` | ||
Условный оператор | ||
Условный оператор. | ||
```xml | ||
<fest:if test="true"> | ||
true | ||
It's true! | ||
</fest:if> | ||
@@ -217,31 +303,31 @@ ``` | ||
Ветвление. Если ни один ```fest:when``` не выполнен, будет выбрана ветвь ```fest:otherwise```. | ||
Ветвление. Если ни у одного `fest:when` условие не выполнено, будет выбрана ветвь `fest:otherwise`. | ||
```xml | ||
<fest:choose> | ||
<fest:when test="1"> | ||
<fest:text>one</fest:text> | ||
</fest:when> | ||
<fest:when test="1"> | ||
<fest:text>one</fest:text> | ||
</fest:when> | ||
<fest:when test="2"> | ||
<fest:text>two</fest:text> | ||
</fest:when> | ||
<fest:when test="2"> | ||
<fest:text>two</fest:text> | ||
</fest:when> | ||
<fest:otherwise> | ||
<fest:text>More than 2</fest:text> | ||
</fest:otherwise> | ||
<fest:otherwise> | ||
<fest:text>More than 2</fest:text> | ||
</fest:otherwise> | ||
</fest:choose> | ||
``` | ||
## Остальное | ||
## Остальные конструкции | ||
### fest:cdata | ||
Блок CDATA | ||
Служит для вывода блока CDATA. | ||
```xml | ||
<script> | ||
<fest:cdata> | ||
<![CDATA[alert ("2" < 3);]]> | ||
</fest:cdata> | ||
<fest:cdata> | ||
<![CDATA[alert ("2" < 3);]]> | ||
</fest:cdata> | ||
</script> | ||
@@ -252,3 +338,3 @@ ``` | ||
HTML комментарий | ||
Выводит HTML комментарий. | ||
@@ -261,3 +347,3 @@ ```xml | ||
Объявление doctype страницы | ||
Задает DOCTYPE генерируемой страницы. | ||
@@ -270,12 +356,14 @@ ```xml | ||
Выполнить javascript | ||
Служит для выполнения произвольного JavaScript. | ||
```xml | ||
<fest:script> | ||
<![CDATA[ | ||
json.script = 2 < 3; | ||
]]> | ||
<![CDATA[ | ||
json.script = 2 < 3; | ||
]]> | ||
</fest:script> | ||
``` | ||
Содержимое `fest:script` можно загрузить из файла, указав в атрибуте `src` путь к нему. | ||
```xml | ||
@@ -287,3 +375,3 @@ <fest:script src="script.js"/> | ||
Вставить содержимое другого шаблона с заданным контекстом. | ||
Вставляет содержимое другого шаблона с заданным контекстом. | ||
@@ -297,7 +385,7 @@ ```xml | ||
Вставить файл напрямую в шаблон | ||
Выводит содержимое файла: | ||
```xml | ||
<style type="text/css"> | ||
<fest:insert src="style.css"/> | ||
<fest:insert src="style.css"/> | ||
<style> | ||
@@ -308,12 +396,5 @@ ``` | ||
## Установка | ||
## Использование | ||
``` | ||
npm install fest | ||
``` | ||
## Как использовать | ||
compile(): | ||
Компиляция с помощью compile(): | ||
```javascript | ||
@@ -331,4 +412,3 @@ var fest = require('fest'); | ||
render(): | ||
Компиляция с последующей отрисовкой с помощью render(): | ||
```javascript | ||
@@ -343,19 +423,16 @@ var fest = require('fest'); | ||
basic.xml | ||
```xml | ||
<?xml version="1.0"?> | ||
<fest:template xmlns:fest="http://fest.mail.ru" context_name="json"> | ||
<h1>Hello,<fest:space/><fest:value output="text">json.name</fest:value></h1> | ||
<!-- По умолчанию все значения fest:value экранируются --> | ||
<!-- | ||
Необходимо использовать fest:space или | ||
fest:text для явного указания строк с пробелами | ||
--> | ||
<h1>Hello,<fest:space/><fest:value output="text">json.name</fest:value></h1> | ||
<!-- По умолчанию все значения fest:value экранируются --> | ||
<!-- | ||
Необходимо использовать fest:space или | ||
fest:text для явного указания строк с пробелами | ||
--> | ||
</fest:template> | ||
``` | ||
Результат | ||
Результат: | ||
@@ -368,18 +445,15 @@ ```html | ||
Данные на вход | ||
Данные на вход: | ||
```javascript | ||
var data = { | ||
people: [ | ||
{name: 'John', age: 20}, | ||
{name: 'Mary', age: 21}, | ||
{name: 'Gary', age: 55} | ||
], | ||
append: '>>' | ||
people: [ | ||
{name: 'John', age: 20}, | ||
{name: 'Mary', age: 21}, | ||
{name: 'Gary', age: 55} | ||
], | ||
append: '>>' | ||
} | ||
``` | ||
foreach.xml (основной шаблон) | ||
foreach.xml (основной шаблон): | ||
```xml | ||
@@ -394,11 +468,9 @@ <?xml version="1.0"?> | ||
<fest:for iterate="json.people.reverse()" index="i"> | ||
<!-- Передаваемые значения будут доступны в контексте params --> | ||
<fest:get name="person">json.people[i]</fest:get> | ||
</fest:for> | ||
<!-- Передаваемые значения будут доступны в контексте params --> | ||
<fest:get name="person">json.people[i]</fest:get> | ||
</fest:for> | ||
</fest:template> | ||
``` | ||
person.xml | ||
person.xml: | ||
```xml | ||
@@ -408,25 +480,23 @@ <?xml version="1.0"?> | ||
<!-- | ||
Используем set для объявления переменной, | ||
которую используем в родительском шаблоне | ||
--> | ||
<fest:set name="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> | ||
<!-- | ||
Используем set для объявления блока, | ||
который используем в родительском шаблоне | ||
--> | ||
<fest:set name="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> | ||
``` | ||
Результат | ||
Результат: | ||
```html | ||
@@ -443,42 +513,42 @@ <p>>><strong>G</strong>ary</p> | ||
<fest:template xmlns:fest="http://fest.mail.ru" context_name="json"> | ||
<fest:set name="host">http://e.mail.ru</fest:set> | ||
<fest:set name="all">msglist</fest:set> | ||
<fest:set name="new">sentmsg?compose</fest:set> | ||
<fest:set name="host">http://e.mail.ru</fest:set> | ||
<fest:set name="all">msglist</fest:set> | ||
<fest:set name="new">sentmsg?compose</fest:set> | ||
<fest:set name="all_link"> | ||
<fest:get name="host"/>/<fest:get name="all"/> | ||
</fest:set> | ||
<fest:set name="all_link"> | ||
<fest:get name="host"/>/<fest:get name="all"/> | ||
</fest:set> | ||
<fest:set name="new_link"> | ||
<fest:get name="host"/>/<fest:get name="new"/> | ||
</fest:set> | ||
<fest:set name="new_link"> | ||
<fest:get name="host"/>/<fest:get name="new"/> | ||
</fest:set> | ||
<ul> | ||
<!-- fest:attribute добавляет параметр к родительскому тегу --> | ||
<ul> | ||
<!-- fest:attribute добавляет параметр к родительскому тегу --> | ||
<li><a> | ||
<fest:attributes> | ||
<fest:attribute name="href"><fest:get name="all_link"/></fest:attribute> | ||
</fest:attributes> | ||
Все сообщения | ||
</a></li> | ||
<li><a> | ||
<fest:attributes> | ||
<fest:attribute name="href"><fest:get name="all_link"/></fest:attribute> | ||
</fest:attributes> | ||
Все сообщения | ||
</a></li> | ||
<li><a> | ||
<fest:attributes> | ||
<fest:attribute name="href"><fest:get name="new_link"/></fest:attribute> | ||
</fest:attributes> | ||
Написать письмо | ||
</a></li> | ||
</ul> | ||
<li><a> | ||
<fest:attributes> | ||
<fest:attribute name="href"><fest:get name="new_link"/></fest:attribute> | ||
</fest:attributes> | ||
Написать письмо | ||
</a></li> | ||
</ul> | ||
</fest:template> | ||
``` | ||
Результат | ||
Результат: | ||
```html | ||
<ul> | ||
<li><a href="http://e.mail.ru/msglist">Все сообщения</a></li> | ||
<li><a href="http://e.mail.ru/sentmsg?compose">Написать письмо</a></li> | ||
<li><a href="http://e.mail.ru/msglist">Все сообщения</a></li> | ||
<li><a href="http://e.mail.ru/sentmsg?compose">Написать письмо</a></li> | ||
</ul> | ||
``` | ||
## Интернационализация | ||
@@ -485,0 +555,0 @@ |
Sorry, the diff of this file is not supported yet
145225
3733
598