From 5f5221f603cfe5ae15d1b4b97ea24d45076f7d92 Mon Sep 17 00:00:00 2001 From: miripiruni Date: Mon, 12 Sep 2016 17:49:36 +0300 Subject: [PATCH] Fixed #274: Support `mod(m)` and `elemMod(em)` without second argument --- docs/en/5-templates-syntax.md | 27 +++++++++++++++++++++++++++ docs/ru/5-templates-syntax.md | 31 +++++++++++++++++++++++++++++-- lib/bemxjst/match.js | 8 +++++++- lib/bemxjst/tree.js | 6 ++++-- test/modes-elemmod-test.js | 22 ++++++++++++++++++++++ test/modes-mod-test.js | 22 ++++++++++++++++++++++ 6 files changed, 111 insertions(+), 5 deletions(-) diff --git a/docs/en/5-templates-syntax.md b/docs/en/5-templates-syntax.md index a2c655cf..cd417434 100644 --- a/docs/en/5-templates-syntax.md +++ b/docs/en/5-templates-syntax.md @@ -123,6 +123,29 @@ The template are applied. Result: ``` +If second argument of `mod()` was omited then templates with any +non-empty value of modifier will be applied. + +```js +block('a').mod('size').tag()('span'); +``` +Template will be applied to BEMJSON node if block equals to 'a' and +'size' modifier exists (equals neither to `undefined` nor to `''` nor to `false` +nor to `null`). + +```js +{ block: 'a', mods: { size: 's' } }, +{ block: 'a', mods: { size: 10 } }, +``` + +But templates will not be applied to entities: +```js +{ block: 'a', mods: { size: '', theme: 'dark' } } +{ block: 'a', mods: { theme: 'dark' } }, +{ block: 'a', mods: { size: undefined } }, +{ block: 'a', mods: {} } +``` + ### elemMod ```js @@ -158,6 +181,10 @@ Both templates are applied. Result: `elemModVal` checked for compliance after converting to String. This behavior is similar to checking `modVal`. +Second argument of `elemMod()` can be omited. In this case +behavior of `elemMods()` will be the same as `mods()` without second argument. +The templates will be applied to BEMJSON nodes with modifier with any value. + ### match ```js diff --git a/docs/ru/5-templates-syntax.md b/docs/ru/5-templates-syntax.md index c3edae65..bec0a421 100644 --- a/docs/ru/5-templates-syntax.md +++ b/docs/ru/5-templates-syntax.md @@ -64,7 +64,7 @@ elem(name) ```js /** * @param {String} modName имя модификатора блока - * @param {String|Boolean} modVal значение модификатора блока + * @param {String|Boolean} [modVal] значение модификатора блока */ mod(modName, modVal) ``` @@ -117,12 +117,36 @@ block('item') ``` +Если второй аргумент `mod()` отсутствует тогда к узлу будут +применены шаблоны для соответствующего модификатора с любым значением. + +```js +block('a').mod('size').tag()('span'); +``` +Шаблон будет применен к узлам BEMJSON-а, у которых блок равен 'a' и +присутствует модификатор 'size' (со значением отличным от `undefined`, `''`, +`false`, `null`). + +```js +{ block: 'a', mods: { size: 's' } }, +{ block: 'a', mods: { size: 10 } }, +``` + +Но шаблоны не будут применены к узлам: +```js +{ block: 'a', mods: { size: '', theme: 'dark' } } +{ block: 'a', mods: { theme: 'dark' } }, +{ block: 'a', mods: { size: undefined } }, +{ block: 'a', mods: {} } +``` + + ### elemMod ```js /** * @param {String} elemModName имя модификатора элемента - * @param {String|Boolean} elemModVal значение модификатора элемента + * @param {String|Boolean} [elemModVal] значение модификатора элемента */ elemMod(elemModName, elemModVal) ``` @@ -152,6 +176,9 @@ block('page').elem('content').elemMod('type', 'index').mix()({ block: 'mixed' }) `elemModVal` проверяются на соответствие после приведения к строке. Это поведение аналогично поведению проверки `modVal`. +Второй аргумент `elemMod()` также может отстуствовать, в этом случае поведение +аналогичное подпредикату `mod()` — шаблоны будут применены к узлам с модификатором любого значения. + ### match ```js diff --git a/lib/bemxjst/match.js b/lib/bemxjst/match.js index c17b38a7..ff725915 100644 --- a/lib/bemxjst/match.js +++ b/lib/bemxjst/match.js @@ -22,13 +22,19 @@ function MatchNested(template, pred) { MatchNested.prototype.exec = function exec(context) { var val = context; + for (var i = 0; i < this.keys.length - 1; i++) { val = val[this.keys[i]]; if (!val) return false; } - return String(val[this.keys[i]]) === this.value; + val = val[this.keys[i]]; + + if (this.value === true) + return val !== undefined && val !== '' && val !== false && val !== null; + + return String(val) === this.value; }; function MatchCustom(template, pred) { diff --git a/lib/bemxjst/tree.js b/lib/bemxjst/tree.js index 0481520d..595d5715 100644 --- a/lib/bemxjst/tree.js +++ b/lib/bemxjst/tree.js @@ -367,11 +367,13 @@ Tree.prototype.mode = function mode(name) { }; Tree.prototype.mod = function mod(name, value) { - return this.match(new PropertyMatch([ 'mods', name ], String(value))); + return this.match(new PropertyMatch([ 'mods', name ], + value === undefined ? true : String(value))); }; Tree.prototype.elemMod = function elemMod(name, value) { - return this.match(new PropertyMatch([ 'elemMods', name ], String(value))); + return this.match(new PropertyMatch([ 'elemMods', name ], + value === undefined ? true : String(value))); }; Tree.prototype.def = function def() { diff --git a/test/modes-elemmod-test.js b/test/modes-elemmod-test.js index 237b33ce..56ffd2a1 100644 --- a/test/modes-elemmod-test.js +++ b/test/modes-elemmod-test.js @@ -60,6 +60,28 @@ describe('Modes elemMod(elemModName, elemModVal)', function() { }); describe('elemModVal types', function() { + it('string should support elemMod with one argument', function() { + test(function() { + block('b').elem('e').elemMod('m').tag()('span'); + }, + [ + { block: 'b', elem: 'e', elemMods: { m: true } }, + { block: 'b', elem: 'e', elemMods: { m: 'test' } }, + { block: 'b', elem: 'e', elemMods: { m: 0 } }, + { block: 'b', elem: 'e', elemMods: { m: false } }, + { block: 'b', elem: 'e', elemMods: { m: null } }, + { block: 'b', elem: 'e', elemMods: { m: '' } }, + { block: 'b', elem: 'e', elemMods: { no: 'test' } } + ], + '' + + '' + + '' + + '
' + + '
' + + '
' + + '
'); + }); + it('number should match to string', function() { test(function() { block('b').elem('e').elemMod('em', 1).tag()('span'); diff --git a/test/modes-mod-test.js b/test/modes-mod-test.js index dec06ac1..871d8ccb 100644 --- a/test/modes-mod-test.js +++ b/test/modes-mod-test.js @@ -83,5 +83,27 @@ describe('Modes .mod(modName, modVal)', function() { { block: 'b', mods: { m: null } }, '
'); }); + + it('string should support mod with one argument', function() { + test(function() { + block('b').mod('m').tag()('span'); + }, + [ + { block: 'b', mods: { m: true } }, + { block: 'b', mods: { m: 'test' } }, + { block: 'b', mods: { m: 0 } }, + { block: 'b', mods: { m: false } }, + { block: 'b', mods: { m: null } }, + { block: 'b', mods: { m: '' } }, + { block: 'b', mods: { no: 'test' } } + ], + '' + + '' + + '' + + '
' + + '
' + + '
' + + '
'); + }); }); });