mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-22 17:24:48 -05:00
LibWeb/HTML: Implement the StorageEvent interface
This commit is contained in:
parent
c5f9710492
commit
f3e92f2ae5
Notes:
github-actions[bot]
2024-12-25 10:58:07 +00:00
Author: https://github.com/shannonbooth Commit: https://github.com/LadybirdBrowser/ladybird/commit/f3e92f2ae5f Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3017
13 changed files with 333 additions and 0 deletions
|
@ -482,6 +482,7 @@ set(SOURCES
|
||||||
HTML/SharedResourceRequest.cpp
|
HTML/SharedResourceRequest.cpp
|
||||||
HTML/SourceSet.cpp
|
HTML/SourceSet.cpp
|
||||||
HTML/Storage.cpp
|
HTML/Storage.cpp
|
||||||
|
HTML/StorageEvent.cpp
|
||||||
HTML/StructuredSerialize.cpp
|
HTML/StructuredSerialize.cpp
|
||||||
HTML/SubmitEvent.cpp
|
HTML/SubmitEvent.cpp
|
||||||
HTML/SyntaxHighlighter/SyntaxHighlighter.cpp
|
HTML/SyntaxHighlighter/SyntaxHighlighter.cpp
|
||||||
|
|
70
Libraries/LibWeb/HTML/StorageEvent.cpp
Normal file
70
Libraries/LibWeb/HTML/StorageEvent.cpp
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibWeb/Bindings/Intrinsics.h>
|
||||||
|
#include <LibWeb/Bindings/StorageEventPrototype.h>
|
||||||
|
#include <LibWeb/HTML/Storage.h>
|
||||||
|
#include <LibWeb/HTML/StorageEvent.h>
|
||||||
|
|
||||||
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
GC_DEFINE_ALLOCATOR(StorageEvent);
|
||||||
|
|
||||||
|
GC::Ref<StorageEvent> StorageEvent::create(JS::Realm& realm, FlyString const& event_name, StorageEventInit const& event_init)
|
||||||
|
{
|
||||||
|
auto event = realm.create<StorageEvent>(realm, event_name, event_init);
|
||||||
|
event->set_is_trusted(true);
|
||||||
|
return event;
|
||||||
|
}
|
||||||
|
|
||||||
|
GC::Ref<StorageEvent> StorageEvent::construct_impl(JS::Realm& realm, FlyString const& event_name, StorageEventInit const& event_init)
|
||||||
|
{
|
||||||
|
return realm.create<StorageEvent>(realm, event_name, event_init);
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageEvent::~StorageEvent() = default;
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/webstorage.html#dom-storageevent-initstorageevent
|
||||||
|
void StorageEvent::init_storage_event(String const& type, bool bubbles, bool cancelable,
|
||||||
|
Optional<String> const& key, Optional<String> const& old_value, Optional<String> const& new_value,
|
||||||
|
String const& url, GC::Ptr<Storage> storage_area)
|
||||||
|
{
|
||||||
|
// The initStorageEvent(type, bubbles, cancelable, key, oldValue, newValue, url, storageArea) method must initialize
|
||||||
|
// the event in a manner analogous to the similarly-named initEvent() method. [DOM]
|
||||||
|
if (dispatched())
|
||||||
|
return;
|
||||||
|
|
||||||
|
initialize_event(type, bubbles, cancelable);
|
||||||
|
m_key = key;
|
||||||
|
m_old_value = old_value;
|
||||||
|
m_new_value = new_value;
|
||||||
|
m_url = url;
|
||||||
|
m_storage_area = storage_area;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageEvent::StorageEvent(JS::Realm& realm, FlyString const& event_name, StorageEventInit const& event_init)
|
||||||
|
: DOM::Event(realm, event_name, event_init)
|
||||||
|
, m_key(event_init.key)
|
||||||
|
, m_old_value(event_init.old_value)
|
||||||
|
, m_new_value(event_init.new_value)
|
||||||
|
, m_url(event_init.url)
|
||||||
|
, m_storage_area(event_init.storage_area)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageEvent::initialize(JS::Realm& realm)
|
||||||
|
{
|
||||||
|
Base::initialize(realm);
|
||||||
|
WEB_SET_PROTOTYPE_FOR_INTERFACE(StorageEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StorageEvent::visit_edges(Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_storage_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
60
Libraries/LibWeb/HTML/StorageEvent.h
Normal file
60
Libraries/LibWeb/HTML/StorageEvent.h
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Shannon Booth <shannon@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/FlyString.h>
|
||||||
|
#include <AK/Optional.h>
|
||||||
|
#include <LibGC/Ptr.h>
|
||||||
|
#include <LibWeb/DOM/Event.h>
|
||||||
|
|
||||||
|
namespace Web::HTML {
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/webstorage.html#storageeventinit
|
||||||
|
struct StorageEventInit : public DOM::EventInit {
|
||||||
|
Optional<String> key;
|
||||||
|
Optional<String> old_value;
|
||||||
|
Optional<String> new_value;
|
||||||
|
String url;
|
||||||
|
GC::Ptr<Storage> storage_area;
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/webstorage.html#storageevent
|
||||||
|
class StorageEvent : public DOM::Event {
|
||||||
|
WEB_PLATFORM_OBJECT(StorageEvent, DOM::Event);
|
||||||
|
GC_DECLARE_ALLOCATOR(StorageEvent);
|
||||||
|
|
||||||
|
public:
|
||||||
|
[[nodiscard]] static GC::Ref<StorageEvent> create(JS::Realm&, FlyString const& event_name, StorageEventInit const& event_init = {});
|
||||||
|
static GC::Ref<StorageEvent> construct_impl(JS::Realm&, FlyString const& event_name, StorageEventInit const& event_init);
|
||||||
|
|
||||||
|
virtual ~StorageEvent() override;
|
||||||
|
|
||||||
|
Optional<String> const& key() const { return m_key; }
|
||||||
|
Optional<String> const& old_value() const { return m_old_value; }
|
||||||
|
Optional<String> const& new_value() const { return m_new_value; }
|
||||||
|
String const& url() const { return m_url; }
|
||||||
|
GC::Ptr<Storage const> storage_area() const { return m_storage_area; }
|
||||||
|
|
||||||
|
void init_storage_event(String const& type, bool bubbles = false, bool cancelable = false,
|
||||||
|
Optional<String> const& key = {}, Optional<String> const& old_value = {}, Optional<String> const& new_value = {},
|
||||||
|
String const& url = {}, GC::Ptr<Storage> storage_area = {});
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void visit_edges(Visitor& visitor) override;
|
||||||
|
virtual void initialize(JS::Realm&) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
StorageEvent(JS::Realm&, FlyString const& event_name, StorageEventInit const& event_init);
|
||||||
|
|
||||||
|
Optional<String> m_key;
|
||||||
|
Optional<String> m_old_value;
|
||||||
|
Optional<String> m_new_value;
|
||||||
|
String m_url;
|
||||||
|
GC::Ptr<Storage> m_storage_area;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
25
Libraries/LibWeb/HTML/StorageEvent.idl
Normal file
25
Libraries/LibWeb/HTML/StorageEvent.idl
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
#import <DOM/Event.idl>
|
||||||
|
#import <HTML/Storage.idl>
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/webstorage.html#storageevent
|
||||||
|
[Exposed=Window]
|
||||||
|
interface StorageEvent : Event {
|
||||||
|
constructor(DOMString type, optional StorageEventInit eventInitDict = {});
|
||||||
|
|
||||||
|
readonly attribute DOMString? key;
|
||||||
|
readonly attribute DOMString? oldValue;
|
||||||
|
readonly attribute DOMString? newValue;
|
||||||
|
readonly attribute USVString url;
|
||||||
|
readonly attribute Storage? storageArea;
|
||||||
|
|
||||||
|
undefined initStorageEvent(DOMString type, optional boolean bubbles = false, optional boolean cancelable = false, optional DOMString? key = null, optional DOMString? oldValue = null, optional DOMString? newValue = null, optional USVString url = "", optional Storage? storageArea = null);
|
||||||
|
};
|
||||||
|
|
||||||
|
// https://html.spec.whatwg.org/multipage/webstorage.html#storageeventinit
|
||||||
|
dictionary StorageEventInit : EventInit {
|
||||||
|
DOMString? key = null;
|
||||||
|
DOMString? oldValue = null;
|
||||||
|
DOMString? newValue = null;
|
||||||
|
USVString url = "";
|
||||||
|
Storage? storageArea = null;
|
||||||
|
};
|
|
@ -224,6 +224,7 @@ libweb_js_bindings(HTML/PromiseRejectionEvent)
|
||||||
libweb_js_bindings(HTML/RadioNodeList)
|
libweb_js_bindings(HTML/RadioNodeList)
|
||||||
libweb_js_bindings(HTML/ShadowRealmGlobalScope GLOBAL)
|
libweb_js_bindings(HTML/ShadowRealmGlobalScope GLOBAL)
|
||||||
libweb_js_bindings(HTML/Storage)
|
libweb_js_bindings(HTML/Storage)
|
||||||
|
libweb_js_bindings(HTML/StorageEvent)
|
||||||
libweb_js_bindings(HTML/SubmitEvent)
|
libweb_js_bindings(HTML/SubmitEvent)
|
||||||
libweb_js_bindings(HTML/TextMetrics)
|
libweb_js_bindings(HTML/TextMetrics)
|
||||||
libweb_js_bindings(HTML/TextTrack)
|
libweb_js_bindings(HTML/TextTrack)
|
||||||
|
|
|
@ -97,6 +97,7 @@ static bool is_platform_object(Type const& type)
|
||||||
"SVGTransform"sv,
|
"SVGTransform"sv,
|
||||||
"ShadowRoot"sv,
|
"ShadowRoot"sv,
|
||||||
"SourceBuffer"sv,
|
"SourceBuffer"sv,
|
||||||
|
"Storage"sv,
|
||||||
"Table"sv,
|
"Table"sv,
|
||||||
"Text"sv,
|
"Text"sv,
|
||||||
"TextMetrics"sv,
|
"TextMetrics"sv,
|
||||||
|
|
|
@ -357,6 +357,7 @@ SourceBuffer
|
||||||
SourceBufferList
|
SourceBufferList
|
||||||
StaticRange
|
StaticRange
|
||||||
Storage
|
Storage
|
||||||
|
StorageEvent
|
||||||
StorageManager
|
StorageManager
|
||||||
String
|
String
|
||||||
StyleSheet
|
StyleSheet
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 6 tests
|
||||||
|
|
||||||
|
6 Pass
|
||||||
|
Pass StorageEvent constructor called as normal function
|
||||||
|
Pass constructor with no arguments
|
||||||
|
Pass constructor with just type argument
|
||||||
|
Pass constructor with sensible type argument and members
|
||||||
|
Pass constructor with null type argument and members
|
||||||
|
Pass constructor with undefined type argument and members
|
|
@ -0,0 +1,10 @@
|
||||||
|
Harness status: OK
|
||||||
|
|
||||||
|
Found 5 tests
|
||||||
|
|
||||||
|
5 Pass
|
||||||
|
Pass initStorageEvent with 0 arguments
|
||||||
|
Pass initStorageEvent with 1 argument
|
||||||
|
Pass initStorageEvent with 8 sensible arguments
|
||||||
|
Pass initStorageEvent with 8 null arguments
|
||||||
|
Pass initStorageEvent with 8 undefined arguments
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
|
||||||
|
<script src="../resources/testharness.js"></script>
|
||||||
|
<script src="../resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<div id=log></div>
|
||||||
|
<script src="../webstorage/event_constructor.window.js"></script>
|
|
@ -0,0 +1,77 @@
|
||||||
|
test(function() {
|
||||||
|
assert_throws_js(
|
||||||
|
TypeError,
|
||||||
|
() => StorageEvent(""),
|
||||||
|
"Calling StorageEvent constructor without 'new' must throw"
|
||||||
|
);
|
||||||
|
}, "StorageEvent constructor called as normal function");
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
assert_throws_js(TypeError, () => new StorageEvent());
|
||||||
|
// should be redundant, but .length can be wrong with custom bindings
|
||||||
|
assert_equals(StorageEvent.length, 1, 'StorageEvent.length');
|
||||||
|
}, 'constructor with no arguments');
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var event = new StorageEvent('type');
|
||||||
|
assert_equals(event.type, 'type', 'type');
|
||||||
|
assert_equals(event.key, null, 'key');
|
||||||
|
assert_equals(event.oldValue, null, 'oldValue');
|
||||||
|
assert_equals(event.newValue, null, 'newValue');
|
||||||
|
assert_equals(event.url, '', 'url');
|
||||||
|
assert_equals(event.storageArea, null, 'storageArea');
|
||||||
|
}, 'constructor with just type argument');
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
assert_not_equals(localStorage, null, 'localStorage'); // precondition
|
||||||
|
|
||||||
|
var event = new StorageEvent('storage', {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
key: 'key',
|
||||||
|
oldValue: 'oldValue',
|
||||||
|
newValue: 'newValue',
|
||||||
|
url: 'url', // not an absolute URL to ensure it isn't resolved
|
||||||
|
storageArea: localStorage
|
||||||
|
});
|
||||||
|
assert_equals(event.type, 'storage', 'type');
|
||||||
|
assert_equals(event.bubbles, true, 'bubbles');
|
||||||
|
assert_equals(event.cancelable, true, 'cancelable');
|
||||||
|
assert_equals(event.key, 'key', 'key');
|
||||||
|
assert_equals(event.oldValue, 'oldValue', 'oldValue');
|
||||||
|
assert_equals(event.newValue, 'newValue', 'newValue');
|
||||||
|
assert_equals(event.url, 'url', 'url');
|
||||||
|
assert_equals(event.storageArea, localStorage, 'storageArea');
|
||||||
|
}, 'constructor with sensible type argument and members');
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var event = new StorageEvent(null, {
|
||||||
|
key: null,
|
||||||
|
oldValue: null,
|
||||||
|
newValue: null,
|
||||||
|
url: null,
|
||||||
|
storageArea: null
|
||||||
|
});
|
||||||
|
assert_equals(event.type, 'null', 'type');
|
||||||
|
assert_equals(event.key, null, 'key');
|
||||||
|
assert_equals(event.oldValue, null, 'oldValue');
|
||||||
|
assert_equals(event.newValue, null, 'newValue');
|
||||||
|
assert_equals(event.url, 'null', 'url');
|
||||||
|
assert_equals(event.storageArea, null, 'storageArea');
|
||||||
|
}, 'constructor with null type argument and members');
|
||||||
|
|
||||||
|
test(function() {
|
||||||
|
var event = new StorageEvent(undefined, {
|
||||||
|
key: undefined,
|
||||||
|
oldValue: undefined,
|
||||||
|
newValue: undefined,
|
||||||
|
url: undefined,
|
||||||
|
storageArea: undefined
|
||||||
|
});
|
||||||
|
assert_equals(event.type, 'undefined', 'type');
|
||||||
|
assert_equals(event.key, null, 'key');
|
||||||
|
assert_equals(event.oldValue, null, 'oldValue');
|
||||||
|
assert_equals(event.newValue, null, 'newValue');
|
||||||
|
assert_equals(event.url, '', 'url'); // not 'undefined'!
|
||||||
|
assert_equals(event.storageArea, null, 'storageArea');
|
||||||
|
}, 'constructor with undefined type argument and members');
|
|
@ -0,0 +1,8 @@
|
||||||
|
<!doctype html>
|
||||||
|
<meta charset=utf-8>
|
||||||
|
|
||||||
|
<script src="../resources/testharness.js"></script>
|
||||||
|
<script src="../resources/testharnessreport.js"></script>
|
||||||
|
|
||||||
|
<div id=log></div>
|
||||||
|
<script src="../webstorage/event_initstorageevent.window.js"></script>
|
|
@ -0,0 +1,60 @@
|
||||||
|
test(() => {
|
||||||
|
const event = new StorageEvent('storage');
|
||||||
|
assert_throws_js(TypeError, () => event.initStorageEvent());
|
||||||
|
// should be redundant, but .length can be wrong with custom bindings
|
||||||
|
assert_equals(event.initStorageEvent.length, 1, 'event.initStorageEvent.length');
|
||||||
|
}, 'initStorageEvent with 0 arguments');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
const event = new StorageEvent('storage');
|
||||||
|
event.initStorageEvent('type');
|
||||||
|
assert_equals(event.type, 'type', 'event.type');
|
||||||
|
assert_equals(event.bubbles, false, 'event.bubbles');
|
||||||
|
assert_equals(event.cancelable, false, 'event.cancelable');
|
||||||
|
assert_equals(event.key, null, 'event.key');
|
||||||
|
assert_equals(event.oldValue, null, 'event.oldValue');
|
||||||
|
assert_equals(event.newValue, null, 'event.newValue');
|
||||||
|
assert_equals(event.url, '', 'event.url');
|
||||||
|
assert_equals(event.storageArea, null, 'event.storageArea');
|
||||||
|
}, 'initStorageEvent with 1 argument');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
assert_not_equals(localStorage, null, 'localStorage'); // precondition
|
||||||
|
|
||||||
|
const event = new StorageEvent('storage');
|
||||||
|
event.initStorageEvent('type', true, true, 'key', 'oldValue', 'newValue', 'url', localStorage);
|
||||||
|
assert_equals(event.type, 'type', 'event.type');
|
||||||
|
assert_equals(event.bubbles, true, 'event.bubbles');
|
||||||
|
assert_equals(event.cancelable, true, 'event.cancelable');
|
||||||
|
assert_equals(event.key, 'key', 'event.key');
|
||||||
|
assert_equals(event.oldValue, 'oldValue', 'event.oldValue');
|
||||||
|
assert_equals(event.newValue, 'newValue', 'event.newValue');
|
||||||
|
assert_equals(event.url, 'url', 'event.url');
|
||||||
|
assert_equals(event.storageArea, localStorage, 'event.storageArea');
|
||||||
|
}, 'initStorageEvent with 8 sensible arguments');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
const event = new StorageEvent('storage');
|
||||||
|
event.initStorageEvent(null, null, null, null, null, null, null, null);
|
||||||
|
assert_equals(event.type, 'null', 'event.type');
|
||||||
|
assert_equals(event.bubbles, false, 'event.bubbles');
|
||||||
|
assert_equals(event.cancelable, false, 'event.cancelable');
|
||||||
|
assert_equals(event.key, null, 'event.key');
|
||||||
|
assert_equals(event.oldValue, null, 'event.oldValue');
|
||||||
|
assert_equals(event.newValue, null, 'event.newValue');
|
||||||
|
assert_equals(event.url, 'null', 'event.url');
|
||||||
|
assert_equals(event.storageArea, null, 'event.storageArea');
|
||||||
|
}, 'initStorageEvent with 8 null arguments');
|
||||||
|
|
||||||
|
test(() => {
|
||||||
|
const event = new StorageEvent('storage');
|
||||||
|
event.initStorageEvent(undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
|
||||||
|
assert_equals(event.type, 'undefined', 'event.type');
|
||||||
|
assert_equals(event.bubbles, false, 'event.bubbles');
|
||||||
|
assert_equals(event.cancelable, false, 'event.cancelable');
|
||||||
|
assert_equals(event.key, null, 'event.key');
|
||||||
|
assert_equals(event.oldValue, null, 'event.oldValue');
|
||||||
|
assert_equals(event.newValue, null, 'event.newValue');
|
||||||
|
assert_equals(event.url, '', 'event.url');
|
||||||
|
assert_equals(event.storageArea, null, 'event.storageArea');
|
||||||
|
}, 'initStorageEvent with 8 undefined arguments');
|
Loading…
Reference in a new issue