bem / bh Goto Github PK
View Code? Open in Web Editor NEWBH template engine
Home Page: http://bem.github.io/bh/
License: MIT License
BH template engine
Home Page: http://bem.github.io/bh/
License: MIT License
Сейчас есть метод ctx.attr, который позволяет работать только с одним атрибутом. Хочется иметь метод, который будет работать с объектами и позволить выставлять несколько атрибутов пачкой.
module.exports = function (bh) {
bh.match("test-block", function (ctx) {
ctx.content([
{
elem: 'test-elem'
},
{
elem: 'test-elem',
elemMods: {
mod: 'val'
}
}
]);
});
bh.match("test-block__test-elem", function (ctx) {
ctx.content('test');
});
bh.match("test-block__test-elem_mod_val", function (ctx) {
ctx.content('test');
});
};
TypeError: Cannot read property 'mod' of undefined
Version is "3.1.2"
Ok in "2.2.0"
API:
ctx.tParams({ p1: 'v1', p2: 'v2' });
Сейчас пакет требует enb
, а еще подключает пакеты, которые используются только в коде enb-технологий.
Есть несколько случаев, когда такие зависимости будут лишними:
bh
, напрямую, без какого бы то ни было инструмента для сборки.bh
вместе с иными инструментами для сборки (bem-tools
, gulp
, grunt
и т.д.), написав для этих инструментов технологий/плагинов, в которых будет требоваться bh
-пакет.I need to get some BEMJSON from BH layer and then compile it to HTML with BEMHTML. But BH process this structure:
{
"block": "input",
"mods": {
"type": "textarea"
},
"content": [
{ "elem": "control" }
]
}
into this:
{
"block": "input",
"mods": {
"type": "textarea"
},
"content": [
{
"elem": "control",
"block": "input",
"blockMods": {
"type": "textarea"
}
}
],
"blockMods": {
"type": "textarea"
}
}
And the fragment
{
"elem": "control",
"block": "input",
"blockMods": {
"type": "textarea"
}
}
is parsed wrong with BEMHTML. If it was mods
instead of blockMods
, BEMHTML would work as I expected.
May be it is possible to add an option for this parameter? How could I solve the problem now?
bemjson:
{
block : 'link',
content : {
block : 'link-content',
tag : '',
content : 'Empty link'
}
}
output:
<a class="link ..." ... ><div class="link-content">Empty link</div></a>
{ block: 'foo', mix: [{ elem: 'bar', elemMods: { baz: 'ololo' } }] }
rendered to:
"<div class="foo foo__bar"></div>"
New bem-core library uses data-bem
attribute instead of onclick
.
https://github.com/bem/bem-core/blob/v1/common.blocks/i-bem/__dom/i-bem__dom.js#L54
Can you add support for the new attribute for your awesome library?
I see two possible solutions:
data-bem
or onclick
.jsAttrName
for technologies bh-server
and bh-client-module
.For example, there is no any information about methods
setOptions
enableInfiniteLoopDetection
BEMJSON
{
block: 'score',
content: [
{ elem: 'goals', content: 0 },
' : ',
{ elem: 'goals', content: 3 }
]
}
BH:
bh.match('score__goals', function(ctx) {
ctx.tag('span');
});
Result HTML
<div class="score">
<span class="score__goals"></span> : <span class="score__goals">3</span>
</div>
add to package.json
I have found very "strange" behavior of matching rules. Suppose I have such setup of bh
:
bh.match('block__elem', function () { console.log('block__elem'); });
bh.match('block__elem_emod', function () { console.log('block__elem_emod'); });
bh.match('block__elem_mod', function () { console.log('block__elem_mod'); });
bh.match('block_mod__elem', function () { console.log('block_mod__elem'); });
bh.match('block_emod__elem', function () { console.log('block_emod__elem'); });
bh.match('block_mod__elem_emod', function () { console.log('block_mod__elem_emod'); });
And applying them with this code:
console.log(bh.apply({block: 'block', elem: 'elem', mods: { mod: true, emod: true } }));
Which gives me this HTML:
<div class="block__elem block__elem_mod block__elem_emod"></div>
As you can see, HTML contains only three classes, but output of a program is:
block_mod__elem_emod
block_emod__elem
block_mod__elem
block__elem_mod
block__elem_emod
block__elem
Which indicates, that all six matchers has been applied. Is this expected behaviour?
Сейчас работает так:
ctx.mix([{
block: 'y-user',
userPic: userPic,
userLogin: userLogin
}]);
Если миксумая сущность одна, хочется передавать её объектом
ctx.mix({
block: 'y-user',
userPic: userPic,
userLogin: userLogin
});
То же самое в bemjson:
return {
block: 'y-user',
mix: {block: 'y-head', elem: 'user'}
}
mix
mix classes and not tags
, attrs
and other mixes
and it's a consistency problem.
I want to use link
block as mixin and not to hack it every time, so I want to write this way, but it's not working:
{
block: 'media',
elem: 'link',
mix: [{ block: 'link', url: 'http://github.com/' }],
content: [
{
elem: 'icon',
url: 'duck.png'
},
{
elem: 'title',
content: 'comment'
}
]
}
So I have to write this ugly code:
{
block: 'link',
mix: [{ block: 'media', elem: 'link' }],
url: 'http://github.com/',
content: [
{
block: 'media', elem: 'icon',
url: 'duck.png'
},
{
block: 'media', elem: 'title',
content: 'comment'
},
]
}
Then, I want to use one block for analytics tracking, and it have onclick
attrs and goal option. I want to mix it and expect to see onclick
attr on parent block like this way:
i-track.bh.js:
bh.match('i-track', function (ctx, json) {
ctx.attr('onclick', 'track("' + json.goal + '")');
});
and use it like this:
{
block: 'link',
mix: [{ block: 'i-track', goal: 'clck_goal' }],
url: 'http://github.com/',
content: 'Tracking link'
}
But it's not working too.
I want to use custom font on my site. So I have one block i-face
with mods for each custom font, but in reality only one font is being used in project, so it's reasonable to create shortcut block textbook
, which have it's own mix with concrete textbook
font.
In other words, I don't want to write mix: [{ block: 'i-font', mods: { face: 'textbook' }}]
every time, because it's hard to remember and want to short it to this: mix: [{ block: 'textbook' }]
, where textbook block have such bh
file:
bh.match('textbook', function (ctx, json) {
ctx.mix([{ block: 'i-font', mods: { face: 'textbook' }}]);
});
And finally it's not working at all.
I got curious, how good BH performance versus some popular template engines. There is a template-benchmark in a wild, so I wrote test runner for BH (this is my first time with BH, so be gentle it's maybe not the fastest version of BEMJSON).
Also I found no way to disable html escaping in bh code, so numbers for escaped and unescaped versions are the same.
P.S. this benchmark is using obsolete versions of engines, so numbers may vary.
Rendering 100000 templates:
ECT
Escaped : 1399ms
Unescaped : 84ms
Total : 1483ms
Dust
Escaped : 1674ms
Unescaped : 278ms
Total : 1952ms
Hogan.js
Escaped : 1964ms
Unescaped : 534ms
Total : 2498ms
Gaikan
Escaped : 1691ms
Unescaped : 50ms
Total : 1741ms
Fest
Escaped : 1651ms
Unescaped : 169ms
Total : 1820ms
EJS without `with`
Escaped : 3335ms
Unescaped : 224ms
Total : 3559ms
doT
Escaped : 2230ms
Unescaped : 46ms
Total : 2276ms
Swig
Escaped : 3882ms
Unescaped : 310ms
Total : 4192ms
Underscore
Escaped : 2355ms
Unescaped : 1440ms
Total : 3795ms
EJS
Escaped : 5350ms
Unescaped : 1448ms
Total : 6798ms
Eco
Escaped : 4927ms
Unescaped : 577ms
Total : 5504ms
Handlebars.js
Escaped : 4653ms
Unescaped : 2049ms
Total : 6702ms
Jade without `with`
Escaped : 6867ms
Unescaped : 2617ms
Total : 9484ms
CoffeeKup
Escaped : 2794ms
Unescaped : 5159ms
Total : 7953ms
BH
Escaped : 6095ms
Unescaped : 5680ms // 5299ms - for manually disabled escaping
Total : 11775ms
Jade
Escaped : 11691ms
Unescaped : 8164ms
Total : 19855ms
/cc @denchistyakov
I have two blocks g-media and person. g-media has such bh.js:
module.exports = function (bh) {
bh.match('g-media', function (ctx) {
ctx.mix([{ block: 'i-clearfix' }], true);
});
bh.match('g-media__content-wrap', function (ctx) {
ctx.mix([{ block: 'i-clearfix' }], true);
});
};
This block applied bh correctly:
{
block: 'g-media',
content: [
{
elem: 'img-wrap',
content: 'img'
},
{
elem: 'content-wrap',
content: 'content'
}
]
}
But when I mix g-media
and g-media__content-wrap
nothing happens (I thought that person__content-wrap should have g-media__content-wrap and i-clearfix classes):
{
block: 'person',
mix: [{block: 'g-media'}],
content: [
{
elem: 'photo',
mix: [{block: 'g-media', elem: 'img-wrap'}],
content: 'img'
},
{
elem: 'content-wrap',
mix: [{block: 'g-media', elem: 'content-wrap'}],
content: 'content'
}
]
}
For example,
we have BEMJSON
{
block : 'bla',
attrs : { a : undefined },
content : 'bla'
}
and BH-template
bh.match('bla', function(ctx) {
ctx.attrs({
a : 0,
b : 'some'
});
});
and HTML
<div class="bla" a="0" b="some">bla</div>
So param from BEMJSON was ignored. But we expect that parameter will not be added
Right now if i call ctx.mix({})
without block
, elem
or mods
key i'll see
<div class="block block">
it('should ignore empty array items', function() {
bh.match('button', function(ctx) {
ctx.isFirst() && ctx.mod('pos', 'first');
ctx.isLast() && ctx.mod('pos', 'last');
});
bh.apply([
false,
{ block: 'button' },
{ block: 'button' },
{ block: 'button' },
[]
]).should.equal(
'<div class="button button_pos_first"></div>' +
'<div class="button"></div>' +
'<div class="button button_pos_last"></div>'
);
});
Expected:
<div class="button button_pos_first"></div>
<div class="button"></div>
<div class="button button_pos_last"></div>
Actual:
<div class="button"></div>
<div class="button"></div>
<div class="button"></div>
E.g. bemjson:
{
block: 'bla'
}
with template
module.exports = function(bh) {
bh.match('bla', function(ctx, json) {
ctx.mix({
mods: { m1: 'v1' }
});
});
}
results in <div class="bla bla bla_m1_v1">
(bla
is duplicated).
Shouldn't these be equivalent?
Bh = require('bh').BH,
lo = require('lodash');
var json1 = {block : 'button', elem : 'item'},
json2 = lo.cloneDeep(json1),
template1 = function (bh) {
bh.match('button__item', function(ctx, json) {
ctx.mix({mods: {'pos': 'last'}});
});
},
template2 = function (bh) {
bh.match('button__item', function(ctx, json) {
ctx.mod('pos', 'last');
});
},
bh1 = new Bh(),
bh2 = new Bh();
template1(bh1);
bh1.apply(json1);
<div class="button__item button_pos_last"></div>
template2(bh2);
bh2.apply(json2);
<div class="button__item button__item_pos_last"></div>
=============================== Coverage summary ===============================
Statements : 89.41% ( 346/387 )
Branches : 80.84% ( 270/334 )
Functions : 85% ( 34/40 )
Lines : 89.53% ( 342/382 )
================================================================================
Should be 100%.
var test = {
block: 'input',
mods: {
type: 'textarea'
},
content: [
{ elem: 'control' }
]
};
var bhResult = bh.processBemJson(test);
console.log(test === bhResult); // => true
In some cases call of ctx.applyBase methon in block matching template could make misunderstanding
Is english readme in roadmap? It would be nice to have one.
bemjson
{ content: '<script>&</script>' }
expected
<div><script>&amp;</script></div>
actual
<div><script>&</script></div>
Result: AssertionError: expected NaN to equal 333
Expected: successfully passed.
it('should return tParam after applyBase #2', function() {
bh.match('select', function(ctx) {
ctx.tParam('foo', 222);
});
bh.match('select__control', function(ctx) {
(ctx.tParam('foo') + ctx.tParam('bar')).should.equal(333);
});
bh.match('select__control', function(ctx) {
ctx.tParam('bar', 111);
ctx.applyBase();
});
bh.apply({ block: 'select', content: { elem: 'control' } });
});
It seems that project's package.json
has some useless decencies like vow
, vow-fs
and inherit
.
Если в метод apply передать undefined
, то BH и BEMHTML ведут себя по разному.
BEMHTML возвращает пустую строку, BH падает с ошибкой.
Замечено при переписывании модуля slider на клиенте - https://github.yandex-team.ru/lego/islands-components/blob/dev/common.blocks/slider/__ui/slider__ui.js#L324
https://gist.github.com/xdghcnt/1253e5f518215577fe22
As you can see, I want my test-block contained two logical sections that don't appear in the output, and it works as I planned:
a1 a2 a3 b1 b2 b3
Then I try to append some more elements in next level of defenition:
https://gist.github.com/xdghcnt/013d17c183e60a897e64
And I get this:
b1 b2 b3 a2 a3 b1 b2 b3 b4 b5 b6
So I have to use workaround like this for now:
https://gist.github.com/xdghcnt/cb688b5d0751cc27eeae
(First I used ctx._somekey to pass value to next level and it was really ugly, but now it seems not bad and may be even better than construction that producing described bug or smth.)
Also, this example works ok:
https://gist.github.com/xdghcnt/4aeb2d2f4c3c7d63d5b9
bh.match(
[ 'item__mark', 'item__text' ],
function(ctx) {
ctx.tag('span')
}
)
BEMJSON
{ block : 'link', mods : { pseudo : true } }
HTML
<div class="link link_pseudo"></div>
Please, describe setOptions
in readme.
it('should not override user js', function() {
bh.match('button', function(ctx) {
ctx.js({ a: 2 });
});
bh.apply({ block: 'button', js: { x: 1 } })
.should.equal('<div class="button i-bem" onclick="return {"button":{"a":2,"x":1}}"></div>');
});
This mix
https://github.com/toivonen/toivonen.github.com/blob/feature/18_bouwdoos/s/desktop.blocks/header/header.bh.js#L9 and all the others do not work in the template.
The same block in bemhtml is https://github.com/toivonen/toivonen.github.com/blob/feature/18_bouwdoos/s/desktop.blocks/header/header.bemhtml . Mix works with bemhtml version.
The expected result you can see here http://varya.me/ in the elements of the header
block.
I have an bemjson object, it contains an array which first element is false
or undefined
{
block: 'button',
content: [
false, // can olso be undefined
{ elem: 'inner' },
{ elem: 'inner' },
{ elem: 'inner' }
]
}
and matcher
bh.match('button__inner', function(ctx) {
if (ctx.isFirst()) {
ctx.mod('first', 'yes');
}
if (ctx.isLast()) {
ctx.mod('last', 'yes');
}
});
when I apply matcher to the bemjson getting
<div class="button">
<div class="button__inner"></div>
<div class="button__inner"></div>
<div class="button__inner button__inner_last_yes"></div>
</div>
instead of expected
<div class="button">
<div class="button__inner button__inner_first_yes"></div>
<div class="button__inner"></div>
<div class="button__inner button__inner_last_yes"></div>
</div>
Trying to use "BH" for building HTML examples in my library https://github.com/toivonen/bouwdoos/tree/v1
I get files like desktop.sets/page/page.examples/myexample.bh.js and inside there is
var BH = require("../../node_modules/bh/lib/bh.js");
As if it tries to look for "node_modules" folder into "desktop.sets" folder, not in a root.
However I run enb
not in the root but like this
varya-2:bouwdoos toivonen$ cd desktop.sets/
varya-2:desktop.sets toivonen$ ../node_modules/enb/bin/enb make
21:36:04.980 - build started
...
I did this to store .bem/enb-make.js
file into desktop.sets
folder because I might have more than one set and different configs for them.
Looks like BH + ENB works properly only if run from the root.
Should I rewrite my configs so that I will use only one? Or this can be fixed here?
Тест в котором реализована асинхронная шаблонизация delfrrr@4e19ef8
После разговора с mdevils@ добавил applyBaseAsync и возможность изменять json дерево в асинхронных матчерах
Если в целом ок, то впиливаю в bh.js и делаю пул риквест
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.