Тестовое задание на 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; } }>>>