Директива декларирует пространство имён для файла в котором оно используется, т. е. все декларируемые в этом файле шаблоны будут частью заданного пространства имён.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только в глобальной области, только одна декларация на файл | Отсутствует | Строковая, логическая | Не требуется |
Пространства имён Snakeskin служат для экспорта шаблонов из файла, поэтому перед тем как начать создавать сами шаблоны нужно предварительно объявить пространство имён, а уже после они будут экспортироваться по схеме exports.namespace.template
.
В рамках одного файла может быть только одно пространство имён.
Например:
- namespace demo
/// Шаблон экспортируется как exports.demo.index
- template index()
Hello world!
{namespace demo}
/// Шаблон экспортируется как exports.demo.index
{template index()}
Hello world!
{/template}
Пространство имён может состоять из множества частей (свойств объекта), причём Snakeskin проверяет существование заданного пути и создаёт только те части, которые отсутствуют.
- namespace demo.helloWorld
/// exports.demo.helloWorld.index
- template index()
Hello world!
/// exports.demo.helloWorld.bar
- template bar()
Hello people!
{namespace demo.helloWorld}
/// exports.demo.helloWorld.index
{template index()}
Hello world!
{/template}
/// exports.demo.helloWorld.bar
{template bar()}
Hello people!
{/template}
Т.к. пространство имён превращается в JS объект, то на декларируемое имя накладываются те же ограничения, что и на свойство объекта, однако можно использовать декларацию через квадратные скобки ([ ... ]
), которая позволяет
применять любые символы и сложные выражения, например:
- namespace ['@demo']['hello' + 'World']
/// exports['@demo']['helloWorld'].index
- template index()
Hello world!
{namespace ['@demo']['hello' + 'World']}
/// exports['@demo']['helloWorld'].index
{template index()}
Hello world!
{/template}
Если первая часть имени использует синтаксис без квадратных скобок, то будет создана глобальная (для Snakeskin) переменная с таким же именем:
/// var demo = exports.demo['helloWorld']
- namespace demo['hello' + 'World']
- template index()
Hello world!
/// var demo = exports.demo['helloWorld']
{namespace ['@demo']['hello' + 'World']}
{template index()}
Hello world!
{/template}
Пространство имён создаёт with биндинг, который можно использовать для удобного вызова шаблонов в рамках файла.
- namespace demo
- template parent()
Hello world!
/// Тоже самое, что и extends exports.demo.parent
- template child() extends @parent
{namespace demo}
{template parent()}
Hello world!
{/template}
/// Тоже самое, что и extends exports.demo.parent
{template child() extends @parent}
{/template}
Директива может использоваться только в глобальной области.
При декларации пространства имён можно использовать специальные плейсхолдеры, которые заменяются при трансляции на некоторое статическое значение в рамках своего контекста.
Плейсхолдер %dirName%
заменяется на имя директории, в которой лежит исходный файл Snakeskin, например:
foo/index.ss
- namespace %dirName%.bar
/// exports.foo.bar.index
- template index()
Hello world!
{namespace %dirName%.bar}
/// exports.foo.bar.index
{template index()}
Hello world!
{/template}
Т.к. в названии директории могут встречаться «запрещённые» символы, то лучше использовать синтаксис с квадратными скобками:
- namespace [%dirName%].bar
- template index()
Hello world!
{namespace [%dirName%].bar}
{template index()}
Hello world!
{/template}
Плейсхолдер %fileName%
заменяется на имя исходного файла-шаблона (без расширения), например:
foo/index.ss
- namespace %fileName%.bar
/// exports.index.bar.index
- template index()
Hello world!
{namespace %fileName%.bar}
/// exports.index.bar.index
{template index()}
Hello world!
{/template}
Т.к. в названии файла могут встречаться «запрещённые» символы, то лучше использовать синтаксис с квадратными скобками:
- namespace [%fileName%].bar
- template index()
Hello world!
{namespace [%fileName%].bar}
{template index()}
Hello world!
{/template}
Директива декларирует шаблон c заданным именем и входными параметрами.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только в глобальной области, необходима предварительная декларация namespace | Отсутствует | Блочная, логическая, функциональная | Не требуется |
Шаблон Snakeskin — это синоним функции в JavaScript, т. е. после трансляции все шаблоны будут представлены как JS функции, которые можно использовать вместе с любым другим JS кодом. По умолчанию шаблоны возвращают строки, однако это поведение можно поменять задав специальный renderMode или явно вернув значение через директиву return.
Название шаблона соответствует названию функции в JavaScript, поэтому оно подчиняется тем же правилам. Начать декларацию шаблона можно только после декларации пространства имён, причём в рамках одного пространства имён не может быть 2-х шаблонов с одинаковым именем, а размещаться шаблон может только в глобальной области декларации, т. е. шаблон не может включать в себя другой шаблон — для этого есть подшаблоны, например, блоки.
Декларация шаблона очень похожа на декларацию функции в JavaScript, только вместо ключевого слова function
используется
template
, например:
- namespace demo
- template index(name = 'world')
Hello {name}!
{namespace demo}
{template index(name = 'world')}
Hello {name}!
{/template}
Параметров у шаблона может быть неограниченное количество, а т. к. директива template является функциональной, то она реализует стандартный механизм декларации параметров.
При декларации шаблона можно использовать пространства имён, подобно тому, как это делается в namespace, например:
foo/index.ss
- namespace demo
- template %fileName%.index(name = 'world')
Hello {name}!
{namespace demo}
{template %fileName%.index(name = 'world')}
Hello {name}!
{/template}
Механика здесь точно такая же, как и у namespace, поэтому рассматриваться отдельно не будет, однако, есть небольшой дополнительный нюанс: если последняя часть имени декларируется без квадратных скобок, то она будет установлена
как свойство
name
полученной функции JavaScript, т. е.
- namespace demo
- template index(name = 'world')
Hello {name}!
{namespace demo}
{template index(name = 'world')}
Hello {name}!
{/template}
Превратится в:
exports.demo.index = function index(name) {
name = name != null ? name : 'world';
return 'Hello ' + name + '!';
};
Каждый шаблон определяет ряд констант и функций, которые можно использовать в нём:
TPL_NAME
— строка, которая содержит полное имя шаблона вместе с пространством имён, причём именно в том виде, как оно было задано при декларации шаблона;
PARENT_TPL_NAME
— строка, которая содержит полное имя родительского шаблона вместе с пространством имён, причём именно в том виде, как оно было задано при декларации шаблона;
callee
— ссылка на исходную функцию-шаблон;
self
— ссылка на объект callee.Blocks
, в котором хранятся вызываемые блоки (методы) исходного шаблона;
$0
— ссылка на активный DOM узел (если renderMode == 'dom'
);
$tagName
— имя созданного через директиву тега (.getVar('$tagName')
);
$attrKey
— ключ атрибута тега созданного через директиву;
$attrs
— объект атрибутов тега созданного через директиву (.getVar('$attrs')
);
$class
— значение липкой ссылки;
getTplResult
— функция, которая возвращает результат работы шаблона, также может принимать один логический входной параметр, при задании которого после вызова функции результат работы шаблона будет обнуляться;
clearTplResult
— функция, которая обнуляет результат работы шаблона.
Шаблоны Snakeskin поддерживают специальные модификаторы декларации.
Шаблон будет транслироваться в JS как функция-генератор (для поддержки в старых браузерах необходимо использовать полифил).
- namespace demo
- template *hello()
- yield
Hello world!
{namespace demo}
{template *hello()}
{yield}
Hello world!
{/}
{/template}
Шаблон будет транслироваться в JS как async функция (для поддержки в браузерах необходимо использовать полифил).
- namespace demo
- async template hello()
- var data = await db.getData()
Hello {data.name}!
{namespace demo}
{async template hello()}
{var data = await db.getData() /}
Hello {data.name}!
{/template}
К любому шаблону может быть добавлено неограниченное количество функций-декораторов (которые также могу быть шаблонами). Функция-декоратор принимает на вход ссылку на исходную функцию и обязана вернуть в качестве ответа функцию.
- namespace demo
- import Typograf from 'typograf'
- template typograf(params)
- return
() => target
- return
() =>
- return new Typograf(params).execute(target.apply(this, arguments))
- @typograf({locale: 'ru'})
- template index()
Спорт - это правильно!
{namespace demo}
{import Typograf from 'typograf'}
{template typograf(params)}
{return}
{() => target}
{return}
{() =>}
{return new Typograf(params).execute(target.apply(this, arguments)) /}
{/}
{/}
{/}
{/}
{/template}
{@typograf({locale: 'ru'})}
{template index()}
Спорт - это правильно!
{/template}
При декларации шаблона ему можно задать определённые параметры трансляции, для этого используется специальный оператор @=
, например:
- namespace demo
- template index() @= literalBounds ['<?php', '?>']
{{ Hello }}
{namespace demo}
{template index() @= literalBounds ['<?php', '?>']}
{{ Hello }}
{/template}
Шаблоны Snakeskin подобны классам в других языках программирования, т. е. у них могут быть методы и свойства, и они могут наследоваться от других шаблонов. Чтобы указать, что шаблон наследуется от другого, необходимо использовать ключевое слово extends, например:
- namespace demo
- template index() extends anotherTemplate
...
{namespace demo}
{template index() extends anotherTemplate
...
{/template}
Т.к. шаблоны Snakeskin являются простыми функциями, то их можно вызывать внутри других шаблонов и для этого удобно использовать директиву call.
- namespace demo
- template hello()
Hello world!
- template index()
/// Т.к. hello находится в одном namespace с index,
/// то мы можем использовать короткий вызов,
/// но можем написать и полную форму += demo.hello()
+= @hello()
{namespace demo}
{template hello()}
Hello world!
{/template}
{template index()}
/// Т.к. hello находится в одном namespace с index,
/// то мы можем использовать короткий вызов,
/// но можем написать и полную форму {+= demo.hello() /}
{+= @hello() /}
{/template}
Директива декларирует шаблон-интерфейс c заданным именем и входными параметрами.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только в глобальной области, необходима предварительная декларация namespace | Отсутствует | Блочная, логическая, функциональная | Не требуется |
Шаблон-интерфейс отличается от простого шаблона тем, что после трансляции в JS будет получена пустая функция с входными параметрами, например:
- namespace demo
- interface index(name = 'world')
Hello {name}!
{namespace demo}
{interface index(name = 'world')}
Hello {name}!
{/interface}
Превратится в:
exports.demo.index = function index(name) {};
В остальном механика таких шаблонов полностью идентичная template.
Директива декларирует шаблон-плейсхолдер c заданным именем и входными параметрами.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только в глобальной области, необходима предварительная декларация namespace | Отсутствует | Блочная, логическая, функциональная | Не требуется |
Шаблон-плейсхолдер отличается от простого шаблона тем, что он существует только на этапе трансляции и не будет включён в конечный JS, например:
- namespace demo
- placeholder index(name = 'world')
Hello {name}!
{namespace demo}
{placeholder index(name = 'world')}
Hello {name}!
{/placeholder}
Превратится в:
В остальном механика таких шаблонов полностью идентичная template.
Директива декларирует статичный блок или подшаблон c заданным именем и входными параметрами.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая, функциональная | Не требуется |
Директива block несёт двойную функциональность: с одной стороны она позволяет создавать статичные блоки, а с другой — вызываемые. Блоки являются фундаментальной ячейкой Snakeskin, т. к. играют ключевую роль при наследовании, но если статичный блок — это просто выделение фрагмента текста, чтобы в дальнейшем иметь возможность его переопределить в дочернем шаблоне, то вызываемый блок — это по сути вложенная функция-шаблон, т. е. после декларации его можно неоднократно вызывать и передавать различные параметры.
Разница в декларации статичного блока от динамического заключается в наличии скобок для параметров, например:
- namespace demo
- template index()
/// Статичный блок
- block hello
Hello world!
/// Вызываемый блок
- block helloWithName(name)
Hello {name}!
{namespace demo}
{template index()}
/// Статичный блок
{block hello}
Hello world!
{/}
/// Вызываемый блок
{block helloWithName(name)}
Hello {name}!
{/}
{/template}
Параметров у блока может быть неограниченное количество, а т. к. директива block является функциональной, то она реализует стандартный механизм декларации параметров. По умолчанию вызываемые блоки возвращают строки, однако это поведение можно поменять задав специальный renderMode или явно вернув значение через директиву return.
Название блока соответствует названию функции в JavaScript, поэтому оно подчиняется тем же правилам, причём статичные блоки и вызываемые лежат в одном пространстве имён. В рамках шаблона не может быть 2-х блоков с одинаковым названием.
Вызываемые блоки — это методы шаблона, т. е. они наследуются в дочерних шаблонах, могут переопределяться и т. д., а сама механика наследования практически идентична со статичными блоками и шаблонами, и описана в отдельной главе.
При создании вызываемого блока он ставиться как свойство .Blocks.названиеБлока
исходного шаблона, и, как правило, вызывается с помощью директивы call и указателя self,
например:
- namespace demo
- template index()
- block hello(name)
Hello {name}!
+= self.hello('kobezzza')
{namespace demo}
{template index()}
{block hello(name)}
Hello {name}!
{/}
{+= self.hello('kobezzza') /}
{/template}
Примечание: this внутри блока ссылается на this шаблона.
Каждый вызываемый блок определяет ряд функций, которые можно использовать в нём:
getTplResult
— функция, которая возвращает результат работы блока, также может принимать один логический входной параметр, при задании которого после вызова функции результат работы блока будет обнуляться;
clearTplResult
— функция, которая обнуляет результат работы блока.
Любые блоки могут декларироваться как внутри шаблона или другого блока, так и в глобальной области, но при такой декларации есть ряд дополнительных правил: блок должен декларироваться до шаблона, методом которого он является;
блок должен явно указывать к какому шаблону он принадлежит (для этого используется оператор ->
), например:
- namespace demo
- block index->hello(name)
Hello {name}!
- template index()
+= self.hello('kobezzza')
{namespace demo}
{block index->hello(name)}
Hello {name}!
{/block}
{template index()}
{+= self.hello('kobezzza') /}
{/template}
Такие блоки могут даже находиться в разных файлах и подключаться через include, но должны обязательно подключаться до декларации шаблона.
Вызываемый блок можно вызвать немедленно после декларации: для этого используется специальный оператор =>
, например:
- namespace demo
- template index()
- block hello(name) => 'kobezzza'
Hello {name}!
{namespace demo}
{template index()}
{block hello(name) => 'kobezzza'}
Hello {name}!
{/}
{/template}
Такой же синтаксис можно использовать и для внешних блоков:
- namespace demo
- block index->hello(name) => 'kobezzza'
Hello {name}!
- template index()
{namespace demo}
{block index->hello(name) => 'kobezzza'}
Hello {name}!
{/block}
{template index()}
{/template}
&
для удобного рекурсивного вызова блокаПри использовании call для вызова блока можно использовать специальный указать &
, который ссылается на блок внутри которого он используется — это удобно для организации рекурсий, например:
- namespace demo
- template index()
- block iterate(i)
{i}
- if i
+= &(--i)
+= self.iterate(5)
{namespace demo}
{template index()}
{block iterate(i)}
{i}
{if i}
{+= &(--i) /}
{/}
{/}
{+= self.iterate(5) /}
{/template}
Директива задаёт значение указанному параметру трансляции.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только в глобальной области | @= |
Строковая, логическая | Не требуется |
Директива декларирует завершение блочной директивы.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | / |
Строковая, логическая | Не требуется |
Директива используется для завершения блочной директивы в классическом синтаксисе Snakeskin (в jade-like) она ставиться автоматически). У директивы есть 4-ре формы использования:
/// Полная форма
{if 1 > 2}
...
{end if}
/// Сокращённая форма
{if 1 > 2}
...
{end}
/// Альтернативная полная форма
{if 1 > 2}
...
{/if}
/// Альтернативная сокращённая форма
{if 1 > 2}
...
{/}
Какую форму использовать решает сам разработчик, но следует отметить, что при использовании форм с указанием имени закрываемой директивы Snakeskin будет проверять правильность, т. е.:
{if 1 > 2}
...
{/else} /// Ошибка
Директива выполняет заданное выражение и выводит результат в шаблон (на выводимое выражение по умолчанию накладываются фильтры html и undef).
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Не требуется | Строковая, текстовая | Не требуется |
Директива output используется когда нам нужно вывести в текст шаблона значение переменной или выражения.
Директива не требует специального ключевого слова (хотя допускается), поэтому достаточно просто взять выводимое выражение в фигурные скобки, например:
- namespace demo
- template calc(a, b)
a + b = {a + b}
{namespace demo}
{template calc(a, b)}
a + b = {a + b}
{/template}
Однако нужно следить, чтобы первое слово выводимого выражения не было равно имени другой директивы Snakeskin, иначе возникнет ошибка:
- namespace demo
- template index(link)
{link} /// Ошибка
{namespace demo}
{template index(link)}
{link} /// Ошибка
{/template}
Для того чтобы пример выше отработал корректно достаточно просто взять наше выражение в круглые скобки:
- namespace demo
- template index(link)
{(link)}
{namespace demo}
{template index(link)}
{(link)}
{/template}
Внутри output можно использовать вызовы функций, тернарные операторы и т. д.
- namespace demo
- template calc(a, b)
{a > 1 ? --a * b : Math.random() * b}
{namespace demo}
{template calc(a, b)}
{a > 1 ? --a * b : Math.random() * b}
{/template}
На всё выводимое выражение по умолчанию накладывается специальный фильтр html, который экранирует html сущности, а также фильтр undef на каждый отдельный чанк выражения, который преобразует значение undefined
в ''
. Чтобы отменить это поведение нужно использовать фильтры !html
и !undef
или задать глобальное через параметр трансляции filters.
- namespace demo
- template index(val1, val2)
{(val1|!undef) + (val2|!undef) |!html}
{namespace demo}
{template index(val1, val2)}
{(val1|!undef) + (val2|!undef) |!html}
{/template}
Директива может использоваться только внутри шаблонов или внешних блоков.
Директива выполняет заданное выражение и выводит результат в шаблон (на выводимое выражение по умолчанию накладываются фильтр undef).
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | += |
Блочная, текстовая | Не требуется |
Директива call похожа на output, т. е. она тоже вставляет результат выражения в шаблон, однако, она не накладывает по умолчанию на выводимые данные фильтр html,
т. е. выводимое выражение не экранируется и это является аналогом использования фильтра !html
.
Директива начинается с ключевого слова call
(или символов +=
), которое должно сопровождаться ссылкой на выводимое значение или выражение (заключать выражение в скобки не обязательно), например:
- namespace demo
- template index()
+= 1 + 2
{namespace demo}
{template index()}
{+= 1 + 2 /}
{/template}
Для удобства использования call в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{+= 1 + 2}{/}
/// Короткая форма закрытия
{+= 1 + 2 /}
Главным кейзом использования call является вызов блоков и других шаблонов внутри шаблона, поэтому выводимые данные не экранируются, т. к. они уже и так экранированы, например:
- namespace demo
- template helper()
< .foo
Hello world!
- template index()
/// <div class="foo">Hello world!</div>
+= @helper()
/// <div class="foo">Hello world!</div>
{@helper()}
{namespace demo}
{template helper()}
{< .foo}
Hello world!
{/}
{/template}
{template index()}
/// <div class="foo">Hello world!</div>
{+= @helper() /}
/// <div class="foo">Hello world!</div>
{@helper()}
{/template}
Директива может использоваться только внутри шаблонов или внешних блоков.
Директива поддерживает специальную расширенную форму для передачи параметров-шаблонов в вызываемую функцию, например:
- namespace demo
- template helper(text)
< .output
{text}
- template index()
/// <div class="output"><div class="foo">Hello world!</div></div>
+= @helper()
< .hello
Hello world!
{namespace demo}
{template helper(text)}
{< .output}
{text}
{/}
{/template}
{template index()}
/// <div class="output"><div class="foo">Hello world!</div></div>
{+= @helper()}
{< .hello}
Hello world!
{/}
{/}
{/template}
Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т. д. Если необходимо передать несколько параметров, то нужно использовать директиву putIn:
- namespace demo
- template helper(text1, text2)
< .output1
{text1}
< .output2
{text2}
- template index()
+= @helper()
*
< .hello
Hello world!
*
< .goodbye
Goodbye cruel world!
{namespace demo}
{template helper(text1, text2)}
{< .output1}
{text1}
{/}
{< .output2}
{text2}
{/}
{/template}
{template index()
{+= @helper()}
{*}
{< .hello}
Hello world!
{/}
{/}
{*}
{< .goodbye}
Goodbye cruel world!
{/}
{/}
{/}
{/template}
Первый вызов putIn можно опустить:
- namespace demo
- template helper(text1, text2)
< .output1
{text1}
< .output2
{text2}
- template index()
+= @helper()
< .hello
Hello world!
*
< .goodbye
Goodbye cruel world!
{namespace demo}
{template helper(text1, text2)}
{< .output1}
{text1}
{/}
{< .output2}
{text2}
{/}
{/template}
{template index()
{+= @helper()}
{< .hello}
Hello world!
{/}
{*}
{< .goodbye}
Goodbye cruel world!
{/}
{/}
{/}
{/template}
Допускается совмещать передачу параметров в обычной и расширенной форме.
- namespace demo
- template helper(a, b, text1, text2)
{a + b}
< .output1
{text1}
< .output2
{text2}
- template index()
+= @helper(1, 2)
< .hello
Hello world!
*
< .goodbye
Goodbye cruel world!
{namespace demo}
{template helper(a, b, text1, text2)}
{a + b}
{< .output1}
{text1}
{/}
{< .output2}
{text2}
{/}
{/template}
{template index()
{+= @helper(1, 2)}
{< .hello}
Hello world!
{/}
{*}
{< .goodbye}
Goodbye cruel world!
{/}
{/}
{/}
{/template}
- namespace demo
- template helper(fn)
+= fn(1, 2)
- template index()
+= @helper()
() => a, b
{a + b}
{namespace demo}
{template helper(fn)}
{+= fn(1, 2) /}
{/template}
{template index()
{+= @helper()}
{() => a, b}
{a + b}
{/}
{/}
{/template}
- namespace demo
- template helper(@params)
{@data}
- template index()
+= @helper()
- target {}
* data
< .hello
Hello world!
{namespace demo}
{template helper(@params)}
{@data}
{/template}
{template index()
{+= @helper()}
{target {}}
{* data}
{< .hello}
Hello world!
{/}
{/}
{/}
{/}
{/template}
Директива выполняет заданное выражение, но ничего не выводит в шаблон.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | ? |
Строковая, логическая | Не требуется |
Директива void используется когда нам нужно выполнить некоторую логику, но чтобы она никак не отобразилась в шаблоне, например, сделать инкремент переменной или вывести текст в консоль разработчика.
Директива начинается с ключевого слова void
(или символа ?
), которое должно сопровождаться выражением (заключать выражение в скобки не обязательно). Самая простая форма выглядит так:
- void console.log('hello')
{void console.log('hello')}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
- namespace demo
? console.log('hello world')
- template index()
: a = 0
- void a++
{a} /// 1
{namespace demo}
{? console.log('hello world')}
{template index()}
{: a = 0}
{void a++}
{a} /// 1
{/template}
Директива return является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри функциональных директив | Отсутствует | Блочная, логическая | Не требуется |
Большинство функциональных директив Snakeskin возвращают свой результат автоматически, но иногда бывает нужно вернуть определённый ответ в зависимости от условия, или если возвращаемое значение отлично от стандартного ответа Snakeskin.
Директива начинается с ключевого слова return
, которое может сопровождаться ссылкой на возвращаемое значение или выражение, например:
- namespace demo
- template index()
- return 1 + 2
{namespace demo}
{template index()}
{return 1 + 2 /}
{/template}
Для удобства использования return в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{return 1 + 2}{/}
/// Короткая форма закрытия
{return 1 + 2 /}
Директива может использоваться только внутри функциональных директив.
Директива может включать возвращаемое значение в своё тело — это удобно, когда возвращаемое значение является подшаблоном, например:
- namespace demo
- template index()
/// Шаблон вернёт ссылку на функцию,
/// которая складывает два числа
- return
() => a, b
- return a + b
{namespace demo}
{template index()}
/// Шаблон вернёт ссылку на функцию,
/// которая складывает два числа
{return}
{() => a, b}
{return a + b /}
{/}
{/}
{/template}
Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т. д.
Директива создаёт блок, который выполнится на этапе трансляции, но не войдёт в конечный JS.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только в глобальной области | Отсутствует | Блочная, логическая | Не требуется |
Т.к. любой код, размещённый вне тела шаблона будет выполняться как на этапе трансляции, так и войдёт в конечный JS код, то директива eval позволяет создать блок, содержимое которого будет исключаться из результирующего кода, но по прежнему будет выполняться на этапе трансляции.
- eval
? console.log('Hello world!')
{eval}
{? console.log('Hello world!')}
{/}
Директива может использоваться только в глобальной области.
Директива создаёт блок, который не выполнится на этапе трансляции, но войдёт в конечный JS.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только в глобальной области | Отсутствует | Блочная, логическая | Не требуется |
Т.к. любой код, размещённый вне тела шаблона будет выполняться как на этапе трансляции, так и войдёт в конечный JS код, то директива head позволяет создать блок, содержимое которого по прежнему не будет исключаться из результирующего кода, но не будет выполняться на этапе трансляции, а также переменные, которые были объявлены на корневом уровне директивы, будут считаться глобальными.
- namespace demo
- head
/// Данный forEach не выполнится на этапе трансляции,
/// но войдёт в конечный JS
- forEach [1, 2, 3] => el
? console.log(el)
/// Данная переменная глобальная,
/// хоть и объявлена внутри блочной директивы
: foo = 'bar'
- template index()
? console.log(foo) /// 'bar'
{namespace demo}
{head}
/// Данный forEach не выполнится на этапе трансляции,
/// но войдёт в конечный JS
{forEach [1, 2, 3] => el}
{? console.log(el)}
{/}
/// Данная переменная глобальная,
/// хоть и объявлена внутри блочной директивы
{var a = 1 /}
{/}
{template index()}
{? console.log(foo)} /// 'bar'
{/template}
Директива может использоваться только в глобальной области.
Директива задаёт область видимости для поиска свойств объекта.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива позволяет задать «виртуальную» область видимости для объекта, чтобы затем обращаться к его свойствам с помощью специального модификатора контекста @
, например:
- var base = {child: {name: 'Moscow'}}
- with base.child
? console.log(@name) /// Moscow
{var base = {child: {name: 'Moscow'}}}
{with base.child}
{? console.log(@name)} /// Kobezzza
{/}
С помощью @
можно как получать, так и устанавливать свойства объекту.
- var base = {child: {name: 'Moscow'}}
- with base.child
? @name = 'Washington'
? @type = 'city'
? console.log(base.child.name) /// Washington
? console.log(base.child.type) /// city
{var base = {child: {name: 'Moscow'}}}
{with base.child}
{? console.log(@name)} /// Kobezzza
{? @name = 'Washington'}
{/}
{console.log(base.child.name)} /// Washington
Любые входные параметры функциональных директив Snakeskin (template, forEach и т. д.) поддерживают короткую запись декларации with.
- namespace demo
- template index(@params)
{@name} /// params.name
{namespace demo}
{template index(@params)}
{@name} /// params.name
{/template}
Такая запись эквивалентна:
- namespace demo
- template index(params)
- with params
{@name}
{namespace demo}
{template index(params)}
{with params}
{@name}
{/}
{/template}
Можно вкладывать with-блоки друг в друга, например:
- namespace demo
- template index()
- with params
{@name} /// params.name
- with @data
{@type} /// params.data.type
{namespace demo}
{template index(params)}
{with params}
{@name} /// params.name
{with params}
{@type} /// params.data.type
{/}
{/}
{/template}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
Директива создаёт переменную/ые с указанным именем и значением.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | : |
Блочная, логическая | Не требуется |
Переменные в Snakeskin имеют блочную область видимости и по своей семантике напоминают let
из JS ES2015.
Директива var позволяет декларировать сразу несколько переменных через запятую (аналогично как это делается в JS).
Директива начинается с ключевого слова var
(или символа :
), которое должно сопровождаться списком имён создаваемых переменных (через запятую). Для присвоения значений созданной переменной необходимо поставить
символ =
после имени.
Самая простая форма выглядит так:
- var a = 1
{var a = 1 /}
Для удобства использования var в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{var a = 1}{/}
/// Короткая форма закрытия
{var b = 2 /}
В отличии от JS переменные в Snakeskin декларируются только после места декларации.
: a = 2
- if true
? console.log(a) /// 2
: a = 1
? console.log(a) /// 1
{: a = 2 /}
{if true}
{? console.log(a)} /// 2
{: a = 1 /}
{? console.log(a)} /// 1
{/}
Допускается в рамках одного блока создавать переменные с одинаковым именем.
: a = 2
? console.log(a) /// 2
: a = 1
? console.log(a) /// 1
{: a = 2 /}
{? console.log(a)} /// 2
{: a = 1 /}
{? console.log(a)} /// 1
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
С помощью ключевого слова putIn
можно присвоить переменной подшаблон Snakeskin, однако при такой декларации допускается создавать только одну переменную за раз, например:
- namespace demo
- template index(value)
: putIn tpl
- if value !== 404
< .hello
Hello world!
- else
< .error
404
{namespace demo}
{template index(value)}
{: putIn tpl}
{if value !== 404}
{< .hello}
Hello world!
{else}
{< .error}
404
{/}
{/}
{/}
{/template}
Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т. д.
- namespace demo
- template index(value)
- if true
: a = 1
{a}
{a} /// Error, a is not defined
: b = 1, c = 2
- if true
{b} /// 1
{c} /// 2
{b} /// 1
{namespace demo}
{template index(value)}
{if true}
{: a = 1 /}
{a}
{/}
{a} /// Error, a is not defined
{: b = 1, c = 2 /}
{if true}
{b} /// 1
{c} /// 2
{/}
{b} /// 1
{/template}
Директива создаёт константу с указанным именем и значением.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Не требуется | Строковая, текстовая / логическая | Не требуется |
Константы Snakeskin не имеют ничего общего с константами из JS ES2015 и служат для других целей. Константы глобальны в рамках своего шаблона, поэтому не может быть 2-х констант с одинаковым именем. Значение константы может меняться по ходу выполнения шаблона.
При декларации константы не требуется специального ключевого слова (хотя допускается), например:
- namespace demo
- template index()
- val = 'hello'
{val}
{namespace demo}
{template calc(a, b)}
{val = 'hello'}
{val}
{/template}
С логической точки зрения константы Snakeskin — это свойства класса (шаблона), т. е. они доступны в любом месте шаблона и их можно переопределять в дочернем шаблоне. Константа может быть свойством объекта (включая свойство другой константы), например:
- namespace demo
- template index()
- val = {}
- val.name = 'Kobezzza'
{namespace demo}
{template calc(a, b)}
{val = {}}
{val.name = 'Kobezzza'}
{/template}
После декларации константы станет невозможным в рамках шаблона объявление переменной с таким же именем.
- namespace demo
- template index()
- val = {}
- var val = 1 /// Ошибка
{namespace demo}
{template calc(a, b)}
{val = {}}
{var val = 1 /} /// Ошибка
{/template}
Константы могут создаваться только внутри шаблонов или внешних блоков.
Если любая функциональная директива содержит параметр с именем равным константе, то он «замещает» константу в рамках своей блочной области видимости, например:
- namespace demo
- template index()
- val = {}
- forEach [1, 2] => val
{val} /// 1, 2
{namespace demo}
{template calc(a, b)}
{val = {}}
{forEach [1, 2] => val}
{val} /// 1, 2
{/}
{/template}
Если в конце декларации константы поставить символ ?
, то её значение сразу же выведется в шаблон.
- namespace demo
- template index()
< title
- title = 'Главная страница' ?
{namespace demo}
{template calc(a, b)}
{< title}
{title = 'Главная страница' ?}
{/}
{/template}
Директива создаёт супер-глобальную переменную с указанным именем и значением.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Не требуется | Строковая, текстовая / логическая | Не требуется |
Супер-глобальная переменная Snakeskin — это свойство объекта Snakeskin.Vars
, т. е. такая переменная доступна как из JavaScript, так и во всех файлах шаблонов. Устанавливать такие переменные можно из JS
(причём можно до трансляции) или из шаблонов. Основной use-case супер-глобальных переменных — это прокидывание конфига, т. е. некоторый аналог переменных среды в операционной системе.
Чтобы задать значение супер-глобальной переменной перед непосредственной трансляцией можно использовать параметр vars, а также в любой момент времени допускается вносить изменения напрямую в объект Snakeskin.Vars
,
например:
Snakeskin.Vars.server = 'localhost';
Snakeskin.Vars.port = '1989';
Для задания супер-глобальной переменной из SS можно использовать несколько способов:
- global server = 'localhost'
- global port = '1989'
{global server = 'localhost'}
{global port = '1989'}
Вне тела шаблонов можно опустить ключевое слово global
:
- server = 'localhost'
- port = '1989'
{server = 'localhost'}
{port = '1989'}
При задании имение допускается использовать скобочную нотацию:
- ['server'] = 'localhost'
- ['port'] = '1989'
{['server'] = 'localhost'}
{['port'] = '1989'}
@@
, например:- @@server = 'localhost'
- @@port = '1989'
{@@server = 'localhost'}
{@@port = '1989'}
Такой вариант можно использовать как вне шаблонов, так и внутри их. Литеральная форма также поддерживает скобочную нотацию:
- @@['server'] = 'localhost'
- @@['port'] = '1989'
{@@['server'] = 'localhost'}
{@@['port'] = '1989'}
Для чтения супер-глобальных переменных используется модификатор @@
, например:
- @@server = 'localhost'
? console.log(@@server)
{@@server = 'localhost'}
{? console.log(@@server)}
Если в конце декларации супер-глобальной переменной поставить символ ?
, то её значение сразу же выведется в шаблон.
- namespace demo
- template index()
< title
- @@title = 'Главная страница' ?
{namespace demo}
{template calc(a, b)}
{< title}
{@@title = 'Главная страница' ?}
{/}
{/template}
Директива if является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива позволяет вашему шаблону в зависимости от условий выполнить некоторую логику или сгенерировать фрагмент шаблона, основываясь на значении переменной или выражения.
Директива начинается с ключевого слова if
, которое должно сопровождаться выражением (заключать выражение в скобки не обязательно).
Самая простая форма выглядит так:
- if true
Hello world!
{if true}
Hello world!
{/if}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Вместе с основной директивой можно использовать дополнительные:
else
— аналог else
в JS;else if
— аналог else if
в JS;else unless
— аналог else if (!(...))
в JS.- namespace demo
- template index(value)
< .result
- if val > 3
< .success
Значение больше чем 3.
- else if val < 3
< .fail
Значение меньше чем 3.
- else
< .error
Значение рано 3.
{namespace demo}
{template index(value)}
{< .result}
{if val > 3}
{< .success}
Значение больше чем 3.
{/}
{else if val < 3}
{< .fail}
Значение меньше чем 3.
{/}
{else}
{< .error}
Значение рано 3.
{/}
{/}
{/}
{/template}
Директива unless является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в CoffeeScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива является инвертной формой if, т. е. если if блок выполнится только в том случае когда условное выражение будет приведено к true
, то unless выполнится в случае false
.
Директива позволяет вашему шаблону в зависимости от условий выполнить некоторую логику или сгенерировать фрагмент шаблона, основываясь на значении переменной или выражения.
Директива начинается с ключевого слова unless
, которое должно сопровождаться выражением (заключать выражение в скобки не обязательно).
Самая простая форма выглядит так:
- unless false
Hello world!
{unless false}
Hello world!
{/}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Вместе с основной директивой можно использовать дополнительные:
else
— аналог else
в JS;else if
— аналог else if
в JS;else unless
— аналог else if (!(...))
в JS.- namespace demo
- template index(value)
< .result
- unless val >= 3
< .success
Значение меньше чем 3.
- else unless val <= 3
< .fail
Значение больше чем 3.
- else
< .error
Значение рано 3.
{namespace demo}
{template index(value)}
{< .result}
{unless val >= 3}
{< .success}
Значение меньше чем 3.
{else unless val <= 3}
{< .fail}
Значение больше чем 3.
{else}
{< .error}
Значение рано 3.
{/}
{/}
{/template}
Директива switch является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript (break
ставится автоматически после каждого блока case).
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | > (для case) |
Блочная, логическая | Не требуется |
Подобно if или unless директива позволяет вашему шаблону в зависимости от условий выполнить некоторую логику или сгенерировать фрагмент шаблона, основываясь на значении переменной или выражения, но предоставляет более удобный синтаксис когда нужно сравнить выражение сразу с несколькими вариантами.
Директива начинается с ключевого слова switch
, которое должно сопровождаться выражением (заключать выражение в скобки не обязательно), а внутри директивы должны использоваться вспомогательные директивы
case и/или default. Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
Директива case начинается с ключевого слова case
(или символа >
), а после должно следовать выражение выражение для сравнения со switch. В отличии от реализации case в JS — оператор
break
ставиться автоматически после каждого блока.
Декларация default полностью идентичная аналогичной в JS.
- namespace demo
- template index(value)
< .result
- switch value
- case 1
< .value-1
value == 1
- case 2
< .value-2
value == 2
> 3
< .value-3
value == 3
- default
Условие, которое выполнится по умолчанию.
{namespace demo}
{template index(value)}
{< .result}
{switch value}
{case 1}
{< .value-1}
value == 1
{/}
{/}
{case 2}
{< .value-2}
value == 2
{/}
{/}
{> 3}
{< .value-3}
value == 3
{/}
{/}
{default}
Условие, которое выполнится по умолчанию.
{/}
{/}
{/}
{/template}
Директива for является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива создаёт цикл, т. е. блок цикла будет выполняется до тех пор, пока управляющее логическое выражение не станет ложным или пока цикл не будет сброшен вручную. Директива проводит инициализацию перед первым шагом цикла. Затем выполняется проверка условия цикла, и в конце каждой итерации происходит изменение управляющей переменной.
for инициализация; логическое выражение (условие); шаг (итерация)
команда
Самая простая форма выглядит так:
- for var i = 0; i < 3; i++
Итерация - {i}
{for var i = 0; i < 3; i++}
Итерация - {i}
{/for}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Для управления циклом внутри блока можно использовать директивы:
- namespace demo
- template index()
- var arr = [1, 2, 3]
/// Т.к. переменные Snakeskin имеют блочную область видимости,
/// то i будет доступен только внутри for
- for var i = 0; i < arr.length; i++
{arr[i]}
{namespace demo}
{template index()}
{var arr = [1, 2, 3] /}
/// Т.к. переменные Snakeskin имеют блочную область видимости,
/// то i будет доступен только внутри for
{for var i = 0; i < arr.length; i++}
{arr[i]}
{/}
{/template}
- namespace demo
- template index()
- var obj = {a: 1, b: 2}
/// Т.к. переменные Snakeskin имеют блочную область видимости,
/// то key будет доступен только внутри for
- for var key in obj
{key}
{namespace demo}
{template index()}
{var obj = {a: 1, b: 2} /}
/// Т.к. переменные Snakeskin имеют блочную область видимости,
/// то key будет доступен только внутри for
{for var key in obj}
{key}
{/}
{/template}
- namespace demo
- template index()
- var obj = {a: 1, b: 2}
- for var key in obj
- if !obj.hasOwnProperty(key)
- continue
{key}
- break
{namespace demo}
{template index()}
{var obj = {a: 1, b: 2} /}
{for var key in obj}
{if !obj.hasOwnProperty(key)}
{continue}
{/}
{key}
{break}
{/}
{/template}
Директива while является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива создаёт цикл, т. е. блок цикла будет выполняется до тех пор, пока управляющее логическое выражение не станет ложным или пока цикл не будет сброшен вручную.
Директива начинается с ключевого слова while
, которое должно сопровождаться выражением (заключать выражение в скобки не обязательно).
Самая простая форма выглядит так:
- var i = 3
- while i--
{i}
{var i = 3 /}
{while i--}
{i}
{/while}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Для управления циклом внутри блока можно использовать директивы:
- namespace demo
- template index()
- var arr = [1, 2, 3]
- while arr.length
{arr[0]}
? arr.shift()
{namespace demo}
{template index()}
{var arr = [1, 2, 3] /}
{while arr.length}
{arr[0]}
{? arr.shift()}
{/}
{/template}
- namespace demo
- template index()
- var i = 3
- while i--
{i}
- break
{namespace demo}
{template index()}
{var i = 3 /}
{while i--}
{i}
{break}
{/}
{/template}
Директива do является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива создаёт цикл, т. е. блок цикла будет выполняется до тех пор, пока управляющее логическое выражение не станет ложным или пока цикл не будет сброшен вручную. Отличие do от while состоит в том,
что цикл do-while
выполняется по крайней мере один раз, даже если условие изначально ложно.
Директива начинается с ключевого слова do
, а выражение для проверки идёт после вложенного блока цикла вместе с директивой while (заключать выражение в скобки не обязательно).
Самая простая форма выглядит так:
- var i = 3
- do
{i}
- while i--
{var i = 3 /}
{do}
{i}
{while i--}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Для управления циклом внутри блока можно использовать директивы:
- namespace demo
- template index()
- var arr = [1, 2, 3]
- do
{arr[0]}
? arr.shift()
- while arr.length
{namespace demo}
{template index()}
{var arr = [1, 2, 3] /}
{do}
{arr[0]}
{? arr.shift()}
{while arr.length}
{/template}
- namespace demo
- template index()
- var i = 0
- do
{i}
? i++
{namespace demo}
{template index()}
{var i = 0 /}
{do}
{i}
{? i++}
{/}
{/template}
- namespace demo
- template index()
- var i = 3
- do
{i}
- break
- while i--
{namespace demo}
{template index()}
{var i = 3 /}
{do}
{i}
{break}
{while i--}
{/template}
Директива итерирует заданный объект (с учётом hasOwnProperty) или массив.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая, функциональная | Не требуется |
Директива итерирует заданное значение с помощью функции Snakeskin.forEach и может работать как с объектами, так и с массивами.
Общая форма директивы следующая:
forEach ссылка на объект или сам объект => параметры функции через запятую
команда
Например:
- forEach [1, 2, 3] => el
{el}
{forEach [1, 2, 3] => el}
{el}
{/forEach}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области, а т. к. forEach является функциональной директивой, то он реализует стандартный механизм декларации параметров.
Для управления обходом внутри итератора можно использовать директивы:
isFirst
— является ли элемент первым;isLast
— является ли элемент последним;length
— длина массива.i
— номер итерации;isFirst
— является ли элемент первым;isLast
— является ли элемент последним;length
— длина массива.Несмотря на то что forEach использует функцию при обходе объекта, поведение директивы приближено к поведению цикла, т. е. внутри можно использовать директивы break, continue и return, принцип работы которых не будет отличаться, например:
- namespace demo
/// Шаблон вернёт 1
- template index()
- forEach [1, 2, 3] => el
- return el
Hello world
{namespace demo
/// Шаблон вернёт 1
{template index()}
{forEach [1, 2, 3] => el}
{return el /}
Hello world
- namespace demo
- template index()
- var arr = [1, 2, 3]
- forEach arr => el
{el}
{namespace demo}
{template index()}
{var arr = [1, 2, 3] /}
{forEach arr => el}
{el}
{/}
{/template}
- namespace demo
- template index()
- var arr = [{name: 'Koba'}, {name: 'Over'}]
- forEach arr => @el
{@name}
{namespace demo}
{template index()}
{var arr = [{name: 'Koba'}, {name: 'Over'}] /}
{forEach arr => @el}
{@name}
{/}
{/template}
- namespace demo
- template index()
- var obj = {a: 1, b: 2}
- forEach obj => el, key
{el} {key}
{namespace demo}
{template index()}
{var obj = {a: 1, b: 2} /}
{forEach obj => el, key}
{el} {key}
{/}
{/template}
- namespace demo
- template index()
- forEach [1, 2, 3] => el
{el}
- break
{namespace demo}
{template index()}
{forEach [1, 2, 3] => el}
{el}
{break}
{/}
{/template}
Директива итерирует заданный объект (без учёта hasOwnProperty).
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая, функциональная | Не требуется |
Директива итерирует заданный объект с помощью функции Snakeskin.forIn.
Общая форма директивы следующая:
forIn ссылка на объект или сам объект => параметры функции через запятую
команда
Например:
- forIn {a: 1, b: 2} => el
{el}
{forIn {a: 1, b: 2} => el}
{el}
{/forIn}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области, а т. к. forIn является функциональной директивой, то он реализует стандартный механизм декларации параметров.
Для управления обходом внутри итератора можно использовать директивы:
i
— номер итерации;isFirst
— является ли элемент первым;isLast
— является ли элемент последним;length
— длина массива.Несмотря на то что forIn использует функцию при обходе объекта, поведение директивы приближено к поведению цикла, т. е. внутри можно использовать директивы break, continue и return, принцип работы которых не будет отличаться, например:
- namespace demo
/// Шаблон вернёт 1
- template index()
- forIn {a: 1, b: 2} => el
- return el
Hello world
{namespace demo
/// Шаблон вернёт 1
{template index()}
{forIn {a: 1, b: 2} => el}
{return el /}
Hello world
- namespace demo
- template index()
- var obj = {a: 1, b: 2}
- forIn obj => el, key
{el} {key}
{namespace demo}
{template index()}
{var obj = {a: 1, b: 2} /}
{forIn obj => el, key}
{el} {key}
{/}
{/template}
- namespace demo
- template index()
- var obj = {a: {name: 'Koba'}, b: {name: 'Over'}}
- forIn obj => @el
{@name}
{namespace demo}
{template index()}
{var obj = {a: {name: 'Koba'}, b: {name: 'Over'}} /}
{forEach obj => @el}
{@name}
{/}
{/template}
- namespace demo
- template index()
- forEach {a: 1, b: 2, c: 3} => el
{el}
- break
{namespace demo}
{template index()}
{forEach {a: 1, b: 2, c: 3} => el}
{el}
{break}
{/}
{/template}
Директива try является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива позволяет вашему шаблону отлавливать и обрабатывать исключения, которые могут возникать по ходу выполнения программы на Snakeskin.
Самая простая форма выглядит так:
- try
? 1 2
{try}
{1 2}
{/try}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Вместе с основной директивой можно использовать дополнительные:
catch
— аналог catch
в JS (функциональная директива);finally
— аналог finally
в JS.- namespace demo
- template index(value)
< .result
- try
? value = JSON.parse(value)
- catch err
? console.error(err)
- finally
Hello world!
{namespace demo}
{template index(value)}
{< .result}
{try}
{? value = JSON.parse(value)}
{catch err}
{? console.error(err)}
{finally}
Hello world!
{/}
{/}
{/template}
Директива throw является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Строковая, логическая | Не требуется |
Директива генерирует заданное исключение и начинается с ключевого слова throw
, которое должно сопровождаться выражением. Самая простая форма выглядит так:
- throw new Error('Ошибка')
{throw new Error('Ошибка')}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
- namespace demo
- template index(value)
< .result
- if value > 1
- throw new Error('Invalid value')
{namespace demo}
{template index(value)}
{< .result}
{if value > 1}
{throw new Error('Invalid value')}
{/}
{/}
{/template}
Директива декларирует, что все последующие пробельные символы до первого не пробельного должны игнорироваться.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | & |
Строковая, логическая | Не требуется |
- namespace demo
- template index(value, area)
Hello{&} World Bar
{namespace demo}
{template index(value, area)}
Hello{&} World Bar
{/template}
Отрендерится как:
HelloWorld Bar
Директива декларирует, что все вложенные в директиву пробельные символы должны игнорироваться.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | &+ |
Блочная, логическая | Не требуется |
- namespace demo
- template index(value, area)
&+
Hello World Bar
{namespace demo}
{template index(value, area)}
{&+}
Hello World Bar
{/}
{/template}
Отрендерится как:
HelloWorldBar
Директива декларирует, что все вложенные в директиву пробельные символы не должны игнорироваться (обычно используется вместе с ignoreAllWhitespaces).
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | &- |
Блочная, логическая | Не требуется |
- namespace demo
- template index(value, area)
&+
Hello World Bar
&-
Hello World Bar
{namespace demo}
{template index(value, area)}
{&+}
Hello World Bar
{&-}
Hello World Bar
{/}
{/}
{/template}
Отрендерится как:
HelloWorldBarHello World Bar
Директива вставляет в шаблон пробельный символ (актуально только для Jade-Like).
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | \ |
Строковая, текстовая | Не требуется |
- namespace demo
- template index(value, area)
< .foo
\
< .bar
Отрендерится как:
<div class="foo"></div> <div class="bar"></div>
Директива вставляет в шаблон код декларации заданного doctype, а также определяет правила форматирования для тегов и атрибутов.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Отсутствует | Строковая, текстовая | Не поддерживается |
Директива предназначена для указания типа текущего документа — DTD (document type definition, описание типа документа). Это необходимо, чтобы клиент/парсер понимал, как следует интерпретировать текущую страницу, а также указывает Snakeskin какие правила он должен применять при генерации кода тегов и атрибутов.
Директива может использоваться только внутри шаблонов или внешних блоков.
<!DOCTYPE html>
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">
<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">
<!DOCTYPE math SYSTEM "http://www.w3.org/Math/DTD/mathml1/mathml.dtd">
<!DOCTYPE math PUBLIC "-//W3C//DTD MathML 2.0//EN" "http://www.w3.org/Math/DTD/mathml2/mathml2.dtd">
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Basic//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-basic.dtd">
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1 Tiny//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11-tiny.dtd">
- namespace demo
- template index(value)
- doctype
{namespace demo}
{template index(value)}
{doctype}
{/template}
- namespace demo
- template index(value)
- doctype xml
{namespace demo}
{template index(value)}
{doctype xml}
{/template}
Директива вставляет в шаблон код декларации HTML/XML атрибута по заданным параметрам.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Отсутствует | Строковая, текстовая | Поддерживается |
Директива attr обычно используется для задания атрибутов вместе с директивой tag. Общая форма директивы следующая:
attr название атрибута = значение атрибута
Например:
- attr foo = bar
{attr foo = bar}
Обратите внимание, что крайние пробелы у символа =
важны, иначе он трактуется как простой текст. Директива может использоваться только внутри шаблонов или внешних блоков.
Если необходимо задать несколько атрибутов, то нужно использовать специальный разделитель |
, например:
- attr foo = bar | baz = bla
{attr foo = bar | baz = bla}
Обратите внимание, что крайние пробелы у символа |
важны, иначе он трактуется как простой текст.
- attr foo = bar|baz=bla
{attr foo = bar|baz=bla}
Если нужно задать атрибут с пустым значением, то достаточно просто ничего не писать после знака присвоения, например:
- attr alt =
{attr alt =}
Отрендерится как:
alt=""
Для задания «инлайновых» HTML атрибутов, например, <input disabled>
нужно просто опустить знак присвоения.
- attr disabled
{attr disabled}
data-
атрибутовДля декларации data-
атрибутов поддерживается короткий синтаксис:
- attr -title = bla | -desc-field = bar
{attr -title = bla | -desc-field = bar}
Однако можно писать и полную форму:
- attr data-title = bla
{attr data-title = bla}
В Snakeskin есть универсальный синтаксис для создания групп атрибутов с автоматическим добавлением указанного префикса, общая форма следующая:
attr опциональный префикс(( название атрибута = значение атрибута ))
Например:
- attr ng-(( repeat = el in data | bind = bla ))
{attr ng-(( repeat = el in data | bind = bla ))}
Отрендерится как:
ng-repeat="el in data" ng-bind="bla"
Обратите внимание, что крайние пробелы у символов ((
и ))
важны, иначе они трактуется как простой текст. Также следует отметить, что при комбинировании групп атрибутов с другими группами не нужно ставить специальный
разделитель, например:
- attr ng-(( repeat = foo of bla )) (( baz = bar )) hello = world | foo = bar
{attr ng-(( repeat = foo of bla )) (( baz = bar )) hello = world | foo = bar}
Для передачи значений Snakeskin внутрь директивы используется стандартный механизм интерполяции, например:
- var name = 'foo'
- attr ${name} = ${1 + 2}
{var name = 'foo' /}
{attr ${name} = ${1 + 2}}
Допускается смешивать интерполяцию с обычной декларацией:
- var name = 'foo'
- attr ${name}-bar = ${1 + 2} hello
{var name = 'foo' /}
{attr ${name}-bar = ${1 + 2} hello}
Snakeskin позволяет используя механизм интерполяции задать атрибуты с помощью объекта, где ключом является название атрибута или группы.
- var attrs = {foo: 'bar', 'ng-': {repeat: 'el in data'}}
- attr ${attrs}
{var attrs = {foo: 'bar', 'ng-': {repeat: 'el in data'}} /}
{attr ${attrs}}
Чтобы сделать атрибут «инлайновым» нужно использовать специальную константу TRUE:
- var attrs = {disabled: TRUE}
- attr ${attrs}
{var attrs = {disabled: TRUE} /}
{attr ${attrs}}
Отрендерится как:
disabled
А чтобы исключить, то нужно использовать константу FALSE
:
- var attrs = {disabled: FALSE}
- attr ${attrs}
{var attrs = {disabled: FALSE} /}
{attr ${attrs}}
Значение ключа автоматически переводится из camelCase в dash-style, например:
- attr ${{fooBarBla: 'baz'}}
{attr ${{fooBarBla: 'baz'}}}
Отрендерится как:
foo-bar-bla="baz"
Для экранирования спецсимволов директивы используется символ \
, например:
- attr foo = bar \= bla
{attr foo = bar \= bla}
Директива вставляет в шаблон код декларации HTML/XML тега по заданным параметрам.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | < |
Блочная, текстовая | Поддерживается |
Директива tag является универсальным инструментом для генерации XML подобных структур. Общая форма директивы следующая:
tag название директивы
Например:
- tag span
< span
{tag span}{/tag}
{< span}{/}
При использовании tag в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{tag input type = text}{/}
/// Короткая форма закрытия
{tag input type = text /}
Директива может использоваться только внутри шаблонов или внешних блоков.
Для удобного задания классов и ИД-а в tag используется синтаксис селекторов CSS, например:
< span#baz.foo.bar
/// Если не указать имя создаваемого тега,
/// то будет использоваться div
< .bla
{< span#baz.foo.bar}{/}
/// Если не указать имя создаваемого тега,
/// то будет использоваться div
{< .bla}{/}
Директива tag поддерживает задание атрибутов с помощью attr, например:
< input value = foo | disabled
{< input value = foo | disabled /}
Отрендерится как:
<input value="foo" disabled>
В Snakeskin существует специальный механизм получения значения родительского класса в дочернем теге, который называется «липкая ссылка». Принцип работы следующий: если при декларации тега задать имя класса, которое начинается с символа
&
, то он будет заменён на ближайший родительский класс, который декларировался без этого символа, например:
< .foo
< .&__bar
< .&__bla
{< .foo}
{< .&__bar}{/}
{< .&__bla}{/}
{/}
Отрендерится как:
<div class="foo">
<div class="foo__bar"></div>
<div class="foo__bla"></div>
</div>
Альтернативным способом получения липкой ссылки является вызов внутренней переменной шаблона $class
, например:
< .foo value = ${$class}
{< .foo value = ${$class}}{/}
Отрендерится как:
<div class="foo" value="foo"></div>
Если поместить декларацию класса в специальную конструкцию [...]
, то классы заданные внутри такого блока не будут запоминаться как липкая ссылка, а также плейсхолдер &
будет ссылаться на ближайший по иерархии
вложенности класс слева.
< .b-button[.g-helper]
< button.&__elem[.&_focused_true]
{< .b-button[.g-helper]}
{< button.&__elem[.&_focused_true]}{/}
{/}
Отрендерится как:
<div class="b-button g-helper">
<button class="b-button__elem b-button__elem_focused_true"></button>
</div>
Специальный тег ?
существует только на этапе трансляции и не включается в конечный код, например:
< ?.b-button
< button.&__elem
{< ?.b-button}
{< button.&__elem}{/}
{/}
Отрендерится как:
<button class="b-button__elem"></button>
Для передачи значений Snakeskin внутрь директивы используется стандартный механизм интерполяции, например:
- var name = 'span'
< ${name}
{var name = 'foo' /}
{< ${name}}{/}
Допускается смешивать интерполяцию с обычной декларацией:
- var name = 'foo'
< .${name}-bla.bar
{var name = 'foo' /}
{< .${name}-bla.bar}{/}
Для интерполяции в атрибутах используется механизмы attr.
< ${'?'}.b-button
< button.&__elem
{< ${'?'}.b-button}
{< button.&__elem}{/}
{/}
Отрендерится как:
<button class="b-button__elem"></button>
В HTML ряд тегов не требуют закрывающей части (</tag>
), например, input или meta, причём если в XHTML такие теги закрываются
явно, например:
<input type="text" />
То в HTML это можно опустить:
<input type="text">
Snakeskin знает про такие теги, а способ их закрытия зависит от выбранного doctype. Правила декларации заданы в объекте Snakeskin.inlineTags, структура следующая:
Snakeskin.inlineTags = {
// Название используемого doctype
'html': {
// Тег br ставится инлайновым
'br': true,
// Тег input ставится инлайновым,
// причём если вставить содержимое в такой тег, например,
//
// < input
// Hello world!
//
// то оно поставится как значение атрибута value
'input': 'value'
}
}
Если для заданного doctype нет своей схемы тегов, то используется html
.
С помощью модификатора !inline
любой тег можно сделать принудительно инлайновым, например:
< textarea!inline
{< textarea!inline /}
Отрендерится как:
<textarea>
Также можно задать локальную схему тегов, которая будет распространяться на все вложенные теги:
- var val = {textarea: true}
< div!inline=val
< textarea
{var val = {textarea: true} /}
{< div!inline=val}
{< textarea /}
{/}
Отрендерится как:
<div><textarea></div>
При разработке шаблонов часто бывает такая ситуация, когда имя создаваемого тега зависит от различных параметров, и для решения такой задачи удобно использовать интерполяцию, например:
- namespace demo
- template index(value, area)
< ${area ? 'textarea' : 'input'}.input
{value}
{namespace demo}
{template index(value, area)}
{< ${area ? 'textarea' : 'input'}.input}
{value}
{/}
{/template}
Snakeskin поймёт такую конструкцию и в случае textarea создаст код вида:
<textarea class="input">значение</textarea>
А в случае input:
<input class="input" value="значение">
Для экранирования спецсимволов директивы используется символ \
, например:
< .bla foo = bar \= bla
{< .bla foo = bar \= bla}{/}
Директива вставляет в шаблон код декларации тега <script>
с заданными параметрами.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Отсутствует | Блочная, текстовая | Поддерживается |
Директива предназначена для более удобного задания тегов <script>
и может использоваться только внутри шаблонов или внешних блоков.
При использовании script в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{script js src = foo.js}{/}
/// Короткая форма закрытия
{script js src = foo.js /}
text/javascript
application/dart
application/coffeescript
application/typescript
application/clojurescript
application/livescript
application/json
text/html
text/x-snakeskin-template
- namespace demo
- template index()
# script
var a = {};
{namespace demo}
{template index()}
#{script}
var a = {};
#{/}
{/template}
- namespace demo
- template index()
# script ts
var a = {};
{namespace demo}
{template index()}
#{script ts}
var a = {};
#{/}
{/template}
- namespace demo
- template index()
# script application/myscript
var a = {};
{namespace demo}
{template index()}
#{script application/myscript}
var a = {};
#{/}
{/template}
(используется синтаксис attr)
- namespace demo
- template index()
# script js class = foo
var a = {};
{namespace demo}
{template index()}
#{script js class = foo}
var a = {};
#{/}
{/template}
Директива вставляет в шаблон код декларации тега <style>
с заданными параметрами.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Отсутствует | Блочная, текстовая | Поддерживается |
Директива предназначена для более удобного задания тегов <style>
и может использоваться только внутри шаблонов или внешних блоков.
text/css
- namespace demo
- template index()
# style
.foo {
color: red;
}
{namespace demo}
{template index()}
#{style}
.foo {
color: red;
}
#{/}
{/template}
- namespace demo
- template index()
# style css
.foo {
color: red;
}
{namespace demo}
{template index()}
#{style css}
.foo {
color: red;
}
#{/}
{/template}
- namespace demo
- template index()
# style text/stylus
.foo
color red
{namespace demo}
{template index()}
#{style text/stylus}
.foo
color red
#{/}
{/template}
(используется синтаксис attr)
- namespace demo
- template index()
# style css class = foo
.foo {
color: red;
}
{namespace demo}
{template index()}
#{style css class = foo}
.foo {
color: red;
}
#{/}
{/template}
Директива вставляет в шаблон код декларации тега <link>
с заданными параметрами.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Отсутствует | Блочная, текстовая | Поддерживается |
Директива предназначена для более удобного задания тегов <link>
и может использоваться только внутри шаблонов или внешних блоков.
При использовании link в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{link css href = foo.css}{/}
/// Короткая форма закрытия
{link css href = foo.css /}
type="text/css" rel="stylesheet"
type="text/css" rel="alternate stylesheet"
type="image/x-icon" rel="icon"
- namespace demo
- template index()
- link
http://bar.com/foo.css
{namespace demo}
{template index()}
{link}http://bar.com/foo.css{/}
{/template}
- namespace demo
- template index()
- link acss
http://bar.com/foo.css
{namespace demo}
{template index()}
{link acss}http://bar.com/foo.css{/}
{/template}
- namespace demo
- template index()
- link (( type = text/stylus | rel = stylesheet ))
http://bar.com/foo.styl
{namespace demo}
{template index()}
{link (( type = text/stylus | rel = stylesheet ))}http://bar.com/foo.styl{/}
{/template}
(используется синтаксис attr)
- namespace demo
- template index()
- link css rel = alternate stylesheet
http://bar.com/foo.css
{namespace demo}
{template index()}
{link css rel = alternate stylesheet}http://bar.com/foo.css{/}
{/template}
Директива вставляет в шаблон код декларации XML комментария с заданными параметрами.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | <! |
Блочная, текстовая | Поддерживается |
Директива предназначена для более удобного задания тегов XML комментариев и может использоваться только внутри шаблонов или внешних блоков.
- namespace demo
- template index()
<!
Hello world!
{namespace demo}
{template index()}
{<!}Hello world!{/}
{/template}
- namespace demo
- template index()
<! IE 7
Hello world!
{namespace demo}
{template index()}
{<! IE 7}Hello world!{/}
{/template}
Отрендерится как:
<!--[if IE 7]>Hello world!<![endif]-->
- namespace demo
- template index()
- var ie = 7
<! IE ${ie}
Hello world!
{namespace demo}
{template index()}
{var ie = 7 /}
{<! IE ${ie}}Hello world!{/}
{/template}
Директива задаёт блок текста, который вырезается до трансляции, а затем вставляется без изменений в результирующую функцию (пробельные символы также остаются неизменны).
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Отсутствует | Блочная, текстовая | Не поддерживается |
Директива используется для экранирования больших фрагментов текста, которые должны вставляться «как есть». Декларация директивы возможно только с помощью расширенного синтаксиса.
Закрывающий end может быть либо #{end cdata}
, либо #{/cdata}
. Директива может использоваться только внутри шаблонов или внешних блоков.
- namespace demo
- template index()
#{cdata}
- if true
Hello world!
#{/cdata}
{namespace demo}
{template index()}
#{cdata}
{if true}
Hello world!
{/}
#{/cdata}
{/template}
Директива задаёт блок текста, который вставляется без изменений в результирующую функцию, а также будет врапиться специальными текстовыми символами согласно параметру literalBounds.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Не требуется | Строковая, текстовая | Поддерживается |
Директива используется для интеграции шаблонов Snakeskin с другими шаблонами. Директива может использоваться только внутри шаблонов или внешних блоков.
- namespace demo
- template index()
{{ Hello }}
{namespace demo}
{template index()
{{ Hello }}
{/template}
Отрендерится как:
{{ Hello }}
Для передачи значений Snakeskin внутрь директивы используется стандартный механизм интерполяции.
- namespace demo
- template index()
{{ Hello${1 + 2} }}
{namespace demo}
{template index()
{{ Hello${1 + 2} }}
{/template}
Отрендерится как:
{{ Hello3 }}
- namespace demo
- template index() @= literalBounds ['<?php', '?>']
{{ Hello }}
{namespace demo}
{template index() @= literalBounds ['<?php', '?>']}
{{ Hello }}
{/template}
Отрендерится как:
<?php Hello ?>
Директива включает содержимое заданного файла-шаблона в текущий.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Вне шаблонов или внешних блоков | Отсутствует | Строковая, логическая | Не требуется |
Любой Snakeskin файл может включать в себя другие SS файлы, т. е. Snakeskin позволяет разбить код на логические части и создавать подключаемые библиотеки (подобно std.ss) и т. д. Чтобы подключить другой файл используется специальная директива include, которая начинается с одноименного ключевого слова и должна сопровождаться выражением, где задаётся путь к подключаемому файлу, например:
math.ss
- namespace math
- template calc(a, b)
{a + b}
{namespace math}
{template calc(a, b)}
{a + b}
{/template}
app.ss
- namespace app
- include './math'
- template index()
/// При вызове шаблона из другого файла
/// нужно обязательно указывать пространство имён
+= math.calc(1, 2)
{namespace app}
{include './math'}
{template index()}
/// При вызове шаблона из другого файла
/// нужно обязательно указывать пространство имён
{+= math.calc(1, 2) /}
{/template}
Snakeskin контролирует чтобы каждый подключаемый файл включался только один раз, т. е. гарантируется отсутствие дубликатов в конечном коде.
- namespace app
- include './math'
/// Этот include игнорируется
- include './math'
- template index()
+= math.calc(1, 2)
{namespace app}
{include './math'}
/// Этот include игнорируется
{include './math'}
{template index()}
{+= math.calc(1, 2) /}
{/template}
В любом Snakeskin файле каждый объявленный шаблон является публичным (экспортируемым), а все глобальные переменные будут инкапсулированы в рамках своего файла, т. е. нет явного способа получить значение такой переменной из другого файла, однако такая возможность есть при наследовании шаблонов.
base.ss
- namespace base
- var foo = 'bar'
{namespace math}
{var foo = 'bar' /}
app.ss
- namespace app
- include './base'
- template index()
? console.log(foo) /// Error: foo is not defined
{namespace app}
{include './base'}
{template index()}
{? console.log(foo)} /// Error: foo is not defined
{/template}
При указании пути можно использовать сложные выражения: вызовы функций, тернарные операторы и т. д.
- namespace app
- include './' + (@@base ? 'base' : 'default')
- template index()
...
{namespace app}
{include './' + (@@base ? 'base' : 'default')}
{template index()}
...
{/template}
Обратите внимание, что при подключении файла нужно обязательно указывать символы ./
или ../
для конкретизации поиска, т. к. если этого не сделать, то файл будет искаться в папке node_modules (как
это делает require
в node.js), а вот расширение файла можно не указывать — по умолчанию используется .ss
. Директива может использоваться только вне шаблонов или внешних блоков.
При указании пути к файлу можно использовать glob-шаблоны, например, чтобы подключить сразу множество файлов.
- namespace app
- include './modules/**/*'
- template index()
...
{namespace app}
{include './modules/**/*'}
{template index()}
...
{/template}
Директиву include можно вызывать динамически, т. е. оборачивать её директивами типа if, forEach и т. д.
- namespace app
- eval
- var fs = require('fs')
- var path = require('path')
/// В момент трансляции каждый файл имеет свои переменные
/// __dirname и __filename
- var url = path.join(__dirname, 'test')
- forEach fs.readdirSync(url) => file
- if path.extname(file) === '.ss'
- include path.join(url, file)
- template index()
...
{namespace app}
{eval}
{var fs = require('fs') /}
{var path = require('path') /}
/// В момент трансляции каждый файл имеет свои переменные
/// __dirname и __filename
{var url = path.join(__dirname, 'test') /}
{forEach fs.readdirSync(url) => file}
{if path.extname(file) === '.ss'}
{include path.join(url, file)}
{/}
{/}
{/eval}
{template index()}
...
{/template}
Если в пути к подключаемому файлу явно указать, что это папка (нужно добавить символ /
в конце пути), то подключаться файл будет по правилу: (название папки|main|index).ss
, например:
- namespace app
/// './base/base.ss' ИЛИ
/// './base/main.ss' ИЛИ
/// './base/index.ss'
- include './base/'
- template index()
...
{namespace app}
/// './base/base.ss' ИЛИ
/// './base/main.ss' ИЛИ
/// './base/index.ss'
{include './base/'}
{template index()}
...
{/template}
Если файл Snakeskin определяет параметры трансляции на глобальном уровне, то они также рекурсивно накладываются на все подключаемые файлы (если они не переопределяются явно в подключаемых файлах), например:
base.ss
- namespace base
@= tolerateWhitespaces true
- template index()
...
{namespace math}
{@= tolerateWhitespaces true}
{template index()}
...
{/template}
app.ss
- namespace app
@= tolerateWhitespaces false
@= renderMode 'dom'
- include './base'
- template index()
...
{namespace app}
{@= tolerateWhitespaces false}
{@= renderMode 'dom'}
{include './base'}
{template index()}
...
{/template}
Здесь файл base.ss наследует параметр renderMode = 'dom'
, но tolerateWhitespaces
он переопределяет явно.
Snakeskin позволяет явно задать параметр renderAs при подключении файла с помощью ключевого слова as
, например:
- namespace app
- include './base' as placeholder
- template index()
...
{namespace app}
{include './base' as placeholder}
{template index()}
...
{/template}
Таким образом мы исключили подключаемые шаблоны из финального файла JS.
При наследовании дочерний шаблон автоматически получает доступ к замыканию родительского шаблона, например:
base.ss
- namespace base
- var hello = 'world'
- template index()
Hello {hello}!
{namespace base}
{var hello = 'world' /}
{template index()}
Hello {hello}!
{/template}
app.ss
- namespace app
- include './base'
- template index() extends base.index
- block info
hello = '{hello}'
{namespace app}
{include './base'}
{template index() extends base.index}
{block info}
hello = '{hello}'
{/}
{/template}
Шаблон app.index
отрендерится как:
Hello world!
hello = 'world'
Если в файле дочернего шаблона существует одноимённая глобальная переменная, то она будет переопределять родительскую:
app.ss
- namespace app
- include './base'
/// var может быть до include - это никак не влияет
- var hello = 'people'
- template index() extends base.index
- block info
hello = '{hello}'
{namespace app}
{include './base'}
/// var может быть до include - это никак не влияет
{var hello = 'people' /}
{template index() extends base.index}
{block info}
hello = '{hello}'
{/}
{/template}
Шаблон app.index
отрендерится как:
Hello people!
hello = 'people'
Директива импортирует в заданный файл ссылки из указанного JavaScript модуля и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только в глобальной области или на глобальном уровне head | Отсутствует | Строковая, логическая | Не требуется |
Директива используется для импортирования JavaScript модулей в шаблон Snakeskin, а тип используемого импортирования зависит от параметра трансляции module (по умолчанию используется UMD). Синтаксис директивы идентичен аналогичной конструкции в JS ES2015. Директива может использоваться только в глобальной области или на глобальном уровне директивы head.
- namespace demo
- import path from 'path'
- import * as os from 'os'
- import { readdirSync } from 'fs'
- template index()
...
{namespace demo}
{import path from 'path'}
{import * as os from 'os'}
{import { readdirSync } from 'fs'}
{template index()}
...
{/template}
Директива декларирует анонимную функцию.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | () или () => |
Блочная, логическая, функциональная | Не требуется |
Директива func декларирует анонимную функцию-литерал и обычно используется в связи с другими директивами, которые требуют аргумент-функцию, например, series или parallel.
Директива начинается с ключевого слова func
(или символов ()
или () =>
), которое может сопровождаться списком аргументов функции через запятую, например:
- namespace demo
- template index()
() => db
? db.ping()
{namespace demo}
{template index()}
{() => db}
{? db.ping()}
{/}
{/template}
Параметров у такой функции может быть неограниченное количество, а т. к. директива func является функциональной, то она реализует стандартный механизм декларации параметров. По умолчанию такие функции возвращают строки, однако это поведение можно поменять задав специальный renderMode или явно вернув значение через директиву return. Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
Каждая директива func (за исключением тех, что используется совместно с асинхронными директивами) определяет ряд функций, которые можно использовать в ней:
getTplResult
— функция, которая возвращает результат работы директивы, также может принимать один логический входной параметр, при задании которого после вызова функции результат работы директивы будет обнуляться;
clearTplResult
— функция, которая обнуляет результат работы директивы.
Чтобы создать переменную с функциональным значением необходимо использовать конструкцию var putIn
:
- namespace demo
- template index()
/// Мы создали функцию,
/// а затем присвоили её переменной calc
- var putIn calc
() => a, b
- return a + b
{namespace demo}
{template index()}
/// Мы создали функцию,
/// а затем присвоили её переменной calc
{var putIn calc}
{() => a, b}
{return a + b /}
{/}
{/}
{/template}
Функцию можно передавать как аргумент при вызове другой функции с помощью директивы call:
- namespace demo
- template index()
+= [1, 2, 3].map()
() => el
el = {el}
{namespace demo}
{template index()}
{+= [1, 2, 3].map()}
{() => el}
el = {el}
{/}
{/}
{/template}
Также функцию можно ставить как свойство объекта или массива через target, например:
- namespace demo
- template index()
- target {} as map
* calc
() => a, b
- return a + b
{namespace demo}
{template index()}
{target {} as map}
{* calc}
{() => a, b}
{return a + b /}
{/}
{/}
{/}
{/template}
И можно установить/изменить значение свойства объекта или переменной на функцию с помощью putIn:
- namespace demo
- template index()
- target {} as map
- putIn map.calc
() => a, b
- return a + b
{namespace demo}
{template index()}
{target {} as map /}
{putIn map.calc}
{() => a, b}
{return a + b /}
{/}
{/}
{/template}
Директива возвращает ссылку на заданный объект и позволяет задавать ему свойства со значениями в виде подшаблонов Snakeskin.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива target несёт двойную функциональность: с одной стороны она возвращает ссылку на указанный объект, а с другой может задавать ему свойства-подшаблоны Snakeskin — т. е. представляет из себя литеральную форму для создания массивов и объектов со значениями в виде шаблонов, например:
- namespace demo
- template index(val)
- target {}
* prop1
< .hello
Hello world!
* prop 2
- if val > 1
Success!
{namespace demo}
{template index()}
{target {}}
{* prop1}
{< .hello}
Hello world!
{/}
{/}
{* prop 2}
{if val > 1}
Success!
{/}
{/}
{/}
{/template}
Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т. д. Свойства объекту ставятся с помощью директивы putIn. Чтобы получить
явную ссылку на созданный объект, то его нужно присвоить переменной: самый простой способ — это использовать оператор as
, например:
- namespace demo
- template index(val)
- target {} as myObj
* prop1
< .hello
Hello world!
* prop 2
- if val > 1
Success!
? console.log(myObj)
{namespace demo}
{template index()}
{target {} as myObj}
{* prop1}
{< .hello}
Hello world!
{/}
{/}
{* prop 2}
{if val > 1}
Success!
{/}
{/}
{/}
{? console.log(myObj)}
{/template}
А также можно использовать директиву var в режиме putIn
:
- namespace demo
- template index(val)
- var putIn myObj
- target {}
* prop1
< .hello
Hello world!
* prop 2
- if val > 1
Success!
? console.log(myObj)
{namespace demo}
{template index()}
{var putIn myObj}
{target {}}
{* prop1}
{< .hello}
Hello world!
{/}
{/}
{* prop 2}
{if val > 1}
Success!
{/}
{/}
{/}
{/}
{? console.log(myObj)}
{/template}
Общая форма директивы следующая:
target ссылка на объект или сам объект [as опциональный идентификатор]
[* опциональные свойства]
При использовании target в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{target {a: 1, b: 2}}{/}
/// Короткая форма закрытия
{target {a: 1, b: 2} /}
Можно использовать директиву для уже созданных объектов, например:
- namespace demo
- template index(val)
- var myObj = {}
- target myObj
* prop1
< .hello
Hello world!
* prop 2
- if val > 1
Success!
? console.log(myObj)
{namespace demo}
{template index()}
{var myObj = {} /}
{target myObj}
{* prop1}
{< .hello}
Hello world!
{/}
{/}
{* prop 2}
{if val > 1}
Success!
{/}
{/}
{/}
{? console.log(myObj)}
{/template}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
Значение переданное в директиву putIn при задании свойства объекта трактуется как простая строка, а для прокидывания значений Snakeskin внутрь директивы используется стандартный механизм интерполяции, например:
- namespace demo
- template index(val)
- target {} as myObj
* some prop name ${1 + 2}
< .hello
Hello world!
? console.log(myObj['some prop name 3'])
{namespace demo}
{template index()}
{target {} as myObj}
{* some prop name ${1 + 2}}
{< .hello}
Hello world!
{/}
{/}
{/}
{? console.log(myObj['some prop name 3'])}
{/template}
Создание и редактирование массивов через target почти не отличается от объектов — просто не нужно указывать название ключа и первый вызов putIn можно опустить, например:
- namespace demo
- template index(val)
- target [] as myArray
< .hello
Hello world!
*
< .hello
Hello people!
? console.log(myArray)
{namespace demo}
{template index()}
{target [] as myArray}
{*}
{< .hello}
Hello world!
{/}
{/}
{*}
{< .hello}
Hello people!
{/}
{/}
{/}
{? console.log(myArray)}
{/template}
Директива может ставить как свойство объекта другой target, который может устанавливать любое значение.
- namespace demo
- template index(val)
- target [] as myArray
- target {a: 1, b: 2}
*
- target 1 + 2
? console.log(myArray)
{namespace demo}
{template index()}
{target [] as myArray}
{*}
{target {a: 1, b: 2} /}
{/}
{*}
{target 1 + 2 /}
{/}
{/}
{? console.log(myArray)}
{/template}
Директиву можно передавать как аргумент при вызове функции с помощью директивы call:
- namespace demo
- template index()
+= someFunction()
- target []
Hello world!
{namespace demo}
{template index()}
{+= someFunction()}
{target []}
Hello world!
{/}
{/}
{/template}
Также target можно ставить как свойство объекта или массива через putIn, например:
- namespace demo
- template index()
- var myObj = {}
- putIn myObj.foo
- target []
Hello world!
{namespace demo}
{template index()}
{var myObj = {} /}
{putIn myObj.foo}
{target []}
Hello world!
{/}
{/}
{/template}
И можно установить функцию как значение свойства объекта или элемент массива:
- namespace demo
- template index()
- target []
() => a, b
- return a + b
{namespace demo}
{template index()}
{target []}
{() => a, b}
{return a + b /}
{/}
{/}
{/template}
Директива задает значение переменной или свойству объекта в виде подшаблона Snakeskin.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | * |
Блочная, логическая | Не требуется |
Директива putIn несёт двойную функциональность: с одной стороны она позволяет присвоить подшаблон Snakeskin переменной или свойству объекта, а с другой — является частью директивы call и target. Совместное использование putIn подробно рассмотрено в других главах, поэтому здесь описываться не будет.
Для изменения переменной или свойства объекта через putIn используется общая форма:
putIn ссылка
Шаблон
Например:
- namespace demo
- template index(val)
- var myObj = {}
- putIn myObj.foo
< .hello
Hello world!
- putIn myObj.calc
() => a, b
- return a + b
- putIn myObj.arr
- target []
Hello people!
? console.log(myObj)
{namespace demo}
{template index()}
{var myObj = {} /}
{putIn myObj.foo}
{< .hello}
Hello world!
{/}
{/}
{putIn myObj.calc}
{() => a, b}
{return a + b}
{/}
{/}
{putIn myObj.arr}
{target []}
Hello people!
{/}
{/}
{? console.log(myObj)}
{/template}
Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т. д. Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
Директива является фасадом для Async.series.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива является обёрткой над функцией series библиотеки Async и позволяет создавать удобные цепочки асинхронных вызовов. Вместе с директивой series должна использоваться директива func. Перед использованием директивы необходимо подключить через import саму библиотеку Async, например:
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index()
- series
() => cb
fs.readFile('foo.txt', cb)
() => cb
fs.readFile('bar.txt', cb)
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index()}
{series}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{() => cb}
fs.readFile('bar.txt', cb)
{/}
{/}
{/template}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Вместе с основной директивой можно использовать дополнительные:
final
— второй параметр Async.series (функциональная директива).Для управления переходами внутри блока можно использовать директивы:
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index()
- series
() => cb
fs.readFile('foo.txt', cb)
() => cb
fs.readFile('bar.txt', cb)
- final err, files
? console.log(err, files)
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index()}
{series}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{() => cb}
fs.readFile('bar.txt', cb)
{/}
{final err, res}
{? console.log(err, files)}
{/}
{/template}
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index(brk)
- series
() => cb
- if brk
- break new Error('Skipped')
? cb()
() => cb
fs.readFile('foo.txt', cb)
- final err, res
...
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index(brk)}
{series}
{() => cb}
{if brk}
{break new Error('Skipped')}
{/}
{? cb()}
{/}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{final err, res}
...
{/}
{/template}
Директива является фасадом для Async.parallel.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива является обёрткой над функцией parallel библиотеки Async и позволяет создавать удобные цепочки асинхронных вызовов. Вместе с директивой parallel должна использоваться директива func. Перед использованием директивы необходимо подключить через import саму библиотеку Async, например:
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index()
- parallel
() => cb
fs.readFile('foo.txt', cb)
() => cb
fs.readFile('bar.txt', cb)
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index()}
{parallel}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{() => cb}
fs.readFile('bar.txt', cb)
{/}
{/}
{/template}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Вместе с основной директивой можно использовать дополнительные:
final
— второй параметр Async.parallel (функциональная директива).Для управления переходами внутри блока можно использовать директивы:
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index()
- parallel
() => cb
fs.readFile('foo.txt', cb)
() => cb
fs.readFile('bar.txt', cb)
- final err, files
? console.log(err, files)
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index()}
{parallel}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{() => cb}
fs.readFile('bar.txt', cb)
{/}
{final err, res}
{? console.log(err, files)}
{/}
{/template}
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index(brk)
- parallel
() => cb
- if brk
- break new Error('Skipped')
? cb()
() => cb
fs.readFile('foo.txt', cb)
- final err, res
...
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index(brk)}
{parallel}
{() => cb}
{if brk}
{break new Error('Skipped')}
{/}
{? cb()}
{/}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{final err, res}
...
{/}
{/template}
Директива является фасадом для Async.waterfall.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива является обёрткой над функцией waterfall библиотеки Async и позволяет создавать удобные цепочки асинхронных вызовов. Вместе с директивой waterfall должна использоваться директива func. Перед использованием директивы необходимо подключить через import саму библиотеку Async, например:
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index()
- waterfall
() => cb
fs.readFile('foo.txt', cb)
() => file1, cb
fs.readFile('bar.txt', cb)
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index()}
{waterfall}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{() => file1, cb}
fs.readFile('bar.txt', cb)
{/}
{/}
{/template}
Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области. Вместе с основной директивой можно использовать дополнительные:
final
— второй параметр Async.waterfall (функциональная директива).Для управления переходами внутри блока можно использовать директивы:
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index()
- waterfall
() => cb
fs.readFile('foo.txt', cb)
- final err, files
? console.log(err, files)
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index()}
{waterfall}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{final err, res}
{? console.log(err, files)}
{/}
{/template}
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index(brk)
- waterfall
() => cb
- if brk
- break new Error('Skipped')
? cb()
() => cb
fs.readFile('foo.txt', cb)
- final err, res
...
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index(brk)}
{waterfall}
{() => cb}
{if brk}
{break new Error('Skipped')}
{/}
{? cb()}
{/}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{final err, res}
...
{/}
{/template}
Директива yield является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблона-генератора | Отсутствует | Блочная, логическая | Не требуется |
Директива используется вместе с шаблонами-генераторами для организации «прерывания», однако, Snakeskin не создаёт полифил, а генерирует «чистый» JavaScript код, поэтому для поддержки старых браузеров используйте Regenerator или Babel.
Директива начинается с ключевого слова yield
, которое может сопровождаться ссылкой на возвращаемое значение или выражение, например:
- namespace demo
- template *index()
- yield 1 + 2
{namespace demo}
{template index()}
{yield *1 + 2 /}
{/template}
Для удобства использования yield в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{yield 1 + 2}{/}
/// Короткая форма закрытия
{yield 1 + 2 /}
Директива может использоваться только внутри шаблона-генератора.
Директива может включать возвращаемое значение в своё тело — это удобно, когда возвращаемое значение является подшаблоном, например:
- namespace demo
- template *index()
/// Шаблон вернёт ссылку на функцию,
/// которая складывает два числа
- yield
() => a, b
- return a + b
{namespace demo}
{template *index()}
/// Шаблон вернёт ссылку на функцию,
/// которая складывает два числа
{yield}
{() => a, b}
{return a + b /}
{/}
{/}
{/template}
Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т. д.
Директива await является эквивалентом одноименного оператора в различных языках программирования и по своей семантике близка к реализации в JavaScript.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблона-генератора | Отсутствует | Блочная, логическая | Не требуется |
Директива используется вместе с async-шаблонами для организации «прерывания», однако, Snakeskin не создаёт полифил, а генерирует «чистый» JavaScript код, поэтому для поддержки старых браузеров используйте Babel.
Директива начинается с ключевого слова await
, которое может сопровождаться ссылкой на ожидаемое значение или выражение, например:
- namespace demo
- async template index(db)
- await db.getData()
{namespace demo}
{async template index(db)}
{await db.getData() /}
{/template}
Для удобства использования await в классическом синтаксисе существует короткая форма закрытия директивы, например:
/// Обычное закрытие
{await db.getData()}{/}
/// Короткая форма закрытия
{await db.getData() /}
Директива может использоваться только внутри async-шаблона.
Директива может включать выражение в своё тело — это удобно, когда ожидаемое значение является подшаблоном, например:
- namespace demo
- async template index(db)
- await
- block getData() =>
- return db.getData()
{namespace demo}
{async template index()}
{await}
{block getData() =>}
{return db.getData() /}
{/}
{/}
{/template}
Внутри такой декларации можно использовать любые допустимые директивы, например, if, forEach и т. д.
Директива вставляет в шаблон тело родительского блока.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри шаблонов или внешних блоков | Отсутствует | Строковая, логическая | Не требуется |
Директива работает по схеме: всплывает по дереву шаблона до тех пор, пока не найдётся блок, который имеет родителя, и вставляет родительское тело в указанное место, а если такого родителя нет, то просто ничего не делает. Директива может использоваться только внутри шаблонов или внешних блоков.
- namespace demo
- template base()
- block base
Какой хороший день!
- template child() extends @base
- block base
- super
Трудиться мне не лень!
{namespace demo}
{template base()}
{block base}
Какой хороший день!
{/}
{/template}
{template child() extends @base}
{block base}
{super}
Трудиться мне не лень!
{/}
{/template}
Директива создаёт логический блок Snakeskin без «побочного эффекта».
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Без ограничений | Отсутствует | Блочная, логическая | Не требуется |
Директива используется для перехода в расширенный синтаксис без «побочных эффектов» других директив, т. е. сама директива ничего не делает. Директива может использоваться как внутри шаблонов или других директив, так и в глобальной области.
- namespace demo
- template index()
# op
{name: 'world'}
{namespace demo}
{template index()}
#{op}
{name: 'world'}
#{/}
{/template}
Директивы прерывает выполнение другой директивы, с которой она находится в связи.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри специальных директив | Отсутствует | Строковая, логическая | Не требуется |
Поведение директивы break зависит от контекста, например, если использовать её внутри циклов или итераторов, то она будет немедленно прерывать итерации, а если использовать совместно с асинхронными директивами, то break будет осуществлять немедленный переход к результирующей функции.
Директива может использоваться только внутри директив:
- namespace demo
- template index()
- var obj = {a: 1, b: 2}
- for var key in obj
{key}
- break
{namespace demo}
{template index()}
{var obj = {a: 1, b: 2} /}
{for var key in obj}
{key}
{break}
{/}
{/template}
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index(brk)
- series
() => cb
- if brk
/// Управление перейдёт в final c ошибкой
- break new Error('Skipped')
? cb()
() => cb
fs.readFile('foo.txt', cb)
- final err, res
...
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index(brk)}
{series}
{() => cb}
{if brk}
/// Управление перейдёт в final c ошибкой
{break new Error('Skipped')}
{/}
{? cb()}
{/}
{() => cb}
fs.readFile('foo.txt', cb)
{/}
{final err, res}
...
{/}
{/template}
Директивы пропускает такт выполнения другой директивы, с которой она находится в связи.
Декларация | Короткий синтаксис | Тип директивы | Интерполяция |
---|---|---|---|
Только внутри специальных директив | Отсутствует | Строковая, логическая | Не требуется |
Поведение директивы continue зависит от контекста, например, если использовать её внутри циклов или итераторов, то она будет немедленно прерывать текущую итерацию и переходить к следующей, а если использовать совместно с асинхронными директивами, то continue будет осуществлять немедленный переход к следующей функции в цепи.
Директива может использоваться только внутри директив:
- namespace demo
- template index()
- var obj = {a: 1, b: 2}
- for var key in obj
- if !obj.hasOwnProperty(key)
- continue
{key}
{namespace demo}
{template index()}
{var obj = {a: 1, b: 2} /}
{for var key in obj}
{if !obj.hasOwnProperty(key)}
{continue}
{/}
{key}
{/}
{/template}
- namespace demo
- import async from 'async'
- import fs from 'fs'
- template index(brk)
- waterfall
() => cb
- if brk
- continue 'foo.txt'
...
? cb('bar.txt')
() => path, cb
fs.readFile(path, cb)
- final err, res
...
{namespace demo}
{import async from 'async'}
{import fs from 'fs'}
{template index(brk)}
{waterfall}
{() => cb}
{if brk}
{continue 'foo.txt'}
{/}
...
{? cb()}
{/}
{() => path, cb}
fs.readFile(path, cb)
{/}
{final err, res}
...
{/}
{/template}
Метод компилирует заданный текст шаблона или содержимое DOM узла.
Snakeskin.compile(src, opt_params, opt_info) {
return string || false || null;
}
(!Element|string)
src
— ссылка на DOM узел, где декларированы шаблоны или исходный текст шаблонов;Object=
opt_params
— дополнительные параметры запуска;Object=
opt_info
— дополнительная информация для отладчика./**
* @type {?boolean=}
* @default true
*/
Если параметр равен false
, то наличие шаблона в кеше не будет проверятся, а сам шаблон не будет кешироваться.
/**
* @type {Object=}
*/
Параметр задаёт суперглобальные переменные Snakeskin.
Snakeskin.compile('<шаблон>', {
vars: {
foo: 'bar'
}
});
/**
* @type {Object=}
*/
Параметр задаёт объект для экспорта свойств при компиляции в стиле CommonJS.
- namespace demo
- template index()
Hello world!
{namespace demo}
{template index()
Hello world!
{/template}
var tpls = {};
Snakeskin.compile('<шаблон>', {
context: tpls
});
tpls.demo.foo() // Hello world
/**
* @type {Object=}
*/
Параметр задаёт объект настроек для Babel для обработки после основной трансляции.
/**
* @type {?function(!Error)=}
*/
Параметр задаёт функцию обратного вызова для обработки ошибок.
/**
* @type {?boolean=}
* @default false
*/
Если параметр равен true
, то в случае ошибки и отсутствия обработчика ошибок — будет возбуждено исключение.
По умолчанию просто выводится сообщение в stderr
и прерывается операция.
/**
* @type {Object=}
*/
Объект, который будет содержать в себе некоторую отладочную информацию.
var info = {};
Snakeskin.compile('<шаблон>', {debug: info});
info.code // Исходный текст полученного JS файла
/**
* @type {(?function(string, string): string)=}
*/
Функция для резолвинга путей в import: первым параметром принимает строку запроса, а вторым полный путь к файлу, в котором вызывается директива. Функция должна возвращать строку, которая будет новым путём к подключаемому файлу.
/**
* @type {?boolean=}
* @default false
*/
Если параметр равен true
, то модель импорта/экспорта модулей будет оптимизирована для использования вместе с WebPack.
/**
* @type {?string=}
* @default 'umd'
*/
Тип импорта/экспорта модулей, доступны варианты:
/**
* @type {?string=}
* @default 'tpls'
*/
ИД модуля для umd
/amd
декларации: первый параметр функции define.
/**
* @type {?string=}
*/
Название модуля для umd
/global
декларации: если задан, то в глобальном объекте (window
и т. д.) будет создано свойство с указанным именем, куда будут сохраняться полученные шаблоны, иначе, всё
будет сохранено напрямую в глобальный объект.
/**
* @type {?boolean=}
* @default true
*/
Если параметр равен false
, то шаблоны компилируются без 'use strict';
.
/**
* @type {?boolean=}
* @default false
*/
Если параметр равен true
, то полученный JS после трансляции будет отформатирован.
/**
* @type {Array<string>=}
* @default ['{{', '}}']
*/
Параметр задаёт «врапперы» для директивы literal, например:
- namespace demo
- template index() @= literalBounds ['<?php', '?>']
{{ Hello }}
{namespace demo}
{template index() @= literalBounds ['<?php', '?>']}
{{ Hello }}
{/template}
Отрендерится как:
<?php Hello ?>
/**
* @type {Array<string>=}
*/
Параметр задаёт «врапперы» для директивы literal при декларации значения атрибута, например:
- namespace demo
- template index() @= attrLiteralBounds ['{', '}']
< .foo title = {{ val }}
{namespace demo}
{template index() @= attrLiteralBounds ['{', '}']}
{< .foo title = {{ val }} /}
{/template}
Отрендерится как:
<div class="foo" title={ val }></div>
/**
* @type {?string=}
*/
Параметр задаёт название фильтра для обработки тега при создании через tag.
/**
* @type {?string=}
*/
Параметр задаёт название фильтра для обработки имени тега при создании через tag.
/**
* @type {?string=}
*/
Параметр задаёт название фильтра для обработки ключа атрибута тега при создании через tag.
/**
* @type {?string=}
*/
Параметр задаёт название фильтра для обработки значения атрибута тега при создании через tag.
/**
* @type {?string=}
*/
Параметр задаёт название фильтра для обработки липких ссылок.
/**
* @type {Object<Array<string>>=}
* @default {global: ['html', 'undef'], local: ['undef']}
*/
Объект фильтров по умолчанию для директивы output: фильтры бывают 2-х видов — глобальные (применяются ко всему полученному выражению, ключ global
) и локальные (применяются
к каждой части выражения по отдельности, ключ local
).
/**
* @type {?boolean=}
* @default true
*/
Если параметр равен false
, то строки локализации будут отключены, т. е. сохраняются «как есть».
/**
* @type {?string=}
* @default 'i18n'
*/
Название используемой глобальной функции локализации: данная функция будет оборачивать строки локализации.
- namespace demo
- template index()
`Hello world!`
{namespace demo}
{template index()}
`Hello world!`
{/template}
Строка `Hello world!`
скомпилируется как
i18n("hello world!")
/**
* @type {?string=}
*/
Передаваемые параметры для глобальной функции локализации в строковом виде, например, '{lang: "en"}, true'
.
/**
* @type {Object=}
*/
Если задан данный параметр, то строки локализации будут заменятся на этапе трансляции.
- namespace demo
- template index()
`Hello world!`
{namespace demo}
{template index()}
`Hello world!`
{/template}
Snakeskin.compile('<шаблон>', {
'Hello world!': 'Привет мир!'
});
/**
* @type {Object=}
*/
Если задан данный параметр, то найденные в шаблонах строки локализации будут добавляться в него в виде свойств.
- namespace demo
- template index()
`Hello world!`
{namespace demo}
{template index()}
`Hello world!`
{/template}
var words = {};
Snakeskin.compile('<шаблон>', {
words: words
});
// {'Hello world!': 'Hello world!'}
console.log(words);
/**
* @type {RegExp=}
*/
Параметр задаёт пробельные символы, которые будут игнорироваться в шаблонах.
/**
* @type {?boolean=}
* @default false
*/
Если параметр равен true
, то все пробельные символы в шаблоне обрабатываются «как есть».
/**
* @type {?string=}
* @default '\n'
*/
Параметр задаёт символ перевода строки, который будет использоваться в сгенерированном файле, можно использовать \n
, \r
или \r\n
.
/**
* @type {?string=}
* @default 'html'
*/
Параметр задаёт тип документа: это влияет на код, который генерируют некоторые директивы, например, tag. Доступные варианты.
/**
* @type {?string=}
*/
Параметр задаёт тип шаблонов для рендеринга, доступны варианты:
interface
— все директивы template рендерятся как interface;placeholder
— все директивы template и interface рендерятся placeholder./**
* @type {?string=}
* @default 'stringConcat'
*/
Параметр задаёт режим рендеринга шаблонов, доступны варианты:
stringConcat
— шаблон генерируется в виде строки, для конкатенаций используется оператор +
;stringBuffer
— шаблон генерируется в виде строки, для конкатенаций используется оператор
StringBuffer;dom
— шаблон генерируется в виде DocumentFragment с помощью DOM API./**
* @type {?string=}
*/
Параметр задаёт адрес компилируемого файла.
Метод импортирует заданный объект в пространство имён фильтров Snakeskin.
Snakeskin.importFilters(filters, opt_namespace) { return undefined; }
!Object
filters
— импортируемый объект;?string=
opt_params
— пространство имён для сохранения, например, foo.bar
.Метод задаёт заданному фильтру дополнительные параметры.
Snakeskin.setFilterParams(filter, params) { return Function; }
(string|!Function)
filter
— название фильтра или функция-фильтр;!Object
params
— параметры фильтра.Метод вернёт true
, если заданный файл шаблонов соответствует скомпилированному по временной метке.
Snakeskin.check(source, result) { return boolean; }
string
source
— путь к исходному файлу;string
result
— путь к скомпилированному файлу.Метод скомпилирует заданный файл и вернёт ссылку на объект полученных шаблонов.
Snakeskin.compileFile(src, opt_params) { return !Object || false; }
string
src
— путь к файлу шаблонов;Object=
opt_params
— дополнительные параметры запуска.Метод скомпилирует заданный текст и вернёт ссылку на главный шаблон.
Главный шаблон определяется по правилу: название файла без расширения
или main
или index
или Object.keys().sort()[0]
.
Snakeskin.exec(txt, opt_params, opt_tplName) { return Function; }
string
txt
— исходный текст;Object=
opt_params
— дополнительные параметры запуска;?string=
opt_tplName
— имя главного шаблона.Метод скомпилирует заданный файл и вернёт ссылку на главный шаблон.
Главный шаблон определяется по правилу: название файла без расширения
или main
или index
или Object.keys().sort()[0]
.
Snakeskin.execFile(src, opt_params, opt_tplName) { return Function; }
string
src
— путь к файлу шаблонов;Object=
opt_params
— дополнительные параметры запуска;?string=
opt_tplName
— имя главного шаблона.