Тестовое задание на JavaScript
Реализовать шаблонизатор на JavaScript (можно использовать функции языка, доступные в последних версиях Chrome, Firefox и IE 9+). Шаблонизатор должен поддерживать функцию генерации контента по заданному шаблону с заданным набором данных. Её прототип приведён ниже:
function render (template, data);
Где template – строка, содержащая текст шаблона на его специальном языке, а data – объект JavaScript, содержащий набор данных для генерации. Функция должна возвращать строку с результатом обработки.
Результат необходимо прислать в виде одного файла JS, либо набора файлов JS с указанием главного файла и порядка включения.
Синтаксис языка шаблонов:
Подстановки:
Должны поддерживаться конструкции вида: {{ name }}, где name имя ключа из набора данных. Если имя отсутствует, то вместо него подставляется пустая строка. Допустимое имя – последовательность из алфавитных и цифровых символов и знаков подчёркивания, начинающаяся с алфавитного символа или знака подчёркивания. Между именем и фигурными скобками допускается произвольное количество пробельных символов. Между парой фигурных скобок пробельные символы не допускаются.
Блоки:
Блоком называется конструкция вида:
{% name %} body {% / %}
Она обрабатывается специальным образом: Если ключ name отсутствует в наборе или его значение равно пустой строке, то тело блока не выводится. Если ключ присутствует и не является списком, то тело блока выводится один раз. Если ключ присутствует и является списком, то тело блока выводится столько раз, сколько элементов списка.
Внутри блока будет доступна специальная переменная с именем . (точка), которая устанавливается на каждой итерации цикла в текущий элемент. Это имя может быть использовано наравне с другими в подстановках и блоках: {{ . }} или {% . %}, и работает по общей логике. Блоки могут быть вложенными, при этом закрывающая конструкция {% / %} относится к ближайшей открывающей конструкции блока, а переменная . (точка) относится к самому глубокому блоку, в который она вложена./p>
Блоки:
Комментарием называется конструкция вида: {# body #} Тело комментария не обрабатывается и не включается в результирующий текст.
Пример работы:
var template = "<h1>Category: {{category}}</h1>\n" +
"<ol>\n" +
"{# items must be non-empty for valid markup #}" +
"{% items %}" +
" <li>{{ . }}</li>\n" +
"{% / %}" +
"</ol>\n";
var result = render(template, {
category: "Fruits",
items: ["Mango", "Banana", "Orange" ]
});
Результатом обработки будет:
<h1>Category: Fruits</h1>
<ol>
<li>Mango</li>
<li>Banana</li>
<li>Orange</li>
</ol>
Пример с вложенными блоками:
var data = { table : [[1,2,3], [4,5,6]] };
var template = "<table>\n" +
"{% table %}" +
" <tr>\n" +
" {% . %}" +
"<td>{{ . }}</td>" +
"{% / %}" +
"\n </tr>\n" +
"{% / %}"+
"</table>\n";
var result = render(template, data);
Результатом обработки будет:
<table>
<tr>
<td>1</td><td>2</td><td>3</td>
</tr>
<tr>
<td>4</td><td>5</td><td>6</td>
</tr>
</table>
Бонусное задание — фильтры:
В конструкциях могут встречаться так называемые фильтры:
{{ name:filter1:filter2:filter.. }}
Фильтр обрабатывает значение по ключу name и возвращает результат обработки. Если указано несколько фильтров, то каждый последующий после первого получает результат предыдущего на вход.
upper : преобразует строку к верхнему регистру
lower : преобразует строку к нижнему регистру
escape : экранирует HTML-символы <, >, & в соответствующие HTML-сущности.
trim : обрезает пробельные символы с начала и с конца строки
capitalize : преобразует к верхнему регистру первые буквы слов в строке.
Также должен быть определён специальный фильтр default, который может принимать значение:
{{ name : default(value) }} – в случае, если ключ name в наборе не присутствует (или соответствующее значение равно пустой строке), то результатом будет являться value. Если же ключ в наборе присутствует, то default возвращает значение без изменений.
Допускается также реализация и других фильтров, по желанию.
Результат примера
Результат примера с блоками
Просто ещё...
test_fn_start {% test %}
123123
{% / %} test_fn_fin
first
{{ val }}{{ val }}
{{bt:upper:lower:escape:capitalize:trim}}
{{ not_exists:default ( nexist ) }}
{% nn %}
{% . %}
{% . %}
[{{ . }}]
{% / %}
{% / %}
asdf 1
{% fda.str %}
zxcv 1 {{.}}
{% / %}
asdf 2
{% fda.sde %}
zxcv 2
{% ssda %}
zxcv 22
{% / %}
{% / %}
asdf 3
{% / %} asdqwer
second {% nn %}
start
{% mda %}
zxcv 3 {{.be}}
{% / %}
end
{% / %} fin
---
{
nn: [ [ [ 123, 321 ], [ 123, 321 ] ], [ [ 123, 321 ], [ 123, 321 ] ] ],
fda: {
str: 321,
sde: 765
},
ssda: 4321,
mda : {
str: {
be: 'be1'
},
sde: {
be: 'be2'
}
},
bt: ' bit testing task <> & ',
val: function (obj, current) {
return 12345 + '\n\t\t';
},
test: function (block, obj, blocks, stars, currt) {
return 123;
}
}
>>>