Serenity Operating System
at master 77 lines 3.4 kB view raw
1/* 2 * Copyright (c) 2022, the SerenityOS developers. 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <LibWeb/Bindings/Intrinsics.h> 8#include <LibWeb/HTML/HTMLOptGroupElement.h> 9#include <LibWeb/HTML/HTMLOptionElement.h> 10#include <LibWeb/HTML/HTMLOptionsCollection.h> 11#include <LibWeb/HTML/HTMLSelectElement.h> 12#include <LibWeb/WebIDL/DOMException.h> 13 14namespace Web::HTML { 15 16WebIDL::ExceptionOr<JS::NonnullGCPtr<HTMLOptionsCollection>> HTMLOptionsCollection::create(DOM::ParentNode& root, Function<bool(DOM::Element const&)> filter) 17{ 18 return MUST_OR_THROW_OOM(root.heap().allocate<HTMLOptionsCollection>(root.realm(), root, move(filter))); 19} 20 21HTMLOptionsCollection::HTMLOptionsCollection(DOM::ParentNode& root, Function<bool(DOM::Element const&)> filter) 22 : DOM::HTMLCollection(root, move(filter)) 23{ 24} 25 26HTMLOptionsCollection::~HTMLOptionsCollection() = default; 27 28JS::ThrowCompletionOr<void> HTMLOptionsCollection::initialize(JS::Realm& realm) 29{ 30 MUST_OR_THROW_OOM(Base::initialize(realm)); 31 set_prototype(&Bindings::ensure_web_prototype<Bindings::HTMLOptionsCollectionPrototype>(realm, "HTMLOptionsCollection")); 32 33 return {}; 34} 35 36// https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-add 37WebIDL::ExceptionOr<void> HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before) 38{ 39 auto resolved_element = element.visit( 40 [](auto& e) -> JS::Handle<HTMLElement> { 41 return JS::make_handle(static_cast<HTML::HTMLElement&>(*e)); 42 }); 43 44 JS::GCPtr<DOM::Node> before_element; 45 if (before.has_value() && before->has<JS::Handle<HTMLElement>>()) 46 before_element = before->get<JS::Handle<HTMLElement>>().ptr(); 47 48 // 1. If element is an ancestor of the select element on which the HTMLOptionsCollection is rooted, then throw a "HierarchyRequestError" DOMException. 49 if (resolved_element->is_ancestor_of(root())) 50 return WebIDL::HierarchyRequestError::create(realm(), "The provided element is an ancestor of the root select element."); 51 52 // 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. 53 if (before_element && !before_element->is_descendant_of(root())) 54 return WebIDL::NotFoundError::create(realm(), "The 'before' element is not a descendant of the root select element."); 55 56 // 3. If element and before are the same element, then return. 57 if (before_element && (resolved_element.ptr() == before_element.ptr())) 58 return {}; 59 60 // 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. 61 JS::GCPtr<DOM::Node> reference; 62 63 if (before_element) 64 reference = move(before_element); 65 else if (before.has_value() && before->has<i32>()) 66 reference = item(before->get<i32>()); 67 68 // 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. 69 DOM::Node* parent = reference ? reference->parent() : root().ptr(); 70 71 // 6. Pre-insert element into parent node before reference. 72 (void)TRY(parent->pre_insert(*resolved_element, reference)); 73 74 return {}; 75} 76 77}