1// https://dom.spec.whatwg.org/#concept-event-dispatch 2 3const host = document.createElement("div"), 4 child = host.appendChild(document.createElement("p")), 5 shadow = host.attachShadow({ mode: "closed" }), 6 slot = shadow.appendChild(document.createElement("slot")); 7 8test(() => { 9 for (target of [shadow, slot]) { 10 for (relatedTarget of [new XMLHttpRequest(), self, host]) { 11 const event = new FocusEvent("demo", { relatedTarget: relatedTarget }); 12 target.dispatchEvent(event); 13 assert_equals(event.target, null); 14 assert_equals(event.relatedTarget, null); 15 } 16 } 17}, "Reset if target pointed to a shadow tree"); 18 19test(() => { 20 for (relatedTarget of [shadow, slot]) { 21 for (target of [new XMLHttpRequest(), self, host]) { 22 const event = new FocusEvent("demo", { relatedTarget: relatedTarget }); 23 target.dispatchEvent(event); 24 assert_equals(event.target, target); 25 assert_equals(event.relatedTarget, host); 26 } 27 } 28}, "Retarget a shadow-tree relatedTarget"); 29 30test(t => { 31 const shadowChild = shadow.appendChild(document.createElement("div")); 32 shadowChild.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild))); 33 const event = new FocusEvent("demo", { relatedTarget: new XMLHttpRequest() }); 34 shadowChild.dispatchEvent(event); 35 assert_equals(shadowChild.parentNode, document.body); 36 assert_equals(event.target, null); 37 assert_equals(event.relatedTarget, null); 38 shadowChild.remove(); 39}, "Reset if target pointed to a shadow tree pre-dispatch"); 40 41test(t => { 42 const shadowChild = shadow.appendChild(document.createElement("div")); 43 document.body.addEventListener("demo", t.step_func(() => document.body.appendChild(shadowChild))); 44 const event = new FocusEvent("demo", { relatedTarget: shadowChild }); 45 document.body.dispatchEvent(event); 46 assert_equals(shadowChild.parentNode, document.body); 47 assert_equals(event.target, document.body); 48 assert_equals(event.relatedTarget, host); 49 shadowChild.remove(); 50}, "Retarget a shadow-tree relatedTarget, part 2"); 51 52test(t => { 53 const event = new FocusEvent("heya", { relatedTarget: shadow, cancelable: true }), 54 callback = t.unreached_func(); 55 host.addEventListener("heya", callback); 56 t.add_cleanup(() => host.removeEventListener("heya", callback)); 57 event.preventDefault(); 58 assert_true(event.defaultPrevented); 59 assert_false(host.dispatchEvent(event)); 60 assert_equals(event.target, null); 61 assert_equals(event.relatedTarget, null); 62 // Check that the dispatch flag is cleared 63 event.initEvent("x"); 64 assert_equals(event.type, "x"); 65}, "Reset targets on early return"); 66 67test(t => { 68 const input = document.body.appendChild(document.createElement("input")), 69 event = new MouseEvent("click", { relatedTarget: shadow }); 70 let seen = false; 71 t.add_cleanup(() => input.remove()); 72 input.type = "checkbox"; 73 input.oninput = t.step_func(() => { 74 assert_equals(event.target, null); 75 assert_equals(event.relatedTarget, null); 76 assert_equals(event.composedPath().length, 0); 77 seen = true; 78 }); 79 assert_true(input.dispatchEvent(event)); 80 assert_true(seen); 81}, "Reset targets before activation behavior"); 82