Skip to content

Commit

Permalink
events: reset event state after dispatch
Browse files Browse the repository at this point in the history
Fixes #54617
  • Loading branch information
KhafraDev committed Aug 29, 2024
1 parent beabcec commit e1c386d
Show file tree
Hide file tree
Showing 18 changed files with 811 additions and 569 deletions.
15 changes: 11 additions & 4 deletions lib/internal/event_target.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ const kEvents = Symbol('kEvents');
const kIsBeingDispatched = Symbol('kIsBeingDispatched');
const kStop = Symbol('kStop');
const kTarget = Symbol('kTarget');
const kCurrentTarget = Symbol('kCurrentTarget');
const kHandlers = Symbol('kHandlers');
const kWeakHandler = Symbol('kWeak');
const kResistStopPropagation = Symbol('kResistStopPropagation');
Expand Down Expand Up @@ -126,6 +127,7 @@ class Event {
}

this[kTarget] = null;
this[kCurrentTarget] = null;
this[kIsBeingDispatched] = false;
}

Expand Down Expand Up @@ -196,7 +198,7 @@ class Event {
get currentTarget() {
if (!isEvent(this))
throw new ERR_INVALID_THIS('Event');
return this[kTarget];
return this[kCurrentTarget];
}

/**
Expand Down Expand Up @@ -757,20 +759,23 @@ class EventTarget {
const createEvent = () => {
if (event === undefined) {
event = this[kCreateEvent](nodeValue, type);
event[kTarget] = this;
event[kCurrentTarget] = this;
event[kIsBeingDispatched] = true;
}
return event;
};
if (event !== undefined) {
event[kTarget] = this;
event[kCurrentTarget] = this;
event[kIsBeingDispatched] = true;
}

const root = this[kEvents].get(type);
if (root === undefined || root.next === undefined) {
if (event !== undefined)
if (event !== undefined) {
event[kCurrentTarget] = null;
event[kIsBeingDispatched] = false;
}
return true;
}

Expand Down Expand Up @@ -827,8 +832,10 @@ class EventTarget {
handler = next;
}

if (event !== undefined)
if (event !== undefined) {
event[kCurrentTarget] = null;
event[kIsBeingDispatched] = false;
}
}

[kCreateEvent](nodeValue, type) {
Expand Down
2 changes: 1 addition & 1 deletion test/fixtures/wpt/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Last update:
- compression: https://github.com/web-platform-tests/wpt/tree/5aa50dd415/compression
- console: https://github.com/web-platform-tests/wpt/tree/767ae35464/console
- dom/abort: https://github.com/web-platform-tests/wpt/tree/d1f1ecbd52/dom/abort
- dom/events: https://github.com/web-platform-tests/wpt/tree/ab8999891c/dom/events
- dom/events: https://github.com/web-platform-tests/wpt/tree/0a811c5161/dom/events
- encoding: https://github.com/web-platform-tests/wpt/tree/5aa50dd415/encoding
- fetch/data-urls/resources: https://github.com/web-platform-tests/wpt/tree/7c79d998ff/fetch/data-urls/resources
- FileAPI: https://github.com/web-platform-tests/wpt/tree/cceaf3628d/FileAPI
Expand Down
56 changes: 56 additions & 0 deletions test/fixtures/wpt/dom/events/Event-dispatch-click.html
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,22 @@
child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
}, "pick the first with activation behavior <a href>")

async_test(function(t) {
var input = document.createElement("input")
input.type = "radio"
dump.appendChild(input)
input.onclick = t.step_func(function() {
assert_false(input.checked, "input pre-click must not be triggered")
})
var child = input.appendChild(document.createElement("input"))
child.type = "radio"
child.onclick = t.step_func(function() {
assert_true(child.checked, "child pre-click must be triggered")
})
child.dispatchEvent(new MouseEvent("click", {bubbles:true}))
t.done()
}, "pick the first with activation behavior <input type=radio>")

async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
Expand Down Expand Up @@ -173,6 +189,46 @@
t.done()
}, "disabled checkbox still has activation behavior, part 2")

async_test(function(t) {
var state = "start"

var form = document.createElement("form")
form.onsubmit = t.step_func(() => {
if(state == "start" || state == "radio") {
state = "failure"
} else if(state == "form") {
state = "done"
}
return false
})
dump.appendChild(form)
var button = form.appendChild(document.createElement("button"))
button.type = "submit"
var radio = button.appendChild(document.createElement("input"))
radio.type = "radio"
radio.onclick = t.step_func(() => {
if(state == "start") {
assert_unreached()
} else if(state == "radio") {
assert_true(radio.checked)
}
})
radio.disabled = true
radio.click()
assert_equals(state, "start")

state = "radio"
radio.disabled = false
radio.click()
assert_equals(state, "radio")

state = "form"
button.click()
assert_equals(state, "done")

t.done()
}, "disabled radio still has activation behavior")

async_test(function(t) {
var input = document.createElement("input")
input.type = "checkbox"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<body>
<script>
// HTML elements that can be disabled
const formElements = ["button", "fieldset", "input", "select", "textarea"];
const formElements = ["button", "input", "select", "textarea"];

test(() => {
for (const localName of formElements) {
Expand Down
17 changes: 17 additions & 0 deletions test/fixtures/wpt/dom/events/EventTarget-constructible.any.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,23 @@ test(() => {
assert_equals(callCount, 2);
}, "A constructed EventTarget can be used as expected");

test(() => {
const target = new EventTarget();
const event = new Event("foo");

function listener(e) {
assert_equals(e, event);
assert_equals(e.target, target);
assert_equals(e.currentTarget, target);
assert_array_equals(e.composedPath(), [target]);
}
target.addEventListener("foo", listener, { once: true });
target.dispatchEvent(event);
assert_equals(event.target, target);
assert_equals(event.currentTarget, null);
assert_array_equals(event.composedPath(), []);
}, "A constructed EventTarget implements dispatch correctly");

test(() => {
class NicerEventTarget extends EventTarget {
on(...args) {
Expand Down
10 changes: 10 additions & 0 deletions test/fixtures/wpt/dom/events/event-global.html
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,14 @@

target.dispatchEvent(new Event("click"));
}, "window.event is set to the current event, which is the event passed to dispatch");

async_test(t => {
let target = new XMLHttpRequest();

target.onload = t.step_func_done(e => {
assert_equals(e, window.event);
});

target.dispatchEvent(new Event("load"));
}, "window.event is set to the current event, which is the event passed to dispatch (2)");
</script>
Loading

0 comments on commit e1c386d

Please sign in to comment.