Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry-pick "LibWeb: Implement window.close and window.closed" #25497

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Tests/LibWeb/Text/expected/HTML/Window-close.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
window.closed = false
window.closed = true
window.closed = true
15 changes: 15 additions & 0 deletions Tests/LibWeb/Text/input/HTML/Window-close.html
Original file line number Diff line number Diff line change
@@ -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>
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/HTML/BrowsingContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class BrowsingContext final : public JS::Cell {
}

bool is_top_level() const;
bool is_auxiliary() const { return m_is_auxiliary; }

DOM::Document const* active_document() const;
DOM::Document* active_document();
Expand Down
15 changes: 15 additions & 0 deletions Userland/Libraries/LibWeb/HTML/Navigable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,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) {
Expand Down
1 change: 1 addition & 0 deletions Userland/Libraries/LibWeb/HTML/Navigable.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ class Navigable : public JS::Cell {

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(); }
Expand Down
5 changes: 3 additions & 2 deletions Userland/Libraries/LibWeb/HTML/TraversableNavigable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1041,8 +1041,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();
Expand Down
52 changes: 48 additions & 4 deletions Userland/Libraries/LibWeb/HTML/Window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -799,15 +799,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;
}

Expand Down
Loading