=== Введение
**Данный документ** представляет собой справочное руководство по шаблонизатору BEMHTML. 

В документе описаны: 
  * основные особенности BEMHTML, отличающие его от других шаблонизаторов;
  * синтаксис описания входных данных BEMJSON и шаблонов BEMHTML;
  * порядок обработки входных данных и генерации HTML;
  * примеры решения типовых задач средствами BEMHTML.

**Целевая аудитория документа** — веб-разработчики и HTML-верстальщики, использующие ((http://bem.github.com/bem-method/pages/beginning/beginning.ru.html БЭМ-методологию)). 

Предполагается, что читатель знаком с: 
  * HTML;
  * JavaScript;
  * CSS;
  * БЭМ.

**В документе не описаны** настройка среды разработки и процедуры компиляции шаблонов.

=== Особенности шаблонизатора BEMHTML
==== Привязка к БЭМ-предметной области
Шаблонизатор BEMHTML входит в связку технологий, обеспечивающих создание веб-интерфейсов в рамках ((http://bem.github.com/bem-method/pages/beginning/beginning.ru.html БЭМ-методологии)).

Входными данными шаблонизатора является описывающее страницу БЭМ-дерево в формате ((#sintaksisbemjson BEMJSON)). Язык шаблонов BEMHTML предлагает специальные конструкции для обработки блоков, элементов и модификаторов.

==== Декларативные шаблоны
===== Императивный подход
Традиционные шаблонизаторы предлагают **императивный подход** к написанию шаблонов: HTML формируется в процессе последовательного чтения и выполнения шаблона. 

#| || **Входные данные** | **Шаблон** | **Результат** || ||
%%(js)
{
  items: [
    { text: '1' },
    { text: '2' }
  ]
}
%%|%%(html)
<ul class="menu">
    [% foreach item in items %]
        <li class="menu__item">
            [% item.text %]
        </li>
    [% end %]
</ul>
%%|%%(html)
<ul class="menu">
    <li class="menu__item">1</li>
    <li class="menu__item">2</li>
</ul>
%% 
|||#

В таком шаблоне неизбежна избыточность, вызванная синтаксическими требованиями HTML: //вывести открывающий тег — сгенерировать содержимое — вывести закрывающий тег//. Еще выше избыточность в таблицах, списках и т.п.

===== Декларативный подход
**Декларативный подход** позволяет формулировать шаблоны как набор простых утверждений вида: //тип входных данных (БЭМ-сущность) — HTML-представление (тег, атрибут, и т.п.)//.
#| || **Входные данные** | **Шаблон** | **Результат** || ||
%%(js)
{
  block: 'menu',
  content: [
    { elem: 'item', content: '1' },
    { elem: 'item', content: '2' }
  ]
}
%%|%%(js)
block menu {
    tag: 'ul'
    elem item, tag: 'li'
}
%%|%%(html)
<ul class="menu">
    <li class="menu__item">1</li>
    <li class="menu__item">2</li>
</ul>
%% 
|||#

Декларативность шаблонов достигается за счет того, что в BEMHTML процедура генерации HTML-элемента стандартизована и выполняется шаблонизатором. Этот же подход к выполнению преобразований данных используется в XSLT и AWK.

==== Язык описания шаблонов — JavaScript
BEMHTML представляет собой специализированный язык (DSL), **расширяющий** JavaScript.

Точнее, BEMHTML является надмножеством языка шаблонов ((https://github.com/veged/xjst XJST)), который, в свою очередь, является надмножеством JavaScript.

Синтаксис BEMHTML предоставляет лаконичный способ записи соответствия БЭМ-сущностей и генерации HTML-элементов и атрибутов.

Помимо этого, в шаблонах могут использоваться **любые** JavaScript-конструкции.

==== Язык исполнения шаблонов — JavaScript
Перед выполнением BEMHTML компилируется в оптимизированный JavaScript, который принимает BEMJSON и возвращает HTML. 

Такой шаблон может выполняться как на стороне сервера, так и на стороне клиента.

==== Ограничения на уровне соглашений
Разработчики BEMHTML стремились сделать его максимально гибким инструментом, поэтому в BEMHTML не предусмотрено технологических ограничений на операции, выполняемые в шаблонах. Фактически, в BEMHTML-коде возможно всё, что возможно в JavaScript.

Все ограничения, обеспечивающие корректность и эффективность выполнения задач шаблонизатора, реализуются на уровне соглашений по написанию шаблонов. Такие соглашения приводятся в данном документе в качестве рекомендаций. Разработчик имеет техническую возможность не следовать соглашениям, но в этом случае следует взвесить преимущества и недостатки своего решения.

=== Основные понятия
==== Входные данные: BEMJSON
Поскольку BEMHTML основан на JavaScript, в качестве формата представления БЭМ-дерева выбран JSON с набором дополнительных соглашений о представлении БЭМ-сущностей — BEMJSON.

Задача шаблонизатора BEMHTML — преобразовать входное БЭМ-дерево в выходной HTML-документ. В целях сохранения гибкости и поддерживаемости, на уровне шаблонизатора не следует производить сложных преобразований входных данных. Шаблоны должны быть максимально простыми утверждениями, сопоставляющими каждому типу БЭМ-сущности нужное HTML-оформление.

Поэтому структура входного БЭМ-дерева должна быть ориентирована на **представление** (view), когда при генерации HTML-дерева не потребуется изменений в наборе и порядке блоков и элементов. Приведение БЭМ-дерева к такому развернутому виду должно производиться на уровне бэкенда, предшествующего шаблонизатору. Иллюстрацией view-ориентированного формата данных может служить пример френдленты, разобранный в разделе ((#privedenievxodnyxdannyxkformatuorientirovannomunapredstavlenie Приведение данных к формату, ориентированному на представление)).

В то же время детали организации HTML-страницы, которые являются зоной ответственности верстальщика, должны определяться только на уровне шаблонизатора. Пример такого решения приведен в разделе ((#dobavleniebjem-sushhnostejjdljazadachvjorstki Добавление БЭМ-сущностей для задач верстки)).

**См. также**:
  * ((#sintaksisbemjson Синтаксис BEMJSON))

==== Шаблон
Единицей программы на BEMHTML является **шаблон**. Шаблон BEMHTML связывает входную БЭМ-сущность (заданную именем сущности, элемента, именем и значением модификатора) и соответствующий этой сущности HTML-элемент.

Шаблон состоит из:
  * **предиката** — набора условий, при выполнении которых применяется шаблон. Типичный предикат описывает свойства входной БЭМ-сущности;
  * и **тела** — инструкций по генерации выходного HTML.

**См. также**:
  * ((#sintaksis Синтаксис BEMHTML)).

==== Мода
В процессе работы шаблонизатор последовательно обходит узлы входного БЭМ-дерева. Для каждого узла — БЭМ-сущности — выполняется цикл генерации выходного HTML-элемента. Для вложенных сущностей цикл генерации HTML-элементов выполняется рекурсивно. Таким образом, выходное HTML-дерево формируется поэлементно в процессе обхода входного БЭМ-дерева.

Цикл генерации каждого элемента последовательно проходит ряд фаз, называемых **модами**. Каждая мода отвечает за определенный фрагмент генерируемого HTML-элемента — тег, атрибуты, класс и т.п. В каждой моде вызывается процедура выбора и выполнения подходящего шаблона. 

Моды позволяют разделить выходной элемент на фрагменты, каждый из которых может быть описан простым типом данных: тег и класс — строкой, атрибуты — словарем, необходимость в БЭМ-классах — логическим значением и т.п. Благодаря этому возможно написание декларативных шаблонов, в предикате которых указана мода, а в теле содержатся данные соответствующего этой моде простого типа. В этом случае полное представление HTML-элемента может быть задано несколькими шаблонами.

Особый статус имеет **((#default мода default))**, которая отвечает за генерацию целого HTML-элемента. В рамках этой моды задан набор и порядок прохождения остальных мод, соответствующих фрагментам HTML-элемента, а также определена процедура сборки финального представления HTML-элемента из фрагментов, сгенерированных в остальных модах. Написание шаблона, который переопределяет поведение в данной моде, позволяет полностью контролировать генерацию элемента из BEMHTML, не пользуясь стандартными модами, позволяющими генерировать выходной элемент по частям.

**См. также**:
  * ((#standartnyemody Стандартные моды)).

==== Контекст
В процессе обхода входного BEMJSON-дерева шаблонизатор строит **контекст** — структуру данных, с которой работают шаблоны. Контекст соответствует текущему элементу (узлу) входного БЭМ-дерева и включает:
  * нормализованные сведения о текущей БЭМ-сущности;
  * фрагмент входных данных без модификаций (текущий элемент BEMJSON-дерева и его потомки);
  * строковый буфер, в который записывается HTML-результат;
  * служебные поля, содержание сведения о текущем состоянии (мода, позиция во входном БЭМ-дереве и т.п.);
  * вспомогательные функции.

БЭМ-сущность, описываемая текущим контекстом, называется **контекстной сущностью**.

**См. также**:
  * ((#poljakonteksta Поля контекста)).
  * ((#dostraivaniebjem-sushhnostejjpokontekstu Достраивание БЭМ-сущностей по контексту)).

=== Синтаксис BEMJSON
==== Типы данных
Типы данных в BEMJSON аналогичны соответствующим типам в JavaScript.
  * Строки и числа:
    * **Строка**  %%'a'%% %%"a"%%;
    * **Число** %%1%% %%0.1%%;
    Структура данных, состоящая из строки или числа, является валидным BEMJSON.
  * **Объект** (ассоциативный массив) %%{ключ: значение}%% и остальные типы, кроме массива.
  * **Массив** — список, может содержать элементы различных типов (строки, числа, объекты, массивы) %%[ "a", 1, {ключ: значение}, [ "b", 2, ... ] ]%%.

==== Специальные поля BEMJSON
Для представления данных предметной области БЭМ и HTML в BEMJSON используются объекты, в которых зарезервированы специальные имена полей. 

=====Представление БЭМ-сущностей
БЭМ-сущности представляются в BEMJSON в виде объектов, в которых могут присутствовать следующие поля:

#|
|| **Поле** | **Значение** | **Тип значения** | **Пример** ||
|| %%block%% | Имя блока | Строка | %%{ block: 'b-menu' }%% ||
|| %%elem%% | Имя элемента | Строка | %%{ elem: 'item' }%% ||
|| %%mods%% | Модификаторы блока | Объект, содержащий имена и значения модификаторов в качестве пар ключ—значение: %%{имя_модификатора: 'значение_модификатора'}%% | 
%%
{
  block: 'b-link', 
  mods: { pseudo: 'yes', color: 'green' }
}
%%||
|| %%elemMods%% | Модификаторы элемента | Объект, содержащий имена и значения модификаторов элемента в качестве пар ключ—значение: %%{имя_модификатора: 'значение_модификатора'}%% | 
%%
{
  elem: 'item', 
  elemMods: { selected: 'yes' }
}
%%||
|| %%mix%% | Подмешанные блоки/элементы | Массив, содержащий объекты, описывающие подмешанные блоки и элементы. В качестве значения может выступать объект, который трактуется как массив, состоящий из одного элемента. | 
%%
{
  block: 'b-link',
  mix: [ { block: 'b-serp-item', elem: 'link' } ]
}
%%||
|#

**См. также**:
  * ((#dostraivaniebjem-sushhnostejjpokontekstu Достраивание БЭМ-сущностей по контексту))

===== Представление HTML
BEMJSON предоставляет возможность задавать некоторые аспекты выходного HTML непосредственно во входных данных. Этой возможностью не следует злоупотреблять, т.к. BEMJSON представляет собой уровень данных, а непосредственное оформление HTML должно выполняться на уровне шаблонизатора (BEMHTML). Однако возможны ситуации, где оправданно описание HTML-представления на уровне BEMJSON. В этом случае автор шаблонов BEMHTML должен понимать, каким образом параметры HTML, заданные входными данными, взаимодействуют с HTML-представлением, определенным на уровне шаблонов.

В BEMJSON предусмотрены следующие поля для непосредственного управления HTML-представлением:
#|
|| **Поле** | **Значение** | **Тип значения** | **Пример** ||
|| %%tag%% | HTML-тег для данной сущности | %%String%% | 
%%
{
  block: 'b-my-block',
  tag: 'img'
}
%%
||
|| %%attrs%% | HTML-атрибуты для данной сущности | %%Object%% | 
%%
{
  block: 'b-my-block',
  tag: 'img',
  attrs: { src: '//yandex.ru/favicon.ico', alt: '' }
}
%%  
||
|| %%cls%% | Строка, добавляемая к HTML-атрибуту %%class%% (помимо автоматически генерируемых классов) | %%String%% | 
%%
{
  block: 'b-my-block',
  cls: 'some-blah-class'
}
%%
||
|| %%bem%% | Флаг — отменить генерацию БЭМ-классов в HTML-атрибуте %%class%% для данной сущности | %%Boolean%% | 
%%
{
block: 'b-page',
tag: 'html',
bem: false
}
%%||
|| %%js%% | Либо флаг о наличии клиентского JavaScript у данной сущности, либо параметры JavaScript. | %%Boolean|Object%%  | 
%%
{
  block: 'b-form-input',
  mods: { autocomplete: 'yes' },
  js: {
    dataprovider: { url: 'http://suggest.yandex.ru/...' }
  }
}
%%||
|#

Обратите внимание, что имена и смысл полей BEMJSON, управляющих HTML-представлением, совпадают с именами и смыслом соответствующих ((#standartnyemody стандартных мод)) BEMHTML (тег, атрибуты, класс и т.п.). В случае, если какие-то из аспектов выходного HTML заданы **и во входных данных, и в BEMHTML-шаблонах**, то более высокий приоритет имеют значения, !!заданные в BEMHTML-шаблонах!!.

При генерации HTML будет выполнено одно из двух действий:
  * **Объединение** значений HTML-параметров, заданных в BEMJSON, cо значениями параметров, заданных в BEMHTML-шаблоне. Объединение значений производится только для тех параметров, для которых оно имеет очевидный смысл: %%attrs%%, %%js%%, %%mix%%.
  * **Замещение** значений HTML-параметров, заданных в BEMJSON, значениями, заданными в **BEMHTML-шаблоне**. Выполняется для всех прочих значений: %%tag%%, %%cls%%, %%bem%%, %%content%%. 

----
!!**NB**!! Приоритет BEMHTML-шаблонов позволяет **автору шаблонов** принимать решение, какие HTML-параметры будут приоритетнее в каждом конкретном случае — заданные в BEMHTML или в BEMJSON. Значения HTML-параметров, заданных в BEMJSON, доступны в шаблонах при обращении к фрагменту входного BEMJSON-дерева в контексте (поле %%this.ctx%%).
----

===== Вложенность: content
Для представления вложенных БЭМ-сущностей (БЭМ-дерева) в BEMJSON зарезервировано поле %%content%%. В качестве значения данного поля может выступать произвольный BEMJSON: 
  * Примитивный тип (строка, число). Значение используется в качестве содержимого (текста) HTML-элемента, соответствующего контекстной сущности.
  * Объект, описывающий БЭМ-дерево. Значение используется для генерации HTML-элементов, вложенных в HTML-элемент, соответствующий контекстной сущности.

Уровень вложенности дерева БЭМ-сущностей, построенного с помощью поля %%content%%, не ограничен.

**См. также**:
  * ((#content Мода content))

===== Произвольные поля
Помимо специальных полей, описывающих БЭМ-сущность и ее HTML-представление, в том же объекте могут присутствовать любые поля с произвольными данными, которые будут доступны для использования в BEMHTML-шаблонах. 

Примером произвольного поля может служить поле %%url%% в блоке ссылки:
%%
{
block: 'b-link',
url: '//yandex.ru'
}
%%

Пример использования данных из поля %%url%% см. в разделе: ((#vyborshablonapousloviju Выбор шаблона по условию)).

==== Произвольный JavaScript в BEMJSON
BEMJSON является менее ограниченным форматом, чем JSON. Произвольные JavaScript-выражения будут валидным BEMJSON. 

Специфика BEMJSON как формата данных заключается в соблюдении описанных в предшествующих разделах соглашений по именованию полей в объектах (для представления БЭМ-сущностей и HTML-представления) и правил вложения объектов.

=== Синтаксис BEMHTML
В данном разделе описаны все синтаксические конструкции языка BEMHTML. 

==== Шаблон
Шаблон состоит из двух выражений — **предиката** и **тела**, разделенных двоеточием. Допускается произвольное количество либо отсутствие пробелов до и после двоеточия:
%%
предикат: тело
%%

Каждый **предикат** представляет собой список из одного или более **подпредикатов** (условий), разделенных запятыми. 
%%
подпредикат1, подпредикат2, подпредикат3: тело
%%

Запятая соответствует логическому оператору "И". Предикат шаблона истинен тогда и только тогда, когда истинны все подпредикаты. Порядок записи подпредикатов не имеет значения, !!порядок проверки подпредикатов не гарантируется!!.

Логически программа на BEMHTML представляет собой одноранговый (плоский) **список шаблонов**. Однако если несколько шаблонов имеют **общие подпредикаты**, они могут быть записаны в виде вложенной структуры для минимизации повторов в коде.

Для обозначения вложенности используются фигурные скобки. Фигурные скобки ставятся после общей части предикатов, в них заключается блок кода, содержащий различающиеся части предикатов и соответствующие им тела шаблонов. Уровень вложенности подпредикатов не ограничен.
%%
подредикат1 {
  подпредикат2: тело1
  подпредикат3: тело2
} 
%%
Данная запись эквивалентна следующей:
%%
подпредикат 1, подпредикат 2: тело1
подпредикат 1, подпредикат 3: тело2
%%

----
!!**NB**!! Если для данного контекста определено более одного шаблона, то выполняется **последний** в порядке перечисления в BEMHTML-файле.
Более специфические шаблоны должны быть ниже в тексте, чем более общие.
----

**См. также**:
  * ((#proverkapodpredikatovvopredelennomporjadke Проверка подпредикатов в определенном порядке))
  
==== Подпредикаты
Предикат шаблона представляет собой набор условий, описывающих момент применения шаблона. Подпредикат шаблона соответствует элементарному условию.

В BEMHTML предусмотрены следующие типы условий:
  * Совпадение с входным БЭМ-деревом.
  * Мода.
  * Произвольное условие.

===== Совпадение с входным БЭМ-деревом
Условия совпадения с входным БЭМ-деревом позволяют описывать применимость шаблона в терминах БЭМ-сущностей: имен блоков и элементов, имен и значений модификаторов.

Для этого в предикатах используются следующие ключевые слова:
#|
|| **Ключевое слово** | **Аргументы** | **Тип значения** | **Пример** ||
|| %%block%% | имя блока | идентификатор %%[a-zA-Z0-9-]+%% или произвольное js-выражение | %%block b-menu%%---%%block 'b-menu'%%---%%block 'b' + '-menu'%% ||
|| %%elem%% | имя элемента | идентификатор %%[a-zA-Z0-9-]+%% или произвольное js-выражение | %%block b-menu, elem item%% ||
|| %%mod%% | имя и значение модификатора блока | идентификатор %%[a-zA-Z0-9-]+%% или произвольное js-выражение | %%block b-head-logo, mod size big%% ||
|| %%elemMod%% | имя и значение модификатора элемента | идентификатор %%[a-zA-Z0-9-]+%% или произвольное js-выражение | %%block b-head-logo, elem text, elemMod size big%% ||
|#

Идентификаторы блоков, элементов, модификаторов и их значений пишутся без кавычек. Парсер BEMHTML рассматривает в качестве идентификатора любую строку, состоящую из латинских символов и дефиса. Вместо идентификатора может быть указано любое JS-выражение, которое будет приведено к строке.

----
!!**NB**!!: Важно не путать в предикатах модификаторы блока и модификаторы элемента. 
  * %%block input, mod theme black, elem hint%% задает элемент %%hint%%, вложенный в блок %%input%% с **модификатором блока** %%theme%% в значении %%black%%.
  * %%block input, elem hint, elemMod visibility visible%% задает элемент %%hint%% с **модификатором элемента** %%visibility%% в значении %%visible%% вложенный в блок %%input%%.
  * %%block input, mod theme black, elem hint, elemMod visibility visible%% задает элемент %%hint%% с **модификатором элемента** %%visibility%% в значении %%visible%% вложенный в блок %%input%% с **модификатором блока** %%theme%% в значении %%black%%.

Для модификаторов блоков и элементов используются разные ключевые слова, чтобы дать возможность комбинировать в предикатах условия, одновременно включающие упоминания модификаторов блоков и элементов.
----

===== Мода
В качестве подпредиката может выступать название одной из ((#standartnyemody стандартных мод)). Это означает, что данный предикат будет истинным в тот момент обработки, когда выставлена соответствующая мода.

Для проверки стандартных мод используются ключевые слова:
  * %%default%%
  * %%tag%%
  * %%bem%%
  * %%mix%%
  * %%cls%%
  * %%js%%
  * %%jsAttr%%
  * %%attrs%%
  * %%content%%

Кроме того, любой подпредикат, состоящий только из идентификатора (%%[a-zA-Z0-9-]+%%), интерпретируется как название нестандартной моды. Например, подпредикат %%my-mode%% эквивалентен подпредикату %%this._mode === 'my-mode'%%.

===== Произвольное условие
Произвольные условия учитывают совпадения с данными, не попадающими под предметную область БЭМ. В качестве произвольного условия может выступать любое JavaScript-выражение, которое будет приведено к логическому значению.

{{a name="xjst-canonical"}}
----
!!**NB**!! Произвольные условия предпочтительно записывать в **канонической форме XJST**: 
%%
предикатное выражение === значение
%%
Где 
  * %%предикатное выражение%% — произвольное JavaScript-выражение, приводимое к логическому значению;
  *  %%значение%% — произвольное JavaScript-выражение. 
При этом количество **различных** предикатных выражений в подпредикатах шаблонов должно быть минимизировано. Соблюдение этих условий позволит компилятору XJST производить оптимизации над произвольными условиями шаблонов наряду с оптимизацией стандартизованных условий (БЭМ-сущности и моды).
----

==== Тело
Тело шаблона представляет собой выражение, результат вычисления которого используется для генерации выходного HTML.
В качестве тела шаблона может выступать: 
  * Отдельное JavaScript-выражение:
  %%предикат: JS-выражение%%
  * Блок JavaScript-кода, заключенный в фигурные скобки:
  %%предикат: { 
  JS-блок
}
%%

----
!!**NB**!! Парсер BEMHTML всегда интерпретирует фигурную скобку в начале тела шаблона как обозначение блока JavaScript-кода, поэтому если необходимо в качестве JavaScript-выражения в теле шаблона использовать хэш (объект), его следует заключать в круглые скобки:
%%
предикат: ({name: value})
%%
----

В рамках тела шаблона можно выполнить следующие действия: 
  * Вычислить и вернуть значение. 
  Если в текущей моде ожидается значение определенного типа, значение, возращаемое при вычислении тела шаблона, будет приведено к этому типу и использовано. Если шаблон не возвращает никакого значения, будет использовано значение %%undefined%%.
  * Вывести данные непосредственно в HTML-результат. 
  Для этого в теле шаблона следует выполнить запись в буфер HTML-результата (%%this._buf.push(...)%%).
  * Производить произвольные операции.


==== Конструкции XJST
Так как язык BEMHTML является расширением языка XJST, в BEMHTML-шаблонах возможно использовать синтаксические конструкции XJST для модификации контекста и явного вызова процедуры выбора и выполнения шаблонов в измененном контексте.

===== local
Конструкция %%local%% (язык XJST) используется для временного изменения контекста и переменных, также для последующих операций с ними. По синтаксису блок кода %%local%% подобен блокам %%while%% и %%for%% в JavaScript.

Возможны следующие варианты записи блока %%local%%:
  * Тело в виде js-выражения:
  %%local(expressions) code%%
  * Тело в виде js-блока:
  %%local(expressions) { code }%%

Здесь 
  * %%expressions%% — это список выражений, представляющих собой операции присваивания значений переменным;
  * %%code%% — JavaScript-код, который выполняется в контексте, где значения переменных соответствуют присвоенным в блоке %%expressions%%.

По выходу из блока local все переменные, значения которых изменялись в блоке %%expressions%%, приобретают те значения, которые в них хранились на момент входа в блок. Возвращение исходных значений производится в порядке, обратном порядку присваивания переменных в блоке %%expressions%%.

----
!!**NB**!! Если в блоке %%expressions%% было присвоено значение переменной (полю объекта), которая не была определена на момент входа в блок %%local%%, по выходу из блока %%local%% эта переменная (поле) будет существовать и получит значение %%undefined%%.
----

**См. также**:
  * Подробнее о конструкции local ((http://github.com/veged/xjst/blob/master/README.md#local в документации XJST)).

===== apply
Конструкция %%apply%% предназначена для явного вызова процедуры выбора и выполнения шаблона, предикат которого истинен в данном контексте. Конструкция позволяет вызывать шаблоны в модифицированном контексте.

Синтаксис:
%%
apply(expressions)
%%

Где %%expressions%% — это список выражений, модифицирующих контекст.  Список может быть пуст. 

Каждое выражение в списке %%expressions%% может представлять собой:
  * Операцию присваивания значений переменным. Аналогично блоку expressions в ((#local конструкции local)).
  * !!(зел)Новое в bem-bl 0.3!! Строку или приводимое к ней выражение. Означает «выставить указанную строку в качестве моды». 
  Например, выражение %%apply('content')%% эквивалентно выражению %%apply(this._mode = 'content')%%.

При вычислении выражения %%apply%% выполняются следующие шаги:
  1. Выполнение выражений (присваиваний) в блоке %%expressions%%.
  2. Вызов процедуры выбора и выполнения шаблона в контексте, полученном в результате шага 1.
  3. Восстановление значений переменных.

Конструкция %%apply(expressions)%% представляет собой сокращенную запись выражения %%local(expressions) { apply() }%%.


===== applyNext
!!(зел)Новое в bem-bl 0.3!!

Конструкция %%applyNext%% позволяет заново запустить процедуру применения шаблонов к текущему контексту непосредственно в теле шаблона. Результат вычисляется так, как если бы шаблона, в котором используется данная конструкция, не было. Конструкция возвращает значение, вычисленное в результате применения шаблонов к текущему контексту.

Синтаксис:
%%(js)
applyNext(expressions)
%%

Где %%expressions%% — список выражений, модифицирующих контекст (операций присваивания значений переменным или строка, означающая присвоение моды). Список может быть пуст. Аналогично блоку %%expressions%% в ((#apply конструкции apply)).

При вызове %%applyNext%% выполняются следующие шаги:
  1. Создание в контексте флага, позволяющего избежать бесконечной рекурсии при вызове шаблонов. В качестве флага используется случайное число.
  2. Добавление в предикат шаблона проверки на наличие флага.
  3. Выполнение блока %%expressions%% (модификация текущего контекста).
  4. Вызов процедуры выбора и выполнения шаблона %%apply()%%.
  5. Возвращение значения, полученного в результате выполнения шаблона.

Например, шаблон 
%%(js)
block b1: {
  statements
  applyNext()
  }
%%

эквивалентен следующему шаблону:

%%(js)
var _randomflag = ~~(Math.random() * 1e9)
block b1, !this.ctx._randomflag: {
    statements
    local(this.ctx._randomflag = true) apply()
}
%%

Где %%statements%% — произвольные JS-выражения, допустимые в теле шаблона.

**См. также**:
  * ((#nasledovanie Наследование)).
  * ((#dobavleniebjem-sushhnostejjdljazadachvjorstki Добавление БЭМ-сущностей для задач верстки)).


===== applyCtx
!!(зел)Новое в bem-bl 0.3!!

Конструкция %%applyCtx%% предназначена для модификации фрагмента входного БЭМ-дерева %%this.ctx%% и последующего вызова процедуры применения шаблонов %%apply()%% к контексту с модифицированным БЭМ-деревом. 

Синтаксис:
%%(js)
applyCtx(newctx)
%%

Где в качестве %%newctx%% может выступать:
  * Объект (хэш), который будет использован в качестве входного фрагмента БЭМ-дерева. Может содержать ссылки на исходный %%this.ctx%%.
  * Операция присваивания переменной.

В ходе вычисления выражения %%applyCtx%% выполняются следующие шаги:
  1. Создание в контексте флага, позволяющего избежать бесконечной рекурсии при вызове шаблонов. В качестве флага используется случайное число.
  2. Добавление в предикат шаблона проверки на наличие флага.
  3. Выставление ((#pustajamodaquotquot пустой моды)) в качестве текущей.
  4. Вызов процедуры выбора и выполнения шаблона %%apply()%%.
  5. Возвращение значения, полученного в результате выполнения шаблона.

Выражение %%applyCtx(newctx)%% представляет собой сокращенную запись для выражения %%applyNext(this.ctx = {newctx}, '')%%.

**См. также**:
  * ((#oborachivanieblokavdrugojjblok Оборачивание блока в другой блок))
  * ((#dobavleniebjem-sushhnostejjdljazadachvjorstki Добавление БЭМ-сущностей для задач верстки)).


=== Стандартные моды
В ядре BEMHTML определен набор стандартных мод, которые задают порядок обхода входного БЭМ-дерева (BEMJSON) и генерации выходного HTML, используемый BEMHTML по умолчанию.

По функциональности моды разделяются на два класса: 
  * **«Пустая» мода** определяет алгоритм обхода узлов входного BEMHTML и вызова остальных мод;
  * Все остальные моды определяют порядок генерации выходного HTML. В каждой из таких мод формируется тот или иной фрагмент выходного HTML-дерева. 

Для генерации HTML в каждой моде вызывается процедура выбора и выполнения подходящего шаблона (предикат которого истинен в данном контексте). Результат вычисления тела выбранного шаблона подставляется в тот фрагмент HTML-дерева (HTML-элемента), за генерацию которого отвечает данная мода.

Данная логика работы накладывает следующие ограничения на шаблоны:
  * Если шаблон выводит какие-то данные в HTML, в его предикате должна быть указана мода.
  * В предикате шаблона может быть указано не более одной моды.
  * В результате вычисления тела шаблона должен возвращаться тот тип объекта, который ожидается в рамках данной моды.

В последующих разделах моды перечислены в порядке их вызова при обработке элемента входного BEMJSON.

==== «Пустая» мода (%%""%%)
!!(зел)Тип значения тела шаблона: %%не используется%%!!

Пустая (не определенная) мода соответствует моменту, когда значение поля контекста %%this._mode%% равно пустой стоке (%%""%%). Это значение выставляется: 
  * перед началом обработки входного дерева;
  * в момент рекурсивного вызова процедуры обхода дерева в моде %%default%%.

Действие, выполняемое в рамках пустой моды, зависит от типа контекстного (текущего) элемента входного BEMJSON-дерева.

#|
|| **Тип элемента** | **Действие** ||
|| **БЭМ-сущность** (блок или элемент) | Выставление значений в служебных полях контекста (%%block elem mods elemMods ctx position%%) и вызов шаблонов по моде %%default%%.
||
|| **строка** или **число** | Вывод значения, приведенного к строке, в буфер HTML-результата. ||
|| **Boolean, undefined, null**| Вывод пустой строки в буфер HTML-результата. ||
|| **массив** | Итерация по массиву с рекурсивным вызовом шаблонов по пустой моде. ||
|#

Определение шаблона по пустой моде (подпредикат %%this._mode === ""%%) имеет смысл только в том случае, если необходимо переопределить принцип обхода входного дерева. 

Вызов шаблонов по пустой моде (конструкция %%apply('')%% в теле шаблона) необходим, если требуется отклониться от однозначного соответствия «входная БЭМ-сущность — выходной HTML-элемент» и сгенерировать более одного элемента на одну входную сущность. В частности, такой вызов осуществляется автоматически при использовании ((#applyctx конструкции  applyCtx)).

**См. также**:
  * ((#oborachivanieblokavdrugojjblok Оборачивание блока в другой блок))

==== default
!!(зел)Тип значения тела шаблона: %%не используется%%!!

В рамках моды %%default%% полностью формируется выходной HTML-элемент, соответствующий входной БЭМ-сущности.

В ходе выполнения моды default происходит: 
  * вызов всех остальных стандартных мод, отвечающих за формирование отдельных аспектов HTML-элемента;
  * объединение результатов выполнения всех вызываемых мод в результирующую HTML-строку;
  * рекурсивный вызов шаблонов на результат выполнения моды %%content%%.

На рисунке ниже схематически отражено, в каких модах генерируются различные фрагменты выходного HTML-элемента. 
file:mode-default.png

Схема отражает вариант обработки элемента, имеющего пару открывающий—закрывающий тег и вложенное содержимое. Обработка коротких (самозакрытых) элементов аналогична и отличается только отсутствием закрывающего тега и рекурсии. Следует ли обрабатывать данный элемент как короткий, определяет вспомогательная функция контекста %%this._.isShortTag%% на основании имени элемента (тега).

Определение шаблона по моде %%default%% (подпредикат %%default%%) необходимо в тех случаях, когда нужно переопределить процедуру генерации выходного HTML-элемента, например, добавить DOCTYPE к тегу HTML:

%%(js)
block b-page {
  default: {
    this._buf.push('<!DOCTYPE html>');
    applyNext();
  }
  tag: 'html'
}
%%

==== tag
!!(зел)Тип значения тела шаблона: %%String%%!!
!!(зел)Значение по умолчанию: %%'div'%%!!

Мода %%tag%% задает имя выходного HTML-элемента (тег). По умолчанию имя элемента равно %%div%%. Фрагменты HTML, за генерацию которых отвечает мода %%tag%%, выделены на рисунке:
file:mode-tag.png

----
!!**NB**!! Если в качестве значения %%tag%% указать пустую строку, для данной сущности будет пропущен этап генерации HTML-элемента (тега и всех атрибутов), но содержимое элемента (%%content%%) будет обработано обычным образом.
----

Определение шаблона по моде %%tag%% (подпредикат %%tag%%) необходимо, если:
  * для данной сущности следует сгенерировать HTML-элемент с именем, отличным от %%div%%;
  * отказаться от генерации HTML-элемента для данной сущности, но обработать вложенные сущности.

#|
|| **Входные данные** | **Шаблон** | **HTML-результат** ||
||
%%(js)
{
  block: 'b1', 
  content: 'text'
}
%% 
|
%%(js)
block b1, tag: 'span'
%%
|
%%(html)
<span class="b1">text</span> 
%%||
||
%%(js)
{
  block: 'b1',
  content: {
    block: 'b2'
    }
}
%%
|
%%(js)
b1, tag: ''
%%
|
%%(html)
<div class="b2"></div>
%%||
|#

==== js
!!(зел)Тип значения тела шаблона: %%Boolean|Object%%!!
!!(зел)Значение по умолчанию: %%false%%!!

Мода %%js%% указывает, есть ли у обрабатываемого блока клиентский JavaScript. В случае наличия JavaScript в моде %%js%% могут быть переданы параметры клиентского JavaScript (записываются в атрибут HTML-элемента, имя которого определяется ((#jsattr модой %%jsAttr%%))). 

Мода %%js%% допускает два типа значения тела шаблона: 
  * %%Boolean%% — Флаг, указывающий, имеет ли данный блок клиентский JavaScript.
  * %%Object%% — Хэш, содержащий параметры JavaScript (подразумевается, что данный блок имеет клиентский JavaScript).
  
Фрагменты HTML, за генерацию которых отвечает мода %%js%%, выделены на рисунке:
file:mode-js.png

Определение шаблона по моде %%js%% (подпредикат %%js%%) имеет смысл только в том случае, если у блока имеется клиентский JavaScript.

#|
|| **Входные данные** | **Шаблон** | **HTML-результат** ||
||
%%(js)
{block: 'b1'}
%%|
%%(js)
block b1, js: true
%% 
| 
%%(html)
<div class="b1 i-bem" onclick="return { 'b1': {} }"></div>
%%||
|| 
%%(js)
{block: 'b1'}
%%|
%%(js)
block b1, js: {param: 'value'}
%%
 | 
%%(html)
<div class="b1 i-bem" onclick="return { 'b1': { 'param': 'value' } }"></div>
%%||
|#

**См. также**:
  * ((http://bem.github.com/bem-bl/sets/common-desktop/i-bem/i-bem.ru.html JS-реализация блока i-bem))

==== bem
!!(зел)Тип значения тела шаблона: %%Boolean%%!!
!!(зел)Значение по умолчанию: %%true%%!!

Мода %%bem%% указывает, нужно ли при формировании HTML-атрибута %%class%% включать автоматически сгенерированные имена классов, описывающие данную БЭМ-сущность. По умолчанию генерация БЭМ-классов выполняется. Фрагмент HTML, за генерацию которого отвечает мода %%bem%%, выделен на рисунке:
file:mode-bem.png

Определение шаблона по моде %%bem%% (подпредикат %%bem%%) имеет смысл только в том случае, если для данной сущности **не нужно** генерировать HTML-классы, относящиеся к БЭМ-предметной области. Это может быть необходимо для соблюдения синтаксических требований HTML. Например, теги %%html%%, %%meta%%, %%link%%, %%script%%, %%style%% не могут иметь атрибута %%class%%.

#|
|| **Входные данные** | **Шаблон** | **HTML-результат** ||
||
%%(js)
{
  block: 'b-page'
}
%%
|
%%(js)
block b-page {
  tag: 'html'
  bem: false
  }
%%
|
%%(html)
<html></html>
%%||
|#

==== cls
!!(зел)Тип значения тела шаблона: %%String%%!!
!!(зел)Значение по умолчанию: %%''%%!!

Мода %%cls%% позволяет определить произвольную строку, добавляемую в значение атрибута %%class%% помимо автоматически генерируемых значений. Фрагмент HTML, за генерацию которого отвечает мода %%cls%%, выделен на рисунке:
file:mode-cls.png

Определение шаблона по моде %%cls%% (подпредикат %%cls%%) имеет смысл в том случае, если для данного элемента необходимы специфические HTML-классы, не относящиеся к предметной области БЭМ. 

#|
|| **Входные данные** | **Шаблон** | **HTML-результат** ||
|| 
%%(js)
{
  block: 'b1'
}
%%
|
%%(js)
block b1, cls: 'custom'
%% 
|
%%(html)
<div class="b1 custom"></div>
%% 
||
|#

==== mix
!!(зел)Тип значения тела шаблона: %%Array|Object%%!!
!!(зел)Значение по умолчанию: %%[]%%!!

Мода %%mix%% задает список БЭМ-сущностей, которые необходимо **примешать** к данной сущности. Сущность, в рамках которой выполняется примешивание, называется **базовой**, а добавляемая сущность — **примешиваемой**. Имеет смысл примешивание блоков и элементов.

Технически примешивание сводится к следующим операциям: 
  * БЭМ-классы примешиваемой сущности добавляются в значение атрибута %%class%% текущего элемента наряду с классами базовой сущности. 
  * Если примешиваемая сущность имеет JavaScript-параметры, они добавляются в значение атрибута, заданного модой %%jsAttr%%. JavaScript-параметры передаются в виде хэша, ключом является имя примешиваемой сущности. 

Все прочие составляющие HTML-элемента (тег, атрибуты и под.) генерируются на основании шаблонов для базовой сущности. 

Значением тела шаблона для данной моды может быть:
  * **Массив**, в котором содержится список объектов (хэшей), каждый из которых описывает БЭМ-сущности, которые необходимо подмешать.
  * **Объект**, описывающий примешиваемую БЭМ-сущность. Интерпретируется как массив, состоящий из одного элемента. 

Фрагмент HTML, за генерацию которого отвечает мода %%mix%%, выделен на рисунке:
file:mode-mix.png

Определение шаблона по моде %%mix%% (подпредикат %%mix%%) требуется, когда необходимо выполнить примешивание блока или элемента на уровне шаблонизатора.

----
!!**NB**!! Примешивание БЭМ-сущностей выполняется рекурсивно. Иными словами, если для примешиваемой сущности определен шаблон, в котором к ней примешиваются еще какие-либо сущности, все такие сущности добавляются рекурсивно и классы для них появятся в атрибуте %%class%% базовой сущности (см. пример ниже).
----

#|
|| **Входные данные** | **Шаблон** | **HTML-результат** ||
||
%%(js)
{
  block: 'b1'
  js: { p: 1 }
}
%%
|
%%(js)
block b1, mix: ({
  block: 'b2', 
  js: { p: 2 }
  })
%%
|
%%(html)
<div class="b1 b2 i-bem" onclick="return { 'b1': { 'p': 1}, 'b2': { 'p': 2} }"></div>
%%||
||
%%(js)
{
  block: 'b1'
}
%% 
|
%%(js)
block b1, mix: [ { block: 'b2' } ]
block b2, mix: [ { block: 'b3' } ]
block b3, mix: [ { block: 'b4' } ]
block b4, mix: [ { block: 'b1' } ]
%%| 
%%(html)
<div class="b1 b2 b3 b4"></div>
%%||
|#

==== jsAttr
!!(зел)Тип значения тела шаблона: %%String%%!!
!!(зел)Значение по умолчанию: %%'onclick'%%!!

Мода %%jsAttr%% определяет имя HTML-атрибута, в значении которого будут переданы параметры клиентского JavaScript для данного блока. По умолчанию используется атрибут %%onclick%%. Фрагмент HTML, за генерацию которого отвечает мода %%jsAttr%%, выделен на рисунке:
file:mode-jsattr.png

Определение шаблона по моде %%jsAttr%% (подпредикат %%jsAttr%%), необходимо в том случае, если требуется передавать параметры JavaScript в нестандартном атрибуте. Например, для тач-сайтов в этих целях используется атрибут %%ondblclick%%.

#|
|| **Входные данные** | **Шаблон** | **HTML-результат** ||
||
%%(js)
{
  block: 'b1',
  js: true
}
%%
|
%%(js)
block b1, jsAttr: 'ondblclick'
%%
|
%%(html)
<div class="b1 i-bem" ondblclick="return {'b1': {} }"></div>
%%||
|#

==== attrs
!!(зел)Тип значения тела шаблона: %%Object%%!!
!!(зел)Значение по умолчанию: %%{}%%!!

Мода %%attrs%% позволяет задать имена и значения произвольных HTML-атрибутов для данного элемента. По умолчанию дополнительные атрибуты не генерируются. Фрагмент HTML, за генерацию которого отвечает мода %%attrs%%, выделен на рисунке:
file:mode-attrs.png

Значением тела шаблона для данной моды должен быть объект (хэш), содержащий имена и значения атрибутов в качестве пар ключ—значение. В качестве ключа должен выступать валидный идентификатор HTML-атрибута, а в качестве значения — строка или число. При выводе HTML специальные символы в значениях атрибутов экранируются вспомогательной функцией %%this._.attrEscape()%%.

----
!!**NB**!! Если в качестве значения атрибута указать %%undefined%%, этот атрибут не будет выведен в HTML-элементе.
----

Определение шаблона по моде %%attrs%% (подпредикат %%attrs%%) необходимо во всех случаях, когда требуется:
  * добавить произвольные HTML-атрибуты на уровне шаблонизатора;
  * исключить указанные атрибуты из вывода, даже если они были определены во входном BEMJSON. 

#|
|| **Входные данные** | **Шаблон** | **HTML-результат** ||
||
%%(js)
{
  block: 'logo',
}
%%
|
%%(js)
block logo {
  tag: 'img'
  attrs: ({alt: 'logo', href: 'http://...'})  
}
%%
|
%%(html)
<img alt="logo" href="http://..." />
%%||
||
%%(js)
{
  block: 'input',
  disabled: true
}
%%
|
%%(js)
block input {
  tag: 'input'
  attrs: ({ disabled: this.ctx.disabled ? 'disabled' : undefined })
}
%%
|
%%(html)
<input class="input" disabled="disabled"/>
%%||
||
%%(js)
{ block: 'input' }
%%
|
Тот же шаблон
|
%%(html)
<input class="input"/>
%%||
|#

==== content
!!(зел)Тип значения тела шаблона: %%BEMJSON%%!!
!!(зел)Значение по умолчанию: %%this.ctx.content%%!!

В рамках моды %%content%% вычисляется содержимое HTML-элемента, в качестве которого может выступать произвольный BEMJSON (как строка или число, так и дерево БЭМ-сущностей). В качестве значения по умолчанию используется значение поля %%content%% контекстной БЭМ-сущности (%%this.ctx.content%%).

Фрагмент HTML, за генерацию которого отвечает мода %%content%%, выделен на рисунке:
file:mode-content.png

Определение шаблона по моде %%content%% (подпредикат %%content%%) необходимо, если: 
  * Необходимо на уровне шаблонизатора добавить содержимое для сущности, у которой отсутствует %%content%% во входном BEMJSON.
  * Необходимо подменить содержимое сущности на уровне шаблонизатора.

#|
|| **Входные данные** | **Шаблон** | **HTML-результат** ||
||
%%(js)
{
  block: 'b1'
}
%%
|
%%(js)
block b1, content: ({
  block: 'b2'
  })
%%
|
%%(html)
<div class="b1"><div class="b2"></div></div>
%%
||
|#

**См. также**:
  * ((#nasledovanie Наследование)).
  * ((#dobavleniebjem-sushhnostejjdljazadachvjorstki Добавление БЭМ-сущностей для задач верстки)).

=== Поля контекста
В процессе работы шаблонизатор BEMHTML строит структуру данных, содержащую сведения об обрабатываемом узле BEMJSON и о состоянии процесса обработки. Помимо этого в контексте доступен ряд вспомогательных функций BEMHTML.

В момент выполнения шаблона контекст доступен в виде объекта, обозначаемого ключевым словом %%this%%. Обращение к контексту возможно как в предикате, так и в теле шаблона.

Автор шаблонов имеет возможность определить любые дополнительные поля в контексте.

Все поля контекста можно разделить на две категории: 
  * **Контекстно-зависимые**, значение которых изменяется в зависимости от обрабатываемого узла и фазы процесса обработки.
  * **Контекстно-независимые**, значение которых постоянно.

**См. также**:
  * ((#kontekst Контекст))

==== Контекстно-зависимые поля

#|
|| **Поле**| **Тип значения** | **Описание** ||
|| %%this.block %%| %%String%% | Имя блока (контекстной БЭМ-сущности)  ||
|| %%this.elem %%| %%String%% | Имя элемента (контекстной БЭМ-сущности) |  ||
|| %%this.mods %%| %%Object%% | Модификаторы блока (контекстной БЭМ-сущности), %%имя_модификатора: значение_модификатора%% ||
|| %%this.elemMods %%| %%Object%%  | Модификаторы элемента (контекстной БЭМ-сущности), %%имя_модификатора: значение_модификатора%%  ||
|| %%this.ctx%%| %%BEMJSON%% | Фрагмент входного BEMJSON-дерева, содержащий обрабатываемый узел и его потомков в неизмененном виде. Используется для получения доступа к произвольным полям данных входного BEMJSON. ||
|| %%this.position%% | %%Number%% | Номер позиции текущей сущности среди ее сиблингов во входном BEMJSON-дереве (начиная с 1). ||
|| %%this._mode%% | %%String%% | Текущая мода. Если необходимо определить собственные (нестандартные) моды, в соответствующем шаблоне следует присваивать этому полю имя моды в момент входа в нее. ||
|| %%this._buf%% | %%Array%% | Буфер HTML-результата. Обычно используется только для записи готовых HTML-фрагментов с использованием метода %%this._buf.push()%%. ||
|| %%this.isFirst()%% | %%Boolean%% | Проверяет, является ли данная БЭМ-сущность первой среди сиблингов во входном БЭМ-дереве. ||
|| %%this.isLast()%% | %%Boolean%% | Проверяет, является ли данная БЭМ-сущность последней среди сиблингов во входном БЭМ-дереве. Подробнее см. ((#algoritmvychislenijapoziciibjem-sushhnosti Алгоритм вычисления позиции БЭМ-сущности)). ||
|| %%this.generateId()%% | %%Number%% | Возвращает уникальный идентификатор для текущего контекста. Используется, когда нужно сгенерировать HTML-элементы, связанные с помощью атрибута %%id%%. ||
|#

----
!!**NB**!!
Ключевые слова для проверки БЭМ-сущностей в предикате являются сокращенной записью для проверки значений полей %%block%%, %%elem%% и т.д. в текущем контексте. Например, подпредикат %%block b1%% эквивалентен подпредикату %%this.block === 'b1'%%.

Аналогично, ключевые слова для проверки моды в предикате являются сокращенной записью для проверки значения служебного поля %%_mode%% в текущем контексте. Например, подпредикат %%tag%% эквивалентен подпредикату %%this._mode === 'tag'%%.
----

===== Достраивание БЭМ-сущностей по контексту
В BEMJSON принято записывать БЭМ-сущности в свернутом виде. Например, если в блок %%menu%% вложен элемент %%item%%, в объекте, описывающем пункт меню, не указывается имя содержащего его блока меню:
%%(js)
{ 
  block: 'menu', 
  content: { 
    elem: 'item' 
    } 
}
%%

Информация о том, что элемент %%item%% принадлежит блоку %%menu%%, достраивается по контексту (на основании вложенности) в процессе работы шаблонизатора. В момент, когда контекстной сущностью является блок %%menu%%, в полях контекста будут выставлены следующие значения:
%%(js)
this.block: 'menu'
this.ctx.block: 'menu'
%%

В момент входа во вложенный элемент %%item%%, в поле %%this.block%% достраивается значение %%menu%%. В то же время в поле %%this.ctx.block%% находится значение %%undefined%%, так как во входном BEMJSON это поле в элементе %%item%% не определено:
%%(js)
this.block: 'menu'
this.elem: 'item'
this.ctx.block: undefined
this.ctx.elem: 'item'
%%

Достраивание выполняется также для элементов, примешанных внутри блоков. Например, в приведенном БЭМ-дереве:
%%(js)
{ block: 'b1', mix: { elem: 'e1' } }
%% 
В примешанном элементе будет достроено имя блока:
%%(js)
{ block: 'b1', mix: { block: 'b1', elem: 'e1' } }
%%

Достраивание БЭМ-сущностей необходимо для корректного срабатывания предикатов на элементы блоков вида %%(js)block menu, elem item%%, так как в таких предикатах проверяются значения полей контекста %%this.block%% и %%this.elem%%.

----
!!**NB**!! Чтобы избежать срабатывания предикатов вида %%block menu%% внутри вложенных в блок элементов, на этапе компиляции шаблонов к таким предикатам в необходимых случаях автоматически добавляется подпредикат %%!this.elem%%. Автоматическое добавление может не сработать, если предикат шаблона содержит подпредикат с произвольным условием, записанный не в ((#xjst-canonical канонической форме XJST)).
----

===== Алгоритм вычисления позиции БЭМ-сущности
Позиция в БЭМ-дереве (поле контекста %%this.position%%) представляет собой натуральное число, соответствующее порядковому номеру текущей (контекстной) БЭМ-сущности среди ее сиблингов в БЭМ-дереве (одноранговых сущностей). 

При вычислении позиции: 
  * Нумеруются только те узлы обрабатываемого BEMJSON, которые соответствуют БЭМ-сущностям, прочим узлам не соответствует никакой номер позиции.
  * Позиции нумеруются начиная с 1.
  * Нумерация производится в порядке обхода дерева (уплощенный список иерархического представления BEMJSON).

Пример нумерации позиций во входном БЭМ-дереве:
%%(js)
{
  block: 'page',         // this.position === 1
  content: [
    { block: 'head' },   // this.position === 1
    { block: 'menu',     // this.position === 2
      content: [ 
        { elem: 'item' }, // this.position === 1
        { elem: 'item' }, // this.position === 2
        { elem: 'item' }  // this.position === 3
      ]
    },
    'text'              // this.position === undefined
  ]
}   
%%

----
!!**NB**!! БЭМ-дерево может быть достроено в процессе выполнения шаблонов с помощью шаблонов по моде %%content%% и шаблонов по пустой моде. Такое динамическое изменение БЭМ-дерева учитывается при вычислении позиции.
----

Функция определения последней БЭМ-сущности среди сиблингов %%this.isLast()%% **не сработает** в том случае, если в массиве, содержащем одноранговые БЭМ-сущности, последний элемент не является БЭМ-сущностью. Например:
%%(js)
{
  block: 'b1',
  content: [
    { block: 'b2' },
    { block: 'b3' }, // this.isLast() === false
    'text'
  ]
}
%% 

Такое поведение объясняется тем, что в целях оптимизации BEMHTML не выполняет предварительного полного обхода БЭМ-дерева. Поэтому в момент обработки блока %%b3%% уже известна длина массива (%%b3%% не является последним элементом), но еще не известно, что последний элемент не является БЭМ-сущностью и не получит номера позиции.

На практике описанный случай некорректного срабатывания %%this.isLast()%% не должен порождать ошибок, так как проверка на первую/последнюю БЭМ-сущность обычно применяется к автоматически сгенерированным спискам сущностей, в которые не имеет смысла включать данные других типов.

==== Контекстно-независимые поля
Все контекстно-независимые поля сгруппированы в объекте %%this._%% и представляют собой вспомогательные функции, используемые при работе шаблонизатора. Автор шаблонов также может пользоваться этими функциями как в теле шаблонов, так и в предикатах.

#|
|| **Поле**| **Тип значения** | **Описание** ||
|| %%this._.isArray(Object)%% | %%Boolean%% | Проверяет, является ли данный объект массивом. ||
|| %%this._.isSimple(Object)%% | %%Boolean%% | Проверяет, является ли данный объект примитивным JavaScript типом. ||
|| %%this._.isShortTag(String)%% | %%Boolean%% | Проверяет, принадлежит ли указанное имя тега к списку коротких тегов (не требующих закрывающего элемента и рекурсивной обработки). Полный список которких тегов: %%area, base, br, col, command, embed, hr, img, input, keygen, link, meta, param, source, wbr%%.||
|| %%this._.extend(Object, Object)%% | %%Object%% | Возвращает хэш, объединяющий содержимое двух хэшей, переданных в качестве аргументов. Если хэши содержат совпадающие ключи, в результат записывается значение из хэша, переданного в качестве второго аргумента. ||
|| %%this._.xmlEscape(String)%%| %%String%% | Возвращает переданную строку с заэкранированными управляющими символами XML (%%[&<>]%%). ||
|| %%this._.attrEscape(String)%%| %%String%% | Экранирует значение управляющих символов для значений XML- и HTML-атрибутов  (%%"[&<>]%%). ||
|#

=== Примеры и рецепты

==== Приведение входных данных к формату, ориентированному на представление
===== Задача
Сформировать входное БЭМ-дерево для страницы френдленты (список постов с указанием информации об авторе), удобное для обработки в терминах шаблонов BEMHTML. Такое дерево должно быть ориентировано на представление, т.е. набор и порядок БЭМ-сущностей должен соответствовать набору и порядку DOM-узлов выходного HTML.

=====Решение
Приведение к формату, ориентированному на представление, должно производиться вне BEMHTML, на уровне подготовки данных в бэкенде. Такой бэкенд обычно работает с нормализованными данными (data-ориентированный формат). В случае френдленты формат исходных данных может быть таким:
%%(js)
{
    posts: [ { text: 'post text', author: 'login' }, … ],
    users: { 'login': { userpic: 'URL', name: 'Full Name' }, … },
}
%%
Данные представлены как два списка объектов разных типов. В списке постов используется только идентификатор пользователя, а полная информация о пользователе находится в соответствующем хеше в списке пользователей.

Формат данных, ориентированный на представление, предполагает денормализацию данных, т.е. развертывание списка постов таким образом, чтобы в каждом посте содержалась полная информация об авторе, даже если в списке присутствует несколько постов одного автора. В BEMJSON подобный формат может выглядеть так:
%%(js)
{
    block: 'posts',
    content: [
        {
            block: 'post',
            content: [
                { block: 'userpic', content: 'URL' },
                { block: 'user', content: 'Full Name' },
                { elem: 'text', content: 'post text' }
            ]
        },
        …
    ]
}
%%

==== Выбор шаблона по условию
===== Задача
Блок %%b-link%% встречается в двух разновидностях: 
  * %%(js){ block: 'b-link', content: 'ссылка без URL' }%%
  * %%(js){ block: 'b-link', url: '//ya.ru', content: 'ссылка с URL' }%%

Необходимо по-разному оформить выходной HTML-элемент в зависимости от наличия/отсутствия поля %%url%% в данных блока.

===== Решение
Следует сделать проверку на наличие поля %%url%% подпредикатом шаблона: выражение %%this.ctx.url%% будет истинным, только если поле %%url%% определено. 

%%(js)
block b-link {
  tag: 'span'
  this.ctx.url {
    tag: 'a'
    attrs: { href: this.ctx.url }
  }
}
%%

**Неправильно** использовать для решения этой задачи условные конструкции JavaScript в теле шаблона:

%%(js)
block b-link, tag: this.ctx.url ? 'a' : 'span'
%%

При компиляции это выражение не будет оптимизировано, что отрицательно скажется на скорости работы шаблона.

**См. также**:
  * ((#shablon1 Синтаксис шаблонов))

==== Наследование
===== Задача
На разных ((http://bem.github.com/bem-method/pages/beginning/beginning.ru.html#Urovnipereopredeleniy уровнях переопределения)) определены два различных шаблона на одну и ту же БЭМ-сущность (%%block b1%%). Каждый из шаблонов определяет своё содержимое по моде %%content%%.

Необходимо на втором уровне переопределения **унаследовать** содержимое, определённое на первом уровне, и добавить дополнительное. Требуется аналог %%<xsl:apply-imports/>%%.

===== Решение
В BEMHTML есть аналог %%<xsl:apply-imports/>%%. Реализация основывается на возможности заново запустить в шаблоне процедуру применения шаблонов к текущему контексту (%%apply()%%). Таким образом можно вызвать тот шаблон, который был определен для данного контекста (БЭМ-сущности, моды и т.п.) ранее или на другом уровне переопределения.

При вычислении выражения %%apply()%% возвращается результат, полученный в ходе применения ранее определенного шаблона. Для избежания бесконечного цикла необходимо добавить подпредикат проверки наличия в контексте какого-то флага (например, %%_myGuard%%), который будет выставлен при выполнении %%apply()%%.

%%(js)
// шаблон на первом уровне переопределения
block b1, content: 'text1'

// шаблон на втором уровне переопределения
block b1, content, !this._myGuard: [
    apply(this._myGuard = true), // получаем предыдущее значение content
    'text2'
]
%%

В результате применения шаблонов к блоку %%b1%% будет получен HTML:
%%(html)
<div class="b1">text1text2</div>
%%

В bem-bl версии 0.3 добавлена конструкция %%applyNext%%, которая автоматически генерирует уникальное имя флага против зацикливания.

%%(js)
block b1, content: 'text1'

block b1, content: [
    applyNext(), // получаем предыдущее значение content
    'text2'
]
%%

**См. также**:
  * ((#applynext Конструкция applyNext))

==== Оборачивание блока в другой блок
===== Задача
Необходимо вложить блок (%%b-inner%%) в другой блок (%%b-wrapper%%) при выполнении шаблона. Таким образом, одному входному блоку будет соответствовать два вложенных друг в друга блока.

===== Решение
При обработке блока %%b-inner%% в шаблоне по моде %%default%% (генерация целого элемента) следует модифицировать фрагмент входного дерева %%this.ctx%%, куда и добавляется блок %%b-wrapper%% и рекурсивно запустить вызов шаблонов по пустой моде %%apply(this._mode = "")%%.

Для избежания бесконечного цикла необходимо при вызове выражения %%apply()%% проверять наличие в контексте специального флага (%%_wrap%%), который будет выставлен при выполнении %%apply()%%.

%%(js)
block b-inner, default, !this.ctx._wrap: apply(
   this._mode = "",
   this.ctx._wrap = true
   this.ctx = {
       block: 'b-wrapper',
       content: this.ctx
   }
)
%%

В bem-bl начиная с версии 0.3 добавлена конструкция %%applyCtx()%%, которая автоматически добавляет флаг от зацикливания, присваивает %%this.ctx%% и применяет шаблоны по пустой моде:
%%(js)
block b-inner, default: applyCtx({ block: 'b-wrapper', content: this.ctx })
%%

----
!!**NB**!! Конструкцию %%applyCtx()%% можно применять для **замены** БЭМ-сущности в исходном дереве, если не использовать исходное содержимое блока (%%this.ctx%%) в аргументе %%applyCtx()%%.
----

**См. также**:
  * ((#applyctx Конструкция applyCtx))

==== Добавление БЭМ-сущностей для задач вёрстки
===== Задача
Необходимо сверстать блок с закруглёнными уголками, работающий во всех браузерах (без использования CSS3).

Входной BEMJSON может быть таким:
%%(js)
{ block: 'box', content: 'text' }
%%

Реализация уголков требует добавления к блоку четырех дополнительных элементов. Поскольку данные элементы отражают детали HTML-верстки, ими не следует загромождать входное БЭМ-дерево. Добавить эти элементы следует на уровне BEMHTML-шаблона. Финальное БЭМ-дерево должно выглядеть так:
%%(js)
{
    block: 'box',
    content: {
        elem: 'left-top',
        content: {
            elem: 'right-top',
            content: {
                elem: 'right-bottom',
                content: {
                    elem: 'left-bottom',
                    content: 'text'
                }
            }
        }
    }
}
%%


===== Решение
Для модификации входного БЭМ-дерева на уровне BEMHTML потребуется написать шаблон по моде %%content%% для блока %%box%%. Подмена фрагмента входного БЭМ-дерева (добавление необходимых элементов) выполняется с помощью конструкции %%applyCtx()%%, а подстановка исходного содержимого — с помощью конструкции %%applyNext()%%
BEMHTML-шаблон, выполняющий это преобразование:
%%(js)
block box, content: applyCtx({
    elem: 'left-top',
    content: {
        elem: 'right-top',
        content: {
            elem: 'right-bottom',
            content: {
                elem: 'left-bottom',
                content: applyNext()
            }
        }
    }
})
%%


В bem-bl начиная с версии 0.3 добавлен короткий синтаксис для применения шаблонов по моде:
%%(js)
block b-source, default: apply("", this.ctx.block = 'b-target')
%%

**См. также**:
  * ((#apply Конструкция apply))
  * ((#applynext Конструкция applyNext))
  * ((#applyctx Конструкция applyCtx))

==== Использование позиции БЭМ-сущности
===== Задача
Необходимо пронумеровать пункты меню, начиная с 1. В текст каждого элемента меню нужно добавить его порядковый номер с точкой.

===== Решение
Используем механизм вычисления позиции БЭМ-сущности среди сиблингов (поле контекста %%this.position%%).
Входные данные могут выглядеть так:
%%(js)
{
  block: 'menu',
  content: [
    { elem: 'item', content: 'aaa' },
    { elem: 'item', content: 'bbb' },
    { elem: 'item', content: 'ccc' },
  ]
}
%%

Для выполнения нумерации следует написать шаблон по моде %%content%% на пункт меню, в котором содержание элемента будет составлено из номера позиции, разделителя (точки с пробелом) и исходного текста элемента (полученного с помощью конструкции %%applyNext()%%): 
%%(js)
block menu {
  tag: 'ul'
  elem item {
    tag: 'li'
    content: [
      this.position, '. ',
      applyNext()
    ]
  }
}
%%

**См. также**:
  * ((#content Мода content))
  * ((#applynext Конструкция applyNext))

==== Проверка подпредикатов в определенном порядке
===== Задача
Необходимо проверять подпредикаты шаблона в строго определенном порядке, например, сначала проверить наличие в контексте объекта %%this.world%%, а затем проверить значение поля в этом объекте %%this.world.answer%%.

===== Решение
Воспользуемся тем, что подпредикат шаблона BEMHTML может быть произвольным JavaScript-выражением и запишем его в следующей форме:
%%(js)
(this.world && this.world.answer === 42)
%%

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




==== Связывание HTML-элементов по id
===== Задача
Необходимо для входного блока %%input%% сгенерировать пару HTML-элементов %%<label>%% и %%<input>%%, так чтобы значение атрибута %%input@id%% было сгенерировано автоматически, уникально и совпадало со значением атрибута %%label@for%%.

Входные данные могут выглядеть так:
%%(js)
{
  block: 'input',
  label: 'My Input',
  content: 'my value'
}
%%

===== Решение
Для генерации уникального идентификатора, подходящего в качестве значения атрибута %%id%%, воспользуемся вспомогательной функцией контекста %%this.generateId()%%. Чтобы сгенерировать два HTML-элемента на основании одного входного блока, потребуется два шаблона:
  * шаблон по моде %%tag%%, указывающий пустую строку, чтобы отменить генерацию HTML-элемента для данного блока, но обработать содержимое;
  * шаблон по моде %%content%%, в котором будут сформированы два необходимых элемента и их атрибуты.

%%(js)
block input {
  tag: ''
  content: [
    {
      tag: 'label',
      attrs: { 'for': this.generateId() },
      content: this.ctx.label
    },
    {
      tag: 'input',
      attrs: {
        id: this.generateId(),
        value: this.ctx.content
      }
    }
  ]
}
%%

=== Источники
Сборник видео:
http://clubs.ya.ru/bem/posts.xml?tag=64664080

Рассказ на пЯТЬнице про BEMHTML
http://clubs.ya.ru/bem/replies.xml?item_no=898

Рассказ про XJST:
http://clubs.ya.ru/bem/replies.xml?item_no=899

"BEMHTML. Not yet another шаблонизатор".
Чем шаблонизатор BEMHTML отличается от сотен других шаблонизаторов и почему мы используем именно его.
http://clubs.ya.ru/bem/replies.xml?item_no=1153
http://clubs.ya.ru/bem/replies.xml?item_no=1172

Шаблонизатор, работающий с несколькими уровнями
http://clubs.ya.ru/bem/replies.xml?item_no=1391

Предварительная документация
http://clubs.ya.ru/bem/replies.xml?item_no=992
http://bem.github.com/bem-bl/pages/bemhtml-syntax/bemhtml-syntax.ru.html

bem-bl: http://bem.github.com/bem-bl/index.ru.html