1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 15:27:35 +00:00

LibWeb: Convert the Location object to IDL

This includes:

- Moving it from Bindings/ to HTML/
- Renaming it from LocationObject to Location
- Removing the manual definitions of the constructor and prototype
- Removing special handling of the Location interface from the bindings
  generator
- Converting the JS_DEFINE_NATIVE_FUNCTIONs to regular functions
  returning DeprecatedString instead of PrimitiveString
- Adding missing (no-op) setters for the various attributes, which are
  expected to exist by the bindings generator
This commit is contained in:
Linus Groh 2023-01-18 17:41:12 +00:00 committed by Tim Flynn
parent 78d6de2ec1
commit afc055c088
19 changed files with 271 additions and 333 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -13,9 +13,9 @@
#include <LibJS/Runtime/Object.h>
#include <LibJS/Runtime/PropertyDescriptor.h>
#include <LibJS/Runtime/PropertyKey.h>
#include <LibWeb/Bindings/LocationObject.h>
#include <LibWeb/Bindings/MainThreadVM.h>
#include <LibWeb/HTML/CrossOrigin/AbstractOperations.h>
#include <LibWeb/HTML/Location.h>
#include <LibWeb/HTML/Scripting/Environments.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/WebIDL/DOMException.h>
@ -23,13 +23,13 @@
namespace Web::HTML {
// 7.2.3.1 CrossOriginProperties ( O ), https://html.spec.whatwg.org/multipage/browsers.html#crossoriginproperties-(-o-)
Vector<CrossOriginProperty> cross_origin_properties(Variant<Bindings::LocationObject const*, HTML::Window const*> const& object)
Vector<CrossOriginProperty> cross_origin_properties(Variant<HTML::Location const*, HTML::Window const*> const& object)
{
// 1. Assert: O is a Location or Window object.
return object.visit(
// 2. If O is a Location object, then return « { [[Property]]: "href", [[NeedsGet]]: false, [[NeedsSet]]: true }, { [[Property]]: "replace" } ».
[](Bindings::LocationObject const*) -> Vector<CrossOriginProperty> {
[](HTML::Location const*) -> Vector<CrossOriginProperty> {
return {
{ .property = "href"sv, .needs_get = false, .needs_set = true },
{ .property = "replace"sv },
@ -89,11 +89,11 @@ bool is_platform_object_same_origin(JS::Object const& object)
}
// 7.2.3.4 CrossOriginGetOwnPropertyHelper ( O, P ), https://html.spec.whatwg.org/multipage/browsers.html#crossorigingetownpropertyhelper-(-o,-p-)
Optional<JS::PropertyDescriptor> cross_origin_get_own_property_helper(Variant<Bindings::LocationObject*, HTML::Window*> const& object, JS::PropertyKey const& property_key)
Optional<JS::PropertyDescriptor> cross_origin_get_own_property_helper(Variant<HTML::Location*, HTML::Window*> const& object, JS::PropertyKey const& property_key)
{
auto& realm = *Bindings::main_thread_vm().current_realm();
auto const* object_ptr = object.visit([](auto* o) { return static_cast<JS::Object const*>(o); });
auto const object_const_variant = object.visit([](auto* o) { return Variant<Bindings::LocationObject const*, HTML::Window const*> { o }; });
auto const object_const_variant = object.visit([](auto* o) { return Variant<HTML::Location const*, HTML::Window const*> { o }; });
// 1. Let crossOriginKey be a tuple consisting of the current settings object, O's relevant settings object, and P.
auto cross_origin_key = CrossOriginKey {
@ -226,7 +226,7 @@ JS::ThrowCompletionOr<bool> cross_origin_set(JS::VM& vm, JS::Object& object, JS:
}
// 7.2.3.7 CrossOriginOwnPropertyKeys ( O ), https://html.spec.whatwg.org/multipage/browsers.html#crossoriginownpropertykeys-(-o-)
JS::MarkedVector<JS::Value> cross_origin_own_property_keys(Variant<Bindings::LocationObject const*, HTML::Window const*> const& object)
JS::MarkedVector<JS::Value> cross_origin_own_property_keys(Variant<HTML::Location const*, HTML::Window const*> const& object)
{
auto& event_loop = HTML::main_thread_event_loop();
auto& vm = event_loop.vm();

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2022, Linus Groh <linusg@serenityos.org>
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -13,13 +13,13 @@
namespace Web::HTML {
Vector<CrossOriginProperty> cross_origin_properties(Variant<Bindings::LocationObject const*, HTML::Window const*> const&);
Vector<CrossOriginProperty> cross_origin_properties(Variant<HTML::Location const*, HTML::Window const*> const&);
bool is_cross_origin_accessible_window_property_name(JS::PropertyKey const&);
JS::ThrowCompletionOr<JS::PropertyDescriptor> cross_origin_property_fallback(JS::VM&, JS::PropertyKey const&);
bool is_platform_object_same_origin(JS::Object const&);
Optional<JS::PropertyDescriptor> cross_origin_get_own_property_helper(Variant<Bindings::LocationObject*, HTML::Window*> const&, JS::PropertyKey const&);
Optional<JS::PropertyDescriptor> cross_origin_get_own_property_helper(Variant<HTML::Location*, HTML::Window*> const&, JS::PropertyKey const&);
JS::ThrowCompletionOr<JS::Value> cross_origin_get(JS::VM&, JS::Object const&, JS::PropertyKey const&, JS::Value receiver);
JS::ThrowCompletionOr<bool> cross_origin_set(JS::VM&, JS::Object&, JS::PropertyKey const&, JS::Value, JS::Value receiver);
JS::MarkedVector<JS::Value> cross_origin_own_property_keys(Variant<Bindings::LocationObject const*, HTML::Window const*> const&);
JS::MarkedVector<JS::Value> cross_origin_own_property_keys(Variant<HTML::Location const*, HTML::Window const*> const&);
}

View file

@ -0,0 +1,387 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/DeprecatedFlyString.h>
#include <AK/StringBuilder.h>
#include <LibJS/Heap/MarkedVector.h>
#include <LibJS/Runtime/Completion.h>
#include <LibJS/Runtime/PropertyDescriptor.h>
#include <LibJS/Runtime/PropertyKey.h>
#include <LibWeb/Bindings/LocationPrototype.h>
#include <LibWeb/DOM/Document.h>
#include <LibWeb/HTML/CrossOrigin/AbstractOperations.h>
#include <LibWeb/HTML/Location.h>
#include <LibWeb/HTML/Window.h>
#include <LibWeb/WebIDL/DOMException.h>
namespace Web::HTML {
// https://html.spec.whatwg.org/multipage/history.html#the-location-interface
Location::Location(JS::Realm& realm)
: PlatformObject(realm)
{
}
Location::~Location() = default;
void Location::visit_edges(Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
for (auto& property : m_default_properties)
visitor.visit(property);
}
void Location::initialize(JS::Realm& realm)
{
Object::initialize(realm);
set_prototype(&Bindings::ensure_web_prototype<Bindings::LocationPrototype>(realm, "Location"));
// FIXME: Implement steps 2.-4.
// 5. Set the value of the [[DefaultProperties]] internal slot of location to location.[[OwnPropertyKeys]]().
// NOTE: In LibWeb this happens before the ESO is set up, so we must avoid location's custom [[OwnPropertyKeys]].
m_default_properties.extend(MUST(Object::internal_own_property_keys()));
}
// https://html.spec.whatwg.org/multipage/history.html#relevant-document
DOM::Document const* Location::relevant_document() const
{
// A Location object has an associated relevant Document, which is this Location object's
// relevant global object's browsing context's active document, if this Location object's
// relevant global object's browsing context is non-null, and null otherwise.
auto* browsing_context = verify_cast<HTML::Window>(HTML::relevant_global_object(*this)).browsing_context();
return browsing_context ? browsing_context->active_document() : nullptr;
}
// https://html.spec.whatwg.org/multipage/history.html#concept-location-url
AK::URL Location::url() const
{
// A Location object has an associated url, which is this Location object's relevant Document's URL,
// if this Location object's relevant Document is non-null, and about:blank otherwise.
auto const* relevant_document = this->relevant_document();
return relevant_document ? relevant_document->url() : "about:blank"sv;
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-href
DeprecatedString Location::href() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
// 2. Return this's url, serialized.
return url().to_deprecated_string();
}
// https://html.spec.whatwg.org/multipage/history.html#the-location-interface:dom-location-href-2
JS::ThrowCompletionOr<void> Location::set_href(DeprecatedString const& new_href)
{
auto& vm = this->vm();
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
// FIXME: 1. If this's relevant Document is null, then return.
// 2. Parse the given value relative to the entry settings object. If that failed, throw a TypeError exception.
auto href_url = window.associated_document().parse_url(new_href);
if (!href_url.is_valid())
return vm.throw_completion<JS::URIError>(DeprecatedString::formatted("Invalid URL '{}'", new_href));
// 3. Location-object navigate given the resulting URL record.
window.did_set_location_href({}, href_url);
return {};
}
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#dom-location-origin
DeprecatedString Location::origin() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
// 2. Return the serialization of this's url's origin.
return url().serialize_origin();
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-protocol
DeprecatedString Location::protocol() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
// 2. Return this's url's scheme, followed by ":".
return DeprecatedString::formatted("{}:", url().scheme());
}
JS::ThrowCompletionOr<void> Location::set_protocol(DeprecatedString const&)
{
auto& vm = this->vm();
return vm.throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Location.protocol setter");
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-host
DeprecatedString Location::host() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
// 2. Let url be this's url.
auto url = this->url();
// 3. If url's host is null, return the empty string.
if (url.host().is_null())
return DeprecatedString::empty();
// 4. If url's port is null, return url's host, serialized.
if (!url.port().has_value())
return url.host();
// 5. Return url's host, serialized, followed by ":" and url's port, serialized.
return DeprecatedString::formatted("{}:{}", url.host(), *url.port());
}
JS::ThrowCompletionOr<void> Location::set_host(DeprecatedString const&)
{
auto& vm = this->vm();
return vm.throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Location.host setter");
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-hostname
DeprecatedString Location::hostname() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
auto url = this->url();
// 2. If this's url's host is null, return the empty string.
if (url.host().is_null())
return DeprecatedString::empty();
// 3. Return this's url's host, serialized.
return url.host();
}
JS::ThrowCompletionOr<void> Location::set_hostname(DeprecatedString const&)
{
auto& vm = this->vm();
return vm.throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Location.hostname setter");
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-port
DeprecatedString Location::port() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
auto url = this->url();
// 2. If this's url's port is null, return the empty string.
if (!url.port().has_value())
return DeprecatedString::empty();
// 3. Return this's url's port, serialized.
return DeprecatedString::number(*url.port());
}
JS::ThrowCompletionOr<void> Location::set_port(DeprecatedString const&)
{
auto& vm = this->vm();
return vm.throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Location.port setter");
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-pathname
DeprecatedString Location::pathname() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
// 2. Return the result of URL path serializing this Location object's url.
return url().path();
}
JS::ThrowCompletionOr<void> Location::set_pathname(DeprecatedString const&)
{
auto& vm = this->vm();
return vm.throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Location.pathname setter");
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-search
DeprecatedString Location::search() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
auto url = this->url();
// 2. If this's url's query is either null or the empty string, return the empty string.
if (url.query().is_empty())
return DeprecatedString::empty();
// 3. Return "?", followed by this's url's query.
return DeprecatedString::formatted("?{}", url.query());
}
JS::ThrowCompletionOr<void> Location::set_search(DeprecatedString const&)
{
auto& vm = this->vm();
return vm.throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Location.search setter");
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-hash
DeprecatedString Location::hash() const
{
// FIXME: 1. If this's relevant Document is non-null and its origin is not same origin-domain with the entry settings object's origin, then throw a "SecurityError" DOMException.
auto url = this->url();
// 2. If this's url's fragment is either null or the empty string, return the empty string.
if (url.fragment().is_empty())
return DeprecatedString::empty();
// 3. Return "#", followed by this's url's fragment.
return DeprecatedString::formatted("#{}", url.fragment());
}
JS::ThrowCompletionOr<void> Location::set_hash(DeprecatedString const&)
{
auto& vm = this->vm();
return vm.throw_completion<JS::InternalError>(JS::ErrorType::NotImplemented, "Location.hash setter");
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-reload
void Location::reload() const
{
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
window.did_call_location_reload({});
}
// https://html.spec.whatwg.org/multipage/history.html#dom-location-replace
void Location::replace(DeprecatedString url) const
{
auto& window = verify_cast<HTML::Window>(HTML::current_global_object());
// FIXME: This needs spec compliance work.
window.did_call_location_replace({}, move(url));
}
// 7.10.5.1 [[GetPrototypeOf]] ( ), https://html.spec.whatwg.org/multipage/history.html#location-getprototypeof
JS::ThrowCompletionOr<JS::Object*> Location::internal_get_prototype_of() const
{
// 1. If IsPlatformObjectSameOrigin(this) is true, then return ! OrdinaryGetPrototypeOf(this).
if (HTML::is_platform_object_same_origin(*this))
return MUST(JS::Object::internal_get_prototype_of());
// 2. Return null.
return nullptr;
}
// 7.10.5.2 [[SetPrototypeOf]] ( V ), https://html.spec.whatwg.org/multipage/history.html#location-setprototypeof
JS::ThrowCompletionOr<bool> Location::internal_set_prototype_of(Object* prototype)
{
// 1. Return ! SetImmutablePrototype(this, V).
return MUST(set_immutable_prototype(prototype));
}
// 7.10.5.3 [[IsExtensible]] ( ), https://html.spec.whatwg.org/multipage/history.html#location-isextensible
JS::ThrowCompletionOr<bool> Location::internal_is_extensible() const
{
// 1. Return true.
return true;
}
// 7.10.5.4 [[PreventExtensions]] ( ), https://html.spec.whatwg.org/multipage/history.html#location-preventextensions
JS::ThrowCompletionOr<bool> Location::internal_prevent_extensions()
{
// 1. Return false.
return false;
}
// 7.10.5.5 [[GetOwnProperty]] ( P ), https://html.spec.whatwg.org/multipage/history.html#location-getownproperty
JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> Location::internal_get_own_property(JS::PropertyKey const& property_key) const
{
auto& vm = this->vm();
// 1. If IsPlatformObjectSameOrigin(this) is true, then:
if (HTML::is_platform_object_same_origin(*this)) {
// 1. Let desc be OrdinaryGetOwnProperty(this, P).
auto descriptor = MUST(Object::internal_get_own_property(property_key));
// 2. If the value of the [[DefaultProperties]] internal slot of this contains P, then set desc.[[Configurable]] to true.
auto property_key_value = property_key.is_symbol()
? JS::Value { property_key.as_symbol() }
: JS::PrimitiveString::create(vm, property_key.to_string());
if (m_default_properties.contains_slow(property_key_value))
descriptor->configurable = true;
// 3. Return desc.
return descriptor;
}
// 2. Let property be CrossOriginGetOwnPropertyHelper(this, P).
auto property = HTML::cross_origin_get_own_property_helper(const_cast<Location*>(this), property_key);
// 3. If property is not undefined, then return property.
if (property.has_value())
return property;
// 4. Return ? CrossOriginPropertyFallback(P).
return TRY(HTML::cross_origin_property_fallback(vm, property_key));
}
// 7.10.5.6 [[DefineOwnProperty]] ( P, Desc ), https://html.spec.whatwg.org/multipage/history.html#location-defineownproperty
JS::ThrowCompletionOr<bool> Location::internal_define_own_property(JS::PropertyKey const& property_key, JS::PropertyDescriptor const& descriptor)
{
// 1. If IsPlatformObjectSameOrigin(this) is true, then:
if (HTML::is_platform_object_same_origin(*this)) {
// 1. If the value of the [[DefaultProperties]] internal slot of this contains P, then return false.
// 2. Return ? OrdinaryDefineOwnProperty(this, P, Desc).
return JS::Object::internal_define_own_property(property_key, descriptor);
}
// 2. Throw a "SecurityError" DOMException.
return throw_completion(WebIDL::SecurityError::create(realm(), DeprecatedString::formatted("Can't define property '{}' on cross-origin object", property_key)));
}
// 7.10.5.7 [[Get]] ( P, Receiver ), https://html.spec.whatwg.org/multipage/history.html#location-get
JS::ThrowCompletionOr<JS::Value> Location::internal_get(JS::PropertyKey const& property_key, JS::Value receiver) const
{
auto& vm = this->vm();
// 1. If IsPlatformObjectSameOrigin(this) is true, then return ? OrdinaryGet(this, P, Receiver).
if (HTML::is_platform_object_same_origin(*this))
return JS::Object::internal_get(property_key, receiver);
// 2. Return ? CrossOriginGet(this, P, Receiver).
return HTML::cross_origin_get(vm, static_cast<JS::Object const&>(*this), property_key, receiver);
}
// 7.10.5.8 [[Set]] ( P, V, Receiver ), https://html.spec.whatwg.org/multipage/history.html#location-set
JS::ThrowCompletionOr<bool> Location::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver)
{
auto& vm = this->vm();
// 1. If IsPlatformObjectSameOrigin(this) is true, then return ? OrdinarySet(this, P, V, Receiver).
if (HTML::is_platform_object_same_origin(*this))
return JS::Object::internal_set(property_key, value, receiver);
// 2. Return ? CrossOriginSet(this, P, V, Receiver).
return HTML::cross_origin_set(vm, static_cast<JS::Object&>(*this), property_key, value, receiver);
}
// 7.10.5.9 [[Delete]] ( P ), https://html.spec.whatwg.org/multipage/history.html#location-delete
JS::ThrowCompletionOr<bool> Location::internal_delete(JS::PropertyKey const& property_key)
{
// 1. If IsPlatformObjectSameOrigin(this) is true, then return ? OrdinaryDelete(this, P).
if (HTML::is_platform_object_same_origin(*this))
return JS::Object::internal_delete(property_key);
// 2. Throw a "SecurityError" DOMException.
return throw_completion(WebIDL::SecurityError::create(realm(), DeprecatedString::formatted("Can't delete property '{}' on cross-origin object", property_key)));
}
// 7.10.5.10 [[OwnPropertyKeys]] ( ), https://html.spec.whatwg.org/multipage/history.html#location-ownpropertykeys
JS::ThrowCompletionOr<JS::MarkedVector<JS::Value>> Location::internal_own_property_keys() const
{
// 1. If IsPlatformObjectSameOrigin(this) is true, then return OrdinaryOwnPropertyKeys(this).
if (HTML::is_platform_object_same_origin(*this))
return JS::Object::internal_own_property_keys();
// 2. Return CrossOriginOwnPropertyKeys(this).
return HTML::cross_origin_own_property_keys(this);
}
}

View file

@ -0,0 +1,84 @@
/*
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2022-2023, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/URL.h>
#include <LibJS/Forward.h>
#include <LibJS/Runtime/Completion.h>
#include <LibWeb/Bindings/PlatformObject.h>
#include <LibWeb/Forward.h>
#include <LibWeb/HTML/CrossOrigin/CrossOriginPropertyDescriptorMap.h>
namespace Web::HTML {
class Location final : public Bindings::PlatformObject {
JS_OBJECT(Location, Bindings::PlatformObject);
public:
virtual ~Location() override;
DeprecatedString href() const;
JS::ThrowCompletionOr<void> set_href(DeprecatedString const&);
DeprecatedString origin() const;
DeprecatedString protocol() const;
JS::ThrowCompletionOr<void> set_protocol(DeprecatedString const&);
DeprecatedString host() const;
JS::ThrowCompletionOr<void> set_host(DeprecatedString const&);
DeprecatedString hostname() const;
JS::ThrowCompletionOr<void> set_hostname(DeprecatedString const&);
DeprecatedString port() const;
JS::ThrowCompletionOr<void> set_port(DeprecatedString const&);
DeprecatedString pathname() const;
JS::ThrowCompletionOr<void> set_pathname(DeprecatedString const&);
DeprecatedString search() const;
JS::ThrowCompletionOr<void> set_search(DeprecatedString const&);
DeprecatedString hash() const;
JS::ThrowCompletionOr<void> set_hash(DeprecatedString const&);
void replace(DeprecatedString url) const;
void reload() const;
virtual JS::ThrowCompletionOr<JS::Object*> internal_get_prototype_of() const override;
virtual JS::ThrowCompletionOr<bool> internal_set_prototype_of(Object* prototype) override;
virtual JS::ThrowCompletionOr<bool> internal_is_extensible() const override;
virtual JS::ThrowCompletionOr<bool> internal_prevent_extensions() override;
virtual JS::ThrowCompletionOr<Optional<JS::PropertyDescriptor>> internal_get_own_property(JS::PropertyKey const&) const override;
virtual JS::ThrowCompletionOr<bool> internal_define_own_property(JS::PropertyKey const&, JS::PropertyDescriptor const&) override;
virtual JS::ThrowCompletionOr<JS::Value> internal_get(JS::PropertyKey const&, JS::Value receiver) const override;
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const&, JS::Value value, JS::Value receiver) override;
virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const&) override;
virtual JS::ThrowCompletionOr<JS::MarkedVector<JS::Value>> internal_own_property_keys() const override;
HTML::CrossOriginPropertyDescriptorMap const& cross_origin_property_descriptor_map() const { return m_cross_origin_property_descriptor_map; }
HTML::CrossOriginPropertyDescriptorMap& cross_origin_property_descriptor_map() { return m_cross_origin_property_descriptor_map; }
private:
explicit Location(JS::Realm&);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
DOM::Document const* relevant_document() const;
AK::URL url() const;
// [[CrossOriginPropertyDescriptorMap]], https://html.spec.whatwg.org/multipage/browsers.html#crossoriginpropertydescriptormap
HTML::CrossOriginPropertyDescriptorMap m_cross_origin_property_descriptor_map;
// [[DefaultProperties]], https://html.spec.whatwg.org/multipage/history.html#defaultproperties
Vector<JS::Value> m_default_properties;
};
}

View file

@ -0,0 +1,19 @@
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#location
[Exposed=Window]
interface Location { // but see also additional creation steps and overridden internal methods
[LegacyUnforgeable] stringifier attribute USVString href;
[LegacyUnforgeable] readonly attribute USVString origin;
[LegacyUnforgeable] attribute USVString protocol;
[LegacyUnforgeable] attribute USVString host;
[LegacyUnforgeable] attribute USVString hostname;
[LegacyUnforgeable] attribute USVString port;
[LegacyUnforgeable] attribute USVString pathname;
[LegacyUnforgeable] attribute USVString search;
[LegacyUnforgeable] attribute USVString hash;
// TODO: [LegacyUnforgeable] undefined assign(USVString url);
[LegacyUnforgeable] undefined replace(USVString url);
[LegacyUnforgeable] undefined reload();
// TODO: [LegacyUnforgeable, SameObject] readonly attribute DOMStringList ancestorOrigins;
};

View file

@ -1,6 +1,7 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2022, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -19,7 +20,6 @@
#include <LibWeb/Bindings/CSSNamespace.h>
#include <LibWeb/Bindings/ExceptionOrUtils.h>
#include <LibWeb/Bindings/FetchMethod.h>
#include <LibWeb/Bindings/LocationObject.h>
#include <LibWeb/Bindings/Replaceable.h>
#include <LibWeb/Bindings/WindowExposedInterfaces.h>
#include <LibWeb/Bindings/WindowPrototype.h>
@ -36,6 +36,7 @@
#include <LibWeb/HTML/EventHandler.h>
#include <LibWeb/HTML/EventLoop/EventLoop.h>
#include <LibWeb/HTML/Focus.h>
#include <LibWeb/HTML/Location.h>
#include <LibWeb/HTML/MessageEvent.h>
#include <LibWeb/HTML/Navigator.h>
#include <LibWeb/HTML/Origin.h>
@ -102,7 +103,7 @@ void Window::visit_edges(JS::Cell::Visitor& visitor)
visitor.visit(m_current_event.ptr());
visitor.visit(m_performance.ptr());
visitor.visit(m_screen.ptr());
visitor.visit(m_location_object);
visitor.visit(m_location);
visitor.visit(m_crypto);
visitor.visit(m_navigator);
for (auto& it : m_timers)
@ -581,7 +582,7 @@ void Window::cancel_animation_frame_impl(i32 id)
m_animation_frame_callback_driver.remove(id);
}
void Window::did_set_location_href(Badge<Bindings::LocationObject>, AK::URL const& new_href)
void Window::did_set_location_href(Badge<HTML::Location>, AK::URL const& new_href)
{
auto* browsing_context = associated_document().browsing_context();
if (!browsing_context)
@ -589,7 +590,7 @@ void Window::did_set_location_href(Badge<Bindings::LocationObject>, AK::URL cons
browsing_context->loader().load(new_href, FrameLoader::Type::Navigation);
}
void Window::did_call_location_reload(Badge<Bindings::LocationObject>)
void Window::did_call_location_reload(Badge<HTML::Location>)
{
auto* browsing_context = associated_document().browsing_context();
if (!browsing_context)
@ -597,7 +598,7 @@ void Window::did_call_location_reload(Badge<Bindings::LocationObject>)
browsing_context->loader().load(associated_document().url(), FrameLoader::Type::Reload);
}
void Window::did_call_location_replace(Badge<Bindings::LocationObject>, DeprecatedString url)
void Window::did_call_location_replace(Badge<HTML::Location>, DeprecatedString url)
{
auto* browsing_context = associated_document().browsing_context();
if (!browsing_context)
@ -1142,7 +1143,7 @@ void Window::initialize_web_interfaces(Badge<WindowEnvironmentSettingsObject>)
// Legacy
define_native_accessor(realm, "event", event_getter, event_setter, JS::Attribute::Enumerable);
m_location_object = heap().allocate<Bindings::LocationObject>(realm, realm);
m_location = heap().allocate<HTML::Location>(realm, realm);
m_navigator = heap().allocate<HTML::Navigator>(realm, realm);
define_direct_property("navigator", m_navigator, JS::Attribute::Enumerable | JS::Attribute::Configurable);
@ -1611,13 +1612,13 @@ JS_DEFINE_NATIVE_FUNCTION(Window::event_setter)
JS_DEFINE_NATIVE_FUNCTION(Window::location_getter)
{
auto* impl = TRY(impl_from(vm));
return impl->m_location_object;
return impl->m_location;
}
JS_DEFINE_NATIVE_FUNCTION(Window::location_setter)
{
auto* impl = TRY(impl_from(vm));
TRY(impl->m_location_object->set(JS::PropertyKey("href"), vm.argument(0), JS::Object::ShouldThrowExceptions::Yes));
TRY(impl->m_location->set(JS::PropertyKey("href"), vm.argument(0), JS::Object::ShouldThrowExceptions::Yes));
return JS::js_undefined();
}

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021-2023, Linus Groh <linusg@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -79,9 +80,9 @@ public:
int inner_width() const;
int inner_height() const;
void did_set_location_href(Badge<Bindings::LocationObject>, AK::URL const& new_href);
void did_call_location_reload(Badge<Bindings::LocationObject>);
void did_call_location_replace(Badge<Bindings::LocationObject>, DeprecatedString url);
void did_set_location_href(Badge<HTML::Location>, AK::URL const& new_href);
void did_call_location_reload(Badge<HTML::Location>);
void did_call_location_replace(Badge<HTML::Location>, DeprecatedString url);
void deallocate_timer_id(Badge<Timer>, i32);
@ -186,8 +187,8 @@ private:
public:
HTML::Origin origin() const;
Bindings::LocationObject* location_object() { return m_location_object; }
Bindings::LocationObject const* location_object() const { return m_location_object; }
HTML::Location* location() { return m_location; }
HTML::Location const* location() const { return m_location; }
virtual JS::ThrowCompletionOr<bool> internal_set_prototype_of(JS::Object* prototype) override;
@ -281,7 +282,7 @@ private:
ENUMERATE_WINDOW_EVENT_HANDLERS(__ENUMERATE);
#undef __ENUMERATE
Bindings::LocationObject* m_location_object { nullptr };
HTML::Location* m_location { nullptr };
// [[CrossOriginPropertyDescriptorMap]], https://html.spec.whatwg.org/multipage/browsers.html#crossoriginpropertydescriptormap
CrossOriginPropertyDescriptorMap m_cross_origin_property_descriptor_map;