diff --git a/Tests/LibWeb/Text/expected/css/CSSStyleSheet-replace.txt b/Tests/LibWeb/Text/expected/css/CSSStyleSheet-replace.txt
new file mode 100644
index 0000000000..d16d62df70
--- /dev/null
+++ b/Tests/LibWeb/Text/expected/css/CSSStyleSheet-replace.txt
@@ -0,0 +1,7 @@
+Exception thrown when calling replace() on non-constructed stylesheet: NotAllowedError
+Number of CSS rules after replace(): 2
+Rule: .test { font-size: 14px; }
+Rule: .test2 { font-size: 16px; }
+cssRules returns the same object before and after replace(): true
+@import rule should be not appear below:
+Rule: .test { padding: 100px; }
diff --git a/Tests/LibWeb/Text/input/css/CSSStyleSheet-replace.html b/Tests/LibWeb/Text/input/css/CSSStyleSheet-replace.html
new file mode 100644
index 0000000000..666c37e9ca
--- /dev/null
+++ b/Tests/LibWeb/Text/input/css/CSSStyleSheet-replace.html
@@ -0,0 +1,50 @@
+
+
+
+
diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp
index ac954c0305..13f3604a86 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp
+++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.cpp
@@ -13,6 +13,7 @@
#include
#include
#include
+#include
#include
namespace Web::CSS {
@@ -130,7 +131,9 @@ WebIDL::ExceptionOr CSSStyleSheet::insert_rule(StringView rule, unsign
{
// FIXME: 1. If the origin-clean flag is unset, throw a SecurityError exception.
- // FIXME: 2. If the disallow modification flag is set, throw a NotAllowedError DOMException.
+ // If the disallow modification flag is set, throw a NotAllowedError DOMException.
+ if (disallow_modification())
+ return WebIDL::NotAllowedError::create(realm(), "Can't call insert_rule() on non-modifiable stylesheets."_fly_string);
// 3. Let parsed rule be the return value of invoking parse a rule with rule.
auto context = m_style_sheet_list ? CSS::Parser::ParsingContext { m_style_sheet_list->document() } : CSS::Parser::ParsingContext { realm() };
@@ -165,7 +168,9 @@ WebIDL::ExceptionOr CSSStyleSheet::delete_rule(unsigned index)
{
// FIXME: 1. If the origin-clean flag is unset, throw a SecurityError exception.
- // FIXME: 2. If the disallow modification flag is set, throw a NotAllowedError DOMException.
+ // 2. If the disallow modification flag is set, throw a NotAllowedError DOMException.
+ if (disallow_modification())
+ return WebIDL::NotAllowedError::create(realm(), "Can't call delete_rule() on non-modifiable stylesheets."_fly_string);
// 3. Remove a CSS rule in the CSS rules at index.
auto result = m_rules->remove_a_css_rule(index);
@@ -178,6 +183,53 @@ WebIDL::ExceptionOr CSSStyleSheet::delete_rule(unsigned index)
return result;
}
+// https://drafts.csswg.org/cssom/#dom-cssstylesheet-replace
+JS::NonnullGCPtr CSSStyleSheet::replace(String text)
+{
+ // 1. Let promise be a promise
+ auto promise = JS::Promise::create(realm());
+
+ // 2. If the constructed flag is not set, or the disallow modification flag is set, reject promise with a NotAllowedError DOMException and return promise.
+ if (!constructed()) {
+ promise->reject(WebIDL::NotAllowedError::create(realm(), "Can't call replace() on non-constructed stylesheets"_fly_string));
+ return promise;
+ }
+
+ if (disallow_modification()) {
+ promise->reject(WebIDL::NotAllowedError::create(realm(), "Can't call replace() on non-modifiable stylesheets"_fly_string));
+ return promise;
+ }
+
+ // 3. Set the disallow modification flag.
+ set_disallow_modification(true);
+
+ // 4. In parallel, do these steps:
+ Platform::EventLoopPlugin::the().deferred_invoke([this, text = move(text), promise] {
+ // 1. Let rules be the result of running parse a stylesheet’s contents from text.
+ auto context = m_style_sheet_list ? CSS::Parser::ParsingContext { m_style_sheet_list->document() } : CSS::Parser::ParsingContext { realm() };
+ auto* parsed_stylesheet = parse_css_stylesheet(context, text);
+ auto& rules = parsed_stylesheet->rules();
+
+ // 2. If rules contains one or more @import rules, remove those rules from rules.
+ JS::MarkedVector> rules_without_import(realm().heap());
+ for (auto rule : rules) {
+ if (rule->type() != CSSRule::Type::Import)
+ rules_without_import.append(rule);
+ }
+
+ // 3. Set sheet’s CSS rules to rules.
+ m_rules->set_rules({}, rules_without_import);
+
+ // 4. Unset sheet’s disallow modification flag.
+ set_disallow_modification(false);
+
+ // 5. Resolve promise with sheet.
+ promise->fulfill(this);
+ });
+
+ return promise;
+}
+
// https://www.w3.org/TR/cssom/#dom-cssstylesheet-removerule
WebIDL::ExceptionOr CSSStyleSheet::remove_rule(unsigned index)
{
diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h
index d7ed4424b1..236db5d6b2 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h
+++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.h
@@ -52,6 +52,8 @@ public:
WebIDL::ExceptionOr remove_rule(unsigned index);
WebIDL::ExceptionOr delete_rule(unsigned index);
+ JS::NonnullGCPtr replace(String text);
+
void for_each_effective_style_rule(Function const& callback) const;
// Returns whether the match state of any media queries changed after evaluation.
bool evaluate_media_queries(HTML::Window const&);
@@ -70,6 +72,8 @@ public:
JS::GCPtr constructor_document() const { return m_constructor_document; }
void set_constructor_document(JS::GCPtr constructor_document) { m_constructor_document = constructor_document; }
+ bool disallow_modification() const { return m_disallow_modification; }
+
private:
CSSStyleSheet(JS::Realm&, CSSRuleList&, MediaList&, Optional location);
@@ -79,6 +83,7 @@ private:
void recalculate_namespaces();
void set_constructed(bool constructed) { m_constructed = constructed; }
+ void set_disallow_modification(bool disallow_modification) { m_disallow_modification = disallow_modification; }
JS::GCPtr m_rules;
JS::GCPtr m_default_namespace_rule;
@@ -90,6 +95,7 @@ private:
Optional m_base_url;
JS::GCPtr m_constructor_document;
bool m_constructed { false };
+ bool m_disallow_modification { false };
};
}
diff --git a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.idl b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.idl
index 07605d2992..cdf2450ae7 100644
--- a/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.idl
+++ b/Userland/Libraries/LibWeb/CSS/CSSStyleSheet.idl
@@ -13,7 +13,7 @@ interface CSSStyleSheet : StyleSheet {
unsigned long insertRule(CSSOMString rule, optional unsigned long index = 0);
undefined deleteRule(unsigned long index);
- // FIXME: Promise replace(USVString text);
+ Promise replace(USVString text);
// FIXME: undefined replaceSync(USVString text);
// https://drafts.csswg.org/cssom/#legacy-css-style-sheet-members