Skip to content

Commit

Permalink
BEMXJST: extend() mode fix #180
Browse files Browse the repository at this point in the history
  • Loading branch information
miripiruni committed Oct 20, 2016
1 parent 5ab2e2f commit ab9d3ca
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 26 deletions.
51 changes: 50 additions & 1 deletion docs/en/5-templates-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ Result of BEMHTML templating:
* [cls](#cls)
* [replace](#replace)
* [wrap](#wrap)
* [extend](#extend)
* [User-defined modes](#user-defined-modes)

#### def
Expand Down Expand Up @@ -540,6 +541,53 @@ Result of BEMHTML templating:
<div class="wrap"><div class="quote">Docendo discimus</div></div>
```

#### extend

`extend` mode allows you to extend context of template.

Example:

```js
// BEMJSON
{ block: 'action' }
```

Templates:

```js
block('action').extend()({ 'ctx.type': 'Sale', sale: '50%' });
block('action').content()(function() {
return this.ctx.type + ' ' + this.sale;
});
```

Result of BEMHTML apply:

```html
<div class="action">Sale 50%</div>
```

`extend()` may used as a data proxy to all child nodes.

Example:

```js
// Templates
block('page').extend()({ meaning: 42 });
block('*').attrs()(function() { return { life: this.meaning }; });
```

```js
// BEMJSON
{ block: 'page', content: { block: 'wrap', content: { block: 'para' } }
```
```html
<div class="page" life="42"><div class="wrap" life="42"><div class="para"
life="42"></div></div></div>
```
## User-defined modes
You can define your own mode and use it in the template body. Example:
Expand Down Expand Up @@ -589,7 +637,8 @@ More information about [apply()](7-runtime.md#apply).
## BEMTREE
Only the [def](#def), [content](#content), [replace](#replace) and [wrap](#wrap) modes are used by the BEMTREE engine. User-defined modes can also be used. The other modes described in the documentation above can only be used in BEMHTML.
Only the [def](#def), [content](#content), [replace](#replace),
[extend](#extend) and [wrap](#wrap) modes are used by the BEMTREE engine. User-defined modes can also be used. The other modes described in the documentation above can only be used in BEMHTML.
***
Expand Down
49 changes: 48 additions & 1 deletion docs/ru/5-templates-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ block('link')(
* [cls](#cls)
* [replace](#replace)
* [wrap](#wrap)
* [extend](#extend)
* [Пользовательские режимы](#Пользовательские-режимы)

#### def
Expand Down Expand Up @@ -536,6 +537,52 @@ block('quote').wrap()(function() {
</div>
```

#### extend

Доопределить контекст исполнения шаблонов.

Пример:

```js
// BEMJSON
{ block: 'action' }
```

Шаблоны:

```js
block('action').extend()({ 'ctx.type': 'Sale', sale: '50%' });
block('action').content()(function() {
return this.ctx.type + ' ' + this.sale;
});
```

Результат шаблонизации BEMHTML:

```html
<div class="action">Sale 50%</div>
```

`extend()` может использоваться для прокидывания данных во все дочерние узлы
через контекст выполнения шаблонов.

Пример:

```js
block('page').extend()({ meaning: 42 });
block('*').attrs()(function() { return { life: this.meaning }; });
```

```js
// BEMJSON
{ block: 'page', content: { block: 'wrap', content: { block: 'para' } }
```
```html
<div class="page" life="42"><div class="wrap" life="42"><div class="para"
life="42"></div></div></div>
```
## Пользовательские режимы
Вы можете определить свой режим и использовать его в теле шаблона.
Expand Down Expand Up @@ -586,7 +633,7 @@ block('control')(
## BEMTREE
Движком BEMTREE используются только режимы [def](#def), [content](#content) и
режимы-хелперы [replace](#replace) и [wrap](#wrap). Пользовательские режимы тоже могут быть использованы. Остальные режимы, описанные в документации выше, применимы только к BEMHTML.
режимы-хелперы [replace](#replace), [extend](#extend) и [wrap](#wrap). Пользовательские режимы тоже могут быть использованы. Остальные режимы, описанные в документации выше, применимы только к BEMHTML.
***
Expand Down
15 changes: 15 additions & 0 deletions lib/bemxjst/match.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ var tree = require('./tree');
var PropertyMatch = tree.PropertyMatch;
var AddMatch = tree.AddMatch;
var WrapMatch = tree.WrapMatch;
var ExtendMatch = tree.ExtendMatch;
var CustomMatch = tree.CustomMatch;

function MatchProperty(template, pred) {
Expand Down Expand Up @@ -57,6 +58,17 @@ MatchWrap.prototype.exec = function exec(context) {
return res;
};

function MatchExtend(template) {
this.template = template;
this.wrap = null;
}

MatchExtend.prototype.exec = function exec(context) {
var res = this.ext !== context.ctx;
this.ext = context.ctx;
return res;
};

function AddWrap(template, pred) {
this.template = template;
this.key = pred.key;
Expand All @@ -81,6 +93,9 @@ function MatchTemplate(mode, template) {
this.predicates[j] = new MatchNested(this, pred);
else
this.predicates[j] = new MatchProperty(this, pred);
} else if (pred instanceof ExtendMatch) {
j--;
postpone.push(new MatchExtend(this));
} else if (pred instanceof AddMatch) {
this.predicates[j] = new AddWrap(this, pred);
} else if (pred instanceof CustomMatch) {
Expand Down
12 changes: 6 additions & 6 deletions lib/bemxjst/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ ExtendMatch.prototype.wrapBody = function wrapBody(body) {

var keys = Object.keys(body);
for (var i = 0; i < keys.length; i++)
changes['ctx.' + keys[i]] = body[keys[i]];
changes[keys[i]] = body[keys[i]];

return local(changes)(function preApplyCtx() {
return applyCtx(this.ctx);
Expand All @@ -122,7 +122,7 @@ ExtendMatch.prototype.wrapBody = function wrapBody(body) {
var obj = body.call(this);
var keys = Object.keys(obj);
for (var i = 0; i < keys.length; i++)
changes['ctx.' + keys[i]] = obj[keys[i]];
changes[keys[i]] = obj[keys[i]];

return local(changes)(function preApplyCtx() {
return applyCtx(this.ctx);
Expand Down Expand Up @@ -399,10 +399,6 @@ Tree.prototype.applyMode = function applyMode(args, mode) {
return this.mode(mode);
};

Tree.prototype.wrap = function wrap() {
return this.def.apply(this, arguments).match(new WrapMatch(this.refs));
};

Tree.prototype.xjstOptions = function xjstOptions(options) {
this.queue.push(new Item(this, [
new CompilerOptions(options)
Expand Down Expand Up @@ -488,6 +484,10 @@ Tree.prototype.prependContent = function prependContent() {
.match(new AddMatch('prependContent', this.refs));
};

Tree.prototype.wrap = function wrap() {
return this.def.apply(this, arguments).match(new WrapMatch(this.refs));
};

Tree.prototype.replace = function replace() {
return this.def.apply(this, arguments).match(new ReplaceMatch(this.refs));
};
Expand Down
62 changes: 44 additions & 18 deletions test/modes-extend-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,33 +13,59 @@ describe('Modes extend', function() {

it('should support basic mode of operation', function () {
test(function() {
block('b1').content()('ok');
block('b1').elem('e').content()('extended');
block('b1').extend()(function() { return { elem: 'e' }; });
}, { block: 'b1' }, '<div class="b1__e">extended</div>');
block('b')(
extend()(function() { return { test: 'it work’s' }; }),
content()(function() { return this.test; })
);
}, { block: 'b' }, '<div class="b">it work’s</div>');
});

it('should support inline argument', function () {
test(function() {
block('b')(
extend()({ test: 'it work’s' }),
content()(function() { return this.test; })
);
}, { block: 'b' }, '<div class="b">it work’s</div>');
});

it('should have proper `this`', function () {
test(function() {
block('b1').content()('ok');
block('b1').elem('e').content()('extended');
block('b1').extend()(function() { return { elem: this.ctx.wtf }; });
}, { block: 'b1', wtf: 'e' }, '<div class="b1__e">extended</div>');
block('b')(
extend()(function() { return { test: this.ctx.wtf }; }),
content()(function() { return this.test; })
);
}, { block: 'b', wtf: 'it work’s' }, '<div class="b">it work’s</div>');
});

it('should work as a singular function', function () {
it('should proxy data', function () {
test(function() {
block('b1').content()('ok');
block('b1').elem('e').content()('extended');
block('b1')(extend()(function() { return { elem: 'e' }; }));
}, { block: 'b1' }, '<div class="b1__e">extended</div>');
block('b').extend()(function() { return { test: 42 }; });
block('*').attrs()(function() { return { life: this.test }; });
},
{
block: 'b',
content: { block: 'a', content: { block: 'c' } }
},
'<div class="b" life="42"><div class="a" life="42">' +
'<div class="c" life="42"></div></div></div>');
});

it('should support inline argument', function () {
it('should extend ctx', function () {
test(function() {
block('b').extend()(function() { return { 'ctx.content': 42 }; });
},
{ block: 'b' },
'<div class="b">42</div>');
});

it('should support applyNext', function () {
test(function() {
block('b1').content()('ok');
block('b1').elem('e').content()('extended');
block('b1').extend()({ elem: 'e' });
}, { block: 'b1' }, '<div class="b1__e">extended</div>');
block('b').extend()(function() { return { 'ctx.content': 1 }; });
block('b').extend()(function() {
return { 'ctx.attrs': { id: 'test' } }; });
},
{ block: 'b' },
'<div class="b" id="test">1</div>');
});
});

0 comments on commit ab9d3ca

Please sign in to comment.