UNPKG

can

Version:

MIT-licensed, client-side, JavaScript framework that makes building rich web applications easy.

375 lines (319 loc) 10.9 kB
steal("can/view/live", "can/observe", "can/test", "steal-qunit", function () { QUnit.module('can/view/live'); test('html', function () { var div = document.createElement('div'), span = document.createElement('span'); div.appendChild(span); var items = new can.List([ 'one', 'two' ]); var html = can.compute(function () { var html = ''; items.each(function (item) { html += '<label>' + item + '</label>'; }); return html; }); can.view.live.html(span, html, div); equal(div.getElementsByTagName('label') .length, 2); items.push('three'); equal(div.getElementsByTagName('label') .length, 3); }); var esc = function (str) { return str.replace(/</g, '&lt;') .replace(/>/g, '&gt;'); }; test('text', function () { var div = document.createElement('div'), span = document.createElement('span'); div.appendChild(span); var items = new can.List([ 'one', 'two' ]); var text = can.compute(function () { var html = ''; items.each(function (item) { html += '<label>' + item + '</label>'; }); return html; }); can.view.live.text(span, text, div); equal(div.innerHTML, esc('<label>one</label><label>two</label>')); items.push('three'); equal(div.innerHTML, esc('<label>one</label><label>two</label><label>three</label>')); }); test('attributes', function () { var div = document.createElement('div'); var items = new can.List([ 'class', 'foo' ]); var text = can.compute(function () { var html = ''; if (items.attr(0) && items.attr(1)) { html += items.attr(0) + '=\'' + items.attr(1) + '\''; } return html; }); can.view.live.attributes(div, text); equal(div.className, 'foo'); items.splice(0, 2); equal(div.className, ''); items.push('foo', 'bar'); equal(div.getAttribute('foo'), 'bar'); }); test('attribute', function () { var div = document.createElement('div'); div.className = 'foo ' + can.view.live.attributePlaceholder + ' ' + can.view.live.attributePlaceholder + ' end'; var firstObject = new can.Map({}); var first = can.compute(function () { return firstObject.attr('selected') ? 'selected' : ''; }); var secondObject = new can.Map({}); var second = can.compute(function () { return secondObject.attr('active') ? 'active' : ''; }); can.view.live.attribute(div, 'class', first); can.view.live.attribute(div, 'class', second); equal(div.className, 'foo end'); firstObject.attr('selected', true); equal(div.className, 'foo selected end'); secondObject.attr('active', true); equal(div.className, 'foo selected active end'); firstObject.attr('selected', false); equal(div.className, 'foo active end'); }); test('specialAttribute with new line', function () { var div = document.createElement('div'); var style = can.compute('style="width: 50px;\nheight:50px;"'); can.view.live.specialAttribute(div, 'style', style); equal(div.style.height, '50px'); equal(div.style.width, '50px'); }); test('list', function () { var div = document.createElement('div'), list = new can.List([ 'sloth', 'bear' ]), template = function (animal) { return '<label>Animal=</label> <span>' + animal + '</span>'; }; div.innerHTML = 'my <b>fav</b> animals: <span></span> !'; var el = div.getElementsByTagName('span')[0]; can.view.live.list(el, list, template, {}); equal(div.getElementsByTagName('label') .length, 2, 'There are 2 labels'); div.getElementsByTagName('label')[0].myexpando = 'EXPANDO-ED'; list.push('turtle'); equal(div.getElementsByTagName('label')[0].myexpando, 'EXPANDO-ED', 'same expando'); equal(div.getElementsByTagName('span')[2].innerHTML, 'turtle', 'turtle added'); }); test('list with a compute', function () { var div = document.createElement('div'), map = new can.Map({ animals: [ 'bear', 'turtle' ] }), template = function (animal) { return '<label>Animal=</label> <span>' + animal + '</span>'; }; var compute = can.compute(function () { return map.attr('animals'); }); div.innerHTML = 'my <b>fav</b> animals: <span></span> !'; var el = div.getElementsByTagName('span')[0]; can.view.live.list(el, compute, template, {}); equal(div.getElementsByTagName('label') .length, 2, 'There are 2 labels'); div.getElementsByTagName('label')[0].myexpando = 'EXPANDO-ED'; map.attr('animals') .push('turtle'); equal(div.getElementsByTagName('label')[0].myexpando, 'EXPANDO-ED', 'same expando'); equal(div.getElementsByTagName('span')[2].innerHTML, 'turtle', 'turtle added'); map.attr('animals', new can.List([ 'sloth', 'bear', 'turtle' ])); var spans = div.getElementsByTagName('span'); equal(spans.length, 3, 'there are 3 spans'); ok(!div.getElementsByTagName('label')[0].myexpando, 'no expando'); }); test('list with a compute that returns a list', function () { var div = document.createElement('div'), template = function (num) { return '<label>num=</label> <span>' + num + '</span>'; }; var compute = can.compute([ 0, 1 ]); div.innerHTML = 'my <b>fav</b> nums: <span></span> !'; var el = div.getElementsByTagName('span')[0]; can.view.live.list(el, compute, template, {}); equal(div.getElementsByTagName('label') .length, 2, 'There are 2 labels'); compute([ 0, 1, 2 ]); var spans = div.getElementsByTagName('span'); equal(spans.length, 3, 'there are 3 spans'); }); test('text binding is memory safe (#666)', function () { for(var prop in can.view.nodeLists.nodeMap) { delete can.view.nodeLists.nodeMap[prop]; } var div = document.createElement('div'), span = document.createElement('span'), el = can.$(div), text = can.compute(function () { return 'foo'; }); div.appendChild(span); can.$('#qunit-fixture')[0].appendChild(div); can.view.live.text(span, text, div); can.remove(el); stop(); setTimeout(function () { ok(can.isEmptyObject(can.view.nodeLists.nodeMap), 'nothing in nodeMap'); start(); }, 100); }); test('html live binding handles getting a function from a compute',5, function(){ var handler = function(el){ ok(true, "called handler"); equal(el.nodeType, 3, "got a placeholder"); }; var div = document.createElement('div'), placeholder = document.createTextNode(''); div.appendChild(placeholder); var count = can.compute(0); var html = can.compute(function(){ if(count() === 0) { return "<h1>Hello World</h1>"; } else { return handler; } }); can.view.live.html(placeholder, html, div); equal(div.getElementsByTagName("h1").length, 1, "got h1"); count(1); equal(div.getElementsByTagName("h1").length, 0, "got h1"); count(0); equal(div.getElementsByTagName("h1").length, 1, "got h1"); }); test("can.view.live.list does not unbind on a list unnecessarily (#1835)", function(){ expect(0); var div = document.createElement('div'), list = new can.List([ 'sloth', 'bear' ]), template = function (animal) { return '<label>Animal=</label> <span>' + animal + '</span>'; }, unbind = list.unbind; list.unbind = function(){ ok(false, "unbind called"); return unbind.apply(this, arguments); }; div.innerHTML = 'my <b>fav</b> animals: <span></span> !'; var el = div.getElementsByTagName('span')[0]; can.view.live.list(el, list, template, {}); }); test("can.live.attribute works with non-string attributes (#1790)", function() { var el = document.createElement('div'), compute = can.compute(function() { return 2; }); can.view.elements.setAttr(el, "value", 1); can.view.live.attribute(el, 'value', compute); ok(true, 'No exception thrown.'); }); test('list and an falsey section (#1979)', function () { var div = document.createElement('div'), template = function (num) { return '<label>num=</label> <span>' + num + '</span>'; }, falseyTemplate = function (num) { return '<p>NOTHING</p>'; }; var compute = can.compute([ 0, 1 ]); div.innerHTML = 'my <b>fav</b> nums: <span></span> !'; var el = div.getElementsByTagName('span')[0]; can.view.live.list(el, compute, template, {}, undefined, undefined, falseyTemplate ); equal(div.getElementsByTagName('label') .length, 2, 'There are 2 labels'); compute([]); var spans = div.getElementsByTagName('span'); equal(spans.length, 0, 'there are 0 spans'); var ps = div.getElementsByTagName('p'); equal(ps.length, 1, 'there is 1 p'); compute([2]); spans = div.getElementsByTagName('span'); equal(spans.length, 1, 'there is 1 spans'); ps = div.getElementsByTagName('p'); equal(ps.length, 0, 'there is 1 p'); }); test('list and an initial falsey section (#1979)', function(){ var div = document.createElement('div'), template = function (num) { return '<label>num=</label> <span>' + num + '</span>'; }, falseyTemplate = function (num) { return '<p>NOTHING</p>'; }; var compute = can.compute([]); div.innerHTML = 'my <b>fav</b> nums: <span></span> !'; var el = div.getElementsByTagName('span')[0]; can.view.live.list(el, compute, template, {}, undefined, undefined, falseyTemplate ); var spans = div.getElementsByTagName('span'); equal(spans.length, 0, 'there are 0 spans'); var ps = div.getElementsByTagName('p'); equal(ps.length, 1, 'there is 1 p'); compute([2]); spans = div.getElementsByTagName('span'); equal(spans.length, 1, 'there is 1 spans'); ps = div.getElementsByTagName('p'); equal(ps.length, 0, 'there is 1 p'); }); test('rendered list items should re-render when updated (#2007)', function () { var partial = document.createElement('div'); var placeholderElement = document.createElement('span'); var list = new can.List([ 'foo' ]); var renderer = function(item) { return '<span>' + item + '</span>'; }; partial.appendChild(placeholderElement); can.view.live.list(placeholderElement, list, renderer, {}); equal(partial.getElementsByTagName('span')[0].firstChild.data, 'foo', 'list item 0 is foo'); list.push('bar'); equal(partial.getElementsByTagName('span')[1].firstChild.data, 'bar', 'list item 1 is bar'); list.attr(0, 'baz'); equal(partial.getElementsByTagName('span')[0].firstChild.data, 'baz', 'list item 0 is baz'); }); test('#each when passed a node list leaks (#2332)', function(){ var partial = document.createElement('div'); var placeholderElement = document.createElement('span'); var list = new can.List([ 'foo' ]); var renderer = function(item) { return '<span>' + item + '</span>'; }; partial.appendChild(placeholderElement); var nodeList = can.view.nodeLists.register([placeholderElement], null, true); can.view.live.list(placeholderElement, list, renderer, {}, partial, nodeList); equal(nodeList.replacements.length, 0, "replacements should not be used because can.view.live.list manages the list itself"); }); });