mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-09-21 03:55:22 -04:00
webapi: prevent click() from triggering click()
/html/editing/activation/click_checkbox.html is a DCHECK crash (debug only) and just a failure in ReleaseFast. click() handler shouldn't trigger its own click(). Click is singled out for this behavior, which is 'do nothing': https://html.spec.whatwg.org/multipage/interaction.html#click-in-progress-flag Used the new Element flags. There's a simple way to implement this in EventManager, but the element flag is cheaper and it's currently not used. If someone ever needs that bit, they can implement the stack-based solution.
This commit is contained in:
3 files changed
+42
-1
No files matched your search
@@ -281,3 +281,30 @@
|
||||
testing.expectEqual(false, r3.checked);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="nested_click_is_noop">
|
||||
{
|
||||
// click() while a click() on the same element is in progress is a no-op
|
||||
// (the "click in progress" flag); a re-entrant handler must not recurse.
|
||||
const cb = document.createElement('input');
|
||||
cb.type = 'checkbox';
|
||||
document.body.appendChild(cb);
|
||||
|
||||
let clicks = 0;
|
||||
cb.addEventListener('click', () => {
|
||||
clicks++;
|
||||
cb.click();
|
||||
});
|
||||
|
||||
cb.click();
|
||||
testing.expectEqual(1, clicks, 'nested click() should not dispatch');
|
||||
testing.expectEqual(true, cb.checked);
|
||||
|
||||
// The flag is cleared afterwards, so a fresh click() works again.
|
||||
cb.click();
|
||||
testing.expectEqual(2, clicks);
|
||||
testing.expectEqual(false, cb.checked);
|
||||
|
||||
document.body.removeChild(cb);
|
||||
}
|
||||
</script>
|
||||
@@ -139,7 +139,14 @@ pub const Namespace = enum(u8) {
|
||||
pub const Flags = packed struct(u8) {
|
||||
shadow_host: bool = false,
|
||||
customized_builtin: bool = false,
|
||||
_unused: u6 = 0,
|
||||
|
||||
// Prevents nested clicks (which have a specific spec-compliant behavior
|
||||
// compared to other events). If this bit can be more useful for something
|
||||
// else, a stack in EventManager (for click-specifically) is an alterantive
|
||||
// approach
|
||||
click_in_progress: bool = false,
|
||||
|
||||
_unused: u5 = 0,
|
||||
};
|
||||
|
||||
_type: Type,
|
||||
|
||||
@@ -402,6 +402,13 @@ pub fn click(self: *HtmlElement, frame: *Frame) !void {
|
||||
else => {},
|
||||
}
|
||||
|
||||
const flags = &self.asElement()._flags;
|
||||
if (flags.click_in_progress) {
|
||||
return;
|
||||
}
|
||||
flags.click_in_progress = true;
|
||||
defer flags.click_in_progress = false;
|
||||
|
||||
const event = (try @import("../event/MouseEvent.zig").init("click", .{
|
||||
.bubbles = true,
|
||||
.cancelable = true,
|
||||
|
||||
Reference in new issue
Block a user