Skip to content

Commit

Permalink
Add capturing support to once function
Browse files Browse the repository at this point in the history
  • Loading branch information
demiazz committed May 4, 2017
1 parent a035784 commit 1b35ee7
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 13 deletions.
2 changes: 1 addition & 1 deletion d.ts/homey.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,6 @@ export function remove(element: Element): boolean;
*/

export function on(element: Element, eventType: EventType, listener: EventListener, useCapture?: boolean): () => void;
export function once(element: Element, eventType: EventType, listener: EventListener): () => void;
export function once(element: Element, eventType: EventType, listener: EventListener, useCapture?: boolean): () => void;
export function delegate(element: Element, selector: Selector, eventType: EventType, listener: EventListener): () => void;
export function dispatch(element: Element, eventType: EventType, listener: EventListener): boolean;
94 changes: 85 additions & 9 deletions spec/events/once.spec.js
Original file line number Diff line number Diff line change
@@ -1,19 +1,14 @@
import { once } from "../../src";

describe("once", () => {
let subject;
let listener;
afterEach(clearFixtures);

beforeEach(() => {
it("adds listener for DOM event", () => {
useFixture(`<div class="root"></div>`);

subject = document.querySelector(".root");
listener = jasmine.createSpy("listener");
});

afterEach(clearFixtures);
const subject = document.querySelector(".root");
const listener = jasmine.createSpy("listener");

it("adds listener for DOM event", () => {
once(subject, "click", listener);

expect(listener).not.toHaveBeenCalled();
Expand All @@ -27,6 +22,11 @@ describe("once", () => {
});

it("adds listener for custom event", () => {
useFixture(`<div class="root"></div>`);

const subject = document.querySelector(".root");
const listener = jasmine.createSpy("listener");

once(subject, "custom", listener);

expect(listener).not.toHaveBeenCalled();
Expand All @@ -40,6 +40,11 @@ describe("once", () => {
});

it("adds listener which called on first event trigger only", () => {
useFixture(`<div class="root"></div>`);

const subject = document.querySelector(".root");
const listener = jasmine.createSpy("listener");

once(subject, "click", listener);

expect(listener).not.toHaveBeenCalled();
Expand All @@ -60,6 +65,11 @@ describe("once", () => {
});

it("returns function for removing listener", () => {
useFixture(`<div class="root"></div>`);

const subject = document.querySelector(".root");
const listener = jasmine.createSpy("listener");

const off = once(subject, "click", listener);

expect(listener).not.toHaveBeenCalled();
Expand All @@ -72,4 +82,70 @@ describe("once", () => {

expect(listener).not.toHaveBeenCalled();
});

describe("supports events capturing", () => {
it("doesn't use capturing by default", () => {
useFixture(`
<div class="parent">
<div class="root">
<div class="child"></child>
</div>
</div>
`);

const parent = document.querySelector(".parent");
const subject = document.querySelector(".root");
const child = document.querySelector(".child");
const parentListener = jasmine.createSpy("parentListener");
const subjectListener = jasmine.createSpy("subjectListener");

once(parent, "click", parentListener);
once(subject, "click", subjectListener);

expect(parentListener).not.toHaveBeenCalled();
expect(subjectListener).not.toHaveBeenCalled();

const event = createEvent("click");

child.dispatchEvent(event);

expect(parentListener).toHaveBeenCalledTimes(1);
expect(parentListener).toHaveBeenCalledWith(event);
expect(subjectListener).toHaveBeenCalledTimes(1);
expect(subjectListener).toHaveBeenCalledWith(event);
expect(subjectListener).toHaveBeenCalledBefore(parentListener);
});

it("uses capturing when flag given", () => {
useFixture(`
<div class="parent">
<div class="root">
<div class="child"></child>
</div>
</div>
`);

const parent = document.querySelector(".parent");
const subject = document.querySelector(".root");
const child = document.querySelector(".child");
const parentListener = jasmine.createSpy("parentListener");
const subjectListener = jasmine.createSpy("subjectListener");

once(parent, "click", parentListener, true);
once(subject, "click", subjectListener, true);

expect(parentListener).not.toHaveBeenCalled();
expect(subjectListener).not.toHaveBeenCalled();

const event = createEvent("click");

child.dispatchEvent(event);

expect(parentListener).toHaveBeenCalledTimes(1);
expect(parentListener).toHaveBeenCalledWith(event);
expect(subjectListener).toHaveBeenCalledTimes(1);
expect(subjectListener).toHaveBeenCalledWith(event);
expect(parentListener).toHaveBeenCalledBefore(subjectListener);
});
});
});
7 changes: 4 additions & 3 deletions src/events/once.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ import on from "./on";
function once(
element: Element,
eventType: EventType,
listener: EventListener
listener: EventListener,
useCapture?: boolean = false
): () => void {
function wrappedListener(event) {
element.removeEventListener(eventType, wrappedListener);
element.removeEventListener(eventType, wrappedListener, useCapture);

listener(event);
}

return on(element, eventType, wrappedListener);
return on(element, eventType, wrappedListener, useCapture);
}

export default once;

0 comments on commit 1b35ee7

Please sign in to comment.