mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 03:57:43 +00:00
LibWeb/WebIDL: Introduce ObservableArray
ObservableArray inherits from JS::Array and overrides `internal_set` and `internal_delete` to run an interceptor callback when an indexed item is added or deleted.
This commit is contained in:
parent
75a8d37c99
commit
fceba6a257
4 changed files with 114 additions and 1 deletions
|
@ -44,7 +44,7 @@ public:
|
||||||
|
|
||||||
virtual ThrowCompletionOr<Optional<PropertyDescriptor>> internal_get_own_property(PropertyKey const&) const override final;
|
virtual ThrowCompletionOr<Optional<PropertyDescriptor>> internal_get_own_property(PropertyKey const&) const override final;
|
||||||
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override final;
|
virtual ThrowCompletionOr<bool> internal_define_own_property(PropertyKey const&, PropertyDescriptor const&) override final;
|
||||||
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override final;
|
virtual ThrowCompletionOr<bool> internal_delete(PropertyKey const&) override;
|
||||||
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override final;
|
virtual ThrowCompletionOr<MarkedVector<Value>> internal_own_property_keys() const override final;
|
||||||
|
|
||||||
[[nodiscard]] bool length_is_writable() const { return m_length_writable; }
|
[[nodiscard]] bool length_is_writable() const { return m_length_writable; }
|
||||||
|
|
|
@ -647,6 +647,7 @@ set(SOURCES
|
||||||
WebIDL/Buffers.cpp
|
WebIDL/Buffers.cpp
|
||||||
WebIDL/CallbackType.cpp
|
WebIDL/CallbackType.cpp
|
||||||
WebIDL/DOMException.cpp
|
WebIDL/DOMException.cpp
|
||||||
|
WebIDL/ObservableArray.cpp
|
||||||
WebIDL/OverloadResolution.cpp
|
WebIDL/OverloadResolution.cpp
|
||||||
WebIDL/Promise.cpp
|
WebIDL/Promise.cpp
|
||||||
WebSockets/WebSocket.cpp
|
WebSockets/WebSocket.cpp
|
||||||
|
|
69
Userland/Libraries/LibWeb/WebIDL/ObservableArray.cpp
Normal file
69
Userland/Libraries/LibWeb/WebIDL/ObservableArray.cpp
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibWeb/Bindings/ExceptionOrUtils.h>
|
||||||
|
#include <LibWeb/WebIDL/ObservableArray.h>
|
||||||
|
|
||||||
|
namespace Web::WebIDL {
|
||||||
|
|
||||||
|
JS::NonnullGCPtr<ObservableArray> ObservableArray::create(JS::Realm& realm)
|
||||||
|
{
|
||||||
|
auto prototype = realm.intrinsics().array_prototype();
|
||||||
|
return realm.heap().allocate<ObservableArray>(realm, prototype);
|
||||||
|
}
|
||||||
|
|
||||||
|
ObservableArray::ObservableArray(Object& prototype)
|
||||||
|
: JS::Array(prototype)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObservableArray::visit_edges(JS::Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
visitor.visit(m_on_set_an_indexed_value);
|
||||||
|
visitor.visit(m_on_delete_an_indexed_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObservableArray::set_on_set_an_indexed_value_callback(SetAnIndexedValueCallbackFunction&& callback)
|
||||||
|
{
|
||||||
|
m_on_set_an_indexed_value = create_heap_function(heap(), move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObservableArray::set_on_delete_an_indexed_value_callback(DeleteAnIndexedValueCallbackFunction&& callback)
|
||||||
|
{
|
||||||
|
m_on_delete_an_indexed_value = create_heap_function(heap(), move(callback));
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::ThrowCompletionOr<bool> ObservableArray::internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* metadata)
|
||||||
|
{
|
||||||
|
if (property_key.is_number() && m_on_set_an_indexed_value)
|
||||||
|
TRY(Bindings::throw_dom_exception_if_needed(vm(), [&] { return m_on_set_an_indexed_value->function()(value); }));
|
||||||
|
return TRY(Base::internal_set(property_key, value, receiver, metadata));
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::ThrowCompletionOr<bool> ObservableArray::internal_delete(JS::PropertyKey const& property_key)
|
||||||
|
{
|
||||||
|
if (property_key.is_number() && m_on_delete_an_indexed_value)
|
||||||
|
TRY(Bindings::throw_dom_exception_if_needed(vm(), [&] { return m_on_delete_an_indexed_value->function()(); }));
|
||||||
|
return JS::Array::internal_delete(property_key);
|
||||||
|
}
|
||||||
|
|
||||||
|
JS::ThrowCompletionOr<void> ObservableArray::append(JS::Value value)
|
||||||
|
{
|
||||||
|
if (m_on_set_an_indexed_value)
|
||||||
|
TRY(Bindings::throw_dom_exception_if_needed(vm(), [&] { return m_on_set_an_indexed_value->function()(value); }));
|
||||||
|
indexed_properties().append(value);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void ObservableArray::clear()
|
||||||
|
{
|
||||||
|
while (!indexed_properties().is_empty()) {
|
||||||
|
indexed_properties().storage()->take_first();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
43
Userland/Libraries/LibWeb/WebIDL/ObservableArray.h
Normal file
43
Userland/Libraries/LibWeb/WebIDL/ObservableArray.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibJS/Runtime/Array.h>
|
||||||
|
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||||
|
|
||||||
|
namespace Web::WebIDL {
|
||||||
|
|
||||||
|
// https://webidl.spec.whatwg.org/#idl-observable-array
|
||||||
|
class ObservableArray final : public JS::Array {
|
||||||
|
public:
|
||||||
|
static JS::NonnullGCPtr<ObservableArray> create(JS::Realm& realm);
|
||||||
|
|
||||||
|
virtual JS::ThrowCompletionOr<bool> internal_set(JS::PropertyKey const& property_key, JS::Value value, JS::Value receiver, JS::CacheablePropertyMetadata* metadata = nullptr) override;
|
||||||
|
virtual JS::ThrowCompletionOr<bool> internal_delete(JS::PropertyKey const& property_key) override;
|
||||||
|
|
||||||
|
using SetAnIndexedValueCallbackFunction = Function<ExceptionOr<void>(JS::Value&)>;
|
||||||
|
using DeleteAnIndexedValueCallbackFunction = Function<ExceptionOr<void>()>;
|
||||||
|
|
||||||
|
void set_on_set_an_indexed_value_callback(SetAnIndexedValueCallbackFunction&& callback);
|
||||||
|
void set_on_delete_an_indexed_value_callback(DeleteAnIndexedValueCallbackFunction&& callback);
|
||||||
|
|
||||||
|
JS::ThrowCompletionOr<void> append(JS::Value value);
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
explicit ObservableArray(Object& prototype);
|
||||||
|
|
||||||
|
virtual void visit_edges(JS::Cell::Visitor&) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
using SetAnIndexedValueCallbackHeapFunction = JS::HeapFunction<SetAnIndexedValueCallbackFunction::FunctionType>;
|
||||||
|
using DeleteAnIndexedValueCallbackHeapFunction = JS::HeapFunction<DeleteAnIndexedValueCallbackFunction::FunctionType>;
|
||||||
|
|
||||||
|
JS::GCPtr<SetAnIndexedValueCallbackHeapFunction> m_on_set_an_indexed_value;
|
||||||
|
JS::GCPtr<DeleteAnIndexedValueCallbackHeapFunction> m_on_delete_an_indexed_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue