HTMLOptionsCollection.cpp 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. /*
  2. * Copyright (c) 2022, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibWeb/Bindings/HTMLOptionsCollectionPrototype.h>
  7. #include <LibWeb/DOM/DOMException.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/HTML/Window.h>
  13. namespace Web::HTML {
  14. JS::NonnullGCPtr<HTMLOptionsCollection> HTMLOptionsCollection::create(DOM::ParentNode& root, Function<bool(DOM::Element const&)> filter)
  15. {
  16. return *root.heap().allocate<HTMLOptionsCollection>(root.realm(), root, move(filter));
  17. }
  18. HTMLOptionsCollection::HTMLOptionsCollection(DOM::ParentNode& root, Function<bool(DOM::Element const&)> filter)
  19. : DOM::HTMLCollection(root, move(filter))
  20. {
  21. set_prototype(&root.window().ensure_web_prototype<Bindings::HTMLOptionsCollectionPrototype>("HTMLOptionsCollection"));
  22. }
  23. HTMLOptionsCollection::~HTMLOptionsCollection() = default;
  24. // https://html.spec.whatwg.org/multipage/common-dom-interfaces.html#dom-htmloptionscollection-add
  25. DOM::ExceptionOr<void> HTMLOptionsCollection::add(HTMLOptionOrOptGroupElement element, Optional<HTMLElementOrElementIndex> before)
  26. {
  27. auto resolved_element = element.visit(
  28. [](auto& e) -> JS::Handle<HTMLElement> {
  29. return JS::make_handle(static_cast<HTML::HTMLElement&>(*e));
  30. });
  31. JS::GCPtr<DOM::Node> before_element;
  32. if (before.has_value() && before->has<JS::Handle<HTMLElement>>())
  33. before_element = before->get<JS::Handle<HTMLElement>>().ptr();
  34. // 1. If element is an ancestor of the select element on which the HTMLOptionsCollection is rooted, then throw a "HierarchyRequestError" DOMException.
  35. if (resolved_element->is_ancestor_of(root()))
  36. return DOM::HierarchyRequestError::create("The provided element is an ancestor of the root select element.");
  37. // 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.
  38. if (before_element && !before_element->is_descendant_of(root()))
  39. return DOM::NotFoundError::create("The 'before' element is not a descendant of the root select element.");
  40. // 3. If element and before are the same element, then return.
  41. if (before_element && (resolved_element.ptr() == before_element.ptr()))
  42. return {};
  43. // 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.
  44. JS::GCPtr<DOM::Node> reference;
  45. if (before_element)
  46. reference = move(before_element);
  47. else if (before.has_value() && before->has<i32>())
  48. reference = item(before->get<i32>());
  49. // 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.
  50. DOM::Node* parent = reference ? reference->parent() : root().ptr();
  51. // 6. Pre-insert element into parent node before reference.
  52. (void)TRY(parent->pre_insert(*resolved_element, reference));
  53. return {};
  54. }
  55. }