LibWeb: Implement window.close and window.closed

This commit is contained in:
Timothy Flynn 2024-10-05 15:56:35 -04:00 committed by Tim Ledbetter
parent ae130822a0
commit aa1df95b31
Notes: github-actions[bot] 2024-10-06 00:43:21 +00:00
7 changed files with 86 additions and 6 deletions

View file

@ -0,0 +1,3 @@
window.closed = false
window.closed = true
window.closed = true

View file

@ -0,0 +1,15 @@
<script src="../include.js"></script>
<script>
asyncTest(done => {
const newWindow = window.open("about:blank", "_blank");
newWindow.addEventListener("beforeunload", () => {
println(`window.closed = ${newWindow.closed}`);
done();
});
println(`window.closed = ${newWindow.closed}`);
newWindow.close();
println(`window.closed = ${newWindow.closed}`);
});
</script>

View file

@ -96,6 +96,7 @@ public:
}
bool is_top_level() const;
bool is_auxiliary() const { return m_is_auxiliary; }
DOM::Document const* active_document() const;
DOM::Document* active_document();

View file

@ -128,6 +128,21 @@ void Navigable::visit_edges(Cell::Visitor& visitor)
m_event_handler.visit_edges(visitor);
}
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#script-closable
bool Navigable::is_script_closable()
{
// A navigable is script-closable if its active browsing context is an auxiliary browsing context that was created
// by a script (as opposed to by an action of the user), or if it is a top-level traversable whose session history
// entries's size is 1.
if (auto browsing_context = active_browsing_context(); browsing_context && browsing_context->is_auxiliary())
return true;
if (is_top_level_traversable())
return get_session_history_entries().size() == 1;
return false;
}
void Navigable::set_delaying_load_events(bool value)
{
if (value) {

View file

@ -69,6 +69,7 @@ public:
bool is_closing() const { return m_closing; }
void set_closing(bool value) { m_closing = value; }
bool is_script_closable();
void set_delaying_load_events(bool value);
bool is_delaying_load_events() const { return m_delaying_the_load_event.has_value(); }

View file

@ -1178,8 +1178,9 @@ void TraversableNavigable::close_top_level_traversable()
VERIFY(is_top_level_traversable());
// 1. If traversable's is closing is true, then return.
if (is_closing())
return;
// FIXME: Spec-issue: The only place in the spec that sets the `is closing` flag to true is `window.close`, and it
// does so immediately before invoking this method. So it does not make sense to return early here.
// https://github.com/whatwg/html/issues/10678
// 2. Let toUnload be traversable's active document's inclusive descendant navigables.
auto to_unload = active_document()->inclusive_descendant_navigables();

View file

@ -787,15 +787,59 @@ String Window::status() const
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-close
void Window::close()
{
// FIXME: Implement this properly
dbgln("(STUBBED) Window::close()");
// 1. Let thisTraversable be this's navigable.
auto traversable = navigable();
// 2. If thisTraversable is not a top-level traversable, then return.
if (!traversable || !traversable->is_top_level_traversable())
return;
// 3. If thisTraversable's is closing is true, then return.
if (traversable->is_closing())
return;
// 4. Let browsingContext be thisTraversable's active browsing context.
auto browsing_context = traversable->active_browsing_context();
// 5. Let sourceSnapshotParams be the result of snapshotting source snapshot params given thisTraversable's active document.
auto source_snapshot_params = traversable->active_document()->snapshot_source_snapshot_params();
auto& incumbent_global_object = verify_cast<HTML::Window>(HTML::incumbent_global_object());
// 6. If all the following are true:
if (
// thisTraversable is script-closable;
traversable->is_script_closable()
// the incumbent global object's browsing context is familiar with browsingContext; and
&& incumbent_global_object.browsing_context()->is_familiar_with(*browsing_context)
// the incumbent global object's navigable is allowed by sandboxing to navigate thisTraversable, given sourceSnapshotParams,
&& incumbent_global_object.navigable()->allowed_by_sandboxing_to_navigate(*traversable, source_snapshot_params))
// then:
{
// 1. Set thisTraversable's is closing to true.
traversable->set_closing(true);
// 2. Queue a task on the DOM manipulation task source to close thisTraversable.
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, incumbent_global_object, JS::create_heap_function(heap(), [traversable] {
verify_cast<TraversableNavigable>(*traversable).close_top_level_traversable();
}));
}
}
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-window-closed
bool Window::closed() const
{
// FIXME: Implement this properly
dbgln("(STUBBED) Window::closed");
// The closed getter steps are to return true if this's browsing context is null or its is closing is true;
// otherwise false.
if (!browsing_context())
return true;
// FIXME: The spec seems a bit out of date. The `is closing` flag is on the navigable, not the browsing context.
if (auto navigable = this->navigable(); !navigable || navigable->is_closing())
return true;
return false;
}