LibWeb: Add hashchange event support

This commit is contained in:
Aliaksandr Kalenik 2024-04-15 04:25:24 +02:00 committed by Alexander Kalenik
parent efefd44a9f
commit ccb363c443
Notes: sideshowbarker 2024-07-17 08:27:05 +09:00
11 changed files with 144 additions and 4 deletions

View file

@ -113,6 +113,7 @@ source_set("HTML") {
"HTMLUListElement.cpp",
"HTMLUnknownElement.cpp",
"HTMLVideoElement.cpp",
"HashChangeEvent.cpp",
"History.cpp",
"ImageBitmap.cpp",
"ImageData.cpp",

View file

@ -117,6 +117,7 @@ standard_idl_files = [
"//Userland/Libraries/LibWeb/HTML/DataTransfer.idl",
"//Userland/Libraries/LibWeb/HTML/ErrorEvent.idl",
"//Userland/Libraries/LibWeb/HTML/FormDataEvent.idl",
"//Userland/Libraries/LibWeb/HTML/HashChangeEvent.idl",
"//Userland/Libraries/LibWeb/HTML/History.idl",
"//Userland/Libraries/LibWeb/HTML/HTMLAllCollection.idl",
"//Userland/Libraries/LibWeb/HTML/HTMLAnchorElement.idl",

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<script>
window.addEventListener('hashchange', (event) => {
const oldURL = new URL(event.oldURL);
const newURL = new URL(event.newURL);
parent.postMessage(`hashchange oldURL.hash=${oldURL.hash} newURL.hash=${newURL.hash}`, "*");
if (location.hash === "#test")
location.hash = "#done";
});
location.hash = "#test";
</script>

View file

@ -0,0 +1,2 @@
hashchange oldURL.hash= newURL.hash=#test
hashchange oldURL.hash=#test newURL.hash=#done

View file

@ -0,0 +1,13 @@
<script src="../include.js"></script>
<iframe src="../../data/iframe-hashchange-event.html"></iframe>
<script>
asyncTest(done => {
let messageCount = 0;
window.addEventListener("message", event => {
println(event.data);
messageCount++;
if (messageCount == 2)
done();
});
});
</script>

View file

@ -277,6 +277,7 @@ set(SOURCES
HTML/FormControlInfrastructure.cpp
HTML/FormDataEvent.cpp
HTML/GlobalEventHandlers.cpp
HTML/HashChangeEvent.cpp
HTML/History.cpp
HTML/HTMLAllCollection.cpp
HTML/HTMLAnchorElement.cpp

View file

@ -79,6 +79,7 @@
#include <LibWeb/HTML/HTMLObjectElement.h>
#include <LibWeb/HTML/HTMLScriptElement.h>
#include <LibWeb/HTML/HTMLTitleElement.h>
#include <LibWeb/HTML/HashChangeEvent.h>
#include <LibWeb/HTML/ListOfAvailableImages.h>
#include <LibWeb/HTML/Location.h>
#include <LibWeb/HTML/MessageEvent.h>
@ -4023,10 +4024,19 @@ void Document::update_for_history_step_application(JS::NonnullGCPtr<HTML::Sessio
// FIXME: 3. Restore persisted state given entry.
// FIXME: 4. If oldURL's fragment is not equal to entry's URL's fragment, then queue a global task on the DOM manipulation task source
// given document's relevant global object to fire an event named hashchange at document's relevant global object,
// using HashChangeEvent, with the oldURL attribute initialized to the serialization of oldURL and the newURL attribute
// initialized to the serialization of entry's URL.
// 4. If oldURL's fragment is not equal to entry's URL's fragment, then queue a global task on the DOM manipulation task source
// given document's relevant global object to fire an event named hashchange at document's relevant global object,
// using HashChangeEvent, with the oldURL attribute initialized to the serialization of oldURL and the newURL attribute
// initialized to the serialization of entry's URL.
if (old_url.fragment() != entry->url().fragment()) {
HTML::HashChangeEventInit hashchange_event_init;
hashchange_event_init.old_url = MUST(String::from_byte_string(old_url.serialize()));
hashchange_event_init.new_url = MUST(String::from_byte_string(entry->url().serialize()));
auto hashchange_event = HTML::HashChangeEvent::create(realm(), "hashchange"_fly_string, hashchange_event_init);
HTML::queue_global_task(HTML::Task::Source::DOMManipulation, relevant_global_object, [hashchange_event, &relevant_global_object]() {
relevant_global_object.dispatch_event(hashchange_event);
});
}
}
// 6. Otherwise:

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibJS/Heap/Heap.h>
#include <LibJS/Runtime/Realm.h>
#include <LibWeb/Bindings/HashChangeEventPrototype.h>
#include <LibWeb/Bindings/Intrinsics.h>
#include <LibWeb/HTML/HashChangeEvent.h>
namespace Web::HTML {
JS_DEFINE_ALLOCATOR(HashChangeEvent);
[[nodiscard]] JS::NonnullGCPtr<HashChangeEvent> HashChangeEvent::create(JS::Realm& realm, FlyString const& event_name, HashChangeEventInit const& event_init)
{
return realm.heap().allocate<HashChangeEvent>(realm, realm, event_name, event_init);
}
JS::NonnullGCPtr<HashChangeEvent> HashChangeEvent::construct_impl(JS::Realm& realm, FlyString const& event_name, HashChangeEventInit const& event_init)
{
return realm.heap().allocate<HashChangeEvent>(realm, realm, event_name, event_init);
}
HashChangeEvent::HashChangeEvent(JS::Realm& realm, FlyString const& event_name, HashChangeEventInit const& event_init)
: DOM::Event(realm, event_name, event_init)
, m_old_url(event_init.old_url)
, m_new_url(event_init.new_url)
{
}
void HashChangeEvent::initialize(JS::Realm& realm)
{
Base::initialize(realm);
WEB_SET_PROTOTYPE_FOR_INTERFACE(HashChangeEvent);
}
void HashChangeEvent::visit_edges(JS::Cell::Visitor& visitor)
{
Base::visit_edges(visitor);
}
}

View file

@ -0,0 +1,39 @@
/*
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/DOM/Event.h>
namespace Web::HTML {
struct HashChangeEventInit : public DOM::EventInit {
String old_url;
String new_url;
};
class HashChangeEvent final : public DOM::Event {
WEB_PLATFORM_OBJECT(HashChangeEvent, DOM::Event);
JS_DECLARE_ALLOCATOR(HashChangeEvent);
public:
[[nodiscard]] static JS::NonnullGCPtr<HashChangeEvent> create(JS::Realm&, FlyString const& event_name, HashChangeEventInit const&);
[[nodiscard]] static JS::NonnullGCPtr<HashChangeEvent> construct_impl(JS::Realm&, FlyString const& event_name, HashChangeEventInit const&);
String old_url() const { return m_old_url; }
String new_url() const { return m_new_url; }
private:
HashChangeEvent(JS::Realm&, FlyString const& event_name, HashChangeEventInit const& event_init);
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(JS::Cell::Visitor& visitor) override;
String m_old_url;
String m_new_url;
};
}

View file

@ -0,0 +1,15 @@
#import <DOM/Event.idl>
// https://html.spec.whatwg.org/multipage/nav-history-apis.html#hashchangeevent
[Exposed=Window]
interface HashChangeEvent : Event {
constructor(DOMString type, optional HashChangeEventInit eventInitDict = {});
readonly attribute USVString oldURL;
readonly attribute USVString newURL;
};
dictionary HashChangeEventInit : EventInit {
USVString oldURL = "";
USVString newURL = "";
};

View file

@ -102,6 +102,7 @@ libweb_js_bindings(HTML/DOMStringMap)
libweb_js_bindings(HTML/DataTransfer)
libweb_js_bindings(HTML/ErrorEvent)
libweb_js_bindings(HTML/FormDataEvent)
libweb_js_bindings(HTML/HashChangeEvent)
libweb_js_bindings(HTML/History)
libweb_js_bindings(HTML/HTMLAllCollection)
libweb_js_bindings(HTML/HTMLAnchorElement)