From e8f5085669ec6e0c9b5f81830407457aee5d0f0b Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 10 Mar 2023 14:56:44 +0100 Subject: [PATCH] LibWeb: Implement Range.createContextualFragment() --- Userland/Libraries/LibWeb/DOM/Range.cpp | 60 ++++++++++++++++++- Userland/Libraries/LibWeb/DOM/Range.h | 4 +- Userland/Libraries/LibWeb/DOM/Range.idl | 3 + .../LibWeb/HTML/HTMLScriptElement.cpp | 10 ++++ .../Libraries/LibWeb/HTML/HTMLScriptElement.h | 3 + 5 files changed, 78 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibWeb/DOM/Range.cpp b/Userland/Libraries/LibWeb/DOM/Range.cpp index 663fd16e51..6627a92a1b 100644 --- a/Userland/Libraries/LibWeb/DOM/Range.cpp +++ b/Userland/Libraries/LibWeb/DOM/Range.cpp @@ -1,7 +1,7 @@ /* * Copyright (c) 2020, the SerenityOS developers. * Copyright (c) 2022, Luke Wilde - * Copyright (c) 2022, Andreas Kling + * Copyright (c) 2022-2023, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -11,13 +11,17 @@ #include #include #include +#include #include #include #include #include +#include #include +#include #include #include +#include namespace Web::DOM { @@ -1142,4 +1146,58 @@ JS::NonnullGCPtr Range::get_bounding_client_rect() const return Geometry::DOMRect::construct_impl(realm(), 0, 0, 0, 0).release_value_but_fixme_should_propagate_errors(); } +// https://w3c.github.io/DOM-Parsing/#dom-range-createcontextualfragment +WebIDL::ExceptionOr> Range::create_contextual_fragment(DeprecatedString const& fragment) +{ + // 1. Let node be the context object's start node. + JS::NonnullGCPtr node = *start_container(); + + // Let element be as follows, depending on node's interface: + JS::GCPtr element; + switch (static_cast(node->node_type())) { + case NodeType::DOCUMENT_NODE: + case NodeType::DOCUMENT_FRAGMENT_NODE: + element = nullptr; + break; + case NodeType::ELEMENT_NODE: + element = static_cast(*node); + break; + case NodeType::TEXT_NODE: + case NodeType::COMMENT_NODE: + element = node->parent_element(); + break; + case NodeType::DOCUMENT_TYPE_NODE: + case NodeType::PROCESSING_INSTRUCTION_NODE: + // [DOM4] prevents this case. + VERIFY_NOT_REACHED(); + default: + VERIFY_NOT_REACHED(); + } + + // 2. If either element is null or the following are all true: + // - element's node document is an HTML document, + // - element's local name is "html", and + // - element's namespace is the HTML namespace; + if (!element || is(*element)) { + // let element be a new Element with + // - "body" as its local name, + // - The HTML namespace as its namespace, and + // - The context object's node document as its node document. + element = TRY(DOM::create_element(node->document(), "body"sv, Namespace::HTML)); + } + + // 3. Let fragment node be the result of invoking the fragment parsing algorithm with fragment as markup, and element as the context element. + auto fragment_node = TRY(DOMParsing::parse_fragment(fragment, *element)); + + // 4. Unmark all scripts in fragment node as "already started" and as "parser-inserted". + fragment_node->for_each_in_subtree_of_type([&](HTML::HTMLScriptElement& script_element) { + script_element.unmark_as_already_started({}); + script_element.unmark_as_parser_inserted({}); + return IterationDecision::Continue; + }); + + // 5. Return the value of fragment node. + return fragment_node; +} + } diff --git a/Userland/Libraries/LibWeb/DOM/Range.h b/Userland/Libraries/LibWeb/DOM/Range.h index e644d84bfa..a6e2490edd 100644 --- a/Userland/Libraries/LibWeb/DOM/Range.h +++ b/Userland/Libraries/LibWeb/DOM/Range.h @@ -1,7 +1,7 @@ /* * Copyright (c) 2020, the SerenityOS developers. * Copyright (c) 2022, Luke Wilde - * Copyright (c) 2022, Andreas Kling + * Copyright (c) 2022-2023, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ @@ -89,6 +89,8 @@ public: void set_associated_selection(Badge, JS::GCPtr); + WebIDL::ExceptionOr> create_contextual_fragment(DeprecatedString const& fragment); + private: explicit Range(Document&); Range(Node& start_container, u32 start_offset, Node& end_container, u32 end_offset); diff --git a/Userland/Libraries/LibWeb/DOM/Range.idl b/Userland/Libraries/LibWeb/DOM/Range.idl index 9f58372356..9ab4b3d4ab 100644 --- a/Userland/Libraries/LibWeb/DOM/Range.idl +++ b/Userland/Libraries/LibWeb/DOM/Range.idl @@ -43,4 +43,7 @@ interface Range : AbstractRange { stringifier; + // Extensions from the DOM Parsing specification: + [CEReactions, NewObject] DocumentFragment createContextualFragment(DOMString fragment); + }; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp index 9aa7ca591e..45d310c7a3 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.cpp @@ -561,4 +561,14 @@ void HTMLScriptElement::mark_as_ready(Result result) m_document_load_event_delayer.clear(); } +void HTMLScriptElement::unmark_as_already_started(Badge) +{ + m_already_started = false; +} + +void HTMLScriptElement::unmark_as_parser_inserted(Badge) +{ + m_parser_document = nullptr; +} + } diff --git a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.h b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.h index df06764ac2..b01159c236 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLScriptElement.h @@ -51,6 +51,9 @@ public: void set_source_line_number(Badge, size_t source_line_number) { m_source_line_number = source_line_number; } + void unmark_as_already_started(Badge); + void unmark_as_parser_inserted(Badge); + public: HTMLScriptElement(DOM::Document&, DOM::QualifiedName);