From b17e627f06ecdf63834891bdd18f258714a2e08d Mon Sep 17 00:00:00 2001 From: Chase Knowlden Date: Mon, 18 Nov 2024 16:55:08 -0500 Subject: [PATCH] LibWeb: Implement more of the download attribute --- Libraries/LibWeb/HTML/HTMLAnchorElement.cpp | 10 ++-- Libraries/LibWeb/HTML/HTMLAnchorElement.h | 1 - .../LibWeb/HTML/HTMLHyperlinkElementUtils.cpp | 53 +++++++++++++++++++ .../LibWeb/HTML/HTMLHyperlinkElementUtils.h | 1 + 4 files changed, 57 insertions(+), 8 deletions(-) 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;