diff --git a/Tests/LibWeb/Text/expected/HTML/HTMLOrSVGElement-nonce.txt b/Tests/LibWeb/Text/expected/HTML/HTMLOrSVGElement-nonce.txt
new file mode 100644
index 00000000000..27b0a1735e0
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/HTML/HTMLOrSVGElement-nonce.txt
@@ -0,0 +1,11 @@
+generic IDL and attribute interaction
+nonce: "" attribute: null;
+nonce: "123" attribute: null;
+nonce: "456" attribute: 456;
+nonce: "null" attribute: 456;
+insertion
+nonce: "foo" attribute: foo;
+nonce: "foo" attribute: ;
+cloning
+nonce: "bar" attribute: bar;
+nonce: "bar" attribute: bar;
diff --git a/Tests/LibWeb/Text/input/HTML/HTMLOrSVGElement-nonce.html b/Tests/LibWeb/Text/input/HTML/HTMLOrSVGElement-nonce.html
new file mode 100644
index 00000000000..b7fcd23c653
--- /dev/null
+++ b/Tests/LibWeb/Text/input/HTML/HTMLOrSVGElement-nonce.html
@@ -0,0 +1,31 @@
+
+
+
diff --git a/Userland/Libraries/LibWeb/HTML/AttributeNames.h b/Userland/Libraries/LibWeb/HTML/AttributeNames.h
index 2423b8b6fcd..0f2544f633c 100644
--- a/Userland/Libraries/LibWeb/HTML/AttributeNames.h
+++ b/Userland/Libraries/LibWeb/HTML/AttributeNames.h
@@ -119,6 +119,7 @@ namespace AttributeNames {
__ENUMERATE_HTML_ATTRIBUTE(name) \
__ENUMERATE_HTML_ATTRIBUTE(nohref) \
__ENUMERATE_HTML_ATTRIBUTE(nomodule) \
+ __ENUMERATE_HTML_ATTRIBUTE(nonce) \
__ENUMERATE_HTML_ATTRIBUTE(noresize) \
__ENUMERATE_HTML_ATTRIBUTE(noshade) \
__ENUMERATE_HTML_ATTRIBUTE(novalidate) \
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
index 9ec1f18b66e..271d53a7102 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.cpp
@@ -576,6 +576,25 @@ void HTMLElement::attribute_changed(FlyString const& name, Optional cons
#undef __ENUMERATE
}
+void HTMLElement::attribute_change_steps(FlyString const& local_name, Optional const& old_value, Optional const& value, Optional const& namespace_)
+{
+ Base::attribute_change_steps(local_name, old_value, value, namespace_);
+ HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_);
+}
+
+WebIDL::ExceptionOr HTMLElement::cloned(Web::DOM::Node& copy, bool clone_children)
+{
+ TRY(Base::cloned(copy, clone_children));
+ TRY(HTMLOrSVGElement::cloned(copy, clone_children));
+ return {};
+}
+
+void HTMLElement::inserted()
+{
+ Base::inserted();
+ HTMLOrSVGElement::inserted();
+}
+
// https://html.spec.whatwg.org/multipage/webappapis.html#fire-a-synthetic-pointer-event
bool HTMLElement::fire_a_synthetic_pointer_event(FlyString const& type, DOM::Element& target, bool not_trusted)
{
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLElement.h b/Userland/Libraries/LibWeb/HTML/HTMLElement.h
index ccb22ffe064..92f7f9eae0c 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLElement.h
@@ -82,6 +82,9 @@ protected:
virtual void initialize(JS::Realm&) override;
virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value) override;
+ virtual void attribute_change_steps(FlyString const&, Optional const&, Optional const&, Optional const&) override;
+ virtual WebIDL::ExceptionOr cloned(DOM::Node&, bool) override;
+ virtual void inserted() override;
virtual void visit_edges(Cell::Visitor&) override;
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.cpp
index 0072ce790c3..80f0d7a9eff 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.cpp
+++ b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.cpp
@@ -56,6 +56,61 @@ void HTMLOrSVGElement::blur()
// User agents may selectively or uniformly ignore calls to this method for usability reasons.
}
+// https://html.spec.whatwg.org/#dom-noncedelement-nonce
+template
+void HTMLOrSVGElement::attribute_change_steps(FlyString const& local_name, Optional const&, Optional const& value, Optional const& namespace_)
+{
+ // 1. If element does not include HTMLOrSVGElement, then return.
+ // 2. If localName is not nonce or namespace is not null, then return.
+ if (local_name != HTML::AttributeNames::nonce || namespace_.has_value())
+ return;
+
+ // 3. If value is null, then set element's [[CryptographicNonce]] to the empty string.
+ if (!value.has_value()) {
+ m_cryptographic_nonce = {};
+ }
+
+ // 4. Otherwise, set element's [[CryptographicNonce]] to value.
+ else {
+ m_cryptographic_nonce = value.value();
+ }
+}
+
+// https://html.spec.whatwg.org/#dom-noncedelement-nonce
+template
+WebIDL::ExceptionOr HTMLOrSVGElement::cloned(DOM::Node& copy, bool)
+{
+ // The cloning steps for elements that include HTMLOrSVGElement must set the
+ // [[CryptographicNonce]] slot on the copy to the value of the slot on the element being cloned.
+ static_cast(copy).m_cryptographic_nonce = m_cryptographic_nonce;
+ return {};
+}
+
+// https://html.spec.whatwg.org/#dom-noncedelement-nonce
+template
+void HTMLOrSVGElement::inserted()
+{
+ // Whenever an element including HTMLOrSVGElement becomes browsing-context connected, the user
+ // agent must execute the following steps on the element:
+ DOM::Element& element = *static_cast(this);
+
+ // FIXME: 1. Let CSP list be element's shadow-including root's policy container's CSP list.
+ [[maybe_unused]] auto policy_container = element.shadow_including_root().document().policy_container();
+
+ // FIXME: 2. If CSP list contains a header-delivered Content Security Policy, and element has a
+ // nonce content attribute attr whose value is not the empty string, then:
+ if (true && element.has_attribute(HTML::AttributeNames::nonce)) {
+ // 2.1. Let nonce be element's [[CryptographicNonce]].
+ auto nonce = m_cryptographic_nonce;
+
+ // 2.2. Set an attribute value for element using "nonce" and the empty string.
+ element.set_attribute_value(HTML::AttributeNames::nonce, {});
+
+ // 2.3. Set element's [[CryptographicNonce]] to nonce.
+ m_cryptographic_nonce = nonce;
+ }
+}
+
template
void HTMLOrSVGElement::visit_edges(JS::Cell::Visitor& visitor)
{
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.h b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.h
index 9080ac78433..da3495fbc15 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.h
+++ b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.h
@@ -17,15 +17,25 @@ class HTMLOrSVGElement {
public:
[[nodiscard]] JS::NonnullGCPtr dataset();
+ // https://html.spec.whatwg.org/#dom-noncedelement-nonce
+ String const& nonce() { return m_cryptographic_nonce; }
+ void set_nonce(String const& nonce) { m_cryptographic_nonce = nonce; }
+
void focus();
void blur();
protected:
+ void attribute_change_steps(FlyString const&, Optional const&, Optional const&, Optional const&);
+ WebIDL::ExceptionOr cloned(DOM::Node&, bool);
+ void inserted();
void visit_edges(JS::Cell::Visitor&);
// https://html.spec.whatwg.org/multipage/dom.html#dom-dataset-dev
JS::GCPtr m_dataset;
+ // https://html.spec.whatwg.org/#cryptographicnonce
+ String m_cryptographic_nonce;
+
// https://html.spec.whatwg.org/multipage/interaction.html#locked-for-focus
bool m_locked_for_focus { false };
};
diff --git a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.idl b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.idl
index ed719ceef04..88c4b22c5ad 100644
--- a/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.idl
+++ b/Userland/Libraries/LibWeb/HTML/HTMLOrSVGElement.idl
@@ -1,7 +1,7 @@
// https://html.spec.whatwg.org/#htmlorsvgelement
interface mixin HTMLOrSVGElement {
[SameObject] readonly attribute DOMStringMap dataset;
- [FIXME] attribute DOMString nonce; // intentionally no [CEReactions]
+ attribute DOMString nonce; // intentionally no [CEReactions]
[CEReactions, Reflect] attribute boolean autofocus;
[CEReactions] attribute long tabIndex;
diff --git a/Userland/Libraries/LibWeb/MathML/MathMLElement.cpp b/Userland/Libraries/LibWeb/MathML/MathMLElement.cpp
index 400c805d011..e5294616cc1 100644
--- a/Userland/Libraries/LibWeb/MathML/MathMLElement.cpp
+++ b/Userland/Libraries/LibWeb/MathML/MathMLElement.cpp
@@ -20,6 +20,25 @@ MathMLElement::MathMLElement(DOM::Document& document, DOM::QualifiedName qualifi
{
}
+void MathMLElement::attribute_change_steps(FlyString const& local_name, Optional const& old_value, Optional const& value, Optional const& namespace_)
+{
+ Base::attribute_change_steps(local_name, old_value, value, namespace_);
+ HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_);
+}
+
+WebIDL::ExceptionOr MathMLElement::cloned(DOM::Node& node, bool clone_children)
+{
+ TRY(Base::cloned(node, clone_children));
+ TRY(HTMLOrSVGElement::cloned(node, clone_children));
+ return {};
+}
+
+void MathMLElement::inserted()
+{
+ Base::inserted();
+ HTMLOrSVGElement::inserted();
+}
+
void MathMLElement::initialize(JS::Realm& realm)
{
Base::initialize(realm);
diff --git a/Userland/Libraries/LibWeb/MathML/MathMLElement.h b/Userland/Libraries/LibWeb/MathML/MathMLElement.h
index d1bdfcdc99e..5fc98f761d8 100644
--- a/Userland/Libraries/LibWeb/MathML/MathMLElement.h
+++ b/Userland/Libraries/LibWeb/MathML/MathMLElement.h
@@ -24,6 +24,9 @@ public:
virtual Optional default_role() const override;
protected:
+ virtual void attribute_change_steps(FlyString const&, Optional const&, Optional const&, Optional const&) override;
+ virtual WebIDL::ExceptionOr cloned(DOM::Node&, bool) override;
+ virtual void inserted() override;
virtual JS::GCPtr global_event_handlers_to_event_target(FlyString const&) override { return *this; }
private:
diff --git a/Userland/Libraries/LibWeb/SVG/SVGElement.cpp b/Userland/Libraries/LibWeb/SVG/SVGElement.cpp
index 1f48e883d12..4c2a997a4ee 100644
--- a/Userland/Libraries/LibWeb/SVG/SVGElement.cpp
+++ b/Userland/Libraries/LibWeb/SVG/SVGElement.cpp
@@ -42,9 +42,23 @@ void SVGElement::attribute_changed(FlyString const& name, Optional const
update_use_elements_that_reference_this();
}
+void SVGElement::attribute_change_steps(FlyString const& local_name, Optional const& old_value, Optional const& value, Optional const& namespace_)
+{
+ Base::attribute_change_steps(local_name, old_value, value, namespace_);
+ HTMLOrSVGElement::attribute_change_steps(local_name, old_value, value, namespace_);
+}
+
+WebIDL::ExceptionOr SVGElement::cloned(DOM::Node& copy, bool clone_children)
+{
+ TRY(Base::cloned(copy, clone_children));
+ TRY(HTMLOrSVGElement::cloned(copy, clone_children));
+ return {};
+}
+
void SVGElement::inserted()
{
Base::inserted();
+ HTMLOrSVGElement::inserted();
update_use_elements_that_reference_this();
}
diff --git a/Userland/Libraries/LibWeb/SVG/SVGElement.h b/Userland/Libraries/LibWeb/SVG/SVGElement.h
index d5c74050109..62791676dc7 100644
--- a/Userland/Libraries/LibWeb/SVG/SVGElement.h
+++ b/Userland/Libraries/LibWeb/SVG/SVGElement.h
@@ -22,12 +22,6 @@ class SVGElement
public:
virtual bool requires_svg_container() const override { return true; }
- virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value) override;
-
- virtual void children_changed() override;
- virtual void inserted() override;
- virtual void removed_from(Node*) override;
-
JS::NonnullGCPtr class_name();
JS::GCPtr owner_svg_element();
@@ -37,6 +31,13 @@ protected:
virtual void initialize(JS::Realm&) override;
virtual void visit_edges(Cell::Visitor&) override;
+ virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value) override;
+ virtual void attribute_change_steps(FlyString const&, Optional const&, Optional const&, Optional const&) override;
+ virtual WebIDL::ExceptionOr cloned(DOM::Node&, bool) override;
+ virtual void children_changed() override;
+ virtual void inserted() override;
+ virtual void removed_from(Node*) override;
+
void update_use_elements_that_reference_this();
void remove_from_use_element_that_reference_this();