BEViS & bt

Марат Дулин, Вадим Макишвили

РИТ 2014

BEViS

& bt

Фреймворк.

Зачем?

  1. Знать только один язык — Javascript
  2. Внедрить в HTML строгое API
  3. Создавать сайты повышенной надёжности

... и получать от этого удовольствие ;)

Smarty, Django и т.п.

контроллер
шаблоны
представления
HTML

BEViS

index.page.js
index.bt.js
HTML

BEViS controller

            pages.declare('index', function () {
                return [
                    { block: 'header' },
                    { block: 'authorization' }
                ];
            });
        

И.И.Шишкин, К.А.Савицкий
«Утро в сосновом бору»,
1889

Простой JSON

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

Одного имени
достаточно

Имя блока

            {
                друг: 'Марат'
            }
        

Необязательные параметры

            {
                суп: 'солянка', 
                сметанаНужна: 'да'
            }
        

Создавать страницы - просто!

            {
                block: 'header', 
                showSearch: true
            }
        

Блок - это

  1. HTML-cтруктура
  2. CSS-представление
  3. JS-поведение

HTML

Императивные шаблоны

            <p>Уважаемый {{ person }}</p>
            <p>Ваш заказ от {{ date:"F j, Y" }} принят на обработку.</p>
            <p>Пожалуйста, убедитесь, что всё выбрано верно:</p>
             
            <ul>
            {% for item in item_list %}
                <li>{{ item }}</li>
            {% endfor %}
            </ul>
             
            {% if ordered_warranty %}
                <p>Гарантия - 12 месяцев.</p>
            {% else %}
                <p>Со всеми неполадками обращайтесь в наш сервиcный центр.</p>
            {% endif %}
        

Smarty

контроллер
императивные
шаблоны
HTML

Smarty

index.php
index.tpl.php
HTML

Декларативные шаблоны

Что это?

            h1 {
                color: red; 
            }
        

Исходный JSON

            pages.declare('index', function () {
                return {
                    block: 'header'
                }
            });
        

Финальный HTML

            <div class="header">
                РИТ 2014
            </div>
        

Абстрактный декларативный шаблон

            header {
                tag: div;
                content: 'РИТ 2014'
            }
        

Абстрактный декларативный шаблон

            header {
                tag: div;
                content: 'РИТ 2014'
            }
        

Реальный декларативный шаблон

            bt.match('header', function (ctx) {
                ctx.setTag('div'); 
                ctx.setContent('РИТ 2014'); 
            });
        

Результат

            <div class="header">
                РИТ 2014
            </div>
        

Простой JSON

            {
                block: "y-header", 
             
                view: "islet-search",
                showSearch: true,
                showSuggest: true
            }
        

Простой JSON

            {
                block: "y-header", 
             
                view: "islet-search",
                showSearch: true,
                showSuggest: true
            }
        

Сложный HTML

                <header class="y-header_islet-search _init _live-events" data-block="y-header" data-options="{"mixins":[{"name":"location-form"}]}">
                    <div class="y-header_islet-search__wrapper">
                        <a class="y-header_islet-search__logo _lang_ru" href="http://www.yandex.ru">
                            <img class="y-header_islet-search__logo-img" alt="Яндекс" src="//yandex.st/lego/_/X31pO5JJJKEifJ7sfvuf3mGeD_8.png">
                        </a>
                        <div class="y-header_islet-search__info">
                            <span class="y-header_islet-search__board-call">
                                <a class="y-button_islet-board _init" data-block="y-button" role="button" href="http://www.yandex.ru/all">
                                    <span class="y-button_islet-board__icon">
                                        <div class="y-header_islet__board-call-icon"></div>
                                    </span>
                                </a>
                            </span>
                        </div>
                        <div class="y-header_islet-search__arrow">
                            <form class="y-header_islet-search__form _live-events" action="/">
                                <div class="y-header_islet-search__button">
                                    <button class="y-button_islet _init" data-block="y-button" tabindex="2" type="submit"><span class="y-button_islet__text">Найти</span></button>
                                </div>
                                <div class="y-header_islet-search__input">
                                    <div class="y-suggest_islet _init" data-block="y-suggest"
                                         data-options="{"options":{"suggestDropOptions":{"view":"islet-header","suggestDropItemView":"islet-header"},"dataProviderOptions":{"queryParams":{"lang":"ru-RU","search_type":"all","fullpath":1,"v":5},"posQueryParamName":"pos","textQueryParamName":"part","disableGrouping":true}},"mixins":[{"name":"header-suggest-configurer"}]}">
                                        <span class="y-input_islet-label-icons _init" data-block="y-input"><span class="y-input_islet-label-icons__label"><a class="y-input_islet-label-icons__label-link" href="/">Карты</a></span><span
                                                class="y-input_islet-label-icons__icons"><span class="y-input_islet-label-icons__close-small"></span></span><span class="y-input_islet-label-icons__context"><input
                                                class="y-input_islet-label-icons__control" id="uniq0" name="text" value="" autocomplete="off"></span></span>
                                        <div class="y-suggest-drop_islet-header" data-block="y-suggest-drop" data-options="{"options":{"wide":true}}"></div>
                                    </div>
                                </div>
                            </form>
                        </div>
                    </div>
                    <div class="y-header_islet-search__board"></div>
                </header>
            

Чем декларативные шаблоны лучше?

  1. Даже в большом проекте остаются простыми
  2. Гарантируют внешнее API блока

BEViS - это как Web Components, только работает уже сегодня ;)

CSS

Мы часто смешивали блоки

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

Г.Данелия, 1977
В.Кикабидзе
«Мимино»

Бивис не смешивает блоки

Мы часто модифицировали блок

            <div class="button button_theme_normal button_shadow_yes">
                нажми меня
            </div>
        

Один блок —
одно имя  

Просто имя

            <div class="button">
                нажми меня
            </div>
        

View

            {
                block: "button", 
                view: "normal-shadow"
            }
        

CSS-
препроцессор

Публичные селекторы

            .button {
                skin-common();
                skin-theme-normal();
            }
             
             
            .button_normal-shadow {
                skin-common();
                skin-theme-normal();
                skin-shadow();
            }
        

Публичные селекторы

            .button {
                skin-common();
                skin-theme-normal();
            }
             
             
            .button_normal-shadow {
                skin-common();
                skin-theme-normal();
                skin-shadow();
            }
        

Приватные функции

                skin-common() {
                    /* общие стили кнопки */
                }
                 
                skin-theme-normal() {
                    /* цвета кнопки */
                }
                 
                skin-shadow() {
                    /* тень под кнопкой */
                }
            

Все конфликты под контролем

            .button {
                skin-common();
                skin-theme-normal();
                /* а здесь разрулил все конфликты этих миксинов */ 
            }
                
            .button_normal-shadow {
                skin-common();
                skin-theme-normal();
                skin-shadow();
                /* а здесь разрулил все конфликты этих миксинов */ 
            }
        

JS

В маленьких проектах

            $(document).ready(function() {
                    var form = $('#my-form');
                    form.submit(onSubmited);
             
                    function onSubmited() {
                        if ($('#my-form .button').hasClass('disabled')) {
                            return false;
                        }
                    }
            });
        

В маленьких проектах с модулями

            modules.define(
                'form',
                ['jquery'],
                function(provide, $) {
                    var form = $('#my-form');
                    form.submit(onSubmited);
             
                    function onSubmited() {
                        if ($('#my-form .button').hasClass('disabled')) {
                            return false;
                        }
                    }
             
                    provide(form);
                }
            );
        

Бивис = Модуль + YBlock-класс

            modules.define(
                'form',
                ['y-button', 'y-block'],
                function(provide, YButton, YBlock) {
                    var Form = inherit(YBlock, {
                        __constructor: function () {
                            this._submitButton = YButton.find(this);
                            this._bindTo(this.getDomNode(), 'submit', this._onSubmitted);
                        },
                        _onSubmitted: function (e) {
                            if (this._submitButton.isDisabled()) {
                                e.preventDefault();
                            } else {
                                this.emit('submit');
                            }
                        }
                    });
                    provide(Form);
                }
            );
        

Бивис = Модуль + YBlock-класс

  1. Код можно реиспользовать
  2. Мы управляем абстракциями, а не DOM-объектами

Поведение отделено от отображения

            <div
                class="header"
                data-block="header">
            </div>
        

Состояние блока

            <input class="login _unfilled" type="text"/>
            
        
            /* обычное состояние */
            .login {
                ...
            }
             
            /* тревожное состояние */
            .login._unfilled {
                border: 1px solid red;
            }
        
Block
Element
View
State

Файлы и сборка

Файлы

            blocks/
                form/
                    form.styl
                    form.js
                    form.bt.js
                header/
                    header.styl
                    header.js
                    header.bt.js
        

ENB-сборщик

http://github.com/enb-make/enb

ENB-конфигуратор

http://enb-make.info/config/

BEViS-документация

http://github.com/bevis-ui/docs

Быстрый старт

            git clone git@github.com:bevis-ui/bevis-stub.git your-project
            cd your-project
            make
        

Todo MVC

http://github.com/bevis-ui/bevis-todo

Blog Engine

http://github.com/bevis-ui/bevis-blog

Теперь мы

BEViS — серьёзный инструмент с добрым лицом ;)

Спасибо

BEViS & bt

Вадим Макишвили