mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-10 11:36:22 +00:00
LibWeb: Send a beforeinput event for pasting
This allows us to paste text into Discord.
This commit is contained in:
parent
8d02f28cc2
commit
a2f3a5a6ce
Notes:
github-actions[bot]
2025-07-23 20:05:52 +00:00
Author: https://github.com/Lubrsi
Commit: a2f3a5a6ce
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5577
8 changed files with 46 additions and 13 deletions
|
@ -155,6 +155,14 @@ void Internals::send_key(HTML::HTMLElement& target, String const& key_name, WebI
|
||||||
page().handle_keydown(key_code, modifiers, 0, false);
|
page().handle_keydown(key_code, modifiers, 0, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Internals::paste(HTML::HTMLElement& target, String const& text)
|
||||||
|
{
|
||||||
|
auto& page = this->page();
|
||||||
|
target.focus();
|
||||||
|
|
||||||
|
page.focused_navigable().paste(text);
|
||||||
|
}
|
||||||
|
|
||||||
void Internals::commit_text()
|
void Internals::commit_text()
|
||||||
{
|
{
|
||||||
page().handle_keydown(UIEvents::Key_Return, 0, 0x0d, false);
|
page().handle_keydown(UIEvents::Key_Return, 0, 0x0d, false);
|
||||||
|
|
|
@ -31,6 +31,7 @@ public:
|
||||||
|
|
||||||
void send_text(HTML::HTMLElement&, String const&, WebIDL::UnsignedShort modifiers);
|
void send_text(HTML::HTMLElement&, String const&, WebIDL::UnsignedShort modifiers);
|
||||||
void send_key(HTML::HTMLElement&, String const&, WebIDL::UnsignedShort modifiers);
|
void send_key(HTML::HTMLElement&, String const&, WebIDL::UnsignedShort modifiers);
|
||||||
|
void paste(HTML::HTMLElement& target, String const& text);
|
||||||
void commit_text();
|
void commit_text();
|
||||||
|
|
||||||
void click(double x, double y);
|
void click(double x, double y);
|
||||||
|
|
|
@ -23,6 +23,7 @@ interface Internals {
|
||||||
|
|
||||||
undefined sendText(HTMLElement target, DOMString text, optional unsigned short modifiers = 0);
|
undefined sendText(HTMLElement target, DOMString text, optional unsigned short modifiers = 0);
|
||||||
undefined sendKey(HTMLElement target, DOMString keyName, optional unsigned short modifiers = 0);
|
undefined sendKey(HTMLElement target, DOMString keyName, optional unsigned short modifiers = 0);
|
||||||
|
undefined paste(HTMLElement target, DOMString text);
|
||||||
undefined commitText();
|
undefined commitText();
|
||||||
|
|
||||||
undefined click(double x, double y);
|
undefined click(double x, double y);
|
||||||
|
|
|
@ -1129,7 +1129,7 @@ static GC::RootVector<GC::Ref<DOM::StaticRange>> target_ranges_for_input_event(D
|
||||||
return target_ranges;
|
return target_ranges;
|
||||||
}
|
}
|
||||||
|
|
||||||
EventResult EventHandler::input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable& navigable, u32 code_point)
|
EventResult EventHandler::input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable& navigable, Variant<u32, String> code_point_or_string)
|
||||||
{
|
{
|
||||||
auto document = navigable.active_document();
|
auto document = navigable.active_document();
|
||||||
if (!document)
|
if (!document)
|
||||||
|
@ -1138,16 +1138,23 @@ EventResult EventHandler::input_event(FlyString const& event_name, FlyString con
|
||||||
return EventResult::Dropped;
|
return EventResult::Dropped;
|
||||||
|
|
||||||
UIEvents::InputEventInit input_event_init;
|
UIEvents::InputEventInit input_event_init;
|
||||||
|
|
||||||
|
if (code_point_or_string.has<u32>()) {
|
||||||
|
auto code_point = code_point_or_string.get<u32>();
|
||||||
if (!is_unicode_control(code_point)) {
|
if (!is_unicode_control(code_point)) {
|
||||||
input_event_init.data = String::from_code_point(code_point);
|
input_event_init.data = String::from_code_point(code_point);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
input_event_init.data = code_point_or_string.get<String>();
|
||||||
|
}
|
||||||
|
|
||||||
input_event_init.input_type = input_type;
|
input_event_init.input_type = input_type;
|
||||||
|
|
||||||
if (auto* focused_element = document->focused_element()) {
|
if (auto* focused_element = document->focused_element()) {
|
||||||
if (is<HTML::NavigableContainer>(*focused_element)) {
|
if (is<HTML::NavigableContainer>(*focused_element)) {
|
||||||
auto& navigable_container = as<HTML::NavigableContainer>(*focused_element);
|
auto& navigable_container = as<HTML::NavigableContainer>(*focused_element);
|
||||||
if (navigable_container.content_navigable())
|
if (navigable_container.content_navigable())
|
||||||
return input_event(event_name, input_type, *navigable_container.content_navigable(), code_point);
|
return input_event(event_name, input_type, *navigable_container.content_navigable(), code_point_or_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document));
|
auto event = UIEvents::InputEvent::create_from_platform_event(document->realm(), event_name, input_event_init, target_ranges_for_input_event(*document));
|
||||||
|
@ -1366,18 +1373,21 @@ EventResult EventHandler::handle_keyup(UIEvents::KeyCode key, u32 modifiers, u32
|
||||||
return fire_keyboard_event(UIEvents::EventNames::keyup, m_navigable, key, modifiers, code_point, false);
|
return fire_keyboard_event(UIEvents::EventNames::keyup, m_navigable, key, modifiers, code_point, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandler::handle_paste(String const& text)
|
EventResult EventHandler::handle_paste(String const& text)
|
||||||
{
|
{
|
||||||
auto active_document = m_navigable->active_document();
|
auto active_document = m_navigable->active_document();
|
||||||
if (!active_document)
|
if (!active_document)
|
||||||
return;
|
return EventResult::Dropped;
|
||||||
if (!active_document->is_fully_active())
|
if (!active_document->is_fully_active())
|
||||||
return;
|
return EventResult::Dropped;
|
||||||
|
|
||||||
auto* target = active_document->active_input_events_target();
|
auto* target = active_document->active_input_events_target();
|
||||||
if (!target)
|
if (!target)
|
||||||
return;
|
return EventResult::Dropped;
|
||||||
|
|
||||||
|
FIRE(input_event(UIEvents::EventNames::beforeinput, UIEvents::InputTypes::insertFromPaste, m_navigable, text));
|
||||||
target->handle_insert(text);
|
target->handle_insert(text);
|
||||||
|
return EventResult::Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EventHandler::set_mouse_event_tracking_paintable(Painting::Paintable* paintable)
|
void EventHandler::set_mouse_event_tracking_paintable(Painting::Paintable* paintable)
|
||||||
|
|
|
@ -39,7 +39,7 @@ public:
|
||||||
|
|
||||||
void set_mouse_event_tracking_paintable(Painting::Paintable*);
|
void set_mouse_event_tracking_paintable(Painting::Paintable*);
|
||||||
|
|
||||||
void handle_paste(String const& text);
|
EventResult handle_paste(String const& text);
|
||||||
|
|
||||||
void visit_edges(JS::Cell::Visitor& visitor) const;
|
void visit_edges(JS::Cell::Visitor& visitor) const;
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ private:
|
||||||
EventResult focus_previous_element();
|
EventResult focus_previous_element();
|
||||||
|
|
||||||
EventResult fire_keyboard_event(FlyString const& event_name, HTML::Navigable&, UIEvents::KeyCode, unsigned modifiers, u32 code_point, bool repeat);
|
EventResult fire_keyboard_event(FlyString const& event_name, HTML::Navigable&, UIEvents::KeyCode, unsigned modifiers, u32 code_point, bool repeat);
|
||||||
[[nodiscard]] EventResult input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable&, u32 code_point);
|
[[nodiscard]] EventResult input_event(FlyString const& event_name, FlyString const& input_type, HTML::Navigable&, Variant<u32, String> code_point_or_string);
|
||||||
CSSPixelPoint compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const;
|
CSSPixelPoint compute_mouse_event_client_offset(CSSPixelPoint event_page_position) const;
|
||||||
CSSPixelPoint compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const;
|
CSSPixelPoint compute_mouse_event_page_offset(CSSPixelPoint event_client_offset) const;
|
||||||
CSSPixelPoint compute_mouse_event_movement(CSSPixelPoint event_client_offset) const;
|
CSSPixelPoint compute_mouse_event_movement(CSSPixelPoint event_client_offset) const;
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Web::UIEvents::InputTypes {
|
||||||
#define ENUMERATE_INPUT_TYPES \
|
#define ENUMERATE_INPUT_TYPES \
|
||||||
__ENUMERATE_INPUT_TYPE(deleteContentBackward) \
|
__ENUMERATE_INPUT_TYPE(deleteContentBackward) \
|
||||||
__ENUMERATE_INPUT_TYPE(deleteContentForward) \
|
__ENUMERATE_INPUT_TYPE(deleteContentForward) \
|
||||||
|
__ENUMERATE_INPUT_TYPE(insertFromPaste) \
|
||||||
__ENUMERATE_INPUT_TYPE(insertLineBreak) \
|
__ENUMERATE_INPUT_TYPE(insertLineBreak) \
|
||||||
__ENUMERATE_INPUT_TYPE(insertParagraph) \
|
__ENUMERATE_INPUT_TYPE(insertParagraph) \
|
||||||
__ENUMERATE_INPUT_TYPE(insertText)
|
__ENUMERATE_INPUT_TYPE(insertText)
|
||||||
|
|
|
@ -6,4 +6,10 @@ beforeinput data=(e) inputType=(insertText)
|
||||||
beforeinput data=(c) inputType=(insertText)
|
beforeinput data=(c) inputType=(insertText)
|
||||||
beforeinput data=(e) inputType=(insertText)
|
beforeinput data=(e) inputType=(insertText)
|
||||||
beforeinput data=(null) inputType=(insertParagraph)
|
beforeinput data=(null) inputType=(insertParagraph)
|
||||||
Text in input: reee
|
Text in input before any paste: reee
|
||||||
|
beforeinput data=(non-cancelled paste) inputType=(insertFromPaste)
|
||||||
|
beforeinput data=(null) inputType=(insertParagraph)
|
||||||
|
Text in input after non-cancelled paste: reeenon-cancelled paste
|
||||||
|
beforeinput data=(cancelled paste) inputType=(insertFromPaste)
|
||||||
|
beforeinput data=(null) inputType=(insertParagraph)
|
||||||
|
Text in input after cancelled paste: reeenon-cancelled paste
|
||||||
|
|
|
@ -13,13 +13,19 @@
|
||||||
const input = document.getElementById("input");
|
const input = document.getElementById("input");
|
||||||
input.addEventListener("beforeinput", (e) => {
|
input.addEventListener("beforeinput", (e) => {
|
||||||
println(`beforeinput data=(${e.data}) inputType=(${e.inputType})`);
|
println(`beforeinput data=(${e.data}) inputType=(${e.inputType})`);
|
||||||
if (e.data !== 'r' && e.data !== 'e') {
|
if (e.data !== 'r' && e.data !== 'e' && e.data !== "non-cancelled paste") {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
internals.sendText(input, "raebece");
|
internals.sendText(input, "raebece");
|
||||||
internals.commitText();
|
internals.commitText();
|
||||||
println(`Text in input: ${input.textContent}`);
|
println(`Text in input before any paste: ${input.textContent}`);
|
||||||
|
internals.paste(input, "non-cancelled paste");
|
||||||
|
internals.commitText();
|
||||||
|
println(`Text in input after non-cancelled paste: ${input.textContent}`);
|
||||||
|
internals.paste(input, "cancelled paste");
|
||||||
|
internals.commitText();
|
||||||
|
println(`Text in input after cancelled paste: ${input.textContent}`);
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue