// https://dom.spec.whatwg.org/#concept-event-dispatch const host = document.createElement("div"), child = host.appendChild(document.createElement("p")), shadow = host.attachShadow({ mode: "closed" }), slot = shadow.appendChild(document.createElement("slot")); test(() => { for (target of [shadow, slot]) { for (relatedTarget of [new XMLHttpRequest(), self, host]) { const event = new FocusEvent("demo", { relatedTarget: relatedTarget }); target.dispatchEvent(event); assert_equals(event.target, null); assert_equals(event.relatedTarget, null); } } }, "Reset if target pointed to a shadow tree"); test(() => { for (relatedTarget of [shadow, slot]) { for (target of [new XMLHttpRequest(), self, host]) { const event = new FocusEvent("demo", { relatedTarget: relatedTarget }); target.dispatchEvent(event); assert_equals(event.target, target); assert_equals(event.relatedTarget, host); } } }, "Retarget a shadow-tree relatedTarget"); test(t => { const shadowChild = shadow.appendChild(document.createElement("div")); shadowChild.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild))); const event = new FocusEvent("demo", { relatedTarget: new XMLHttpRequest() }); shadowChild.dispatchEvent(event); assert_equals(shadowChild.parentNode, document.body); assert_equals(event.target, null); assert_equals(event.relatedTarget, null); shadowChild.remove(); }, "Reset if target pointed to a shadow tree pre-dispatch"); test(t => { const shadowChild = shadow.appendChild(document.createElement("div")); document.body.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild))); const event = new FocusEvent("demo", { relatedTarget: shadowChild }); document.body.dispatchEvent(event); assert_equals(shadowChild.parentNode, document.body); assert_equals(event.target, document.body); assert_equals(event.relatedTarget, host); shadowChild.remove(); }, "Retarget a shadow-tree relatedTarget, part 2"); test(t => { const event = new FocusEvent("heya", { relatedTarget: shadow, cancelable: true }), callback = t.unreached_func(); host.addEventListener("heya", callback); t.add_cleanup(() => host.removeEventListener("heya", callback)); event.preventDefault(); assert_true(event.defaultPrevented); assert_false(host.dispatchEvent(event)); assert_equals(event.target, null); assert_equals(event.relatedTarget, null); // Check that the dispatch flag is cleared event.initEvent("x"); assert_equals(event.type, "x"); }, "Reset targets on early return"); test(t => { const input = document.body.appendChild(document.createElement("input")), event = new MouseEvent("click", { relatedTarget: shadow }); let seen = false; t.add_cleanup(() => input.remove()); input.type = "checkbox"; input.oninput = t.step_func(() => { assert_equals(event.target, null); assert_equals(event.relatedTarget, null); assert_equals(event.composedPath().length, 0); seen = true; }); assert_true(input.dispatchEvent(event)); assert_true(seen); }, "Reset targets before activation behavior");