mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-14 15:28:57 +00:00
Document.activeElement, focus and blur
This commit is contained in:
81
src/browser/tests/document/focus.html
Normal file
81
src/browser/tests/document/focus.html
Normal file
@@ -0,0 +1,81 @@
|
||||
<!DOCTYPE html>
|
||||
<script src="../testing.js"></script>
|
||||
<body>
|
||||
<input id="input1" type="text">
|
||||
<input id="input2" type="text">
|
||||
<button id="btn1">Button</button>
|
||||
</body>
|
||||
|
||||
<script id="activeElement_default">
|
||||
{
|
||||
const body = document.querySelector('body');
|
||||
body.focus();
|
||||
testing.expectEqual('BODY', document.activeElement.tagName);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="focus_method">
|
||||
{
|
||||
const input1 = $('#input1');
|
||||
input1.focus();
|
||||
testing.expectEqual(input1, document.activeElement);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="focus_events">
|
||||
{
|
||||
const input1 = $('#input1');
|
||||
const input2 = $('#input2');
|
||||
|
||||
// Explicitly blur any focused element
|
||||
if (document.activeElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
let focusCount = 0;
|
||||
let blurCount = 0;
|
||||
|
||||
input1.addEventListener('focus', () => focusCount++);
|
||||
input1.addEventListener('blur', () => blurCount++);
|
||||
input2.addEventListener('focus', () => focusCount++);
|
||||
|
||||
input1.focus();
|
||||
testing.expectEqual(1, focusCount);
|
||||
testing.expectEqual(0, blurCount);
|
||||
|
||||
input2.focus();
|
||||
testing.expectEqual(2, focusCount);
|
||||
testing.expectEqual(1, blurCount);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="blur_method">
|
||||
{
|
||||
const btn = $('#btn1');
|
||||
btn.focus();
|
||||
testing.expectEqual(btn, document.activeElement);
|
||||
|
||||
btn.blur();
|
||||
testing.expectEqual('BODY', document.activeElement.tagName);
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="focus_already_focused">
|
||||
{
|
||||
const input1 = $('#input1');
|
||||
|
||||
// Explicitly blur any focused element
|
||||
if (document.activeElement) {
|
||||
document.activeElement.blur();
|
||||
}
|
||||
|
||||
let focusCount = 0;
|
||||
input1.addEventListener('focus', () => focusCount++);
|
||||
|
||||
input1.focus();
|
||||
testing.expectEqual(1, focusCount);
|
||||
|
||||
input1.focus();
|
||||
testing.expectEqual(1, focusCount);
|
||||
}
|
||||
</script>
|
||||
@@ -24,6 +24,7 @@ _location: ?*Location = null,
|
||||
_ready_state: ReadyState = .loading,
|
||||
_current_script: ?*Element.Html.Script = null,
|
||||
_elements_by_id: std.StringHashMapUnmanaged(*Element) = .empty,
|
||||
_active_element: ?*Element = null,
|
||||
|
||||
pub const Type = union(enum) {
|
||||
generic,
|
||||
@@ -155,6 +156,22 @@ pub fn getReadyState(self: *const Document) []const u8 {
|
||||
return @tagName(self._ready_state);
|
||||
}
|
||||
|
||||
pub fn getActiveElement(self: *Document) ?*Element {
|
||||
if (self._active_element) |el| {
|
||||
return el;
|
||||
}
|
||||
|
||||
// Default to body if it exists
|
||||
if (self.is(HTMLDocument)) |html_doc| {
|
||||
if (html_doc.getBody()) |body| {
|
||||
return body.asElement();
|
||||
}
|
||||
}
|
||||
|
||||
// Fallback to document element
|
||||
return self.getDocumentElement();
|
||||
}
|
||||
|
||||
const ReadyState = enum {
|
||||
loading,
|
||||
interactive,
|
||||
@@ -182,6 +199,7 @@ pub const JsApi = struct {
|
||||
pub const documentElement = bridge.accessor(Document.getDocumentElement, null, .{});
|
||||
pub const readyState = bridge.accessor(Document.getReadyState, null, .{});
|
||||
pub const implementation = bridge.accessor(Document.getImplementation, null, .{});
|
||||
pub const activeElement = bridge.accessor(Document.getActiveElement, null, .{});
|
||||
|
||||
pub const createElement = bridge.function(Document.createElement, .{});
|
||||
pub const createElementNS = bridge.function(Document.createElementNS, .{});
|
||||
|
||||
@@ -82,6 +82,10 @@ pub fn asNode(self: *Element) *Node {
|
||||
return self._proto;
|
||||
}
|
||||
|
||||
pub fn asEventTarget(self: *Element) *@import("EventTarget.zig") {
|
||||
return self._proto.asEventTarget();
|
||||
}
|
||||
|
||||
pub fn asConstNode(self: *const Element) *const Node {
|
||||
return self._proto;
|
||||
}
|
||||
@@ -390,6 +394,32 @@ pub fn remove(self: *Element, page: *Page) void {
|
||||
page.removeNode(parent, node, .{ .will_be_reconnected = false });
|
||||
}
|
||||
|
||||
pub fn focus(self: *Element, page: *Page) !void {
|
||||
const Event = @import("Event.zig");
|
||||
|
||||
if (page.document._active_element) |old| {
|
||||
if (old == self) return;
|
||||
|
||||
const blur_event = try Event.init("blur", null, page);
|
||||
try page._event_manager.dispatch(old.asEventTarget(), blur_event);
|
||||
}
|
||||
|
||||
page.document._active_element = self;
|
||||
|
||||
const focus_event = try Event.init("focus", null, page);
|
||||
try page._event_manager.dispatch(self.asEventTarget(), focus_event);
|
||||
}
|
||||
|
||||
pub fn blur(self: *Element, page: *Page) !void {
|
||||
if (page.document._active_element != self) return;
|
||||
|
||||
page.document._active_element = null;
|
||||
|
||||
const Event = @import("Event.zig");
|
||||
const blur_event = try Event.init("blur", null, page);
|
||||
try page._event_manager.dispatch(self.asEventTarget(), blur_event);
|
||||
}
|
||||
|
||||
pub fn getChildren(self: *Element, page: *Page) !collections.NodeLive(.child_elements) {
|
||||
return collections.NodeLive(.child_elements).init(null, self.asNode(), {}, page);
|
||||
}
|
||||
@@ -831,6 +861,8 @@ pub const JsApi = struct {
|
||||
pub const getElementsByTagName = bridge.function(Element.getElementsByTagName, .{});
|
||||
pub const getElementsByClassName = bridge.function(Element.getElementsByClassName, .{});
|
||||
pub const children = bridge.accessor(Element.getChildren, null, .{});
|
||||
pub const focus = bridge.function(Element.focus, .{});
|
||||
pub const blur = bridge.function(Element.blur, .{});
|
||||
};
|
||||
|
||||
pub const Build = struct {
|
||||
|
||||
Reference in New Issue
Block a user