UNPKG

data-binding

Version:

Data attribute binding and interpolation

476 lines (385 loc) 13.7 kB
var assert = require('assert'); var domify = require('domify'); var Store = require('datastore'); var Binding = require('binding'); describe("Binding", function() { describe("factory", function() { it("binding()", function() { var obj = Binding(); assert.equal(typeof obj.add, 'function'); assert.equal(typeof obj.scan, 'function'); }); it("new Binding()", function() { var obj = new Binding(); assert.equal(typeof obj.add, 'function'); assert.equal(typeof obj.scan, 'function'); }); }); describe('single node data binding', function() { describe('Attribute and Dataset binding', function() { it('should add attribute binding', function() { var el = domify('<a link></a>'); var binding = new Binding(); binding.add('link', function(el){ el.setAttribute('href', 'http://github.com/bredele'); }); binding.scan(el); assert('http://github.com/bredele' === el.getAttribute('href')); }); it('should add dataset binding', function() { var el = domify('<a data-text="olivier"></a>'); var binding = new Binding(); binding.add('data-text', function(el, value){ el.innerText = value; }); binding.scan(el); assert('olivier' === el.innerText); }); }); describe('function binding', function() { var plugin = null; beforeEach(function(){ plugin = { test : function(el){ el.innerText = 'awesome'; }, other : function(el){ el.className = 'beauty'; } }; }); it('should apply function as binding', function(){ var el = domify('<a data-test="something"></a>'); var binding = new Binding(); binding.add('data-test', plugin.test); binding.scan(el); assert('awesome' === el.innerText); }); it('should apply multiple function bindings', function(){ var el = domify('<a data-test="something" data-other="">link</a>'); var binding = new Binding(); binding.add('data-test', plugin.test); binding.add('data-other', plugin.other); binding.scan(el); assert('beauty' === el.className); assert('awesome' === el.innerText); }); it('should apply the binding model as the scope of the function binding', function(){ var el = domify('<a data-scope="name"></a>'); var store = new Store({ name : 'Wietrich' }); var binding = new Binding(store); binding.add('data-scope', function(el){ el.innerText = this.get('name'); //TODO: should pass the model attribute's name }); binding.scan(el); assert('Wietrich' === el.innerText); }); it('should binding and interpolation', function(){ var el = domify('<a href="{{ link }}" data-other>{{ title}}</a>'); var store = new Store({ link : 'http://github.com/bredele', title : 'bredele' }); var binding = new Binding(store); binding.add('data-other', plugin.other); binding.scan(el); assert('beauty' === el.className); assert('http://github.com/bredele' === el.getAttribute('href')); assert('bredele' === el.innerHTML); }); }); describe('Object binding', function() { it('shoud apply Object as binding', function() { var el = domify('<a data-model="bind:innerHTML,prop"></a>'); var binding = new Binding(); var Plugin = function(model){ this.bind = function(el, attr, prop){ el[attr] = model.prop; }; }; binding.add('data-model', new Plugin({ prop : 'http://github.com/bredele' })); binding.scan(el); assert('http://github.com/bredele' === el.innerHTML); }); it('should apply nested bindings', function() { var el = domify('<ul><li class="first" data-model="bind:innerHTML,firstname"></li>' + '<li class="last" data-model="bind:innerHTML,lastname"></li>' + '</ul>'); var binding = new Binding(); var Plugin = function(model){ this.bind = function(el, attr, prop){ el[attr] = model[prop]; }; }; binding.add('data-model', new Plugin({ firstname : 'Olivier', lastname : 'Wietrich' })); binding.scan(el); assert('Olivier' === el.querySelector('.first').innerHTML); assert('Wietrich' === el.querySelector('.last').innerHTML); }); it('should apply bindings and inteprolation', function() { var el = domify('<a class="{{className}}" data-model="bind:innerHTML,prop"></a>'); var store = new Store({ prop : 'http://github.com/bredele', className : 'bredele' }); var binding = new Binding(store); var Plugin = function(model){ this.bind = function(el, attr, prop){ el[attr] = model.get(prop); }; }; binding.add('data-model', new Plugin(store)); binding.scan(el); assert('http://github.com/bredele' === el.innerHTML); assert('bredele' === el.className); }); it('should call default binding method', function() { var el = domify('<input required>'); var binding = new Binding(); var Plugin = function(){ this.main = function(el){ el.value = 'bredele'; }; }; binding.add('required', new Plugin()); binding.scan(el); assert('bredele' === el.value); }); }); }); describe('nested node dataset binding', function() { it('shoud apply bindings on different dom nodes', function() { var el = domify('<a data-plug1><span data-plug2>test</span></a>'); var binding = new Binding(); binding.add('data-plug1', function(node){ node.setAttribute('href', 'http://github.com/bredele'); }); binding.add('data-plug2', function(node){ node.innerText = 'bredele'; }); binding.scan(el); assert('http://github.com/bredele' === el.getAttribute('href')); assert('bredele' === el.firstChild.innerText); }); it('shoud apply bindings on different dom nodes with interpolation', function() { var el = domify('<a data-plug1>{link}<span data-plug2>{label}</span></a>'); var binding = new Binding(new Store({ link : 'Click to go on', label : 'bredele website' })); binding.add('data-plug1', function(node){ node.setAttribute('href', 'http://github.com/bredele'); }); binding.add('data-plug2', function(node){ node.innerText = 'bredele'; }); binding.scan(el); assert('http://github.com/bredele' === el.getAttribute('href')); assert('bredele' === el.querySelector('span').innerText); }); }); describe('data-set plugin', function() { it('should call data set plugin and pass the node and its content', function() { var el = domify('<span data-bind="name"></span>'); var store = new Store({ name : 'olivier' }); var value = null; var node = null; var binding = new Binding(store); binding.add('data-bind', function(el, val){ value = val; node = el; }); binding.scan(el); assert('name' === value); assert.equal(node, el); }); }); describe('interpolation', function() { it('single attribute', function() { var el = domify('<span>{{name}}</span>'); var store = new Store({ name : 'olivier' }); var binding = new Binding(store); binding.scan(el); assert('olivier' === el.innerHTML); store.set('name', 'bruno'); assert('bruno' === el.innerHTML); }); it('should display an empty string for undefined variables', function() { var el = domify('<span>{{name}}</span>'); var store = new Store(); var binding = new Binding(store); binding.scan(el); assert.equal(el.innerHTML, ''); }); it('multiple attributes on different nodes', function() { var el = domify('<a href={{link}}>{{label}}</a>'); var store = new Store({ label : 'bredele' }); var binding = new Binding(store); binding.scan(el); assert('bredele' === el.innerHTML); assert('' === el.getAttribute('href')); store.set('link', 'http://github.com/bredele'); assert('http://github.com/bredele' === el.getAttribute('href')); }); it('multiple attributes on the same node', function() { var el = domify('<a href={{link}}/repo/{{name}}></a>'); var store = new Store({ link : 'http://github.com/bredele', name:'store' }); var binding = new Binding(store); binding.scan(el); assert('http://github.com/bredele/repo/store' === el.getAttribute('href')); store.set('link', 'http://github.com'); assert('http://github.com/repo/store' === el.getAttribute('href')); store.set('name', 'bredele'); assert('http://github.com/repo/bredele' === el.getAttribute('href')); }); it('nested attributes', function() { var el = domify('<a href="{{link}}"><span>{{label}}</span></a>'); var store = new Store({ link: 'http://github.com/bredele', label : 'bredele' }); var binding = new Binding(store); binding.scan(el); assert('bredele' === el.firstChild.innerHTML); assert('http://github.com/bredele' === el.getAttribute('href')); store.set('link', 'http://www.google.com'); assert('http://www.google.com' === el.getAttribute('href')); store.set('label', 'olivier'); assert('olivier' === el.firstChild.innerHTML); }); describe("expressions", function() { it("should render inteprolation expressions", function() { var el = domify('<span>{{ label.length }}</span>'); var store = new Store({ label : 'label' }); var binding = new Binding(store); binding.scan(el); assert.equal(el.innerHTML, '5'); }); it('should listen changes on expressions', function() { var el = domify('<span>{{ label.length }}</span>'); var store = new Store({ label : 'label' }); var binding = new Binding(store); binding.scan(el); store.set('label', 'bredele'); assert.equal(el.innerHTML, '7'); }); }); describe("filters", function() { var el, store, binding; beforeEach(function() { el = domify('<span>{{ name }| hello }</span>'); store = new Store({ name: 'bredele' }); binding = new Binding(store); }); it('should filter variable', function(done) { binding.subs.filter('hello', function(str) { if(str === 'bredele') done(); }); binding.scan(el); }); it("should apply filter", function() { binding.subs.filter('hello', function(str) { return str.toUpperCase(); }); binding.scan(el); assert.equal(el.innerHTML, 'BREDELE'); }); it('should chain filters', function() { el = domify('<span>{{ name }| hello | world }</span>'); binding.subs.filter('hello', function(str) { return str.toUpperCase(); }); binding.subs.filter('world', function(str) { return 'hello ' + str + '!'; }); binding.scan(el); assert.equal(el.innerHTML, 'hello BREDELE!'); }); it('should update expression if store changes', function() { binding.subs.filter('hello', function(str) { return str.toUpperCase(); }); binding.scan(el); store.set('name', 'brick'); assert.equal(el.innerHTML, 'BRICK'); }); it('should pass arguments to filters'); }); }); describe("Query", function() { it('should only query select the plugins (no interpolation)', function() { var el = domify('<span data-query1="hello world" data-query2="test:hello">{{label}}</span>'), query1 = false, query2 = false; Binding() .add('data-query1', function(el, str) { query1 = true; }) .add('data-query2', { test: function(el, arg) { query2 = true; } }) .scan(el, true); assert.equal(query1, true); assert.equal(query2, true); assert.equal(el.innerHTML, '{{label}}'); }); }); describe("remove", function() { it("should destroy plugins", function() { var el = document.createElement('div'), plugin = { called:false, destroy:function() { this.called = true; } }; var binding = Binding() .add('plug', plugin) .scan(el); binding.remove(); assert.equal(plugin.called, true); }); it("should unsubscribe to store"); // it("should unsubscribe to store", function() { // var el = domify('<span>{{label}}</span>'), // store = new Store({ // label: 'maple' // }), // changed = false; // store.on('change github', function() { // changed = true; // }); // Binding(store) // .scan(el) // .remove(); // store.set('label', 'bredele'); // assert.equal(el.innerHTML, 'maple'); // store.set('github', 'http://github.com/leafs'); // assert.equal(changed, true); // }); }); });