Skip to content

Commit

Permalink
i-bem__dom: update _elemCache on findElem
Browse files Browse the repository at this point in the history
Fixes #583
  • Loading branch information
Alexej Yaroshevich committed Mar 11, 2015
1 parent 9876bf9 commit 0b4b89d
Show file tree
Hide file tree
Showing 2 changed files with 141 additions and 14 deletions.
29 changes: 16 additions & 13 deletions common.blocks/i-bem/__dom/i-bem__dom.js
Original file line number Diff line number Diff line change
Expand Up @@ -736,13 +736,23 @@ DOM = BEM.decl('i-bem__dom',/** @lends BEMDOM.prototype */{
modName = undef;
}

names = names.split(' ');

var _self = this.__self,
selector = '.' +
names.split(' ').map(function(name) {
return _self.buildClass(name, modName, modVal);
}).join(',.'),
keys = names.map(function(name) {
return _self.buildClass(name, modName, modVal);
}),
isSingleName = keys.length === 1,
selector = '.' + (isSingleName? keys[0] : keys.join(',.')),
res = findDomElem(ctx, selector);

// caching results if possible
(ctx === this.domElem) && keys.forEach(function(key, i) {
var elem = this._elemCache[key] = isSingleName? res : res.filter('.' + key);
delete elem.prevObject; // drop link to original set after filtering
elem.__bemElemName = names[i];
}, this);

return strictMode? this._filterFindElemResults(res) : res;
},

Expand All @@ -768,15 +778,8 @@ DOM = BEM.decl('i-bem__dom',/** @lends BEMDOM.prototype */{
* @returns {jQuery} DOM elements
*/
_elem : function(name, modName, modVal) {
var key = name + buildModPostfix(modName, modVal),
res;

if(!(res = this._elemCache[key])) {
res = this._elemCache[key] = this.findElem(name, modName, modVal);
res.__bemElemName = name;
}

return res;
var key = this.__self.buildClass(name, modName, modVal);
return this._elemCache[key] || this.findElem(name, modName, modVal);
},

/**
Expand Down
126 changes: 125 additions & 1 deletion common.blocks/i-bem/__dom/i-bem__dom.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ describe('i-bem__dom', function() {

afterEach(function() {
DOM.destruct(rootNode);
delete DOM.blocks['b-root'];
delete DOM.blocks['root'];
delete DOM.blocks['b1'];
});

Expand Down Expand Up @@ -339,6 +339,130 @@ describe('i-bem__dom', function() {
});
});

describe('findElem', function() {
function getElemIds(elems) {
return Array.prototype.map.call(elems, function(elem) {
return elem.id;
});
}

var rootNode, rootBlock;
beforeEach(function() {
rootNode = $(BEMHTML.apply(
{
block : 'root',
content : [
{ elem : 'e1', attrs : { id : '1' } },
{
elem : 'e2', attrs : { id : '2' },
content : [
{
elem : 'e1', attrs : { id : '2-1' },
mods : { inner : 'no' }
},
{
elem : 'e3', attrs : { id : '2-3' },
mods : { inner : 'no', bool : true }
}
]
},
{
elem : 'e3', attrs : { id : '3' },
content : {
elem : 'e2', attrs : { id : '3-2' },
mods : { inner : 'yes', bool : true },
content : {
elem : 'e1', attrs : { id : '3-2-1' },
mods : { inner : 'yes', bool : true }
}
}
},
{ elem : 'e2', attrs : { id : '2.' }, mods : { bool : true } }
]
}));
rootBlock = DOM.init(rootNode).bem('root');
});

afterEach(function() {
DOM.destruct(rootNode);
delete DOM.blocks['root'];
});

it('should find all elems by name', function() {
getElemIds(rootBlock.findElem('e1')).should.be.eql(['1', '2-1', '3-2-1']);
getElemIds(rootBlock.findElem('e2')).should.be.eql(['2', '3-2', '2.']);
getElemIds(rootBlock.findElem('e3')).should.be.eql(['2-3', '3']);
});

it('should find all elems by name, modName and modVal', function() {
getElemIds(rootBlock.findElem('e1', 'inner', 'no')).should.be.eql(['2-1']);
getElemIds(rootBlock.findElem('e1', 'inner', 'yes')).should.be.eql(['3-2-1']);
getElemIds(rootBlock.findElem('e2', 'inner', 'no')).should.be.eql([]);
getElemIds(rootBlock.findElem('e2', 'inner', 'yes')).should.be.eql(['3-2']);
getElemIds(rootBlock.findElem('e3', 'inner', 'no')).should.be.eql(['2-3']);
getElemIds(rootBlock.findElem('e3', 'inner', 'yes')).should.be.eql([]);
});

it('should find all elems by name and boolean mod', function() {
getElemIds(rootBlock.findElem('e1', 'bool', true)).should.be.eql(['3-2-1']);
getElemIds(rootBlock.findElem('e2', 'bool', true)).should.be.eql(['3-2', '2.']);
getElemIds(rootBlock.findElem('e3', 'bool', true)).should.be.eql(['2-3']);
});

it('should find all elems by name and boolean mod', function() {
getElemIds(rootBlock.findElem('e1', 'bool', false)).should.be.eql(['1', '2-1', '3-2-1']);
getElemIds(rootBlock.findElem('e2', 'bool', false)).should.be.eql(['2', '3-2', '2.']);
getElemIds(rootBlock.findElem('e3', 'bool', false)).should.be.eql(['2-3', '3']);
});

it('should cache found elems', function() {
// should cache results after first calls
rootBlock.findElem('e1 e2 e3');
rootBlock.findElem('e1 e2 e3', 'inner', 'no');
rootBlock.findElem('e1 e2 e3', 'inner', 'yes');
rootBlock.findElem('e1 e2 e3', 'bool', true);

// and shouldn't touch `findElem` inside `elem`
sinon.spy(rootBlock, 'findElem');

getElemIds(rootBlock.elem('e1')).should.be.eql(['1', '2-1', '3-2-1']);
getElemIds(rootBlock.elem('e2')).should.be.eql(['2', '3-2', '2.']);
getElemIds(rootBlock.elem('e3')).should.be.eql(['2-3', '3']);
getElemIds(rootBlock.elem('e1', 'inner', 'yes')).should.be.eql(['3-2-1']);
getElemIds(rootBlock.elem('e2', 'inner', 'yes')).should.be.eql(['3-2']);
getElemIds(rootBlock.elem('e3', 'inner', 'no')).should.be.eql(['2-3']);
getElemIds(rootBlock.elem('e1', 'bool', true)).should.be.eql(['3-2-1']);
getElemIds(rootBlock.elem('e2', 'bool', true)).should.be.eql(['3-2', '2.']);
getElemIds(rootBlock.elem('e3', 'bool', true)).should.be.eql(['2-3']);

rootBlock.findElem.called.should.be.false;
rootBlock.findElem.restore();
});

it('should not update _elemCache on findElem call with ctx', function() {
rootBlock.findElem(rootNode.find('[id=2]'), 'e2');

sinon.stub(rootBlock, 'findElem');

rootBlock.elem('e2');

rootBlock.findElem.should.have.been.calledOnce;
rootBlock.findElem.restore();
});

it('should update _elemCache after findElem call', function() {
rootBlock.elem('e1');
rootNode.html(BEMHTML.apply({
block : 'root',
elem : 'e1',
attrs : { id : '1.' }
}));
rootBlock.findElem('e1');

getElemIds(rootBlock.elem('e1')).should.be.eql(['1.']);
});
});

describe('DOM.init', function() {
it('should init block', function() {
var spy = sinon.spy();
Expand Down

0 comments on commit 0b4b89d

Please sign in to comment.