LibWeb: Add a NavigationObserver to be notified of navigable updates

This contains a hook to be notified when a navigable navigation is
complete, to be used by WebDriver.

(cherry picked from commit 74ef9dc3936d678fdf811bb3c1b39a6ffba2b106)
This commit is contained in:
Timothy Flynn 2024-10-25 10:26:01 -04:00 committed by Nico Weber
parent 750ef1466f
commit 528fa3bbdb
6 changed files with 105 additions and 0 deletions

View file

@ -410,6 +410,7 @@ set(SOURCES
HTML/NavigationDestination.cpp
HTML/NavigationCurrentEntryChangeEvent.cpp
HTML/NavigationHistoryEntry.cpp
HTML/NavigationObserver.cpp
HTML/NavigationParams.cpp
HTML/NavigationTransition.cpp
HTML/Navigator.cpp

View file

@ -490,6 +490,7 @@ class Navigation;
class NavigationCurrentEntryChangeEvent;
class NavigationDestination;
class NavigationHistoryEntry;
class NavigationObserver;
class NavigationTransition;
class Navigator;
class PageTransitionEvent;

View file

@ -21,6 +21,7 @@
#include <LibWeb/HTML/HistoryHandlingBehavior.h>
#include <LibWeb/HTML/Navigable.h>
#include <LibWeb/HTML/Navigation.h>
#include <LibWeb/HTML/NavigationObserver.h>
#include <LibWeb/HTML/NavigationParams.h>
#include <LibWeb/HTML/POSTResource.h>
#include <LibWeb/HTML/Parser/HTMLParser.h>
@ -124,6 +125,7 @@ void Navigable::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_current_session_history_entry);
visitor.visit(m_active_session_history_entry);
visitor.visit(m_container);
visitor.visit(m_navigation_observers);
m_event_handler.visit_edges(visitor);
}
@ -213,6 +215,13 @@ void Navigable::activate_history_entry(JS::GCPtr<SessionHistoryEntry> entry)
// 5. Make active newDocument.
new_document->make_active();
if (m_ongoing_navigation.has<Empty>()) {
for (auto navigation_observer : m_navigation_observers) {
if (navigation_observer->navigation_complete())
navigation_observer->navigation_complete()->function()();
}
}
}
// https://html.spec.whatwg.org/multipage/document-sequences.html#nav-document
@ -2228,4 +2237,16 @@ void Navigable::paste(String const& text)
m_event_handler.handle_paste(text);
}
void Navigable::register_navigation_observer(Badge<NavigationObserver>, NavigationObserver& navigation_observer)
{
auto result = m_navigation_observers.set(navigation_observer);
VERIFY(result == AK::HashSetResult::InsertedNewEntry);
}
void Navigable::unregister_navigation_observer(Badge<NavigationObserver>, NavigationObserver& navigation_observer)
{
bool was_removed = m_navigation_observers.remove(navigation_observer);
VERIFY(was_removed);
}
}

View file

@ -57,6 +57,9 @@ public:
ErrorOr<void> initialize_navigable(JS::NonnullGCPtr<DocumentState> document_state, JS::GCPtr<Navigable> parent);
void register_navigation_observer(Badge<NavigationObserver>, NavigationObserver&);
void unregister_navigation_observer(Badge<NavigationObserver>, NavigationObserver&);
Vector<JS::Handle<Navigable>> child_navigables() const;
bool is_traversable() const;
@ -239,6 +242,8 @@ private:
JS::NonnullGCPtr<Page> m_page;
HashTable<JS::NonnullGCPtr<NavigationObserver>> m_navigation_observers;
bool m_has_been_destroyed { false };
CSSPixelSize m_size;

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/HTML/Navigable.h>
#include <LibWeb/HTML/NavigationObserver.h>
namespace Web::HTML {
JS_DEFINE_ALLOCATOR(NavigationObserver);
NavigationObserver::NavigationObserver(JS::Realm& realm, Navigable& navigable)
: Bindings::PlatformObject(realm)
, m_navigable(navigable)
{
m_navigable->register_navigation_observer({}, *this);
}
void NavigationObserver::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
visitor.visit(m_navigable);
visitor.visit(m_navigation_complete);
}
void NavigationObserver::finalize()
{
Base::finalize();
m_navigable->unregister_navigation_observer({}, *this);
}
void NavigationObserver::set_navigation_complete(Function<void()> callback)
{
if (callback)
m_navigation_complete = JS::create_heap_function(vm().heap(), move(callback));
else
m_navigation_complete = nullptr;
}
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2024, Tim Flynn <trflynn89@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibJS/Heap/GCPtr.h>
#include <LibJS/Heap/HeapFunction.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
namespace Web::HTML {
class NavigationObserver final : public Bindings::PlatformObject {
WEB_PLATFORM_OBJECT(NavigationObserver, Bindings::PlatformObject);
JS_DECLARE_ALLOCATOR(NavigationObserver);
public:
[[nodiscard]] JS::GCPtr<JS::HeapFunction<void()>> navigation_complete() const { return m_navigation_complete; }
void set_navigation_complete(Function<void()>);
private:
NavigationObserver(JS::Realm&, Navigable&);
virtual void visit_edges(Cell::Visitor&) override;
virtual void finalize() override;
JS::NonnullGCPtr<Navigable> m_navigable;
JS::GCPtr<JS::HeapFunction<void()>> m_navigation_complete;
};
}