UNPKG

can

Version:

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

213 lines (212 loc) 5.35 kB
steal("can/list", "can/map/delegate", "can/test", "steal-qunit", function () { QUnit.module('can/map/delegate'); var matches = can.Map.prototype.delegate.matches; test('matches', function () { equal(matches(['**'], [ 'foo', 'bar', '0' ]), 'foo.bar.0', 'everything'); equal(matches(['*.**'], ['foo']), null, 'everything at least one level deep'); equal(matches([ 'foo', '*' ], [ 'foo', 'bar', '0' ]), 'foo.bar'); equal(matches(['*'], [ 'foo', 'bar', '0' ]), 'foo'); equal(matches([ '*', 'bar' ], [ 'foo', 'bar', '0' ]), 'foo.bar'); }); test('delegate', 4, function () { var state = new can.Map({ properties: { prices: [] } }); var prices = state.attr('properties.prices'); state.delegate('properties.prices', 'change', function (ev, attr, how, val, old) { equal(attr, '0', 'correct change name'); equal(how, 'add'); equal(val[0].attr('foo'), 'bar', 'correct'); ok(this === prices, 'rooted element'); }); prices.push({ foo: 'bar' }); state.undelegate(); }); test('delegate on add', 2, function () { var state = new can.Map({}); state.delegate('foo', 'add', function (ev, newVal) { ok(true, 'called'); equal(newVal, 'bar', 'got newVal'); }) .delegate('foo', 'remove', function () { ok(false, 'remove should not be called'); }); state.attr('foo', 'bar'); }); test('delegate set is called on add', 2, function () { var state = new can.Map({}); state.delegate('foo', 'set', function (ev, newVal) { ok(true, 'called'); equal(newVal, 'bar', 'got newVal'); }); state.attr('foo', 'bar'); }); test('delegate\'s this', 5, function () { var state = new can.Map({ person: { name: { first: 'justin', last: 'meyer' } }, prop: 'foo' }); var n = state.attr('person.name'), check; // listen to person name changes state.delegate('person.name', 'set', check = function (ev, newValue, oldVal, from) { // make sure we are getting back the person.name equal(this, n); equal(newValue, 'Brian'); equal(oldVal, 'justin'); // and how to get there equal(from, 'first'); }); n.attr('first', 'Brian'); state.undelegate('person.name', 'set', check); // stop listening // now listen to changes in prop state.delegate('prop', 'set', function () { equal(this, 'food'); }); // this is weird, probably need to support direct bind ... // update the prop state.attr('prop', 'food'); }); test('delegate on deep properties with *', function () { var state = new can.Map({ person: { name: { first: 'justin', last: 'meyer' } } }); state.delegate('person', 'set', function (ev, newVal, oldVal, attr) { equal(this, state.attr('person'), 'this is set right'); equal(attr, 'name.first'); }); state.attr('person.name.first', 'brian'); }); test('compound sets', function () { var state = new can.Map({ type: 'person', id: '5' }); var count = 0; state.delegate('type=person id', 'set', function () { equal(state.type, 'person', 'type is person'); ok(state.id !== undefined, 'id has value'); count++; }); // should trigger a change state.attr('id', 0); equal(count, 1, 'changing the id to 0 caused a change'); // should not fire a set state.removeAttr('id'); equal(count, 1, 'removing the id changed nothing'); state.attr('id', 3); equal(count, 2, 'adding an id calls callback'); state.attr('type', 'peter'); equal(count, 2, 'changing the type does not fire callback'); state.removeAttr('type'); state.removeAttr('id'); equal(count, 2, ''); state.attr({ type: 'person', id: '5' }); equal(count, 3, 'setting person and id only fires 1 event'); state.removeAttr('type'); state.removeAttr('id'); state.attr({ type: 'person' }); equal(count, 3, 'setting person does not fire anything'); }); test('undelegate within event loop', 1, function () { var state = new can.Map({ type: 'person', id: '5' }); var f1 = function () { state.undelegate('type', 'add', f2); }, f2 = function () { ok(false, 'I am removed, how am I called'); }, f3 = function () { state.undelegate('type', 'add', f1); }, f4 = function () { ok(true, 'f4 called'); }; state.delegate('type', 'set', f1); state.delegate('type', 'set', f2); state.delegate('type', 'set', f3); state.delegate('type', 'set', f4); state.attr('type', 'other'); }); test('selector types', 5, function () { var state = new can.Map({ foo: 'a', bar: 'b', baz: 'c', box: 'd', baw: 'e' }); state.delegate('foo=aa', 'change', function () { ok(true, 'Unquoted value in selector matched.'); }); state.attr({ foo: 'aa' }); state.delegate('bar=\'b b\'', 'change', function () { ok(true, 'Single-quoted value in selector matched.'); }); state.attr({ bar: 'b b' }); state.delegate('baz="c c"', 'change', function () { ok(true, 'Double-quoted value in selector matched.'); }); state.attr({ baz: 'c c' }); state.delegate('box', 'change', function () { ok(true, 'No-value attribute in selector matched.'); }); state.attr({ box: 'quux' }); state.delegate('baw=', 'change', function () { ok(true, 'Empty-value shortcut in selector matched.'); }); state.attr({ baw: '' }); }); });