Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
904 lines (700 sloc) 75.2 KB

Предисловие

Если вы хотя бы немного в курсе, что такое HTML, CSS, Javascript, суть нашей придумки вы ухватите так же легко, как ребёнок запоминает лицо матери, то есть без каких бы то ни было особенных умственных усилий. Потому что BEViS - это очень просто.

В добрый путь?

Блок

Начнём со странного :)

Представьте себе взвод солдат. Взвод - это сила, особенно, если это взвод специально обученных солдат:). Точно так же, как один солдат представляет собой минимальную единицу армейской силы, блок представляет собой минимальную единицу WEB-сайта. Блок - это кусок WEB-страницы, который выполняет какую-то очень понятную функцию, например, формирует логотип сайта. Давайте (пока) думать, что блок - это фрагмент HTML-кода и связанные с ним CSS-правила.

Но вернёмся ко взводу. Взвод может быть укомплектован "одинаковыми" солдатами, например, все как один пехотинцы, а может состоять из бойцов разных подразделений. WEB-страница — это скорее взвод второго типа, состоящий из разношёрстных блоков, каждый из которых отвечает за свою функцию: один, к примеру, формирует логотип на странице, другой — меню, третий — подвал, форму авторизации. Да мало ли что.

Задайте нам вопрос: "Когда я создаю страницу, как понять, что считать блоком, а что блоком считать недостойно?"

А мы сразу и ответим. Солдат стреляет рукой, а на спусковой крючок жмёт указательным пальцем. Можно ли считать, что палец может выполнять свою функцию в отрыве (в прямом и переносном смыслах) от остального тела? Перефразирую вопрос. Можно ли считать палец минимальной единицей армейской силы?

Здравый смысл подсказывает: нельзя. Но в вёрстке не как в бою — только вы один решаете, что будет блоком на вашем сайте. Если вам захочется, то и палец у вас будет получать приказы командира и сам давить на гашетку. Решать только вам :)

Что касается нас, мы считаем, что палец, как и рука, как и нога - неотъемлемые части солдата. Элементы. Мы подошли к новому термину - элемент блока.

Непонятно? И правда, давайте ближе к HTML.

На вашей странице есть форма авторизации: поле логина, поле пароля и кнопка отправки данных. Форма представлена в HTML тегом <form>, поля — тегами <input>, кнопка — тегом <button>. У формы одна задача - собрать в себя данные и отправить на сервер. Поэтому давайте считать, что этот кусок HTML - отдельный блок. Все мы в школе проходили информатику. Лично меня учили прежде всего составлять алгоритмы. Я вам предлагаю сейчас нечто аналогичное. Давайте каким-нибудь простым (несуществующим) языком опишем наш блок.

Кажется, что для работы формы авторизации нам нужно знать только две вещи:

  • какая форма нам нужна
  • куда форма передаёт данные
block: "form-auth"
url: "http://someUrl.php"

Это как с солдатом. Командир зовёт нужного бойца (block: 'form-auth') и говорит ему стрелять в "ту сторону" (url:'http://someUrl.php').

А форма сама должна решать, какое поле принимает логин, какое поле принимает пароль. А солдат сам выбирает, какой рукой стрелять - левой или правой.

Стало понятнее? Не будем сейчас заострять внимание на элементах, об этом чуть позже будет раздел.

Итак, блок - это блок, который делает какую-то понятную однозначную вещь. Что тут можно ещё добавить? Даже если вы не знакомы с "методологиями" web-разработки, вы конечно же используете в своей верстке блоки, только вполне возможно, что называете их иначе. Или вообще не называете, потому что надобности в этом не испытываете :)

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

Всё верно. Я предлагал вам думать о блоке, как о куске HTML и CSS, чтобы легче погрузиться в BEViS. Никаких сомнений, вы умеете писать теги и стилизовать их через CSS. Несомненно так же и то, что прочитав этот документ, вы в совершенстве овладеете Бивисом, потому что Бивис сильно похож на олдскульный способ верстки; потому что все знания о Бивисе в этом документе описаны понятным языком с уместными аналогиями из бытовой жизни; а ещё по одной важной причине — мы будем часто проводить параллель между Бивисом и хорошо известными вам областями технического знания, как например, HTML и CSS. "Сравнение отличий и выявление общих черт" - неиссякаемый источник новых знаний :)

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

Важно научиться думать о блоке как о логической единице. А уж как он там написан, на чём (на HTML, CSS и JS или вообще на каком-то мета-языке) - это "детали реализации" (с).

И если научиться смотреть на страницу и видеть её не в HTML-тегах, а именно в блоках (примерно, как Нео в конце первой части "Матрицы"), тогда очень быстро становится ясно, что HTML - не самая удобная технология для описания WEB-страниц. И нужно придумать другой способ описывать страницы — другой язык, удобный именно для блочной вёрстки (не той блочной вёрстки, от которой лихорадило интернет лет восемь назад, а именно блочной - модульной верстки). И да, такой язык мы придумали, и называется он btjson:

btjson = [B]EViS [T]emplater [JSON]

Стоп, ерунда какая-то непонятная. Какой "язык"? Что за чушь? Где HTML-теги?

Нет же, не чушь. Вам всё это знакомо. Смотрите.

###Какие мы знаем способы верстать сайты?

  1. Можно сверстать статическую страницу, например page.html и положить её на сервер. Когда пользователь вашего сайта запросит её в браузере, сервер отдаст её такой, какой вы её сверстали — статическую страницу из сплошных HTML-тегов. Это может быть страница с контактными телефонами. Или с адресом.

  2. Но если вы хотите на странице отображать динамические данные, которые хранятся в базе данных, тогда мы создаём динамическую страницу, например page.php, и опять же кладём на сервер. Внутри такой страницы мы пишем уже не чистые HTML-теги, а некие управляющие конструкции типа:

<?php
    if ($a > $b) {
        echo "<div>";
        echo getDataFromDataBase();
        echo "</div>";
    }
?>

А дальше просто - пользователь позовёт эту страницу в браузере, сервер запустит PHP-парсер, который обработает page.php, сделает запрос в базу данных, получит оттуда данные, вставит их в page.php, сгенерит HTML-код и отдаст назад в браузер пользователю.

Есть ещё какие-то способы? Если и есть, то все они — частные случаи второго способа. Вам знакома вторая схема? Всякому знакома вторая схема. Ну, так мы её в BEViS и не поменяли ;)

Мы предлагаем вам точно так же генерить конечный HTML динамически. Разница с PHP лишь в том, что в BEViS это делается удобно и естественно. Заметьте, мы говорим не "удобнее и естественнее, чем в PHP", а просто — "удобно и естественно". Чувствуете разницу? :)

Чтобы на странице отобразилась форма авторизации, вы просто декларируете блок (ключевое слово - "просто")

{
    block: "form-auth"
    url: "http://someUrl.php"
}

Эта декларация каким-то образом превратится в нужный HTML с динамическими данными. Всё. И так остальные блоки.

Вам пока непонятно, как из этого получается HTML. Об этом позже. Пока мы должны твёрдо понять, что вместо того, чтобы создавать статическую страницу page.html или динамическую page.php, мы в BEViS создаём динамическую страницу page.btjson.js (на расширение .js не заостряйте внимания, не важно). А в ней вместо перечисления всех нужных HTML-тегов, лаконично объявляем одни только блоки (ключевое слово "лаконично"), из которых состоит наша WEB-страница. А дальше некий парсер читает наш btjson и строит в памяти динамический HTML, который отсылается в браузер пользователю. Как видите, мы не придумывали новой схемы и вам не придётся перестраивать мышление для того, чтобы понять BEViS :)

Но тут вы должны воскликнуть (в Яндексе это прям традиция - задавать такой вопрос): "Опа, так это же новый шаблонизатор? Ну, начинается..."

А мы на это ответим: "Ну, да. Новый быстрый, понятный, лаконичный, надёжный, полностью документированный и покрытый тестами шаблонизатор. Плюс к нему прилагается быстрая система сборки. Вдобавок ко всему сервер для разработки. Как бонус — сильный хелпер для написания клиентских javascript-нужд. И мы честно признались в том, что написали шаблонизатор, когда несколько абзацев выше вам говорили, что bt произошёл от слов BEViS Templater". Ну что, с этим разобрались, двигаемся дальше?

Страницу мы описали блоками, блоки описали с помощью btjson-а. Это понятно. Дальше что? Btjson отдаётся на разбор некоему парсеру. Некий парсер - это и есть BT. Относитесь к BT, как к PHP-парсеру, если вам так понятнее. Вообще-то BT написан на Javascript. Это серверное javascript-приложение, работающее на Node.js. У него одна простая задача: пройтись по btjson-странице, прочитать там все блоки, описанные в btjson-формате, и для каждого блока вызвать шаблоны, которые сгенерят HTML-блока.

bt.match('form-auth', function(){
    // Здесь ваш блок превращается в `HTML`-код
});

— Шаблоны? Ну, начинается! — воскликнули вы.

Мммм, если вы не писали на XSLT, вам точно непонятно. Но вы же писали на CSS! Тогда вы легко поймёте, что шаблоны в XSLT и в BT - то же самое, что селекторы в CSS. И пишутся они похожим образом. Что мы имеем в виду?

Вы понимаете этот код?

.header .logo {
    width: 200px; 
    height: 200px
}

Конечно, понимаете, зачем спрашивать очевидное :) Логотип приобретёт размеры 200px только если он:

  1. на странице есть

  2. и находится внутри блока .header

Если логотипа нет (или он есть, но не в шапке), стилевые свойства ширины и высоты не применятся. Для вас это само собой разумеется. Ну если так, тогда поздравляю — вы уже знаете, что такое декларативные языки программирования :)

XSLT и CSS - примеры декларативных языков. В них нет управляющих конструкций, типа if-else, как в PHP. Что там есть, так только декларации поведения при совпадении каких-то условий, типа как .header .logo{}

Только в CSS такая декларация зовётся селектором (от английского to select), потому что селектор как бы выбирает блоки, к которым нужно применить стилевые свойства, а в других декларативных языках эта же декларация зовётся шаблоном (трудно сказать почему). И ещё говорят, что шаблон матчится на блок (от английского to match, что переводится, как "подбирать", "приводить в соответствие"). Кстати to select имеет те же самые значения, что и to match. То есть это равнозначные слова с одинаковым смыслом :)

Теперь мы знаем, что процесс матчинга - по сути и есть селекция, выбор, проверка совпадения условий в селекторе (матчере). То же самое, что вы делаете, когда пишете CSS-стили.

Термины "шаблон" и "матчинг" лично мне знакомы из XSLT, да и многим из нас тоже. XSLT - великая школа :) Чтобы не создавать новый словарь терминов, в BT используются ровно те же самые термины.

bt.match('form-auth', function(){
    // Здесь ваш блок превращается в `HTML`-код
});

Мысленно наложите на этот код ваши знания о CSS-селекторах. Суть та же: если есть на странице блок form-auth, выполни для него функцию, переданную вторым аргументом. А в той функции мы специальным образом можем построить любое HTML-дерево блока. А если блока такого на странице нет, не произойдёт ровным счётом ничего, как и в CSS. Разобрались?

Что такое bt-шаблоны и как их писать - это пока неважно. Это опять же детали реализации, давайте в неё не вдаваться, будем мыслить блоками. Единственное, что мы сейчас запомним, что шаблоны - это Plain Valid Javascript и они генерят не стилевое представление (как это делает CSS-селектор), а HTML-структуру (как это делали ваши PHP-инструкции).

Подошло время подробно познакомиться, что такое BEViS-блок, чем он представлен на файловой системе и из каких частей он состоит.

Блок - триедин. Блок — это то, из чего он состоит (скелет); то, как он выглядит (внешность); и то, как он себя ведёт (поведение). Три составляющие. Ничего нового. В окружающей нас жизни схожее устройство имеют большинство предметов и это вовсе не случайно. Мудрецы подметили у Природы закон композиции и используют его, чтобы создать что-то приближённое к природе - что-то натуральное и жизнеспособное. Этот закон используется в изобразительном искусстве, в литературе, в музыке. И не только в творчестве. Архитектура, гидромелиорация, медицина, сайтостроительство, наконец. Всё долговечное и жизнеспособное, что сделал человек, отвечает закону композиции. Закону трёх частей.

Но я боюсь дальше развивать тему всех затронутых специальностей, поскольку не являюсь специалистом в них, кроме, пожалуй, одной. Поэтому, давайте сузим беседу и сведем все аналогии к теме, близкой каждому из нас — к нам самим ;)

Если сравнить анатомо-физиологическое устройство человека и устройство блока, то можно обнаружить схожие черты:

  1. Структура. У человека есть скелет и мышцы, у блока — HTML-разметка.

  2. Внешний вид. У человека это рост, вес, цвет кожи и выражение лица :) У блока - CSS-стили.

  3. Поведение. У человека это привычки и социальная активность. У блока - JS-интерактивность на странице.

Есть и ещё схожие моменты. Например, почти у каждого человека есть дом - место, откуда он выходит утром и куда возвращается вечером. У кого-то это частный дом, у кого-то квартира, а кто-то своим домом считает рабочий офис. Зависит от человека.

У блока тоже есть свой дом - место, где блок отдыхает и ждёт, когда его "позовут поработать" в веб-странице. В корне проекта есть директория /blocks, в ней живут все блоки. Только в ней. Это дом блоков. Не ищите других мест. Если блока здесь нет, больше нет нигде.

Тут нужно оговориться. Бивис - не догма. Его можно использовать, как мы придумали (все блоки в одной папке), но какая-то Команда может решить, что блоки нужно распылять по нескольким директориям. Как мы можем запретить это? Да и зачем, если кому-то так нравится больше? Пусть. Мы лишь рекомендуем хранить блоки в одной папке.

Вы открыли /blocks и увидели там поддиректорию form-auth. Это дом блока. Каждый блок на файловой системе представлен отдельной директорией, а в ней хранятся какие-то файлы, которые относятся конкретно к этому блоку (какие - об этом позже). Важно сейчас то, что блок легко искать по его имени и на файловой системе проекта, и в btjson-описании блока и в сгенерённом HTML-коде блока.

Я уже упоминал, скажу ещё раз. Когда мы общаемся с человеком, мы не думаем о том, как он устроен внутри - из каких костей и мышц. Или из чего другого. Это всё скрыто за внешностью и поведением. И это прекрасно. Я не представляю, как могла бы на планете Земля зародиться любовь, если бы человеку приходилось всё время помнить о сферических желеобразных телах вместо глаз. Бррр...

Вот и с блоками на web-странице должно быть ровно так. Когда мы "общаемся" с блоком (вставляем его на страницу или обращаемся к нему из другого блока), нам не надо знать, ни как он устроен, ни сколько у него детей. Вам нужно знать только его имя.

Ведь правда же, чтобы пригласить друга к себе домой в гости (а он вообще-то женат и у него двое детей) — вы зовёте друга по имени и говорите: "Марат, а давай вечером к нам в гости, жена пирог с яблоками испечёт". Вам нет нужды приглашать отдельно друга, отдельно его жену и ещё каждого его ребенка персонально. Он сам приведёт всех, будьте уверены :)

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

{
    block: "form-auth"
}

Причём оно может быть простым — просто Марат, или просто Костя, или просто form-auth. А может быть более точным. С фамилией — например Марат Дулин, или Костя Иконников, или form-auth_yandex. Чтобы добавить в имя уникальности.

Например, Аркадиев в мире сотни тысяч. А вот Аркадий Волож — гораздо более редкое сочетание (правда же, жизнь доказывает, что имени и фамилии достаточно для идентификации человека? У славян есть ещё и отчество, но, в принципе, двух достаточно, если, конечно, ваше имя не Иван Иванов)

Когда мы зовём block: 'form-auth', мы зовём наш блок по имени. Обратите внимание, имя блока может быть само по себе достаточно подробным, если записать его несколькими словами через дефис. Но если мы хотим добавить ещё больше уникальности, мы добавляем здесь же "фамилию" через знак одиночного подчеркивания: {block: 'form-auth_yandex'}. Читать это следует так: создай на странице форму авторизации для логина в Яндекс. Пример этот выдуманный, служит исключительно для иллюстрации специфичного имени блока. Такой формы не существует. Но если бы существовал, то вполне мог бы превратиться в следующий HTML:

<form class="form-auth_yandex">
    ....
</form>

Важный момент: строка, которую вы видите в CSS-классе - это имя блока, необходимое для представления, отображения внешнего вида блока. У блока есть ещё и "фамилия", которую мы называем view - ведь, по сути, фамилия - это вариант отображения блока.

Представим, у нас есть форма авторизации:

{block: "form-auth_yandex"}

Форм авторизации на странице мы можем сверстать несколько. Каждой можем захотеть дать имя form-auth. Но если мы хотим точно указать специфичность одной из них, мы говорим, что нужна форма авторизация в яндексе:

form-auth_yandex - это:

  • form-auth - имя блока
  • yandex - вью блока

И тогда к блоку применятся CSS-правила, написанные специально для "формы авторизации в Яндексе", а не для "формы авторизации вообще".

Теперь об именах блока подробнее.

###Имя блока Итак, у нас есть блок. Пусть это будет форма авторизации. Или нет, лучше пусть это будет шапка. А вообще-то, не важно. Какой блок ни возьми, сколько у него может быть имён? Странный вопрос мы задали, правда? Одно, конечно. Несколько имён у блока - это абсурд. Что это за супер-блок, который словно из той глупой присказки про "я и лошадь, я и бык, я и баба, и мужик"? В обычной жизни не бывает так, чтобы человек носил несколько фамилий одновременно. Конечно, шпионы имеют несколько паспортов и фальшивых имён, но шпионы живут не в обычном мире, а в очень специфическом. Есть, правда, и в обычном мире двойные фамилии — Немирович-Данченко, Титула-Бойченко, Лебедев-Кумач. Но даже двойные представляют собой единое целое.

К чему это всё? К тому, что в Бивисе блок не может иметь второго имени. Такого, как в примере ниже, быть не может. Не должно такого быть, по нашему разумению:

class="form-auth header"

Не может блок быть одновременно и шапкой и формой авторизации, как худой человек не может одновременно сесть на два стула с посадочной площадкой 60 сантиметров.

Это утверждение выглядит очевидным и естественным. Но в других мирах есть прецеденты, которые мы считаем неудобными. В тех мирах блоки часто садятся на один стул (и как-то сидят). Там можно к одному блоку примиксовать на одной DOM-ноде другой блок (class="form-auth header") и получить гибрид - HTML-теги придут от "form-auth", а CSS-стили придут от обоих.

В CSS нет надёжного механизма разруливания весов стилевых селекторов. Какой селектор позже записан, тот и применится к тегу. В нашем случае, если в стилевом файле селектор .header {border-color: red} записан позже селектора .form-auth {border-color: green}, то блок окажется окружён красным бордером А если вдруг селекторы придут в обратном порядке - вокруг блока будет зелёный бордер. А приходить они могут в разной последовательности, когда у вас динамическое построение CSS-файла.

Когда мы смешиваем два блока на одной HTML-ноде, нет способа влиять на эту ситуацию, нет возможности контролировать её. Управлять ей. Точнее, он есть, но он вообще не гарантирует результат — надо загружать стилевые селекторы в "правильном" порядке, собирать CSS-файл в "правильном" порядке.

А правильный — это какой? Как понять, в каком порядке, если есть возможность смешать два произвольных блока в произвольном порядке? А если три блока? Или четыре? Количество сочетаний блоков на одной простой странице исчисляется тысячами. Точно ли разработчик сможет учесть всё многообразие сочетаний? Сможет?

В других мирах это пытаются решать зависимостями. Например, пишут специальный файл, в котором указывают, какие блоки должны загружаться ДО этого блока, а какие ПОСЛЕ.

В BEViS мы отказались от смешивания блоков друг с другом. Нет миксов блоков на одной ноде - нет конфликтов. Стабильность и надёжность.

Итого, в BEViS всё однозначно. Блок может иметь только одно имя. Внешний вид блока определяется представлением блока, которое тоже является частью имени блока. Что-то ещё нужно добавлять? Кажется, нет.

###Файловое устройство блока Каждый блок хранится в своей директории. Это мы уже знаем. Так как блок состоит из трёх сущностей (напомню - структура, представление и поведение), то и на файловой системе мы эти сущности выделяем в отдельные файлы.

blocks/
├── form-auth/
    ├── form-auth.css   // в этом файле описываются стили, которые разукрашивают блок
    ├── form-auth.js    // здесь программируется интерактивное поведение блока
    └── form-auth.bt.js // в этом файле описываются шаблоны, которые строят `HTML`-структуру блока

Тут нужно запомнить.

  1. Если в имени файла есть только "имя блока + расширение js" — form-auth.js - это файл, в котором описаны js-функции, "оживляющие" блок в браузере пользователя

  2. Если всё то же самое, только в середине ещё и суффикс btform-auth.bt.js - в этом файле описаны js-шаблоны, которые строят HTML-код блока на сервере (и потом отправляют в браузер пользователю)

  3. Ну и третье, сразу карты на стол. Мы не пишем чистый CSS-код, мы используем препроцессоры. Вот прямо сейчас используем Stylus, поэтому на файловой системе в Бивисе нет CSS файлов — вместо них styl-файлы, например form-auth.styl. Но об этом пока не думайте, не робейте: препроцессоры - этот тот же любимый CSS, только чуть-чуть удобнее и легче :)

В-общем, у самого простого блока обязательно есть bt.js файл и CSS файл. А вот js файла вполне может не быть, потому что без интерактивности блок может жить на странице. Это без структуры и оформления - никуда.

Только блоки имеют своё отображение на файловой системе. Это мы заранее ответили на вопрос: "Как блок отличается на fs от неблока?"

"Хорошо", — скажете вы.— "Теперь я знаю, как устроены блоки на файловой системе, как они декларируются на странице и примерно представляю, что существуют некие шаблоны, которые из btjson-декларации блока создают HTML-теги. Как это помогает мне создавать HTML-страницы?"

###Как это всё работает? Давайте на примере. Пусть наша страница main.btjson.js состоит из двух btjson-блоков:

[
    {block: 'header'},
    {block: 'footer'}
]

Этот пример условный, но вполне для иллюстрации достаточный. Да, мы описали страницу в виде массива из двух json-объектов, которые называем btjson-блоками. Мы эту страницу написали и сохранили в директории /pages/main. Можно и в другой папке, если вам хочется. Мы сохраняем здесь.

Нам нужно, чтобы из этого мета-языка сформировался HTML-код, который сервер будет отдавать в браузер клиенту. И вместе с этим HTML сервер должен возвращать CSS-код и JS-код. Что ещё? Вроде, ничего.

Схема взаимодействия браузера и сервера примерно такая:

  1. В адресную строку в браузере пользователь вводит http://my-server/main.html.

  2. Браузер отправляет http-запрос к серверу и ждёт страницу main.html

  3. Сервер (это наше node.js приложение, но об этом не сейчас) принимает запрос. Понимает, что нужно создать страницу maih.html и поэтому он открывает на чтение файл /pages/main/main.btjson.js

  4. После этого он парсит main.btjson.js (анализирует каждый элемент btjson-массива и запоминает из каких блоков будет построена будущая HTML-страница)

  5. После этого сервер запускает ENB — специальную программу-файлосборщик, которая нужна исключительно для сборки (чёрт, это же всем очевидно из названия, зачем это писать?) файлов. Об этой программе мы расскажем подробнее позже. На этом этапе, когда сервер принял запрос, ENB начинает с того, что создаёт пустые файлы

  • /pages/main/main.css,
  • /pages/main/main.js,
  • /pages/main/main.bt.js

Если такие файлы уже есть, ENB пропускает этот шаг и переходит к следующему.

  1. Дальше ENB получает от сервера на вход имя первого блока — "header". ENB идёт на файловую систему проекта, находит в папке /blocks директорию /blocks/header и заходит в неё.

  2. Ищет файл header.css. Если он есть - копирует его содержимое в /pages/main/main.css. Делает то же самое для js и bt-файлов, создавая /pages/main/main.js и /pages/main/main.bt.js.

  3. Выходит из /blocks/header и заходит в /blocks/footer и делает то же самое.

  4. В результате работы сборщика файлы main.bt.js, main.css, main.js заполнены BT-шаблонами, CSS-селекторами и JS-скриптами, необходимыми для генерации HTML обоих блоков, для стилизации обоих блоков и для программирования js-поведения обоих блоков. То есть ENB занимается тем, что создаёт страничные файлы. Страничные от слова "страница" (или пейджовые от слова "page").

  5. Это почти всё, стилевой и яваскриптовый файлы готовы к отправке в браузер, но мы не можем пока отправлять, потому что у нас не готов конечный HTML страницы. Поэтому ENB отключается, и сервер передаёт инициативу другой программке, с которой мы уже знакомы — BT.

  6. BT принимает на вход наш btjson (с декларацией шапки и подвала) и "накладывает на него" только что сгенерённый main.bt.js. Напомню, процесс "наложения" - это почти то же самое, что происходит в CSS. Трансформация. Превращение btjson-а в HTML-теги. В результате, в памяти сервера формируется HTML-код шапки и подвала, которые вставляются в обязательные теги, получается примерно такое:

<!DOCTYPE HTML>
<HTML>
    <head></head>
    <body>
        <div class="header" />
        <div class="footer" />
    </body>
</HTML>
  1. Всё, это финал. BT создал HTML, ENB собрал CSS и JS. Сервер отправляет всё это назад в браузер по HTTP-протоколу.

  2. И ура! В окне браузера у пользователя отобразилась наша страница.

Теперь вы представляете, как работает Бивис-приложение. Поэтому можно углубляться.

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

Вообще-то мы уже рассказывали про элементы, только не акцентировали ваше внимание. Помните руку и палец на руке, которым солдат стреляет? Палец и рука - это элементы. И смотрите — очень важная деталь — палец может быть толстым или худым, длинным или коротким, это неважно вообще. Никому нет до этого дела. Важно только то, как солдат этим пальцем управляется. Солдату отдают приказ стрелять, и он стреляет. И вообще неважно, нажимает он на спуск указательным пальцем или средним или обеими сразу. Никто в здравом уме не отдаёт приказ солдатскому пальцу. Это, во-первых, неестественно, а во-вторых, расточительно в условиях боя. Командиру что, нужно помнить, кто каким пальцем стреляет? Знать эти пальцы наизусть, что ли? Ну, бред же. Все эти нюансы от командира спрятаны за... интерфейсом, который предоставляет ему солдат. Солдат умеет стрелять — всё! Иди и стреляй.

Так и работают элементы в BEViS. Элементы блока в BEViS недоступны для манипулирования. Вы можете пользоваться блоками из BEViS и вообще никогда не задумываться, что внутри блоков, оказывается, есть элементы.

То есть в шаблонизаторе элемент блока не вызывается никак. Из каких элементов строится конкретный блок, знает только сам блок, а если точнее, то конкретный view блока. И это определяется не только с помощью view (который вы передали в btjson), а ещё и с помощью параметров (мы ещё их называем опциями). Получая опции в bt-шаблоне, блок будет сам решать, из каких элементов строить самого себя.

Этим мы защищаем верстку блока от неконтролируемого многообразия, которое возникает, если разрешить смешивать блоки с элементами и модификаторами в непредсказуемых комбинациях.

Вернемся к форме авторизации. Мы её описали очень лаконично:

{
    block: "form-auth"
    url: "http://someUrl.php"
}

Здесь ни слова не сказано о том, какие input выливать и каким тегом генерить кнопку - тоже тегом <input> с type="submit" или же тегом <button>. Всё правильно, так задумано. Детали реализации блока спрятаны за интерфейсом блока.

Вам, как командиру, нет нужды знать какой рукой стреляет ваш боец. Вы отдали приказ — солдат выстрелил. Только солдат знает, что делать с вашим приказом. Это его личное (можно сказать, интимное, приватное, если говорить заимствованным из английского языка словом) дело. Только ваш блок знает, в какой HTML должен превратиться его JSON.

Как он это знает? Как строится нужное HTML-дерево? За это отвечает BT-шаблон блока, который я показывал выше.

bt.match('form-auth', function(){
    // Здесь ваш блок превращается в HTML-код
});

Именно здесь мы будем строить HTML и именно здесь будем решать, какие теги выливать.

И давайте уже наконец что-нибудь сверстаем и всё-всё увидим на примерах. Что хотите верстать? Шапку хотите? Или форму авторизации? Ок, давайте шапку.

Cоздадим содержимое блока

Из чего состоит наша шапка? Из логотипа и заголовка с названием сайта? Хорошо, пусть так. Такая вот простая, незатейливая шапка. Но даже если бы мы придумали сложную структуру, мы бы всё равно декларировали её максимально просто:

{block: "header"}

Давайте же превратим наш BTJSON в старый добрый HTML. Напишем шаблон:

bt.match('header', function (ctx) {
    ctx.setTag('div');
});

Этот шаблон применится к блоку header и превратит его в HTML:

<div class="header"></div>

Тут всё просто, сказали setTag('div') - вылился тег div. Передали бы в аргумент этого метода другой тег - вылился бы другой. Но это неинтересно. Как будем создавать логотип и заголовок-название? Смотрим:

bt.match('header', function (ctx) {
    ctx.setTag('div');
    ctx.setContent([
        {elem: 'logo'},
        {elem: 'title'}
    ]);
});

Блок говорит: "А вообще-то я состою из двух элементов. Это мой контент". На выходе получаем:

<div class="header">
    <div class="header__logo"></div>
    <div class="header__title"></div>
</div>

То есть метод setContent() делает... Вообще-то из названия понятно, что он делает. BT тем и хорош, что его методы имеют очевидные интуитивно-понятные имена. Каждый метод делает только то, что заявлено в его имени.

Наш HTML улучшается, но всё ещё не тот. Мы хотим, чтобы логотип был ссылкой, а название сайта - заголовком. Расширяем наш пример:

bt.match('header', function (ctx) {
    ctx.setTag('div');
    ctx.setContent([
        {elem: 'logo'},
        {elem: 'title'}
    ]);
});

bt.match('header__logo', function (ctx) {
    ctx.setTag('a');
});

bt.match('header__title', function (ctx) {
    ctx.setTag('h1');
});

Результат:

<div class="header">
    <a class="header__logo"></a>
    <h1 class="header__title"></h1>
</div>

Уже лучше. Но в ссылке не хватает атрибутов. Добавим. Используем метод setAttr():

bt.match('header__logo', function (ctx) {
    ctx.setTag('a');
    ctx.setAttr('href', '/');
});

Проверяем:

<div class="header">
    <a class="header__logo" href="/"></a>
    <h1 class="header__title"></h1>
</div>

Осталось малость - установить контент логотипу и заголовку. Сначала займёмся заголовком.

У вас будет один и тот же заголовок в шапке на всех страницах? Тогда хардкодьте контент:

bt.match('header__title', function (ctx) {
    ctx.setTag('h1');
    ctx.setContent('Мой суперский сайт!');
});

Или заголовок может быть разным на разных страницах? Тогда хардкодить нельзя. Тогда нужно использовать опции.

Опции. Новое понятие. Это необязательные параметры в BTJSON-описании блока. Сейчас поймём на примере. До сих пор мы деклариовали шапку очень лаконично:

{block: "header"}

Нам этого хватало. В действительности, такой декларации может хватать половине блоков на реальной боевой странице сайта. Но вдруг нам понадобилось задавать статический контент в зависимости от страницы. Предположим, на вашей главной странице нужен заголовок "Мой суперский сайт!", а на странице поиска по сайту он должен звучать как "Найдётся всё!". Декларируем btjson шапки для страницы поиска:

{
    block: "header",
    text: "Найдётся всё!"
}

И нам осталось усовершенствовать bt-шаблоны. Я временно исключу из примера шаблон для логотипа. Для наглядности:

bt.match('header', function (ctx) {
    ctx.setTag('div');

    var currentTitleText = ctx.getParam('text');
    ctx.setContent([
        {elem: 'logo'},
        {
            elem: 'title',
            titleText: currentTitleText
        }
    ]);
});

bt.match('header__title', function (ctx) {
    ctx.setTag('h1');

    var text = ctx.getParam('titleText');
    ctx.setContent(text);
});
  1. В шаблоне блока мы читаем параметр text из BTJSON-а и сохраняем его значение в переменной currentTitleText
  2. Потом блок говорит: "А вообще-то внутри меня есть элемент title, а у него есть своя опция/параметр titleText, которой я установлю значение из переменной currentTitleText
  3. Потом в шаблоне элемента header__title мы читаем опцию элемента titleText и передаём в контент элемента.

В результате в title придёт нужная строка:

<div class="header">
    <a class="header__logo" href="/"></a>
    <h1 class="header__title">Найдётся всё!</h1>
</div>

Осталась ссылка. А что в ней вы хотите видеть? Если текст, то поступаем, как с заголовком — можно добавить в описание блока новую опцию, вида:

{
    block: "header",
    logo: "Яндекс"
    text: "Найдётся всё!"
}

И шаблон переписать по типу title. Но особо незачем - логотип же не меняется. Это же логотип. Давайте харкодить.

Пусть декларация блока остаётся минимальной:

{
    block: "header",
    text: "Найдётся всё!"
}

И мы хотим внутри ссылки видеть графический логотип. Дописываем шаблон на header__logo и пишем шаблон для картинки:

bt.match('header__logo', function (ctx) {
    ctx.setTag('a');
    ctx.setAttr('href', '/');

    ctx.setContent({
        elem: 'image'
    });
});

bt.match('header__image', function (ctx) {
    ctx.setTag('img');
    ctx.setAttr('src', 'http://yandex.st/logo.png');
    ctx.setAttr('alt', 'Яндекс лого');
});

Вот и всё. Хотя, нет. Погодите. Результат какой?

<div class="header">
    <a class="header__logo" href="/">
        <img class="header__image" src="http://yandex.st/logo.png" alt="Яндекс лого"/>
    </a>
    <h1 class="header__title">Найдётся всё!</h1>
</div>

Вот, теперь всё. Простая декларация блока трансформируется в довольно развесистый HTML.

В BT-шаблонах можно использовать ещё ряд методов, позже обязательно прочтите документацию. Но позже, не сейчас. Пока не будем отвлекаться.

Сейчас важно усвоить, что элементы блока скрыты внутри блока. К ним нельзя получить доступ снаружи. Никак. Нельзя поменять их. Нельзя ни доопределить, ни переопределить. Блок "прячет" их внутри себя и никому не разрешает ими пользоваться. И это поведение я очень понимаю. Я бы не хотел, чтобы моему ребенку кто-то отдавал приказы без моего ведома. Мало ли, что моему ребенку прикажут сделать? Чур-чур, не надо. Всё - через меня, всё - через родителя. Всё - через вызов блока и передачу ему опций.

"Негибко", — скажете вы? "А как же нам переопределить или доопределить структуру блока?", — спросите вы, — "А если я хочу точно такой же, только вместо заголовка header__title в моей шапке хочу слоган header__tagline. Как?"

А никак. Если в вашей шапке хотя бы немного (хотя бы чуть-чуть) другая структура, это уже другой блок. Ну в самом деле, о чём вы говорите? Когда вы хотите чуть-чуть переопределить структуру блока, чтобы сделать "такой же, но с перламутровыми пуговицами" (с) вы делаете себе же хуже. Завтра мы (те, кто сделал первую реализацию блока) видоизменим внутреннюю структуру своего блока, от которого вы отнаследовались, и у вас всё к чертям сломается.

Если вам нужен блок точно "такой же, но чуть-чуть (самую малость) другой", то вам нужен другой блок! Всё, без вариантов. Другой блок вам нужен и точка. Да, ваш другой блок будет построен точно так же, как первый. В нём на 90 - 99% будут те же шаблоны. Вроде как копипаст, а общеизвестно, что копипаст - зло. Но когда стабильность проекта приносится в жертву ради удобной разработки - это надругательство над своим же продуктом.

Короче, мы тоже не любим копипаст, но это отдельная тема и о ней мы написали целый документ, прочтите его потом. Обо всех документах, на которые мы ссылаемся в тексте, мы напомним вам в конце. Там будет список, пока не отвлекайтесь.

Сейчас мы должны извиниться за то, что недоговорили вам правду. Мы говорили: "имя блока используется только для представления, для стилизации блока в браузере". Это не совсем так. Простите нас, мы обманули вас специально. Знаете ли, в первом классе тоже никому всей правды не говорили, а оказалось, числа бывают отрицательными, дробными и вообще...

###Использование имени блока в служебных целях Отделить внешность от внутреннего строения невозможно. Это неприродно. Внешность человека зачастую зависит от анатомического строения. К примеру, человек высокого роста такой высокий не от того что носит длинные брюки, а потому что в его организме больше гормона роста, чем у других людей. Природа щедро наделила его этим прекрасным гормоном. Вот и получилось, что кости стали длиннее, мышцы вытянулись, ноги-руки стали стройными и длинными, а пальцы тонкими как у пианиста. То есть внутреннее строение организма влияет на внешность.

Вот и с блоком так же: когда BT получает на вход декларацию {block: "form-auth"}, он находит шаблоны, написанные для блока с именем 'form-auth', выполняет их, строя HTML-дерево блока, а потом добавляет в главную ноду блока (в нашем случае, это тег <form>) CSS-класс 'form-auth', чтобы стили могли наложиться на этот блок и сделать его красивым - одеть его в одежды. То есть полная правда в том, что имя блока нужны дважды - чтобы построить блок, а потом оформить его отображение на веб-странице.

И даже трижды - чтобы создать js-имя блоку...

JS-компонент блока

А что с js-поведением блока? Это что такое? Под поведением блока мы понимаем некую активность, интерактивность, взаимодействие с пользователем. Например, наша форма перед отправкой данных может проверять валидность введённых данных. И если в поле логина введены пробелы, тут же сообщить об ошибке, без лишнего запроса на сервер. Это банальный пример js-поведения.

Чтобы блок мог такое делать, нужно:

  1. Написать клиентский javascript-код, который реализует нужное поведение

  2. Инициализировать этот код на нужном блоке (на нужном HTML-теге)

И то и другое мы делаем с помощью js-хелпера YBlock, но о нём сейчас не будем, о нём подробнее позже и вообще в другой статье. Здесь же важно понять следующее — имя блока используется ещё и в клиентском js-коде. Каким образом?

Когда BT-шаблонизатор строит HTML-дерево для вашей формы, он в тег <form> выливает кастомный атрибут data-block="form-auth", в который пишет имя вашего блока. Этот атрибут работает флагом, который полощется на ветру над средневековым замком - издалека видно, кому этот замок принадлежит.

При загрузке страницы браузером специальный js-хелпер "обходит" всё DOM-дерево вашей страницы и разглядывает такие флаги, сохраняя внутри себя информацию о том, какие блоки есть на странице. То есть имя блока нам нужно и для того, чтобы написать клиентский javascript-код. Я понятно этот момент объяснил, или не очень? Не переживайте, если до сих пор не поняли, как написать свой блок с нуля. Мы написали отдельный документ, в котором по шагам создадим с вами сайт на BEViS, от первого символа до полностью рабочей версии.

А сейчас нам нужно вернуться к стилевому оформлению блока.

##Состояния блока У любого вещества (и существа) на планете бывают состояния. Или правильнее сказать иначе — вещество (или существо) может находиться в разных состояниях. Вода бывает твёрдая, жидкая и газообразная, а человек трезвый и красивый, или пьяный и безобразный. Человек остаётся человеком, а вещество остаётся веществом, но выглядят они в разных состояниях по-разному.

Блок на странице может находиться в разных состояниях. Кнопка может быть hovered, focused, disabled. В состоянии disabled кнопка не только выглядит неактивной, но и ведёт себя соответствующим образом. Как? А никак! Она серая, бледная и не реагирует ни на клики, ни на наведении мышкой, ни на получение фокуса.

Когда кнопка становится disabled? Например, она должна быть неактивной до тех пор, пока пользователь не дозаполнил поля формы. Пользователь просто не должен иметь возможности нажать на кнопку submit, это вам скажет любой дизайнер-проектировщик интерфейсов. Для нас, разработчиков, это означает только то, что мы должны уметь из клиентского js-кода переводить кнопку в состояние disabled, а когда пользователь данные введёт, уметь это состояние убрать.

Как это мы делаем? Мы вводим в BEViS такое понятие, как состояние блока. Это некий CSS-класс, который может мгновенно видоизменить отображение блока.

    <div class="button _disabled"></div>

    <div class="button _focused"></div>

А в CSS-коде мы опираемся на эти классы, чтобы видоизменить отображение. Например, кнопка станет бледной и призрачной (от слова "призрак"):

    .button._disabled {
        opacity: 0.5
    }

Вдобавок, она станет глуха к вашим действиям, потому что в JS-коде мы тоже опираемся на это состояние, чтобы не реагировать на клики, например. Подробнее мы вернём к этому в другом хорошем документе.

Обратите внимание, в этом месте мы сталкиваемся с тем, что невозможно на 100% отделить отображение от поведения, можно лишь стремиться к этому. Состояния блока - это та точка, в которой стилевое отображение и интерактивное-поведение пересекаются на одной сущности.

Как мы придумываем имена состояниям?

Ответ простой - Passive Voice, страдательный залог английского языка. Вы учили в школе английский? Я — нет, французский был в школе и в ВУЗе. Но это не беда. Страдательный залог формируется по простой формуле: берём глагол to be в третьем лице (is) и добавляем к нему смысловой глагол во второй форме прошедшего времени:

Block is disabled or hovered or focused...

Ничего не поняли? Да и не надо. Рецепт простой — дайте глаголу окончание ed, и получится примерно то, что нужно:

Block disabled

А чтобы легко отличать состояния от имени блока, мы добавляем перед состоянием знак одиночного подчёркивания. Исключительно, чтобы легче читать код:

    <div class="button _disabled"></div>

Бывают, правда случаи, когда состояния одним словом описать невозможно. Например, нужно для попапа сказать, что его носик направлен строго вверх. Попробуйте выразить это в Passive Voice? У нас не получилось :)

У вас тоже? ;) Ну и ладно. Будем это делать с помощью... не знаю как сказать... по-русски я бы сказал, с помощью существительных в именительном падеже :)

Давайте скажем: "Попап ориентирован вверх".

    <div class="popup _orientation_top"></div>

Вот, сказали, и выразили это с помощью состояния _orientation_top

Больше тут добавить нечего. Да и вообще, пора заканчивать с общую часть и переходить к практической. Давайте уже сделаем что-нибудь стоящее, что-нибудь ценное. Сверстаем сайт?

##Заключение

  • Мы осознали, что разработка страницы неудобна, если мыслить тегами и классами.

  • Мы пришли к описанию страницы логическими блоками, выраженными в json.

  • Такой json превращается в привычные html-теги с помощью специального серверного парсера BT, который пишете вы сами на javascript.

  • Стилизуем блок так, как это делали всегда - через единственный класс, в котором описано всё стилевое оформление, в том числе и состояния этого блока.

  • Через состояния мы можем управлять внешним видом блока из клиентских javascript-функций.

И ещё мы увидели, что для описания страницы, для её генерации и для стилизации вам нужно знать только HTML, CSS и Javascript. А сама схема взаимодействия сервера и клиента не изменилась и знакома каждому, кто хотя бы раз делал динамические сайтики.

На этом статья заканчивается, и вы, наверное, чувствуете себя обманутым. Примерно так же я чувствовал себя, когда нас с супругой и нашим первенцем уже через день после рождения выписывали из роддома. Мне хотелось цепляться за халат медсестры: "Подождите! Мы не готовы! Мы ещё не умеем обращаться с дитём без вашей помощи!"

Нет, мы не бросаем вас :)

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

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

Сделайте себе новую чашку чая и приходите, я вас буду ждать здесь :)