diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp index 27ef92aa697..828fc26dff6 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.cpp @@ -69,7 +69,7 @@ JS::GCPtr HTMLInputElement::create_layout_node(NonnullRefPtr(document(), *this, move(style)); if (type_state() == TypeAttributeState::Checkbox) @@ -206,14 +206,16 @@ static void show_the_picker_if_applicable(HTMLInputElement& element) return; } - // FIXME: show "any relevant user interface" for other type attribute states "in the way [the user agent] normally would" - // 4. Otherwise, the user agent should show any relevant user interface for selecting a value for element, // in the way it normally would when the user interacts with the control. (If no such UI applies to element, then this step does nothing.) // If such a user interface is shown, it must respect the requirements stated in the relevant parts of the specification for how element // behaves given its type attribute state. (For example, various sections describe restrictions on the resulting value string.) // This step can have side effects, such as closing other pickers that were previously shown by this algorithm. // (If this closes a file selection picker, then per the above that will lead to firing either input and change events, or a cancel event.) + if (element.type_state() == HTMLInputElement::TypeAttributeState::Color) { + auto weak_element = element.make_weak_ptr(); + element.document().browsing_context()->top_level_browsing_context()->page()->did_request_color_picker(weak_element, Color::from_string(MUST(String::from_deprecated_string(element.value()))).value_or(Color(0, 0, 0))); + } } // https://html.spec.whatwg.org/multipage/input.html#dom-input-showpicker @@ -276,7 +278,7 @@ WebIDL::ExceptionOr HTMLInputElement::run_input_activation_behavior() // 3. Submit the form owner from the element. TRY(form->submit_form(*this)); - } else if (type_state() == TypeAttributeState::FileUpload) { + } else if (type_state() == TypeAttributeState::FileUpload || type_state() == TypeAttributeState::Color) { show_the_picker_if_applicable(*this); } else { dispatch_event(DOM::Event::create(realm(), EventNames::change)); @@ -303,6 +305,38 @@ void HTMLInputElement::did_edit_text_node(Badge) }); } +void HTMLInputElement::did_pick_color(Optional picked_color) +{ + // https://html.spec.whatwg.org/multipage/input.html#common-input-element-events + // For input elements without a defined input activation behavior, but to which these events apply + // and for which the user interface involves both interactive manipulation and an explicit commit action + + if (type_state() == TypeAttributeState::Color && picked_color.has_value()) { + // then when the user changes the element's value + m_value = value_sanitization_algorithm(picked_color.value().to_deprecated_string_without_alpha()); + m_dirty_value = true; + + // the user agent must queue an element task on the user interaction task source + queue_an_element_task(HTML::Task::Source::UserInteraction, [this] { + // given the input element to fire an event named input at the input element, with the bubbles and composed attributes initialized to true + auto input_event = DOM::Event::create(realm(), HTML::EventNames::input); + input_event->set_bubbles(true); + input_event->set_composed(true); + dispatch_event(*input_event); + }); + + // and any time the user commits the change, the user agent must queue an element task on the user interaction task source + queue_an_element_task(HTML::Task::Source::UserInteraction, [this] { + // given the input element + // FIXME: to set its user interacted to true + // and fire an event named change at the input element, with the bubbles attribute initialized to true. + auto change_event = DOM::Event::create(realm(), HTML::EventNames::change); + change_event->set_bubbles(true); + dispatch_event(*change_event); + }); + } +} + DeprecatedString HTMLInputElement::value() const { // https://html.spec.whatwg.org/multipage/input.html#dom-input-value-filename @@ -480,6 +514,7 @@ void HTMLInputElement::create_shadow_tree_if_needed() case TypeAttributeState::SubmitButton: case TypeAttributeState::ResetButton: case TypeAttributeState::ImageButton: + case TypeAttributeState::Color: return; default: break; diff --git a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h index 755e695cf95..e9fbe5182a4 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h +++ b/Userland/Libraries/LibWeb/HTML/HTMLInputElement.h @@ -85,6 +85,8 @@ public: bool is_mutable() const { return m_is_mutable; } + void did_pick_color(Optional picked_color); + JS::GCPtr files(); void set_files(JS::GCPtr); diff --git a/Userland/Libraries/LibWeb/Page/Page.cpp b/Userland/Libraries/LibWeb/Page/Page.cpp index 21b3e3a599d..5a30ba4dfd0 100644 --- a/Userland/Libraries/LibWeb/Page/Page.cpp +++ b/Userland/Libraries/LibWeb/Page/Page.cpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -286,6 +287,28 @@ void Page::accept_dialog() } } +void Page::did_request_color_picker(WeakPtr target, Color current_color) +{ + if (m_pending_non_blocking_dialog == PendingNonBlockingDialog::None) { + m_pending_non_blocking_dialog = PendingNonBlockingDialog::ColorPicker; + m_pending_non_blocking_dialog_target = move(target); + + m_client.page_did_request_color_picker(current_color); + } +} + +void Page::color_picker_closed(Optional picked_color) +{ + if (m_pending_non_blocking_dialog == PendingNonBlockingDialog::ColorPicker) { + m_pending_non_blocking_dialog = PendingNonBlockingDialog::None; + + if (m_pending_non_blocking_dialog_target) { + m_pending_non_blocking_dialog_target->did_pick_color(picked_color); + m_pending_non_blocking_dialog_target.clear(); + } + } +} + void Page::did_request_media_context_menu(i32 media_id, CSSPixelPoint position, DeprecatedString const& target, unsigned modifiers, MediaContextMenu menu) { m_media_context_menu_element_id = media_id; diff --git a/Userland/Libraries/LibWeb/Page/Page.h b/Userland/Libraries/LibWeb/Page/Page.h index bbb383d3745..4ce02b47368 100644 --- a/Userland/Libraries/LibWeb/Page/Page.h +++ b/Userland/Libraries/LibWeb/Page/Page.h @@ -120,6 +120,14 @@ public: void dismiss_dialog(); void accept_dialog(); + void did_request_color_picker(WeakPtr target, Color current_color); + void color_picker_closed(Optional picked_color); + + enum class PendingNonBlockingDialog { + None, + ColorPicker, + }; + struct MediaContextMenu { AK::URL media_url; bool is_video { false }; @@ -168,6 +176,9 @@ private: Optional m_pending_confirm_response; Optional> m_pending_prompt_response; + PendingNonBlockingDialog m_pending_non_blocking_dialog { PendingNonBlockingDialog::None }; + WeakPtr m_pending_non_blocking_dialog_target; + Optional m_media_context_menu_element_id; Optional m_user_style_sheet_source; @@ -241,6 +252,7 @@ public: // https://html.spec.whatwg.org/multipage/input.html#show-the-picker,-if-applicable virtual void page_did_request_file_picker(WeakPtr, [[maybe_unused]] bool multiple) {}; + virtual void page_did_request_color_picker([[maybe_unused]] Color current_color) {}; virtual void page_did_finish_text_test() {}; diff --git a/Userland/Libraries/LibWebView/ViewImplementation.cpp b/Userland/Libraries/LibWebView/ViewImplementation.cpp index d855ac28e1c..8b92d32d73c 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.cpp +++ b/Userland/Libraries/LibWebView/ViewImplementation.cpp @@ -207,6 +207,11 @@ void ViewImplementation::prompt_closed(Optional response) client().async_prompt_closed(move(response)); } +void ViewImplementation::color_picker_closed(Optional picked_color) +{ + client().async_color_picker_closed(picked_color); +} + void ViewImplementation::toggle_media_play_state() { client().async_toggle_media_play_state(); diff --git a/Userland/Libraries/LibWebView/ViewImplementation.h b/Userland/Libraries/LibWebView/ViewImplementation.h index 9dd41dcfac0..34bcfca32ae 100644 --- a/Userland/Libraries/LibWebView/ViewImplementation.h +++ b/Userland/Libraries/LibWebView/ViewImplementation.h @@ -82,6 +82,7 @@ public: void alert_closed(); void confirm_closed(bool accepted); void prompt_closed(Optional response); + void color_picker_closed(Optional picked_color); void toggle_media_play_state(); void toggle_media_mute_state(); @@ -150,6 +151,7 @@ public: Function on_maximize_window; Function on_minimize_window; Function on_fullscreen_window; + Function on_request_color_picker; Function on_finish_handling_input_event; Function on_text_test_finish; diff --git a/Userland/Libraries/LibWebView/WebContentClient.cpp b/Userland/Libraries/LibWebView/WebContentClient.cpp index e49a3e7ac68..304030c91c9 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.cpp +++ b/Userland/Libraries/LibWebView/WebContentClient.cpp @@ -384,6 +384,12 @@ void WebContentClient::did_request_file(DeprecatedString const& path, i32 reques m_view.on_request_file(path, request_id); } +void WebContentClient::did_request_color_picker(Color const& current_color) +{ + if (m_view.on_request_color_picker) + m_view.on_request_color_picker(current_color); +} + void WebContentClient::did_finish_handling_input_event(bool event_was_accepted) { if (m_view.on_finish_handling_input_event) diff --git a/Userland/Libraries/LibWebView/WebContentClient.h b/Userland/Libraries/LibWebView/WebContentClient.h index 3c8b9e4db81..c90615e7719 100644 --- a/Userland/Libraries/LibWebView/WebContentClient.h +++ b/Userland/Libraries/LibWebView/WebContentClient.h @@ -82,6 +82,7 @@ private: virtual Messages::WebContentClient::DidRequestMinimizeWindowResponse did_request_minimize_window() override; virtual Messages::WebContentClient::DidRequestFullscreenWindowResponse did_request_fullscreen_window() override; virtual void did_request_file(DeprecatedString const& path, i32) override; + virtual void did_request_color_picker(Color const& current_color) override; virtual void did_finish_handling_input_event(bool event_was_accepted) override; virtual void did_finish_text_test() override; diff --git a/Userland/Services/WebContent/ConnectionFromClient.cpp b/Userland/Services/WebContent/ConnectionFromClient.cpp index b19c0bd7ed0..f8587144843 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.cpp +++ b/Userland/Services/WebContent/ConnectionFromClient.cpp @@ -892,6 +892,11 @@ void ConnectionFromClient::prompt_closed(Optional const& response) m_page_host->prompt_closed(response); } +void ConnectionFromClient::color_picker_closed(Optional const& picked_color) +{ + m_page_host->color_picker_closed(picked_color); +} + void ConnectionFromClient::toggle_media_play_state() { m_page_host->toggle_media_play_state().release_value_but_fixme_should_propagate_errors(); diff --git a/Userland/Services/WebContent/ConnectionFromClient.h b/Userland/Services/WebContent/ConnectionFromClient.h index 84b8617ced5..b989f5c8818 100644 --- a/Userland/Services/WebContent/ConnectionFromClient.h +++ b/Userland/Services/WebContent/ConnectionFromClient.h @@ -97,6 +97,7 @@ private: virtual void alert_closed() override; virtual void confirm_closed(bool accepted) override; virtual void prompt_closed(Optional const& response) override; + virtual void color_picker_closed(Optional const& picked_color) override; virtual void toggle_media_play_state() override; virtual void toggle_media_mute_state() override; diff --git a/Userland/Services/WebContent/PageHost.cpp b/Userland/Services/WebContent/PageHost.cpp index 7492b33d706..45b3bbf6d08 100644 --- a/Userland/Services/WebContent/PageHost.cpp +++ b/Userland/Services/WebContent/PageHost.cpp @@ -358,6 +358,11 @@ void PageHost::prompt_closed(Optional response) page().prompt_closed(move(response)); } +void PageHost::color_picker_closed(Optional picked_color) +{ + page().color_picker_closed(picked_color); +} + Web::WebIDL::ExceptionOr PageHost::toggle_media_play_state() { return page().toggle_media_play_state(); @@ -453,4 +458,9 @@ void PageHost::request_file(Web::FileRequest file_request) m_client.request_file(move(file_request)); } +void PageHost::page_did_request_color_picker(Color current_color) +{ + m_client.async_did_request_color_picker(current_color); +} + } diff --git a/Userland/Services/WebContent/PageHost.h b/Userland/Services/WebContent/PageHost.h index c481c9315c0..0d73bff31c4 100644 --- a/Userland/Services/WebContent/PageHost.h +++ b/Userland/Services/WebContent/PageHost.h @@ -48,6 +48,7 @@ public: void alert_closed(); void confirm_closed(bool accepted); void prompt_closed(Optional response); + void color_picker_closed(Optional picked_color); Web::WebIDL::ExceptionOr toggle_media_play_state(); void toggle_media_mute_state(); @@ -113,6 +114,7 @@ private: virtual void page_did_request_activate_tab() override; virtual void page_did_close_browsing_context(Web::HTML::BrowsingContext const&) override; virtual void request_file(Web::FileRequest) override; + virtual void page_did_request_color_picker(Color current_color) override; virtual void page_did_finish_text_test() override; explicit PageHost(ConnectionFromClient&); diff --git a/Userland/Services/WebContent/WebContentClient.ipc b/Userland/Services/WebContent/WebContentClient.ipc index 0dfc51eabe1..854542157b8 100644 --- a/Userland/Services/WebContent/WebContentClient.ipc +++ b/Userland/Services/WebContent/WebContentClient.ipc @@ -59,6 +59,7 @@ endpoint WebContentClient did_request_minimize_window() => (Gfx::IntRect window_rect) did_request_fullscreen_window() => (Gfx::IntRect window_rect) did_request_file(DeprecatedString path, i32 request_id) =| + did_request_color_picker(Color current_color) =| did_finish_handling_input_event(bool event_was_accepted) =| did_output_js_console_message(i32 message_index) =| diff --git a/Userland/Services/WebContent/WebContentServer.ipc b/Userland/Services/WebContent/WebContentServer.ipc index 9f71e918d95..72a23fbb38c 100644 --- a/Userland/Services/WebContent/WebContentServer.ipc +++ b/Userland/Services/WebContent/WebContentServer.ipc @@ -78,6 +78,7 @@ endpoint WebContentServer alert_closed() =| confirm_closed(bool accepted) =| prompt_closed(Optional response) =| + color_picker_closed(Optional picked_color) =| toggle_media_play_state() =| toggle_media_mute_state() =|