mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-05-22 02:52:52 +00:00
The drag-and-drop processing model allows for users to drag around either elements within the DOM or objects completely outside the DOM. This drag event can either end without action (via cancellation or user input), or in a drop event, where the dragged object is dropped onto another element within the DOM. The processing model is rather large. This implements enough of it to allow the UI process to specifically handle dragging objects outside of the DOM onto the DOM. For example, dragging an image from the OS file manager onto a file-upload input element. This does not implement the ability to drag DOM elements.
142 lines
4.6 KiB
C++
142 lines
4.6 KiB
C++
/*
|
||
* Copyright (c) 2023, Andreas Kling <kling@serenityos.org>
|
||
*
|
||
* SPDX-License-Identifier: BSD-2-Clause
|
||
*/
|
||
|
||
#include <LibJS/Runtime/VM.h>
|
||
#include <LibWeb/Bindings/InternalsPrototype.h>
|
||
#include <LibWeb/Bindings/Intrinsics.h>
|
||
#include <LibWeb/DOM/Document.h>
|
||
#include <LibWeb/DOM/Event.h>
|
||
#include <LibWeb/DOM/EventTarget.h>
|
||
#include <LibWeb/HTML/BrowsingContext.h>
|
||
#include <LibWeb/HTML/HTMLElement.h>
|
||
#include <LibWeb/HTML/Window.h>
|
||
#include <LibWeb/Internals/Internals.h>
|
||
#include <LibWeb/Page/InputEvent.h>
|
||
#include <LibWeb/Page/Page.h>
|
||
#include <LibWeb/Painting/PaintableBox.h>
|
||
#include <LibWeb/Painting/ViewportPaintable.h>
|
||
|
||
namespace Web::Internals {
|
||
|
||
JS_DEFINE_ALLOCATOR(Internals);
|
||
|
||
Internals::Internals(JS::Realm& realm)
|
||
: Bindings::PlatformObject(realm)
|
||
{
|
||
}
|
||
|
||
Internals::~Internals() = default;
|
||
|
||
void Internals::initialize(JS::Realm& realm)
|
||
{
|
||
Base::initialize(realm);
|
||
WEB_SET_PROTOTYPE_FOR_INTERFACE(Internals);
|
||
}
|
||
|
||
void Internals::signal_text_test_is_done()
|
||
{
|
||
global_object().browsing_context()->page().client().page_did_finish_text_test();
|
||
}
|
||
|
||
void Internals::gc()
|
||
{
|
||
vm().heap().collect_garbage();
|
||
}
|
||
|
||
JS::Object* Internals::hit_test(double x, double y)
|
||
{
|
||
auto* active_document = global_object().browsing_context()->top_level_browsing_context()->active_document();
|
||
// NOTE: Force a layout update just before hit testing. This is because the current layout tree, which is required
|
||
// for stacking context traversal, might not exist if this call occurs between the tear_down_layout_tree()
|
||
// and update_layout() calls
|
||
active_document->update_layout();
|
||
auto result = active_document->paintable_box()->hit_test({ x, y }, Painting::HitTestType::Exact);
|
||
if (result.has_value()) {
|
||
auto hit_tеsting_result = JS::Object::create(realm(), nullptr);
|
||
hit_tеsting_result->define_direct_property("node", result->dom_node(), JS::default_attributes);
|
||
hit_tеsting_result->define_direct_property("indexInNode", JS::Value(result->index_in_node), JS::default_attributes);
|
||
return hit_tеsting_result;
|
||
}
|
||
return nullptr;
|
||
}
|
||
|
||
void Internals::send_text(HTML::HTMLElement& target, String const& text)
|
||
{
|
||
auto& page = global_object().browsing_context()->page();
|
||
target.focus();
|
||
|
||
for (auto code_point : text.code_points())
|
||
page.handle_keydown(UIEvents::code_point_to_key_code(code_point), 0, code_point);
|
||
}
|
||
|
||
void Internals::commit_text()
|
||
{
|
||
global_object().browsing_context()->page().handle_keydown(UIEvents::Key_Return, 0, 0);
|
||
}
|
||
|
||
void Internals::click(double x, double y)
|
||
{
|
||
click(x, y, UIEvents::MouseButton::Primary);
|
||
}
|
||
|
||
void Internals::middle_click(double x, double y)
|
||
{
|
||
click(x, y, UIEvents::MouseButton::Middle);
|
||
}
|
||
|
||
void Internals::click(double x, double y, UIEvents::MouseButton button)
|
||
{
|
||
auto& page = global_object().browsing_context()->page();
|
||
page.handle_mousedown({ x, y }, { x, y }, button, 0, 0);
|
||
page.handle_mouseup({ x, y }, { x, y }, button, 0, 0);
|
||
}
|
||
|
||
void Internals::move_pointer_to(double x, double y)
|
||
{
|
||
auto& page = global_object().browsing_context()->page();
|
||
page.handle_mousemove({ x, y }, { x, y }, 0, 0);
|
||
}
|
||
|
||
void Internals::wheel(double x, double y, double delta_x, double delta_y)
|
||
{
|
||
auto& page = global_object().browsing_context()->page();
|
||
page.handle_mousewheel({ x, y }, { x, y }, 0, 0, 0, delta_x, delta_y);
|
||
}
|
||
|
||
WebIDL::ExceptionOr<bool> Internals::dispatch_user_activated_event(DOM::EventTarget& target, DOM::Event& event)
|
||
{
|
||
event.set_is_trusted(true);
|
||
return target.dispatch_event(event);
|
||
}
|
||
|
||
JS::NonnullGCPtr<InternalAnimationTimeline> Internals::create_internal_animation_timeline()
|
||
{
|
||
auto& realm = this->realm();
|
||
return realm.heap().allocate<InternalAnimationTimeline>(realm, realm);
|
||
}
|
||
|
||
void Internals::simulate_drag_start(double x, double y, String const& name, String const& contents)
|
||
{
|
||
Vector<HTML::SelectedFile> files;
|
||
files.empend(name.to_byte_string(), MUST(ByteBuffer::copy(contents.bytes())));
|
||
|
||
auto& page = global_object().browsing_context()->page();
|
||
page.handle_drag_and_drop_event(DragEvent::Type::DragStart, { x, y }, { x, y }, UIEvents::MouseButton::Primary, 0, 0, move(files));
|
||
}
|
||
|
||
void Internals::simulate_drag_move(double x, double y)
|
||
{
|
||
auto& page = global_object().browsing_context()->page();
|
||
page.handle_drag_and_drop_event(DragEvent::Type::DragMove, { x, y }, { x, y }, UIEvents::MouseButton::Primary, 0, 0, {});
|
||
}
|
||
|
||
void Internals::simulate_drop(double x, double y)
|
||
{
|
||
auto& page = global_object().browsing_context()->page();
|
||
page.handle_drag_and_drop_event(DragEvent::Type::Drop, { x, y }, { x, y }, UIEvents::MouseButton::Primary, 0, 0, {});
|
||
}
|
||
|
||
}
|