diff --git a/Libraries/LibWeb/HTML/HTMLAnchorElement.cpp b/Libraries/LibWeb/HTML/HTMLAnchorElement.cpp
index 8eb6ca51b21..5bd4fdcc504 100644
--- a/Libraries/LibWeb/HTML/HTMLAnchorElement.cpp
+++ b/Libraries/LibWeb/HTML/HTMLAnchorElement.cpp
@@ -122,22 +122,18 @@ void HTMLAnchorElement::activation_behavior(Web::DOM::Event const& event)
// 5. If the user has expressed a preference to download the hyperlink, then set userInvolvement to "browser UI".
// NOTE: That is, if the user has expressed a specific preference for downloading, this no longer counts as merely "activation".
- if (has_download_preference())
+ if (has_attribute(HTML::AttributeNames::download))
user_involvement = UserNavigationInvolvement::BrowserUI;
- // FIXME: 6. If element has a download attribute, or if the user has expressed a preference to download the
+ // 6. If element has a download attribute, or if the user has expressed a preference to download the
// hyperlink, then download the hyperlink created by element with hyperlinkSuffix set to hyperlinkSuffix and
// userInvolvement set to userInvolvement.
+ download_hyperlink(hyperlink_suffix, user_involvement);
// 7. Otherwise, follow the hyperlink created by element with hyperlinkSuffix set to hyperlinkSuffix and userInvolvement set to userInvolvement.
follow_the_hyperlink(hyperlink_suffix, user_involvement);
}
-bool HTMLAnchorElement::has_download_preference() const
-{
- return has_attribute(HTML::AttributeNames::download);
-}
-
// https://html.spec.whatwg.org/multipage/interaction.html#dom-tabindex
i32 HTMLAnchorElement::default_tab_index_value() const
{
diff --git a/Libraries/LibWeb/HTML/HTMLAnchorElement.h b/Libraries/LibWeb/HTML/HTMLAnchorElement.h
index feb2c28aa6f..b910419f9b6 100644
--- a/Libraries/LibWeb/HTML/HTMLAnchorElement.h
+++ b/Libraries/LibWeb/HTML/HTMLAnchorElement.h
@@ -43,7 +43,6 @@ private:
virtual bool has_activation_behavior() const override;
virtual void activation_behavior(Web::DOM::Event const&) override;
- virtual bool has_download_preference() const;
// ^DOM::Element
virtual void attribute_changed(FlyString const& name, Optional const& old_value, Optional const& value, Optional const& namespace_) override;
diff --git a/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp b/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp
index d574997db4a..75175720566 100644
--- a/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp
+++ b/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.cpp
@@ -8,6 +8,9 @@
#include
#include
#include
+#include
+#include
+#include
namespace Web::HTML {
@@ -509,4 +512,54 @@ void HTMLHyperlinkElementUtils::follow_the_hyperlink(Optional hyperlink_
MUST(target_navigable->navigate({ .url = url_string, .source_document = hyperlink_element_utils_document(), .referrer_policy = referrer_policy, .user_involvement = user_involvement }));
}
+void HTMLHyperlinkElementUtils::download_hyperlink(Optional hyperlink_suffix, UserNavigationInvolvement user_involvement)
+{
+ // 1. If subject cannot navigate, then return.
+ if (cannot_navigate())
+ return;
+
+ // 2. If subject's node document's active sandboxing flag set has the sandboxed downloads browsing context flag set, then return.
+ if (has_flag(hyperlink_element_utils_document().active_sandboxing_flag_set(), SandboxingFlagSet::SandboxedDownloads))
+ return;
+
+ // 3. Let urlString be the result of encoding-parsing-and-serializing a URL given subject's href attribute value, relative to subject's node document.
+ auto url = hyperlink_element_utils_document().parse_url(href());
+
+ // 4. If urlString is failure, then return.
+ if (!url.is_valid())
+ return;
+
+ auto url_string = MUST(url.to_string());
+
+ // 5. If hyperlinkSuffix is non-null, then append it to urlString.
+ if (hyperlink_suffix.has_value()) {
+ StringBuilder url_builder;
+ url_builder.append(url_string);
+ url_builder.append(*hyperlink_suffix);
+
+ url_string = MUST(url_builder.to_string());
+ }
+
+ // 6. If userInvolvement is not "browser UI", then:
+ if (user_involvement != UserNavigationInvolvement::BrowserUI) {
+ // 1. Assert: subject has a download attribute.
+ VERIFY(hyperlink_element_utils_element().has_attribute(HTML::AttributeNames::download));
+
+ // 2. Let navigation be subject's relevant global object's navigation API.
+ auto navigation = verify_cast(relevant_global_object(hyperlink_element_utils_element())).navigation();
+
+ // 3. Let filename be the value of subject's download attribute.
+ auto filename = hyperlink_element_utils_element().attribute(HTML::AttributeNames::download).value_or(String {});
+
+ // 4. Let continue be the result of firing a download request navigate event at navigation with destinationURL set to urlString, userInvolvement set to userInvolvement, and filename set to filename.
+ bool continue_ = navigation->fire_a_download_request_navigate_event(url_string, user_involvement, filename);
+
+ // 5. If continue is false, then return.
+ if (!continue_)
+ return;
+ }
+
+ // FIXME: 7. Run these steps in parallel:
+}
+
}
diff --git a/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.h b/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.h
index 17741d54240..8dfba0d32d3 100644
--- a/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.h
+++ b/Libraries/LibWeb/HTML/HTMLHyperlinkElementUtils.h
@@ -65,6 +65,7 @@ protected:
void set_the_url();
void follow_the_hyperlink(Optional hyperlink_suffix, UserNavigationInvolvement = UserNavigationInvolvement::None);
+ void download_hyperlink(Optional hyperlink_suffix, UserNavigationInvolvement = UserNavigationInvolvement::None);
private:
void reinitialize_url() const;