Skip to content

Instantly share code, notes, and snippets.

@a-x-
Last active March 8, 2016 00:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save a-x-/39242cb6ee00231900f0 to your computer and use it in GitHub Desktop.
Save a-x-/39242cb6ee00231900f0 to your computer and use it in GitHub Desktop.
XJT/BEMS - Xtendable js/json Transformation (BEMTREE killer) based on `Block Elem Mod State` concept
// TOC
// Intro
// # New BEM based blocks concept — BEMS
// # New 3-step templating concept
// Example
/**
# New BEM based blocks concept — BEMS
## Нейминг: Не мода, а поле
Вместо термина "мода" (mode), используется "поле" (prop)
Ибо, какая нафиг мода (=режим), если это просто поле?
## mods
Модификаторы расщепляются на mods (view) и state
## mix
Миксы расщепляются на mix и base (наследование)
*/
/**
# New 3-step templating concept (data-data-bemjson-html)
bempriv is optional. Uses for complex blocks
[BEMPRIV] XJT BEMHTML
-- data ---------@-- data ------@-- bemjson --@-- html
fp js code --/ xjt tpls --/ bemhtml --/
instead of old model:
[BEMPRIV] BEMTREE BEMHTML
-- data ---------@-- bemjson --@--- bemjson --@-- html
js code --/ bemtree --/ bemhtml --/
Clear Data aren't contain `{ block: 'foo' }`
xjt - Data JSON to BEMJSON transition tool (concept)
## Нейминг: не ctx, а data
## Доопределения и переопределения
Merge strategies
merge: 'override', // by entire propSet - переопределение
merge: 'extend', // by entire props (default) - доопределение, переопределяющее имеющиеся поля
merge: 'deep', // deep props scan, not workin' on arrays - глубокое доопределение
Note: Массивы не мержатся (На массивах всегда выставляется стратегия extend)
*/
// Example
// common:
[{
// match section (block, elem, mods, elemMods)
block: 'carousel',
// apply (body) section (state, content, mix)
state: { offset: 'start' }, // start|middle|end
// gives -> [{elem:'item'..},{elem:'item'..},{elem:'item'..},,,]
// .items <- this.data.items = [{thumb:{},title,,},,,]
content: { mapData: '.items', elem: 'item' },
},
{
block: 'carousel', elem: 'item',
state: { theme: 'square' },
url: '.thumb.url',
title: '.title' // original data: this.data.items[i].title
}]
// deskpad:
[{
merge: 'override', // not recomended at all
block: 'carousel', elem: 'item',
state: { hovered: false }, // after override: { hovered: false } (loose theme: 'square' )
}]
// desktop:
[{
merge: 'deep',
// matches `carousel__has-header` only
block: 'carousel', mods: { 'has-header': true },
content: [ { elem: 'header' }, '::content' ] // access super block prop
},
{
merge: 'deep',
block: 'carousel', elem: 'item',
state: { theme: 'rect' }, // after merge: { full: true, theme: 'rect' }
content: '.title'
}]
@a-x-
Copy link
Author

a-x- commented Mar 7, 2016

Небольшое сравнение читаемости синтаксисов BEM-XJST и XJT

// common bemtree:
block('carousel')(
    def()(function(){
        var mods = { offset: 'start' };
        this.mods = this.extend(this.mods || {}, mods);
        return applyNext()
    }),
    content()(function(){
        this.ctx.items.map(function(item) {
            return {
                elem: 'item',
                url: item.thumb.url,
                title: item.title
            }
        });
    }),
    elem('item')(
        def()(function(){
            var mods = { hovered: 'no' };
            this.mods = this.extend(this.mods || {}, mods);
            return applyNext()
        }),
        mode('url')(function(){return this.ctx.url}),
        mode('title')(function(){return this.ctx.title}),
    )
)
// common xjt:
[{
    block: 'carousel',

    state: { offset: 'start' }, // start|middle|end
    content: { mapData: '.items', elem: 'item' },
},
{
    block: 'carousel', elem: 'item',

    state: { theme: 'square' },
    url: '.thumb.url',
    title: '.title'
}]

@a-x-
Copy link
Author

a-x- commented Mar 7, 2016

В реальном проекте код bemhtml часто становится излишне сложным и нечитаемым с обилием имеративщины
Но куда больше у нас есть плохих привов, с обилием present'тативщины
Сложно не нарушать баланс данные/представление (то и дело всё скатывается в PHP)
И без имеративных конструкций не обходится

Возникает и такая проблема: Если полностью вынести представление из (bem)priv,
то в bemhtml (или в bemtree) придётся написать map'ы, а это при всей декларативнсти FP всё-равно too much императивно для декларативного шаблона

@a-x-
Copy link
Author

a-x- commented Mar 7, 2016

Детали:

Некоторые проблемы bempriv-bemtree-bemhtml

  • в привах и маппинг данных и накладывание view
  • в bemhtml/bemtree обилие иперативщины
    • ...map(...,function(){...})
    • applyNext(function(){this.mods || ...})
    • this.ctx.foo.push(...))

Проблема: Доопределения и переопределения

{ someProp: '::someProp' } // access super prop as is
{ someProp: ['::someProp', 'foo', 'bar'] } // access super prop to embeding
{ someProp: function(baseProp, ctx){} } // complex access super prop - not recomended

Merge strategies

merge: 'override',  // by entire propSet
merge: 'extend',    // by entire props
merge: 'deep',      // deep props scan, not workin' on arrays
merge: 'inherit',   // inherit parent propSet strategy or default
merge: 'default',   // = 'extend'

На массивах всегда выставляется стратегия extend

NOTE: Не следует на js писать доопределение встраивание внутрь массива,
Вместо этого поместить в массив заглушки,
которые уже переопределять.

Фича: Сквозные поля для блоков

this.blockData (= this.data блока, к которому относятся элементы)

Сахар: Блоки-Алиасы

bemhtml

block('share-dropdown').replace()({ block: 'dropdown', popup: 'share' })

xjt

{ block: 'share-dropdown', is: { block: 'dropdown', popop: 'share' } }

Синтаксис: Маппинг данных на блоки и элементы

{ mapData: '.key1.nestedKey2', elem: 'el' }
Результат:
// [{elem:'el',,},{elem:'el',,},{elem:'el'},,,]

Концептуальная проблема: теряется гибкость?

Q: раньше можно было где угодно в данных (в BEMPRIV/vanilla.node.js) выставить поле представления (block/elem)
и включить шаблонизацию

A: Да и теперь можно в XJT, и более декларативно.
BEMPRIV тоже можно использовать между бекендом и XJT для слодных блоков, но не обязательно

mix или наследование?

И о и другое

mix

блок foo-bar в content'е блока qux-pux, миксуется на элемент foo этого родительского блока

{ mix: [{ block: 'qux-pux', elem: 'foo' }] } // or mix: ['qux-pux__foo']

base

блок foo-bar наследует блок bar

{ block: 'foo-bar', base: { block: 'bar'} } // or base: 'bar'

@a-x-
Copy link
Author

a-x- commented Mar 7, 2016

Q: Как отлаживать? Мы только отказались от bemhtml DSL
A: в любом месте XJT-шаблона предполагается возможным заменить короткую запись на функцию и поставить туда console.log или debugger, а затем вернуть обратно декларативную запись.

Кроме того, есть идея использовать спец-символ в строках типа '.key' для включения отладки
например: '!log!.key' будет выводить подробный лог проходящих через маппинг данных со всеми "явками и паролями"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment