From ff9856a21447445394ce34543b301ac9a9460d57 Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Mon, 21 Mar 2022 20:02:40 -0400 Subject: [PATCH] LibWeb: Implement HTMLOptionsCollection.add() --- .../LibWeb/HTML/HTMLOptionsCollection.cpp | 43 +++++++++++++++++++ .../LibWeb/HTML/HTMLOptionsCollection.h | 7 +++ .../LibWeb/HTML/HTMLOptionsCollection.idl | 2 +- 3 files changed, 51 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.cpp b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.cpp index 7e5484506a..365f75ed3b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.cpp @@ -4,7 +4,11 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include +#include +#include #include +#include namespace Web::HTML { @@ -13,4 +17,43 @@ HTMLOptionsCollection::HTMLOptionsCollection(DOM::ParentNode& root, Function HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement element, Optional before) +{ + auto resolved_element = element.visit([](auto const& e) -> NonnullRefPtr { return e; }); + + RefPtr before_element; + if (before.has_value() && before->has>()) + before_element = before->get>(); + + // 1. If element is an ancestor of the select element on which the HTMLOptionsCollection is rooted, then throw a "HierarchyRequestError" DOMException. + if (resolved_element->is_ancestor_of(root())) + return DOM::HierarchyRequestError::create("The provided element is an ancestor of the root select element."); + + // 2. If before is an element, but that element isn't a descendant of the select element on which the HTMLOptionsCollection is rooted, then throw a "NotFoundError" DOMException. + if (before_element && !before_element->is_descendant_of(root())) + return DOM::NotFoundError::create("The 'before' element is not a descendant of the root select element."); + + // 3. If element and before are the same element, then return. + if (before_element && (resolved_element.ptr() == before_element.ptr())) + return {}; + + // 4. If before is a node, then let reference be that node. Otherwise, if before is an integer, and there is a beforeth node in the collection, let reference be that node. Otherwise, let reference be null. + RefPtr reference; + + if (before_element) + reference = move(before_element); + else if (before.has_value() && before->has()) + reference = item(before->get()); + + // 5. If reference is not null, let parent be the parent node of reference. Otherwise, let parent be the select element on which the HTMLOptionsCollection is rooted. + DOM::Node* parent = reference ? reference->parent() : root().ptr(); + + // 6. Pre-insert element into parent node before reference. + if (auto result = parent->pre_insert(resolved_element, reference); result.is_exception()) + return result.exception(); + + return {}; +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.h b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.h index 1d2bfcd2c5..7444607cfd 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.h @@ -6,10 +6,15 @@ #pragma once +#include +#include #include namespace Web::HTML { +using HTMLOptionOrOptGroupElement = Variant, NonnullRefPtr>; +using HTMLElementOrElementIndex = Variant, i32>; + class HTMLOptionsCollection final : public DOM::HTMLCollection { public: using WrapperType = Bindings::HTMLOptionsCollectionWrapper; @@ -19,6 +24,8 @@ public: return adopt_ref(*new HTMLOptionsCollection(root, move(filter))); } + DOM::ExceptionOr add(HTMLOptionOrOptGroupElement element, Optional before = {}); + protected: HTMLOptionsCollection(DOM::ParentNode& root, Function filter); }; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.idl b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.idl index ae33079903..084317ab03 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.idl +++ b/Userland/Libraries/LibWeb/HTML/HTMLOptionsCollection.idl @@ -6,7 +6,7 @@ interface HTMLOptionsCollection : HTMLCollection { // [CEReactions] attribute unsigned long length; // shadows inherited length // [CEReactions] setter undefined (unsigned long index, HTMLOptionElement? option); - // [CEReactions] undefined add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null); + [CEReactions] undefined add((HTMLOptionElement or HTMLOptGroupElement) element, optional (HTMLElement or long)? before = null); // [CEReactions] undefined remove(long index); // attribute long selectedIndex; };