From 8a5d7464128e6743930f7cbac1c6784142930497 Mon Sep 17 00:00:00 2001 From: Timothy Farrell Date: Sun, 29 Jan 2017 23:02:20 -0600 Subject: [PATCH] Add event tests and bugfixes --- packages/projector/spec/projector.spec.js | 96 ++++++++++++++++++++++- packages/projector/src/index.js | 15 +++- 2 files changed, 105 insertions(+), 6 deletions(-) diff --git a/packages/projector/spec/projector.spec.js b/packages/projector/spec/projector.spec.js index b2c974d..d3cb453 100644 --- a/packages/projector/spec/projector.spec.js +++ b/packages/projector/spec/projector.spec.js @@ -62,7 +62,7 @@ describe('Projector', () => { }); describe('queueFrame', () => { - describe('patch to add elements', () => { + describe('add elements patch', () => { it('patch to add a basic element with a class', () => { expect(container.childNodes.length).toBe(0); @@ -117,9 +117,24 @@ describe('Projector', () => { expect(document.querySelector('.child')).toBe(child); expect(projector.getElement(child._id)).toBe(child); }); + + it('patch to add an eventHandler', done => { + function eventHandler(evt) { + expect(evt.target._id).toBe(id); + done(); + } + projector.subscribe(eventHandler); + + const id = add(h('input', { type: 'text', value: 'test', onclick: true })); + waitForNextFrame() + .then(() => { + projector.getElement(id).click(); + }) + .catch(console.error.bind(console)); + }); }); - describe('patch to update elements', () => { + describe('update element patch', () => { it('patch to change a class', done => { const id = add(h('div', { className: 'first' })); waitForNextFrame() @@ -161,10 +176,54 @@ describe('Projector', () => { .then(done) .catch(console.error.bind(console)); }); + + it('patch to add an eventHandler', done => { + function eventHandler(evt) { + expect(evt.target._id).toBe(id); + done(); + } + projector.subscribe(eventHandler); + + const id = add(h('input', { type: 'text', value: 'test' })); + waitForNextFrame() + .then(() => { + patch(id, { onclick: true }); + return waitForNextFrame(); + }) + .then(() => { + projector.getElement(id).click(); + }) + .catch(console.error.bind(console)); + }); + + it('patch to remove an eventHandler', done => { + let callCount = 1; + function eventHandler(evt) { + expect(evt.target._id).toBe(id); + patch(id, { onclick: null }); + if (0 === callCount--) { + fail('Should not be called twice.'); + } + } + projector.subscribe(eventHandler); + + const id = add(h('input', { type: 'text', value: 'test', onclick: true })); + waitForNextFrame() + .then(() => { + projector.getElement(id).click(); + return waitForNextFrame(); + }) + .then(() => { + projector.getElement(id).click(); + return waitForNextFrame(); + }) + .then(done) + .catch(console.error.bind(console)); + }); }); - describe('patch to remove an element', () => { - it('', done => { + describe('remove element patch', () => { + it('remove an element', done => { const id = add(h('div', {}, [h('span', { className: 'child' })])); const parent = projector.getElement(id); const child = parent.childNodes[0]; @@ -181,4 +240,33 @@ describe('Projector', () => { }); }); }); + + describe('subscribe', () => { + it('do not propagate a removed sibling event', done => { + let callCount = 1; + function eventHandler(evt) { + expect(evt.target._id).toBe(Bid); + patch(Bid, { onclick: null }); + if (0 === callCount--) { + fail('Should not be called twice.'); + } + } + projector.subscribe(eventHandler); + + const Aid = add(h('input', { type: 'text', value: 'A', onclick: true })); + const Bid = add(h('input', { type: 'text', value: 'B', onclick: true })); + waitForNextFrame() + .then(() => { + projector.getElement(Bid).click(); + return waitForNextFrame(); + }) + .then(() => { + // debugger; + projector.getElement(Bid).click(); + return waitForNextFrame(); + }) + .then(done) + .catch(console.error.bind(console)); + }); + }); }); diff --git a/packages/projector/src/index.js b/packages/projector/src/index.js index c1c7ad8..1f0d95a 100644 --- a/packages/projector/src/index.js +++ b/packages/projector/src/index.js @@ -16,16 +16,27 @@ export function Projector(domRoot) { let runningNextFrame; function eventHandler(evt) { + const eventName = evt.type; + const eventSet = eventMap.get(eventName); + if (!eventSet || (evt.target && !eventSet.has(evt.target._id))) { + return; + } + if (OVERRIDING_EVENTS.includes(eventName)) { evt.preventDefault(); } + evt.stopPropagation(); + eventCallbacks.forEach(cb => cb(evt)); } + function removeEvent(eventSet, id, eventName) { - eventSet.remove(element._id); + eventSet.delete(id); if (!eventSet.size) { domRoot.removeEventListener(eventName, eventHandler); + // Probably unnecessary to remove the eventSet from the map. + // eventMap.delete(eventName); } } @@ -76,8 +87,8 @@ export function Projector(domRoot) { } else if (type === 1) { element = document.createElement(name); } - setAttributes(element, props); elementMap.set((element._id = id), element); + setAttributes(element, props); for (let i = 0; i < children.length; i++) { element.appendChild(createElement(children[i]));