From be52e7171adca720954e18250be0bdce68665982 Mon Sep 17 00:00:00 2001 From: Kenneth Myhra Date: Sun, 5 Mar 2023 17:29:11 +0100 Subject: LibWeb: Add FormDataIterator implementation This adds the FormDataIterator implementation so we can iterate over FormData.{keys(),values(),entries()}. --- Userland/Libraries/LibWeb/CMakeLists.txt | 1 + Userland/Libraries/LibWeb/Forward.h | 1 + Userland/Libraries/LibWeb/XHR/FormData.cpp | 10 +++ Userland/Libraries/LibWeb/XHR/FormData.h | 5 ++ Userland/Libraries/LibWeb/XHR/FormData.idl | 2 +- Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp | 79 ++++++++++++++++++++++ Userland/Libraries/LibWeb/XHR/FormDataIterator.h | 35 ++++++++++ Userland/Libraries/LibWeb/idl_files.cmake | 2 +- 8 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp create mode 100644 Userland/Libraries/LibWeb/XHR/FormDataIterator.h (limited to 'Userland') diff --git a/Userland/Libraries/LibWeb/CMakeLists.txt b/Userland/Libraries/LibWeb/CMakeLists.txt index a542847773..216eebcc17 100644 --- a/Userland/Libraries/LibWeb/CMakeLists.txt +++ b/Userland/Libraries/LibWeb/CMakeLists.txt @@ -473,6 +473,7 @@ set(SOURCES WebSockets/WebSocket.cpp XHR/EventNames.cpp XHR/FormData.cpp + XHR/FormDataIterator.cpp XHR/ProgressEvent.cpp XHR/XMLHttpRequest.cpp XHR/XMLHttpRequestEventTarget.cpp diff --git a/Userland/Libraries/LibWeb/Forward.h b/Userland/Libraries/LibWeb/Forward.h index 200c2f61d6..26a99cc382 100644 --- a/Userland/Libraries/LibWeb/Forward.h +++ b/Userland/Libraries/LibWeb/Forward.h @@ -489,6 +489,7 @@ class WebGLRenderingContextBase; namespace Web::XHR { class FormData; +class FormDataIterator; class ProgressEvent; class XMLHttpRequest; class XMLHttpRequestEventTarget; diff --git a/Userland/Libraries/LibWeb/XHR/FormData.cpp b/Userland/Libraries/LibWeb/XHR/FormData.cpp index d2fca57323..ca9fe5ef72 100644 --- a/Userland/Libraries/LibWeb/XHR/FormData.cpp +++ b/Userland/Libraries/LibWeb/XHR/FormData.cpp @@ -171,4 +171,14 @@ WebIDL::ExceptionOr FormData::set_impl(String const& name, Variant FormData::for_each(ForEachCallback callback) +{ + for (auto i = 0u; i < m_entry_list.size(); ++i) { + auto& entry = m_entry_list[i]; + TRY(callback(entry.name, entry.value)); + } + + return {}; +} + } diff --git a/Userland/Libraries/LibWeb/XHR/FormData.h b/Userland/Libraries/LibWeb/XHR/FormData.h index b8a3f300ef..7cfbc9934a 100644 --- a/Userland/Libraries/LibWeb/XHR/FormData.h +++ b/Userland/Libraries/LibWeb/XHR/FormData.h @@ -41,7 +41,12 @@ public: WebIDL::ExceptionOr set(String const& name, String const& value); WebIDL::ExceptionOr set(String const& name, JS::NonnullGCPtr const& blob_value, Optional const& filename = {}); + using ForEachCallback = Function(String const&, FormDataEntryValue const&)>; + JS::ThrowCompletionOr for_each(ForEachCallback); + private: + friend class FormDataIterator; + explicit FormData(JS::Realm&, Vector entry_list = {}); virtual JS::ThrowCompletionOr initialize(JS::Realm&) override; diff --git a/Userland/Libraries/LibWeb/XHR/FormData.idl b/Userland/Libraries/LibWeb/XHR/FormData.idl index 38af410dfc..269f15801e 100644 --- a/Userland/Libraries/LibWeb/XHR/FormData.idl +++ b/Userland/Libraries/LibWeb/XHR/FormData.idl @@ -19,5 +19,5 @@ interface FormData { boolean has(USVString name); undefined set(USVString name, USVString value); undefined set(USVString name, Blob blobValue, optional USVString filename); - // FIXME: iterable; + iterable; }; diff --git a/Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp b/Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp new file mode 100644 index 0000000000..32c17eb6ed --- /dev/null +++ b/Userland/Libraries/LibWeb/XHR/FormDataIterator.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023, Kenneth Myhra + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +namespace Web::Bindings { + +template<> +void Intrinsics::create_web_prototype_and_constructor(JS::Realm& realm) +{ + auto prototype = heap().allocate(realm, realm).release_allocated_value_but_fixme_should_propagate_errors(); + m_prototypes.set("FormDataIterator"sv, prototype); +} + +} + +namespace Web::XHR { + +WebIDL::ExceptionOr> FormDataIterator::create(FormData const& form_data, JS::Object::PropertyKind iterator_kind) +{ + return MUST_OR_THROW_OOM(form_data.heap().allocate(form_data.realm(), form_data, iterator_kind)); +} + +FormDataIterator::FormDataIterator(Web::XHR::FormData const& form_data, JS::Object::PropertyKind iterator_kind) + : PlatformObject(form_data.realm()) + , m_form_data(form_data) + , m_iterator_kind(iterator_kind) +{ +} + +FormDataIterator::~FormDataIterator() = default; + +JS::ThrowCompletionOr FormDataIterator::initialize(JS::Realm& realm) +{ + MUST_OR_THROW_OOM(Base::initialize(realm)); + set_prototype(&Bindings::ensure_web_prototype(realm, "FormDataIterator")); + + return {}; +} + +void FormDataIterator::visit_edges(Cell::Visitor& visitor) +{ + Base::visit_edges(visitor); + visitor.visit(&m_form_data); +} + +JS::Object* FormDataIterator::next() +{ + auto& vm = this->vm(); + + if (m_index >= m_form_data.m_entry_list.size()) + return create_iterator_result_object(vm, JS::js_undefined(), true); + + auto& entry = m_form_data.m_entry_list[m_index++]; + if (m_iterator_kind == JS::Object::PropertyKind::Key) + return create_iterator_result_object(vm, JS::PrimitiveString::create(vm, entry.name), false); + + auto entry_value = entry.value.visit( + [&](JS::Handle const& file) -> JS::Value { + return file.cell(); + }, + [&](String const& string) -> JS::Value { + return JS::PrimitiveString::create(vm, string); + }); + + if (m_iterator_kind == JS::Object::PropertyKind::Value) + return create_iterator_result_object(vm, entry_value, false); + + return create_iterator_result_object(vm, JS::Array::create_from(realm(), { JS::PrimitiveString::create(vm, entry.name), entry_value }), false); +} + +} diff --git a/Userland/Libraries/LibWeb/XHR/FormDataIterator.h b/Userland/Libraries/LibWeb/XHR/FormDataIterator.h new file mode 100644 index 0000000000..c50153ae09 --- /dev/null +++ b/Userland/Libraries/LibWeb/XHR/FormDataIterator.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023, Kenneth Myhra + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#pragma once + +#include +#include + +namespace Web::XHR { + +class FormDataIterator : public Bindings::PlatformObject { + WEB_PLATFORM_OBJECT(FormDataIterator, Bindings::PlatformObject); + +public: + static WebIDL::ExceptionOr> create(FormData const&, JS::Object::PropertyKind iterator_kind); + + virtual ~FormDataIterator() override; + + JS::Object* next(); + +private: + FormDataIterator(FormData const&, JS::Object::PropertyKind iterator_kind); + + virtual JS::ThrowCompletionOr initialize(JS::Realm&) override; + virtual void visit_edges(Cell::Visitor&) override; + + FormData const& m_form_data; + JS::Object::PropertyKind m_iterator_kind; + size_t m_index { 0 }; +}; + +} diff --git a/Userland/Libraries/LibWeb/idl_files.cmake b/Userland/Libraries/LibWeb/idl_files.cmake index cae18ad006..39f39c242b 100644 --- a/Userland/Libraries/LibWeb/idl_files.cmake +++ b/Userland/Libraries/LibWeb/idl_files.cmake @@ -203,7 +203,7 @@ libweb_js_bindings(WebGL/WebGLContextEvent) libweb_js_bindings(WebGL/WebGLRenderingContext) libweb_js_bindings(WebIDL/DOMException) libweb_js_bindings(WebSockets/WebSocket) -libweb_js_bindings(XHR/FormData) +libweb_js_bindings(XHR/FormData ITERABLE) libweb_js_bindings(XHR/ProgressEvent) libweb_js_bindings(XHR/XMLHttpRequest) libweb_js_bindings(XHR/XMLHttpRequestEventTarget) -- cgit v1.2.3