diff --git a/lib/each.js b/lib/each.js index 6a70232..c50b271 100644 --- a/lib/each.js +++ b/lib/each.js @@ -2,10 +2,6 @@ module.exports = function(el, val) { var self = this; - // get the reactive constructor from the current reactive instance - // TODO(shtylman) port over adapter and bindings from instance? - var Reactive = self.reactive.constructor; - var val = val.split(/ +/); el.removeAttribute('each'); @@ -31,11 +27,7 @@ module.exports = function(el, val) { var views = []; function childView(el, model) { - return Reactive(el, model, { - delegate: self.view, - adapter: self.reactive.opt.adapter, - bindings: self.reactive.bindings - }); + return self.reactive.subview(model).render(el) } var array; diff --git a/lib/index.js b/lib/index.js index b7f1f00..61b027d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -30,43 +30,49 @@ exports = module.exports = Reactive; * @api public */ -function Reactive(el, model, opt) { - if (!(this instanceof Reactive)) return new Reactive(el, model, opt); +function Reactive(model, opt) { + if (!(this instanceof Reactive)) return new Reactive(model, opt); opt = opt || {}; - if (typeof el === 'string') { - el = domify(el); - } - var self = this; self.opt = opt || {}; self.model = model || {}; self.adapter = (opt.adapter || Adapter)(self.model); - self.el = el; self.view = opt.delegate || Object.create(null); - self.bindings = opt.bindings || Object.create(null); - // TODO undo this crap and just export bindings regularly - // not that binding order matters!! - bindings({ - bind: function(name, fn) { - self.bindings[name] = fn; - } - }); - - self._bind(this.el, []); + this.use(bindings) } Emitter(Reactive.prototype); +/** + * Render the view. + * + * @param {String|DOM} el + * @return {Reactive} + * @api public + */ + +Reactive.prototype.render = function (el) { + var self = this; + + if (typeof el === 'string') { + el = domify(el); + } + + self.el = el; + self._bind(this.el, []); + return self; +} + /** * Subscribe to changes on `prop`. * * @param {String} prop * @param {Function} fn * @return {Reactive} - * @api private + * @api public */ Reactive.prototype.sub = function(prop, fn){ @@ -288,24 +294,18 @@ Reactive.prototype._bind = function() { Reactive.prototype.bind = function(name, fn) { var self = this; if ('object' == typeof name) { - for (var key in name) { - this.bind(key, name[key]); - } - return; + Object.keys(name).forEach(function (key) { + self.bind(key, name[key]); + }) + return self; } - var els = query.all('[' + name + ']', this.el); - if (this.el.hasAttribute && this.el.hasAttribute(name)) { - els = [].slice.call(els); - els.unshift(this.el); + if (!self.el) { + self.bindings[name] = fn; + return self; } - if (!els.length) return; - debug('bind [%s] (%d elements)', name, els.length); - for (var i = 0; i < els.length; i++) { - var binding = new Binding(name, this, els[i], fn); - binding.bind(); - } + throw new Error('.bind() cannot be called after .render()') }; /** @@ -326,6 +326,7 @@ Reactive.prototype.destroy = function() { self.adapter.unsubscribeAll(); self.emit('destroyed'); self.removeAllListeners(); + delete self.el; }; /** @@ -339,6 +340,22 @@ Reactive.prototype.use = function(fn) { return this; }; +/** + * Create a Dommit view with the given model but the same bindings, etc. + * + * @param {Object} model + * @return {Reactive} subview + * @api public + */ + +Reactive.prototype.subview = function (model) { + return new Reactive(model, { + bindings: this.bindings, + adapter: this.opt.adapter, + bindings: this.bindings, + delegate: this.view || {} + }) +} function inDomTree(el) { try { diff --git a/test/adapters.js b/test/adapters.js index 3f81725..8522a23 100644 --- a/test/adapters.js +++ b/test/adapters.js @@ -73,17 +73,17 @@ describe('custom adapter', function() { }); it('setting obj[prop] should update view', function() { - reactive(el, person, { + reactive(person, { adapter: BackboneAdapter - }); + }).render(el); person.set('name', 'TJ'); assert('TJ' == el.children[0].textContent); }); it('should not double set when updating reactive instance', function(done) { - var react = reactive(el, person, { + var react = reactive(person, { adapter: BackboneAdapter - }); + }).render(el); react.sub('name', function(val) { assert.equal(val, 'TJ'); done(); @@ -92,18 +92,18 @@ describe('custom adapter', function() { }); it('shouldnt update view after being unsubscribed', function() { - var react = reactive(el, person, { + var react = reactive(person, { adapter: BackboneAdapter - }); + }).render(el); react.unsub('name'); person.set('name', 'TJ'); assert('Matt' == el.children[0].textContent); }); it('setting view should update object', function() { - var react = reactive(el, person, { + var react = reactive(person, { adapter: BackboneAdapter - }); + }).render(el); react.set('name', 'TJ'); assert('TJ' == el.children[0].textContent); assert('TJ' == person.get('name')); diff --git a/test/attr-interpolation.js b/test/attr-interpolation.js index 9f5da41..77b3974 100644 --- a/test/attr-interpolation.js +++ b/test/attr-interpolation.js @@ -9,21 +9,21 @@ describe('attr interpolation', function(){ it('should support initialization', function(){ var el = domify(''); var user = { id: '1234' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('/download/1234' == el.getAttribute('href')); }) it('should ignore whitespace', function(){ var el = domify(''); var user = { id: '1234' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('/download/1234' == el.getAttribute('href')); }) it('should react to changes', function(){ var el = domify(''); var user = { id: '1234' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('/download/1234' == el.getAttribute('href')); @@ -34,7 +34,7 @@ describe('attr interpolation', function(){ it('should support multiple attributes', function(){ var el = domify('Download {{file}}'); var user = { id: '1234' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('/download/1234' == el.getAttribute('href')); assert('file-1234' == el.getAttribute('id')); @@ -47,7 +47,7 @@ describe('attr interpolation', function(){ it('should support multiple properties', function(){ var el = domify(''); var user = { id: '1234', file: 'something' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('/download/1234-something' == el.getAttribute('href')); diff --git a/test/bindings.js b/test/bindings.js index 716f441..f674ffa 100644 --- a/test/bindings.js +++ b/test/bindings.js @@ -8,14 +8,12 @@ var reactive = require('../'); describe('reactive.bind(name, fn)', function(){ it('should define a new binding', function(done){ var el = domify('

Title

'); - var react = reactive(el, {}, { - bindings: { - 'data-editable': function(el, url){ - el.setAttribute('contenteditable', 'true'); - assert('/item/12' == url); - } - } - }); + var react = reactive() + .bind('data-editable', function(el, url){ + el.setAttribute('contenteditable', 'true'); + assert('/item/12' == url); + }) + .render(el) assert(el.children[0].getAttribute('contenteditable')); done(); @@ -26,64 +24,56 @@ describe('reactive.bind(name, fn)', function(){ var model = { todos: [ { title: 'test title' } ] }; - var react = reactive(el, model, { - bindings: { - 'lowercase': function(el, prop){ - var binding = this; - assert(prop === 'title'); - var val = binding.value(prop); - assert(val === 'test title'); - done(); - } - } - }); + var react = reactive(model) + .bind('lowercase', function(el, prop){ + var binding = this; + assert(prop === 'title'); + var val = binding.value(prop); + assert(val === 'test title'); + done(); + }) + .render(el) }); }) describe('reactive.bind(obj)', function(){ it('should define several bindings', function(done){ var el = domify('

Title

'); - var react = reactive(el, {}, { - bindings: { - 'hello': function(el, val){ - assert('world' == val); - done(); - } - } - }); + var react = reactive({}) + .bind('hello', function(el, val){ + assert('world' == val); + done(); + }) + .render(el) }) }) describe('Reactive#bind(name, fn)', function(){ it('should initialize a view-specific binding', function(done){ var el = domify(''); - var view = reactive(el, {}, { - bindings: { - 'removable': function(el){ - assert('LI' == el.nodeName); - done(); - } - } - }); + var view = reactive() + .bind('removable', function(el){ + assert('LI' == el.nodeName); + done(); + }) + .render(el) }) it('should support root-level bindings', function(done){ var el = domify(''); - var view = reactive(el, {}, { - bindings: { - 'removable': function(el){ - assert('UL' == el.nodeName); - done(); - } - } - }); + var view = reactive() + .bind('removable', function(el){ + assert('UL' == el.nodeName); + done(); + }) + .render(el) }) }) describe('Reactive#bind(name, fn)', function(){ it('should not use setAttribute to update input\'s value', function(){ var el = domify(''); - var view = reactive(el, { value: 'old value' }); + var view = reactive({ value: 'old value' }).render(el); view.el.value = 'old value'; assert(el.value == 'old value'); @@ -93,14 +83,14 @@ describe('Reactive#bind(name, fn)', function(){ it('should not use setAttribute to update textarea\'s value', function(){ var el = domify(''); - var view = reactive(el, { value: 'old value' }); + var view = reactive({ value: 'old value' }).render(el); view.set('value', 'value'); assert(el.value == 'value'); }) it('should change value of `.value` to update textarea\'s text content', function(){ var el = domify(''); - var view = reactive(el, { value: 'old value' }); + var view = reactive({ value: 'old value' }).render(el); view.set('value', 'value'); assert(el.value == 'value'); }) diff --git a/test/each.js b/test/each.js index a0da65b..f9c5b5e 100644 --- a/test/each.js +++ b/test/each.js @@ -8,7 +8,7 @@ var reactive = require('../'); describe('each', function(){ it('empty should not fail', function(){ var el = domify(''); - var view = reactive(el); + var view = reactive().render(el); assert.equal(el.children.length, 0); }) @@ -19,7 +19,7 @@ describe('each', function(){ todos: ['milk', 'cereal', 'apples'] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 3); assert.equal(el.children[0].textContent, 'milk'); @@ -34,7 +34,7 @@ describe('each', function(){ todos: ['candy'] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 1); assert.equal(el.children[0].textContent, 'candy'); @@ -51,7 +51,7 @@ describe('each', function(){ var el = domify(''); var model = { todos: ['candy'] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 1); assert.equal(el.children[0].textContent, 'candy'); @@ -71,7 +71,7 @@ describe('each', function(){ var array = ['candy']; var model = { todos: array }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 1); assert.equal(el.children[0].textContent, 'candy'); @@ -95,7 +95,7 @@ describe('each', function(){ ] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 3); assert.equal(el.children[0].textContent, 'milk'); @@ -124,7 +124,7 @@ describe('each', function(){ } }; - var r = reactive(el, model, { delegate: view }); + var r = reactive(model, { delegate: view }).render(el); el.firstChild.firstChild.click(); }); @@ -136,7 +136,7 @@ describe('each', function(){ todos: [] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 0); @@ -154,7 +154,7 @@ describe('each', function(){ todos: [] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 0); @@ -175,7 +175,7 @@ describe('each', function(){ todos: ['milk','cereal','apples'] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 3); @@ -208,7 +208,7 @@ describe('each', function(){ todos: ['milk','cereal','apples'] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 3); @@ -240,7 +240,7 @@ describe('each', function(){ }; var testArray = model.todos.splice(0,model.todos.length); - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, model.todos.length); @@ -273,7 +273,7 @@ describe('each', function(){ }; var testArray = model.todos.splice(0,model.todos.length); - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, model.todos.length); @@ -301,7 +301,7 @@ describe('each', function(){ todos: [] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 0); @@ -337,7 +337,7 @@ describe('each', function(){ tonots: [] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 0); @@ -365,7 +365,7 @@ describe('each', function(){ }] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 1); assert.equal(el.children[0].textContent, 'milk'); @@ -382,7 +382,7 @@ describe('each', function(){ }] }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 1); assert.equal(el.children[0].textContent, 'milk'); @@ -394,7 +394,7 @@ describe('each', function(){ var model = { nested: { arr: ['a', 'b'] } }; - var view = reactive(el, model); + var view = reactive(model).render(el); assert.equal(el.children.length, 2); assert.equal(el.children[0].textContent, 'a'); diff --git a/test/plugins.js b/test/plugins.js new file mode 100644 index 0000000..df3dac7 --- /dev/null +++ b/test/plugins.js @@ -0,0 +1,90 @@ +require('reactive-ie8-shims'); + +var domify = require('domify'); +var assert = require('assert'); + +var reactive = require('../'); + +describe('plugins', function(){ + it('should allow plugins to work', function () { + var view = reactive() + .use(function () {}) + .render('
') + + assert(view.el.tagName.toUpperCase() === 'DIV') + }) + + it('should allow bindings using .bind()', function () { + var view = reactive() + .bind('add-exclamation', addExclamation) + .render('

hey

') + + assert(view.el.textContent == 'hey!') + + function addExclamation(el, attr) { + el.textContent = el.textContent + '!' + } + }) + + it('should allow plugins to add bindings', function () { + var view = reactive() + .use(addExclamationPlugin) + .render('

hey

') + + assert(view.el.textContent == 'hey!') + + function addExclamationPlugin(reactive) { + reactive.bind('add-exclamation', function (el, attr) { + el.textContent = el.textContent + '!' + }) + } + }) + + it('should allow plugins to get/set values', function () { + var view = reactive({ foo: 'bar' }) + .use(bindFoo) + .render('

') + + assert(view.el.textContent == 'GO!') + assert(view.get('foo') == 'not-bar') + + function bindFoo(reactive) { + reactive.bind(reactive.get('foo'), function (el) { + el.textContent = 'GO!' + reactive.set('foo', 'not-bar') + }) + } + }) + + it('should pass bindings to subviews', function () { + var view = reactive() + .bind('lolz', function (el, attr) { el.textContent = 'lol' }) + .render('

') + + var subview = view.subview() + .render('

') + + assert(subview.el.textContent == 'lol') + }) + + it('should pass bindings set in plugins to subviews', function () { + var view = reactive() + .use(function (reactive) { reactive.bind('lolz', function (el, attr) { el.textContent = 'lol' }) }) + .render('

') + + var subview = view.subview() + .render('

') + + assert(subview.el.textContent == 'lol') + }) + + it('should pass bindings set in plugins to each-created subviews', function () { + var view = reactive({arr: [1,2,3]}) + .use(function (reactive) { reactive.bind('lolz', function (el, attr) { el.textContent = 'lol' }) }) + .render('

') + + assert(view.el.children[0].textContent == 'lol') + assert(view.el.children[1].textContent == 'lol') + assert(view.el.children[2].textContent == 'lol') + }) +}) diff --git a/test/reactive.js b/test/reactive.js index 99ab48d..1156a60 100644 --- a/test/reactive.js +++ b/test/reactive.js @@ -10,14 +10,14 @@ describe('reactive(el, obj)', function(){ it('should set values on initialization', function(){ var el = domify('

'); var user = { name: 'Tobi' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Tobi' == el.children[0].textContent); }) it('should implicitly domify on initialization', function(){ var tmpl = '

'; var user = { name: 'Tobi' }; - var view = reactive(tmpl, user); + var view = reactive(user).render(tmpl); var el = view.el; assert('Tobi' == el.textContent); }) @@ -25,7 +25,7 @@ describe('reactive(el, obj)', function(){ it('should work with multiple bindings', function(){ var el = domify('
'); var user = { first: 'Tobi', last: 'Ferret' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Tobi' == el.children[0].textContent); assert('Ferret' == el.children[1].textContent); }) @@ -38,7 +38,7 @@ describe('reactive(el, obj)', function(){ first: function(){ return this._first } }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Tobi' == el.children[0].textContent); }); @@ -58,9 +58,9 @@ describe('reactive(el, obj)', function(){ } }; - var view = reactive(el, user, { + var view = reactive(user, { delegate: delegate - }); + }).render(el); assert('Tobi Ferret' == el.children[0].textContent); }) @@ -75,19 +75,19 @@ describe('reactive(el, obj)', function(){ } }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Tobi Ferret' == el.textContent); }) it('should support deeply nested properties', function(){ var model = { foo: { bar: { baz: { rofl: 'ok' } } } }; - var view = reactive(domify('
{{ foo.bar.baz.rofl }}
'), model); + var view = reactive(model).render(domify('
{{ foo.bar.baz.rofl }}
')); assert('ok' == view.el.textContent); }) it('should support falsey properties', function(){ var model = { zero: 0, nil: null, empty: '' }; - var view = reactive(domify('
{{zero}}
'), model); + var view = reactive(model).render(domify('
{{zero}}
')); assert('0' === view.el.textContent); assert('' === view.el.getAttribute('class')); assert(null === view.get('nil')); @@ -97,16 +97,16 @@ describe('reactive(el, obj)', function(){ }) it('should not fail for undefined properties', function(){ - var view = reactive(domify('
{{ foo }}
'), {}); + var view = reactive().render(domify('
{{ foo }}
')); assert.equal('', view.el.textContent); - var view = reactive(domify('
{{ foo.bar }}
'), {}); + var view = reactive().render(domify('
{{ foo.bar }}
')); assert.equal('', view.el.textContent); }); it('shouldnt update view after being destroyed', function(done) { var el = domify('

'); - var react = reactive(el, { name: 'Matt' }); + var react = reactive({ name: 'Matt' }).render(el); assert('Matt' == el.children[0].textContent); react.on('destroyed', function() { @@ -130,7 +130,7 @@ describe('.set(prop, value)', function(){ } var user = new User('Tobi'); - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Tobi' == el.children[0].textContent); @@ -147,7 +147,7 @@ describe('.set(prop, value)', function(){ } var user = new User('Tobi', 24); - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Tobi' == el.children[0].textContent); assert('24' == el.children[1].textContent); @@ -168,7 +168,7 @@ describe('.set(prop, value)', function(){ it('should support setting parent property of a nested property', function() { var el = domify('
{{user.name}} {{user.age}}
'); - var view = reactive(el, { user: { name: 'Keith', age: 45 } }); + var view = reactive({ user: { name: 'Keith', age: 45 } }).render(el); assert.equal(el.textContent, 'Keith 45'); view.set('user', { name: 'Seth', age: 50 }); @@ -180,7 +180,7 @@ describe('data-text', function(){ it('should set element text', function(){ var el = domify('

'); var user = { name: 'Tobi' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Tobi' == el.children[0].textContent); }) }) @@ -189,19 +189,19 @@ describe('data-html', function(){ it('should set element html', function(){ var el = domify('

'); var user = { name: 'Tobi' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('tobi' == el.children[0].innerHTML.toLowerCase()); }) it('should support computed values', function(){ var el = domify('
'); var user = { diet : [ 'apples', 'pears', 'oranges' ] }; - var view = reactive(el, user, { delegate: { + var view = reactive(user, { delegate: { fruits : function(fruits) { var html = user.diet.map(function(food) { return '
  • ' + food + '
  • '; }); return html.join(''); } - }}); + }}).render(el); var items = el.querySelectorAll('li'); assert(3 == items.length); @@ -215,33 +215,33 @@ describe('data-visible', function(){ it('should add .visible when truthy', function(){ var el = domify('

    Has a file

    '); var item = { file: 'some.png' }; - var view = reactive(el, item); + var view = reactive(item).render(el); assert('visible' == el.children[0].className); }) it('should remove .hidden when truthy', function(){ var el = domify('
    '); var item = { file: 'some.png' }; - var view = reactive(el, item); + var view = reactive(item).render(el); assert('file visible' == el.children[0].className); }) it('should add .hidden when array is empty', function() { var tmpl = ''; - var view = reactive(tmpl, { items: [] }); + var view = reactive({ items: [] }).render(tmpl); assert('hidden' == view.el.className); }) it('should add .visible when array is not empty', function() { var tmpl = ''; - var view = reactive(tmpl, { items: [ 'one' ] }); + var view = reactive({ items: [ 'one' ] }).render(tmpl); assert('visible' == view.el.className); }) it('should update on array changes', function() { var tmpl = ''; var model = { items: [] }; - var view = reactive(tmpl, model); + var view = reactive(model).render(tmpl); assert('hidden' == view.el.className); model.items.push('one'); assert('visible' == view.el.className); @@ -253,26 +253,26 @@ describe('data-hidden', function(){ it('should add .hidden when truthy', function(){ var el = domify('

    Has a file

    '); var item = { file: 'some.png' }; - var view = reactive(el, item); + var view = reactive(item).render(el); assert('hidden' == el.children[0].className); }) it('should remove .visible when truthy', function(){ var el = domify('

    Has a file

    '); var item = { file: 'some.png' }; - var view = reactive(el, item); + var view = reactive(item).render(el); assert('file hidden' == el.children[0].className); }) it('should add .visible when array is empty', function() { var tmpl = ''; - var view = reactive(tmpl, { items: [] }); + var view = reactive({ items: [] }).render(tmpl); assert('visible' == view.el.className); }) it('should add .hidden when array is not empty', function() { var tmpl = ''; - var view = reactive(tmpl, { items: [ 'one' ] }); + var view = reactive({ items: [ 'one' ] }).render(tmpl); assert('hidden' == view.el.className); }) @@ -282,14 +282,14 @@ describe('data-checked', function(){ it('should check when truthy', function(){ var el = domify('
    '); var user = { agree: true }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('checked' == el.children[0].getAttribute('checked')); }) it('should uncheck when falsey', function(){ var el = domify('
    '); var user = { agree: false }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert(!el.children[0].getAttribute('checked')); // IE8 returns "", modern returns null }) }) @@ -298,7 +298,7 @@ describe('data-append', function(){ it('should append an element', function(){ var li = domify('
  • li
  • '); var el = domify('
    '); - var view = reactive(el, {}, { delegate: { msg: li } }); + var view = reactive({}, { delegate: { msg: li } }).render(el); assert(li == el.children[0].children[0]); }) }) @@ -307,14 +307,14 @@ describe('data-replace', function(){ it('should replace an element', function(){ var canvas = document.createElement('canvas'); var el = domify('
    '); - var view = reactive(el, {}, { delegate: { canvas: canvas } }); + var view = reactive({}, { delegate: { canvas: canvas } }).render(el); assert(canvas == el.children[0]); }) it('should carryover attributes', function(){ var input = document.createElement('input'); var el = domify('
    '); - var view = reactive(el, {}, { delegate: { input: input } }); + var view = reactive({}, { delegate: { input: input } }).render(el); assert('foobar' == input.getAttribute('data-value')); }) @@ -322,7 +322,7 @@ describe('data-replace', function(){ var input = document.createElement('input'); input.setAttribute('data-value','barbaz') var el = domify('
    '); - var view = reactive(el, {}, { delegate: { input: input } }); + var view = reactive({}, { delegate: { input: input } }).render(el); assert('barbaz' == input.getAttribute('data-value')); }) @@ -330,7 +330,7 @@ describe('data-replace', function(){ var toggle = document.createElement('toggle'); toggle.className = 'toggle'; var el = domify('
    '); - var view = reactive(el, {}, { delegate: { toggle: toggle } }); + var view = reactive({}, { delegate: { toggle: toggle } }).render(el); assert('toggle integration-toggle' == toggle.className); }) }) @@ -339,7 +339,7 @@ describe('data-[attr]', function(){ it('should set attribute value', function(){ var el = domify('
    '); var user = { name: 'Tobi' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Tobi' == el.children[0].value); }) }) @@ -347,7 +347,7 @@ describe('data-[attr]', function(){ describe('data-html', function () { it('should replace html content', function(){ var el = domify('
    text to be replaced
    '); - var view = reactive(el, { value: '
    ' }); + var view = reactive({ value: '
    ' }).render(el); assert(el.innerHTML.toLowerCase() === '
    '); }) }) diff --git a/test/text-interpolation.js b/test/text-interpolation.js index 71eae1b..df28a9e 100644 --- a/test/text-interpolation.js +++ b/test/text-interpolation.js @@ -9,21 +9,21 @@ describe('text interpolation', function(){ it('should support initialization', function(){ var el = domify('
    Download {{file}}
    '); var user = { id: '1234', file: 'tobi.png' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Download tobi.png' == el.children[0].textContent); }) it('should ignore whitespace', function(){ var el = domify('
    Download {{ file }}
    '); var user = { id: '1234', file: 'tobi.png' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Download tobi.png' == el.children[0].textContent); }) it('should ignore null values', function(){ var el = domify('
    {{ id }}
    '); var user = { id: null }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('' === el.textContent); }) @@ -31,7 +31,7 @@ describe('text interpolation', function(){ var el = domify('
    Download {{file}}
    '); var user = { id: '1234', file: 'tobi.png' }; - var view = reactive(el, user); + var view = reactive(user).render(el); assert('Download tobi.png' == el.children[0].textContent); view.set('file', 'loki.png'); @@ -41,7 +41,7 @@ describe('text interpolation', function(){ it('should support multiple properties', function(){ var el = domify('

    {{first}} {{last}} is a {{species}}

    '); var pet = { first: 'tobi', last: 'holowaychuk', species: 'ferret' }; - var view = reactive(el, pet); + var view = reactive(pet).render(el); assert('tobi holowaychuk is a ferret' == el.children[0].textContent); }) @@ -49,7 +49,7 @@ describe('text interpolation', function(){ var el = domify('

    {{first + " " + last}}

    '); var pet = { first: 'tobi', last: 'holowaychuk' }; - var view = reactive(el, pet); + var view = reactive(pet).render(el); assert('tobi holowaychuk' == el.textContent); view.set('last', 'ferret'); @@ -65,7 +65,7 @@ describe('text interpolation', function(){ } }; - reactive(el, pet); + reactive(pet).render(el); assert('first: Loki' == el.textContent); }) @@ -80,7 +80,7 @@ describe('text interpolation', function(){ ] }; - var view = reactive(el, pet); + var view = reactive(pet).render(el); assert('first: Loki, last: Jane' == el.textContent); view.set('siblings', ['Loki', 'Abby']); @@ -96,7 +96,7 @@ describe('text interpolation', function(){ last: function(){ return 'the Pet' } }; - reactive(el, pet); + reactive(pet).render(el); assert('name: Loki the Pet' == el.textContent); }) @@ -113,9 +113,9 @@ describe('text interpolation', function(){ casual: function(){ return pet.first() + ' ' + pet.last() } } - reactive(el, pet, { + reactive(pet, { delegate: view - }); + }).render(el); assert.equal('name: Loki the Pet', el.textContent); }) @@ -123,23 +123,23 @@ describe('text interpolation', function(){ it('should support the root element', function(){ var el = domify('

    Hello {{name}}'); var user = { name: 'Tobi' }; - reactive(el, user); + reactive(user).render(el); assert('Hello Tobi' == el.textContent); }) it('should support calling a property as a function', function(){ var model = { name: { first: 'Some Really Long Name' } }; - var view = reactive('

    Hello {{name.first.slice(0,6)}}

    ', model); + var view = reactive(model).render('

    Hello {{name.first.slice(0,6)}}

    '); assert('Hello Some R' == view.el.textContent); var model = { name: 'Some Really Long Name' }; - var view = reactive('

    Hello {{name.slice(0,4)}}

    ', model); + var view = reactive(model).render('

    Hello {{name.slice(0,4)}}

    '); assert('Hello Some' == view.el.textContent); }) it('should support setting base property', function(){ var model = { name: { first: 'foobar' } }; - var view = reactive('

    {{name.first}}

    ', model); + var view = reactive(model).render('

    {{name.first}}

    '); assert('foobar' == view.el.textContent); view.set('name', { first: 'baz' });