Skip to content

Commit

Permalink
Merge 9c26569 into 13b0e2d
Browse files Browse the repository at this point in the history
  • Loading branch information
domenic authored Jun 30, 2017
2 parents 13b0e2d + 9c26569 commit 00d82d0
Show file tree
Hide file tree
Showing 2 changed files with 211 additions and 4 deletions.
194 changes: 194 additions & 0 deletions dom/events/EventTarget-group-option.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>EventTarget's ability to remove event listeners by group</title>
<link rel="author" title="Domenic Denicola" href="mailto:[email protected]">
<link rel="help" href="https://dom.spec.whatwg.org/#dom-addeventlisteneroptions-group">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>

<script>
"use strict";
test(() => {
const target = document.createElement("div");
const happenings = [];

target.addEventListener("e1", () => { happenings.push("e1.1"); }, { group: "g" });
target.addEventListener("e1", () => { happenings.push("e1.2"); }, { group: "g" });
target.addEventListener("e2", () => { happenings.push("e2.1"); }, { group: "g" });
target.addEventListener("e2", () => { happenings.push("e2.2"); }, { group: "g" });

target.removeEventListener({ group: "g" });

target.dispatchEvent(new CustomEvent("e1"));
target.dispatchEvent(new CustomEvent("e2"));

assert_array_equals(happenings, []);
}, "Removing via a string group works");

test(() => {
const target = document.createElement("div");
const happenings = [];

target.addEventListener("e1", () => { happenings.push("e1.1"); }, { group: "g" });
target.addEventListener("e1", () => { happenings.push("e1.2"); }, { group: "g" });
target.addEventListener("e2", () => { happenings.push("e2.1"); }, { group: "g" });
target.addEventListener("e2", () => { happenings.push("e2.2"); }, { group: "g" });

target.removeEventListener("e1", { group: "g" });

target.dispatchEvent(new CustomEvent("e1"));
target.dispatchEvent(new CustomEvent("e2"));

assert_array_equals(happenings, ["e2.1", "e2.2"]);
}, "Removing via a string group with a type specified works");

test(() => {
const target = document.createElement("div");
const happenings = [];
const group = Symbol();

target.addEventListener("e1", () => { happenings.push("e1.1"); }, { group });
target.addEventListener("e1", () => { happenings.push("e1.2"); }, { group });
target.addEventListener("e2", () => { happenings.push("e2.1"); }, { group });
target.addEventListener("e2", () => { happenings.push("e2.2"); }, { group });

target.removeEventListener({ group });

target.dispatchEvent(new CustomEvent("e1"));
target.dispatchEvent(new CustomEvent("e2"));

assert_array_equals(happenings, []);
}, "Removing via a symbol group works");

test(() => {
const target = document.createElement("div");
const happenings = [];
const group = Symbol();

target.addEventListener("e1", () => { happenings.push("e1.1"); }, { group });
target.addEventListener("e1", () => { happenings.push("e1.2"); }, { group });
target.addEventListener("e2", () => { happenings.push("e2.1"); }, { group });
target.addEventListener("e2", () => { happenings.push("e2.2"); }, { group });

target.removeEventListener("e1", { group });

target.dispatchEvent(new CustomEvent("e1"));
target.dispatchEvent(new CustomEvent("e2"));

assert_array_equals(happenings, ["e2.1", "e2.2"]);
}, "Removing via a symbol group with a type specified works");

test(() => {
const target = document.createElement("div");
const happenings = [];

target.addEventListener("e1", () => { happenings.push("e1.1"); }, { group: navigator });
target.addEventListener("e1", () => { happenings.push("e1.2"); }, { group: "[object Navigator]" });
target.addEventListener("e1", () => { happenings.push("e1.3"); }, { group: "other value" });

target.removeEventListener({ group: navigator });

target.dispatchEvent(new CustomEvent("e1"));

assert_array_equals(happenings, ["e1.3"]);
}, "Attempting to use a platform object as a group converts it to a string");

test(() => {
const target = document.createElement("div");
const happenings = [];

assert_throws(new TypeError(), () => target.addEventListener("e1", () => {}, { group: null }));
assert_throws(new TypeError(), () => target.removeEventListener("e1", { group: null }));
assert_throws(new TypeError(), () => target.removeEventListener({ group: null }));
}, "Attempting to use null as a group does not work");

test(() => {
const target = document.createElement("div");
const happenings = [];

// undefined is treated as not present (i.e. not grouped) for addEventListener
target.addEventListener("e1", () => { happenings.push("e1.1"); }, { group: undefined });
target.addEventListener("e1", () => { happenings.push("e1.2"); }, { group: undefined });
target.addEventListener("e2", () => { happenings.push("e2.1"); }, { group: undefined });
target.addEventListener("e2", () => { happenings.push("e2.2"); }, { group: undefined });

// undefined is not allowed for removeEventListener
assert_throws(new TypeError(), () => target.removeEventListener({ group: undefined }));
assert_throws(new TypeError(), () => target.removeEventListener({ }));
assert_throws(new TypeError(), () => target.removeEventListener("e1", { group: undefined }));
assert_throws(new TypeError(), () => target.removeEventListener("e1", { }));

target.dispatchEvent(new CustomEvent("e1"));
target.dispatchEvent(new CustomEvent("e2"));

assert_array_equals(happenings, ["e1.1", "e1.2", "e2.1", "e2.2"]);
}, "Attempting to use undefined as a group does not work");

test(() => {
const target = document.createElement("div");
const happenings = [];
const g2 = Symbol("g2");

target.addEventListener("e1", () => { happenings.push("e1.1"); }, { group: ["g", g2] });
target.addEventListener("e1", () => { happenings.push("e1.2"); }, { group: ["f", "g"] });
target.addEventListener("e2", () => { happenings.push("e2.1"); }, { group: [g2] });
target.addEventListener("e2", () => { happenings.push("e2.2"); }, { group: "g" });
target.addEventListener("e2", () => { happenings.push("e2.3"); }, { group: "h" });

target.removeEventListener({ group: "g" });
target.removeEventListener({ group: g2 });

target.dispatchEvent(new CustomEvent("e1"));
target.dispatchEvent(new CustomEvent("e2"));

assert_array_equals(happenings, ["e2.3"]);
}, "Multiple groups can be added via an array");

test(() => {
const target = document.createElement("div");

target.removeEventListener({ group: "g" });
target.removeEventListener({ group: new Symbol() });

target.removeEventListener("e1", { group: "g" });
target.removeEventListener("e1", { group: new Symbol() });
}, "Removing using non-existant groups doesn't throw or do anything weird");

test(() => {
const target = document.createElement("div");
const happenings = [];

target.addEventListener("e1", () => { happenings.push("e1.1"); }, { group: ["g", "g2"] });
target.addEventListener("e1", () => { happenings.push("e1.2"); }, { group: ["f", "g"] });
target.addEventListener("e2", () => { happenings.push("e2.1"); }, { group: ["g2"] });
target.addEventListener("e2", () => { happenings.push("e2.2"); }, { group: "g" });
target.addEventListener("e2", () => { happenings.push("e2.3"); }, { group: "g,g2" });

target.removeEventListener({ group: ["g", "g2"] });

target.dispatchEvent(new CustomEvent("e1"));
target.dispatchEvent(new CustomEvent("e2"));

assert_array_equals(happenings, ["e1.1", "e1.2", "e2.1", "e2.2"]);
}, "Attempting to pass an array to remove stringifies it");

test(() => {
const target = document.createElement("div");
let counter = 0;

function handler() {
++counter;
}

target.addEventListener("e1", handler, { group: "g" });
target.addEventListener("e1", handler);
target.addEventListener("e1", handler, { group: "f" });

target.dispatchEvent(new CustomEvent("e1"));
assert_equals(counter, 1, "The handler must only have been added once");

target.removeEventListener({ group: "g" });
target.dispatchEvent(new CustomEvent("e1"));
assert_equals(counter, 1, "Dispatching the event after removing the handler must not call the handler");
}, "Groups are not considered when checking for duplicates");
</script>
21 changes: 17 additions & 4 deletions interfaces/dom.idl
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ dictionary CustomEventInit : EventInit {
};


//[Exposed=(Window,Worker)]
[Exposed=(Window,Worker)]
interface EventTarget {
void addEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
void addEventListener(DOMString type, EventListener? callback, optional (AddEventListenerOptions or boolean) options);

void removeEventListener(DOMString type, EventListener? callback, optional (EventListenerOptions or boolean) options);
void removeEventListener(DOMString type, RemoveEventListenerGroupOptions options);
void removeEventListener(RemoveEventListenerGroupOptions options);

boolean dispatchEvent(Event event);
};

Expand All @@ -56,8 +60,17 @@ callback interface EventListener {
};

dictionary EventListenerOptions {
boolean capture;
boolean passive;
boolean capture = false;
};

dictionary RemoveEventListenerGroupOptions {
required any group;
};

dictionary AddEventListenerOptions : EventListenerOptions {
boolean passive = false;
boolean once = false;
any group;
};


Expand Down

0 comments on commit 00d82d0

Please sign in to comment.