mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12:45 +00:00 
			
		
		
		
	Ladybird+LibWeb+WebContent: Parse the <input type=file> accept attribute
This parses the accept attribute value for file input types and passes it along to the browser chromes.
This commit is contained in:
		
							parent
							
								
									e4213f5767
								
							
						
					
					
						commit
						6760d236e4
					
				
					 20 changed files with 267 additions and 24 deletions
				
			
		|  | @ -626,7 +626,7 @@ static void copy_data_to_clipboard(StringView data, NSPasteboardType pasteboard_ | ||||||
|         [panel makeKeyAndOrderFront:nil]; |         [panel makeKeyAndOrderFront:nil]; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     m_web_view_bridge->on_request_file_picker = [self](auto allow_multiple_files) { |     m_web_view_bridge->on_request_file_picker = [self](auto const&, auto allow_multiple_files) { | ||||||
|         auto* panel = [NSOpenPanel openPanel]; |         auto* panel = [NSOpenPanel openPanel]; | ||||||
|         [panel setCanChooseFiles:YES]; |         [panel setCanChooseFiles:YES]; | ||||||
|         [panel setCanChooseDirectories:NO]; |         [panel setCanChooseDirectories:NO]; | ||||||
|  |  | ||||||
|  | @ -232,7 +232,7 @@ Tab::Tab(BrowserWindow* window, WebContentOptions const& web_content_options, St | ||||||
|         m_dialog = nullptr; |         m_dialog = nullptr; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     view().on_request_file_picker = [this](auto allow_multiple_files) { |     view().on_request_file_picker = [this](auto const&, auto allow_multiple_files) { | ||||||
|         Vector<Web::HTML::SelectedFile> selected_files; |         Vector<Web::HTML::SelectedFile> selected_files; | ||||||
| 
 | 
 | ||||||
|         auto create_selected_file = [&](auto const& qfile_path) { |         auto create_selected_file = [&](auto const& qfile_path) { | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ source_set("HTML") { | ||||||
|     "ErrorEvent.cpp", |     "ErrorEvent.cpp", | ||||||
|     "EventHandler.cpp", |     "EventHandler.cpp", | ||||||
|     "EventNames.cpp", |     "EventNames.cpp", | ||||||
|  |     "FileFilter.cpp", | ||||||
|     "Focus.cpp", |     "Focus.cpp", | ||||||
|     "FormAssociatedElement.cpp", |     "FormAssociatedElement.cpp", | ||||||
|     "FormControlInfrastructure.cpp", |     "FormControlInfrastructure.cpp", | ||||||
|  |  | ||||||
							
								
								
									
										12
									
								
								Tests/LibWeb/Text/expected/input-file-accept.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								Tests/LibWeb/Text/expected/input-file-accept.txt
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,12 @@ | ||||||
|  | Select file...file1 Select files...4 files selected. Select file...file1.cpp Select files...2 files selected.   input1: | ||||||
|  | file1: text/plain: Contents for file1 | ||||||
|  | input2: | ||||||
|  | file1: text/plain: Contents for file1 | ||||||
|  | file2: text/plain: Contents for file2 | ||||||
|  | file3: text/plain: Contents for file3 | ||||||
|  | file4: text/plain: Contents for file4 | ||||||
|  | input3: | ||||||
|  | file1.cpp: text/plain: int main() {{ return 1; }} | ||||||
|  | input4: | ||||||
|  | file1.cpp: text/plain: int main() {{ return 1; }} | ||||||
|  | file2.cpp: text/plain: int main() {{ return 2; }} | ||||||
							
								
								
									
										34
									
								
								Tests/LibWeb/Text/input/input-file-accept.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								Tests/LibWeb/Text/input/input-file-accept.html
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,34 @@ | ||||||
|  | <input id="input1" type="file" accept="text/plain" /> | ||||||
|  | <input id="input2" type="file" accept="text/plain" multiple /> | ||||||
|  | <input id="input3" type="file" accept=".cpp" /> | ||||||
|  | <input id="input4" type="file" accept=".cpp" multiple /> | ||||||
|  | <script src="./include.js"></script> | ||||||
|  | <script type="text/javascript"> | ||||||
|  |     const runTest = async id => { | ||||||
|  |         let input = document.getElementById(id); | ||||||
|  | 
 | ||||||
|  |         return new Promise(resolve => { | ||||||
|  |             input.addEventListener("input", async () => { | ||||||
|  |                 println(`${id}:`); | ||||||
|  | 
 | ||||||
|  |                 for (let file of input.files) { | ||||||
|  |                     const text = await file.text(); | ||||||
|  |                     println(`${file.name}: ${file.type}: ${text}`); | ||||||
|  |                 } | ||||||
|  | 
 | ||||||
|  |                 resolve(); | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |             internals.dispatchUserActivatedEvent(input, new Event("mousedown")); | ||||||
|  |             input.showPicker(); | ||||||
|  |         }); | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     asyncTest(async done => { | ||||||
|  |         await runTest("input1"); | ||||||
|  |         await runTest("input2"); | ||||||
|  |         await runTest("input3"); | ||||||
|  |         await runTest("input4"); | ||||||
|  |         done(); | ||||||
|  |     }); | ||||||
|  | </script> | ||||||
|  | @ -556,7 +556,7 @@ Tab::Tab(BrowserWindow& window) | ||||||
|         m_dialog = nullptr; |         m_dialog = nullptr; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     view().on_request_file_picker = [this](auto allow_multiple_files) { |     view().on_request_file_picker = [this](auto const&, auto allow_multiple_files) { | ||||||
|         // FIXME: GUI::FilePicker does not allow selecting multiple files at once.
 |         // FIXME: GUI::FilePicker does not allow selecting multiple files at once.
 | ||||||
|         (void)allow_multiple_files; |         (void)allow_multiple_files; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -268,6 +268,7 @@ set(SOURCES | ||||||
|     HTML/EventLoop/Task.cpp |     HTML/EventLoop/Task.cpp | ||||||
|     HTML/EventLoop/TaskQueue.cpp |     HTML/EventLoop/TaskQueue.cpp | ||||||
|     HTML/EventNames.cpp |     HTML/EventNames.cpp | ||||||
|  |     HTML/FileFilter.cpp | ||||||
|     HTML/Focus.cpp |     HTML/Focus.cpp | ||||||
|     HTML/FormAssociatedElement.cpp |     HTML/FormAssociatedElement.cpp | ||||||
|     HTML/FormControlInfrastructure.cpp |     HTML/FormControlInfrastructure.cpp | ||||||
|  |  | ||||||
							
								
								
									
										61
									
								
								Userland/Libraries/LibWeb/HTML/FileFilter.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								Userland/Libraries/LibWeb/HTML/FileFilter.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,61 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org> | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #include <LibIPC/Decoder.h> | ||||||
|  | #include <LibIPC/Encoder.h> | ||||||
|  | #include <LibWeb/HTML/FileFilter.h> | ||||||
|  | 
 | ||||||
|  | namespace Web::HTML { | ||||||
|  | 
 | ||||||
|  | void FileFilter::add_filter(FilterType filter) | ||||||
|  | { | ||||||
|  |     if (!filters.contains_slow(filter)) | ||||||
|  |         filters.append(move(filter)); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<void> IPC::encode(Encoder& encoder, Web::HTML::FileFilter::MimeType const& mime_type) | ||||||
|  | { | ||||||
|  |     TRY(encoder.encode(mime_type.value)); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<Web::HTML::FileFilter::MimeType> IPC::decode(Decoder& decoder) | ||||||
|  | { | ||||||
|  |     auto value = TRY(decoder.decode<String>()); | ||||||
|  |     return Web::HTML::FileFilter::MimeType { move(value) }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<void> IPC::encode(Encoder& encoder, Web::HTML::FileFilter::Extension const& extension) | ||||||
|  | { | ||||||
|  |     TRY(encoder.encode(extension.value)); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<Web::HTML::FileFilter::Extension> IPC::decode(Decoder& decoder) | ||||||
|  | { | ||||||
|  |     auto value = TRY(decoder.decode<String>()); | ||||||
|  |     return Web::HTML::FileFilter::Extension { move(value) }; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<void> IPC::encode(Encoder& encoder, Web::HTML::FileFilter const& filter) | ||||||
|  | { | ||||||
|  |     TRY(encoder.encode(filter.filters)); | ||||||
|  |     return {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<Web::HTML::FileFilter> IPC::decode(Decoder& decoder) | ||||||
|  | { | ||||||
|  |     auto filters = TRY(decoder.decode<Vector<Web::HTML::FileFilter::FilterType>>()); | ||||||
|  |     return Web::HTML::FileFilter { move(filters) }; | ||||||
|  | } | ||||||
							
								
								
									
										62
									
								
								Userland/Libraries/LibWeb/HTML/FileFilter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								Userland/Libraries/LibWeb/HTML/FileFilter.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | ||||||
|  | /*
 | ||||||
|  |  * Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org> | ||||||
|  |  * | ||||||
|  |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <AK/String.h> | ||||||
|  | #include <AK/Variant.h> | ||||||
|  | #include <AK/Vector.h> | ||||||
|  | #include <LibIPC/Forward.h> | ||||||
|  | 
 | ||||||
|  | namespace Web::HTML { | ||||||
|  | 
 | ||||||
|  | struct FileFilter { | ||||||
|  |     enum class FileType { | ||||||
|  |         Audio, | ||||||
|  |         Image, | ||||||
|  |         Video, | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     struct MimeType { | ||||||
|  |         bool operator==(MimeType const&) const = default; | ||||||
|  |         String value; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     struct Extension { | ||||||
|  |         bool operator==(Extension const&) const = default; | ||||||
|  |         String value; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     using FilterType = Variant<FileType, MimeType, Extension>; | ||||||
|  | 
 | ||||||
|  |     void add_filter(FilterType); | ||||||
|  | 
 | ||||||
|  |     Vector<FilterType> filters; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | namespace IPC { | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<void> encode(Encoder&, Web::HTML::FileFilter::MimeType const&); | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<Web::HTML::FileFilter::MimeType> decode(Decoder&); | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<void> encode(Encoder&, Web::HTML::FileFilter::Extension const&); | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<Web::HTML::FileFilter::Extension> decode(Decoder&); | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<void> encode(Encoder&, Web::HTML::FileFilter const&); | ||||||
|  | 
 | ||||||
|  | template<> | ||||||
|  | ErrorOr<Web::HTML::FileFilter> decode(Decoder&); | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | @ -39,6 +39,7 @@ | ||||||
| #include <LibWeb/Layout/CheckBox.h> | #include <LibWeb/Layout/CheckBox.h> | ||||||
| #include <LibWeb/Layout/ImageBox.h> | #include <LibWeb/Layout/ImageBox.h> | ||||||
| #include <LibWeb/Layout/RadioButton.h> | #include <LibWeb/Layout/RadioButton.h> | ||||||
|  | #include <LibWeb/MimeSniff/MimeType.h> | ||||||
| #include <LibWeb/MimeSniff/Resource.h> | #include <LibWeb/MimeSniff/Resource.h> | ||||||
| #include <LibWeb/Namespace.h> | #include <LibWeb/Namespace.h> | ||||||
| #include <LibWeb/Page/Page.h> | #include <LibWeb/Page/Page.h> | ||||||
|  | @ -181,6 +182,43 @@ void HTMLInputElement::set_files(JS::GCPtr<FileAPI::FileList> files) | ||||||
|     m_selected_files = files; |     m_selected_files = files; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // https://html.spec.whatwg.org/multipage/input.html#attr-input-accept
 | ||||||
|  | FileFilter HTMLInputElement::parse_accept_attribute() const | ||||||
|  | { | ||||||
|  |     FileFilter filter; | ||||||
|  | 
 | ||||||
|  |     // If specified, the attribute must consist of a set of comma-separated tokens, each of which must be an ASCII
 | ||||||
|  |     // case-insensitive match for one of the following:
 | ||||||
|  |     get_attribute_value(HTML::AttributeNames::accept).bytes_as_string_view().for_each_split_view(',', SplitBehavior::Nothing, [&](StringView value) { | ||||||
|  |         // The string "audio/*"
 | ||||||
|  |         //     Indicates that sound files are accepted.
 | ||||||
|  |         if (value.equals_ignoring_ascii_case("audio/*"sv)) | ||||||
|  |             filter.add_filter(FileFilter::FileType::Audio); | ||||||
|  | 
 | ||||||
|  |         // The string "video/*"
 | ||||||
|  |         //     Indicates that video files are accepted.
 | ||||||
|  |         if (value.equals_ignoring_ascii_case("video/*"sv)) | ||||||
|  |             filter.add_filter(FileFilter::FileType::Video); | ||||||
|  | 
 | ||||||
|  |         // The string "image/*"
 | ||||||
|  |         //     Indicates that image files are accepted.
 | ||||||
|  |         if (value.equals_ignoring_ascii_case("image/*"sv)) | ||||||
|  |             filter.add_filter(FileFilter::FileType::Image); | ||||||
|  | 
 | ||||||
|  |         // A valid MIME type string with no parameters
 | ||||||
|  |         //     Indicates that files of the specified type are accepted.
 | ||||||
|  |         else if (auto mime_type = MUST(MimeSniff::MimeType::parse(value)); mime_type.has_value() && mime_type->parameters().is_empty()) | ||||||
|  |             filter.add_filter(FileFilter::MimeType { mime_type->essence() }); | ||||||
|  | 
 | ||||||
|  |         // A string whose first character is a U+002E FULL STOP character (.)
 | ||||||
|  |         //     Indicates that files with the specified file extension are accepted.
 | ||||||
|  |         else if (value.starts_with('.')) | ||||||
|  |             filter.add_filter(FileFilter::Extension { MUST(String::from_utf8(value.substring_view(1))) }); | ||||||
|  |     }); | ||||||
|  | 
 | ||||||
|  |     return filter; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // https://html.spec.whatwg.org/multipage/input.html#update-the-file-selection
 | // https://html.spec.whatwg.org/multipage/input.html#update-the-file-selection
 | ||||||
| void HTMLInputElement::update_the_file_selection(JS::NonnullGCPtr<FileAPI::FileList> files) | void HTMLInputElement::update_the_file_selection(JS::NonnullGCPtr<FileAPI::FileList> files) | ||||||
| { | { | ||||||
|  | @ -227,12 +265,11 @@ static void show_the_picker_if_applicable(HTMLInputElement& element) | ||||||
|         //    with the bubbles attribute initialized to true.
 |         //    with the bubbles attribute initialized to true.
 | ||||||
|         // 5. Otherwise, update the file selection for element.
 |         // 5. Otherwise, update the file selection for element.
 | ||||||
| 
 | 
 | ||||||
|  |         auto accepted_file_types = element.parse_accept_attribute(); | ||||||
|         auto allow_multiple_files = element.has_attribute(HTML::AttributeNames::multiple) ? AllowMultipleFiles::Yes : AllowMultipleFiles::No; |         auto allow_multiple_files = element.has_attribute(HTML::AttributeNames::multiple) ? AllowMultipleFiles::Yes : AllowMultipleFiles::No; | ||||||
|         auto weak_element = element.make_weak_ptr<HTMLInputElement>(); |         auto weak_element = element.make_weak_ptr<HTMLInputElement>(); | ||||||
| 
 | 
 | ||||||
|         // FIXME: Pass along accept attribute information https://html.spec.whatwg.org/multipage/input.html#attr-input-accept
 |         element.document().browsing_context()->top_level_browsing_context()->page().did_request_file_picker(weak_element, move(accepted_file_types), allow_multiple_files); | ||||||
|         //    The accept attribute may be specified to provide user agents with a hint of what file types will be accepted.
 |  | ||||||
|         element.document().browsing_context()->top_level_browsing_context()->page().did_request_file_picker(weak_element, allow_multiple_files); |  | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -12,6 +12,7 @@ | ||||||
| #include <LibWeb/DOM/Text.h> | #include <LibWeb/DOM/Text.h> | ||||||
| #include <LibWeb/FileAPI/FileList.h> | #include <LibWeb/FileAPI/FileList.h> | ||||||
| #include <LibWeb/HTML/ColorPickerUpdateState.h> | #include <LibWeb/HTML/ColorPickerUpdateState.h> | ||||||
|  | #include <LibWeb/HTML/FileFilter.h> | ||||||
| #include <LibWeb/HTML/FormAssociatedElement.h> | #include <LibWeb/HTML/FormAssociatedElement.h> | ||||||
| #include <LibWeb/HTML/HTMLElement.h> | #include <LibWeb/HTML/HTMLElement.h> | ||||||
| #include <LibWeb/Layout/ImageProvider.h> | #include <LibWeb/Layout/ImageProvider.h> | ||||||
|  | @ -102,6 +103,8 @@ public: | ||||||
|     JS::GCPtr<FileAPI::FileList> files(); |     JS::GCPtr<FileAPI::FileList> files(); | ||||||
|     void set_files(JS::GCPtr<FileAPI::FileList>); |     void set_files(JS::GCPtr<FileAPI::FileList>); | ||||||
| 
 | 
 | ||||||
|  |     FileFilter parse_accept_attribute() const; | ||||||
|  | 
 | ||||||
|     // NOTE: User interaction
 |     // NOTE: User interaction
 | ||||||
|     // https://html.spec.whatwg.org/multipage/input.html#update-the-file-selection
 |     // https://html.spec.whatwg.org/multipage/input.html#update-the-file-selection
 | ||||||
|     void update_the_file_selection(JS::NonnullGCPtr<FileAPI::FileList>); |     void update_the_file_selection(JS::NonnullGCPtr<FileAPI::FileList>); | ||||||
|  |  | ||||||
|  | @ -344,13 +344,13 @@ void Page::color_picker_update(Optional<Color> picked_color, HTML::ColorPickerUp | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void Page::did_request_file_picker(WeakPtr<HTML::HTMLInputElement> target, HTML::AllowMultipleFiles allow_multiple_files) | void Page::did_request_file_picker(WeakPtr<HTML::HTMLInputElement> target, HTML::FileFilter accepted_file_types, HTML::AllowMultipleFiles allow_multiple_files) | ||||||
| { | { | ||||||
|     if (m_pending_non_blocking_dialog == PendingNonBlockingDialog::None) { |     if (m_pending_non_blocking_dialog == PendingNonBlockingDialog::None) { | ||||||
|         m_pending_non_blocking_dialog = PendingNonBlockingDialog::FilePicker; |         m_pending_non_blocking_dialog = PendingNonBlockingDialog::FilePicker; | ||||||
|         m_pending_non_blocking_dialog_target = move(target); |         m_pending_non_blocking_dialog_target = move(target); | ||||||
| 
 | 
 | ||||||
|         m_client->page_did_request_file_picker(allow_multiple_files); |         m_client->page_did_request_file_picker(move(accepted_file_types), allow_multiple_files); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,6 +31,7 @@ | ||||||
| #include <LibWeb/Forward.h> | #include <LibWeb/Forward.h> | ||||||
| #include <LibWeb/HTML/ActivateTab.h> | #include <LibWeb/HTML/ActivateTab.h> | ||||||
| #include <LibWeb/HTML/ColorPickerUpdateState.h> | #include <LibWeb/HTML/ColorPickerUpdateState.h> | ||||||
|  | #include <LibWeb/HTML/FileFilter.h> | ||||||
| #include <LibWeb/HTML/SelectItem.h> | #include <LibWeb/HTML/SelectItem.h> | ||||||
| #include <LibWeb/HTML/TokenizedFeatures.h> | #include <LibWeb/HTML/TokenizedFeatures.h> | ||||||
| #include <LibWeb/HTML/WebViewHints.h> | #include <LibWeb/HTML/WebViewHints.h> | ||||||
|  | @ -134,7 +135,7 @@ public: | ||||||
|     void did_request_color_picker(WeakPtr<HTML::HTMLInputElement> target, Color current_color); |     void did_request_color_picker(WeakPtr<HTML::HTMLInputElement> target, Color current_color); | ||||||
|     void color_picker_update(Optional<Color> picked_color, HTML::ColorPickerUpdateState state); |     void color_picker_update(Optional<Color> picked_color, HTML::ColorPickerUpdateState state); | ||||||
| 
 | 
 | ||||||
|     void did_request_file_picker(WeakPtr<HTML::HTMLInputElement> target, HTML::AllowMultipleFiles); |     void did_request_file_picker(WeakPtr<HTML::HTMLInputElement> target, HTML::FileFilter accepted_file_types, HTML::AllowMultipleFiles); | ||||||
|     void file_picker_closed(Span<HTML::SelectedFile> selected_files); |     void file_picker_closed(Span<HTML::SelectedFile> selected_files); | ||||||
| 
 | 
 | ||||||
|     void did_request_select_dropdown(WeakPtr<HTML::HTMLSelectElement> target, Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items); |     void did_request_select_dropdown(WeakPtr<HTML::HTMLSelectElement> target, Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items); | ||||||
|  | @ -285,7 +286,7 @@ public: | ||||||
| 
 | 
 | ||||||
|     // https://html.spec.whatwg.org/multipage/input.html#show-the-picker,-if-applicable
 |     // https://html.spec.whatwg.org/multipage/input.html#show-the-picker,-if-applicable
 | ||||||
|     virtual void page_did_request_color_picker([[maybe_unused]] Color current_color) {}; |     virtual void page_did_request_color_picker([[maybe_unused]] Color current_color) {}; | ||||||
|     virtual void page_did_request_file_picker(Web::HTML::AllowMultipleFiles) {}; |     virtual void page_did_request_file_picker([[maybe_unused]] HTML::FileFilter accepted_file_types, Web::HTML::AllowMultipleFiles) {}; | ||||||
|     virtual void page_did_request_select_dropdown([[maybe_unused]] Web::CSSPixelPoint content_position, [[maybe_unused]] Web::CSSPixels minimum_width, [[maybe_unused]] Vector<Web::HTML::SelectItem> items) {}; |     virtual void page_did_request_select_dropdown([[maybe_unused]] Web::CSSPixelPoint content_position, [[maybe_unused]] Web::CSSPixels minimum_width, [[maybe_unused]] Vector<Web::HTML::SelectItem> items) {}; | ||||||
| 
 | 
 | ||||||
|     virtual void page_did_finish_text_test() {}; |     virtual void page_did_finish_text_test() {}; | ||||||
|  |  | ||||||
|  | @ -18,6 +18,7 @@ | ||||||
| #include <LibWeb/Forward.h> | #include <LibWeb/Forward.h> | ||||||
| #include <LibWeb/HTML/ActivateTab.h> | #include <LibWeb/HTML/ActivateTab.h> | ||||||
| #include <LibWeb/HTML/ColorPickerUpdateState.h> | #include <LibWeb/HTML/ColorPickerUpdateState.h> | ||||||
|  | #include <LibWeb/HTML/FileFilter.h> | ||||||
| #include <LibWeb/HTML/SelectItem.h> | #include <LibWeb/HTML/SelectItem.h> | ||||||
| #include <LibWeb/Page/InputEvent.h> | #include <LibWeb/Page/InputEvent.h> | ||||||
| #include <LibWebView/Forward.h> | #include <LibWebView/Forward.h> | ||||||
|  | @ -170,7 +171,7 @@ public: | ||||||
|     Function<Gfx::IntRect()> on_minimize_window; |     Function<Gfx::IntRect()> on_minimize_window; | ||||||
|     Function<Gfx::IntRect()> on_fullscreen_window; |     Function<Gfx::IntRect()> on_fullscreen_window; | ||||||
|     Function<void(Color current_color)> on_request_color_picker; |     Function<void(Color current_color)> on_request_color_picker; | ||||||
|     Function<void(Web::HTML::AllowMultipleFiles)> on_request_file_picker; |     Function<void(Web::HTML::FileFilter const& accepted_file_types, Web::HTML::AllowMultipleFiles)> on_request_file_picker; | ||||||
|     Function<void(Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> items)> on_request_select_dropdown; |     Function<void(Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> items)> on_request_select_dropdown; | ||||||
|     Function<void(Web::KeyEvent const&)> on_finish_handling_key_event; |     Function<void(Web::KeyEvent const&)> on_finish_handling_key_event; | ||||||
|     Function<void()> on_text_test_finish; |     Function<void()> on_text_test_finish; | ||||||
|  |  | ||||||
|  | @ -806,7 +806,7 @@ void WebContentClient::did_request_color_picker(u64 page_id, Color const& curren | ||||||
|         view.on_request_color_picker(current_color); |         view.on_request_color_picker(current_color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WebContentClient::did_request_file_picker(u64 page_id, Web::HTML::AllowMultipleFiles allow_multiple_files) | void WebContentClient::did_request_file_picker(u64 page_id, Web::HTML::FileFilter const& accepted_file_types, Web::HTML::AllowMultipleFiles allow_multiple_files) | ||||||
| { | { | ||||||
|     auto maybe_view = m_views.get(page_id); |     auto maybe_view = m_views.get(page_id); | ||||||
|     if (!maybe_view.has_value()) { |     if (!maybe_view.has_value()) { | ||||||
|  | @ -816,7 +816,7 @@ void WebContentClient::did_request_file_picker(u64 page_id, Web::HTML::AllowMult | ||||||
|     auto& view = *maybe_view.value(); |     auto& view = *maybe_view.value(); | ||||||
| 
 | 
 | ||||||
|     if (view.on_request_file_picker) |     if (view.on_request_file_picker) | ||||||
|         view.on_request_file_picker(allow_multiple_files); |         view.on_request_file_picker(accepted_file_types, allow_multiple_files); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void WebContentClient::did_request_select_dropdown(u64 page_id, Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> const& items) | void WebContentClient::did_request_select_dropdown(u64 page_id, Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> const& items) | ||||||
|  |  | ||||||
|  | @ -9,6 +9,7 @@ | ||||||
| #include <AK/HashMap.h> | #include <AK/HashMap.h> | ||||||
| #include <LibIPC/ConnectionToServer.h> | #include <LibIPC/ConnectionToServer.h> | ||||||
| #include <LibWeb/HTML/ActivateTab.h> | #include <LibWeb/HTML/ActivateTab.h> | ||||||
|  | #include <LibWeb/HTML/FileFilter.h> | ||||||
| #include <LibWeb/HTML/SelectItem.h> | #include <LibWeb/HTML/SelectItem.h> | ||||||
| #include <LibWeb/HTML/WebViewHints.h> | #include <LibWeb/HTML/WebViewHints.h> | ||||||
| #include <WebContent/WebContentClientEndpoint.h> | #include <WebContent/WebContentClientEndpoint.h> | ||||||
|  | @ -89,7 +90,7 @@ private: | ||||||
|     virtual Messages::WebContentClient::DidRequestFullscreenWindowResponse did_request_fullscreen_window(u64 page_id) override; |     virtual Messages::WebContentClient::DidRequestFullscreenWindowResponse did_request_fullscreen_window(u64 page_id) override; | ||||||
|     virtual void did_request_file(u64 page_id, ByteString const& path, i32) override; |     virtual void did_request_file(u64 page_id, ByteString const& path, i32) override; | ||||||
|     virtual void did_request_color_picker(u64 page_id, Color const& current_color) override; |     virtual void did_request_color_picker(u64 page_id, Color const& current_color) override; | ||||||
|     virtual void did_request_file_picker(u64 page_id, Web::HTML::AllowMultipleFiles) override; |     virtual void did_request_file_picker(u64 page_id, Web::HTML::FileFilter const& accepted_file_types, Web::HTML::AllowMultipleFiles) override; | ||||||
|     virtual void did_request_select_dropdown(u64 page_id, Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> const& items) override; |     virtual void did_request_select_dropdown(u64 page_id, Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> const& items) override; | ||||||
|     virtual void did_finish_handling_input_event(u64 page_id, bool event_was_accepted) override; |     virtual void did_finish_handling_input_event(u64 page_id, bool event_was_accepted) override; | ||||||
|     virtual void did_finish_text_test(u64 page_id) override; |     virtual void did_finish_text_test(u64 page_id) override; | ||||||
|  |  | ||||||
|  | @ -549,9 +549,9 @@ void PageClient::page_did_request_color_picker(Color current_color) | ||||||
|     client().async_did_request_color_picker(m_id, current_color); |     client().async_did_request_color_picker(m_id, current_color); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PageClient::page_did_request_file_picker(Web::HTML::AllowMultipleFiles allow_multiple_files) | void PageClient::page_did_request_file_picker(Web::HTML::FileFilter accepted_file_types, Web::HTML::AllowMultipleFiles allow_multiple_files) | ||||||
| { | { | ||||||
|     client().async_did_request_file_picker(m_id, allow_multiple_files); |     client().async_did_request_file_picker(m_id, move(accepted_file_types), allow_multiple_files); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void PageClient::page_did_request_select_dropdown(Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items) | void PageClient::page_did_request_select_dropdown(Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items) | ||||||
|  |  | ||||||
|  | @ -10,6 +10,7 @@ | ||||||
| 
 | 
 | ||||||
| #include <LibAccelGfx/Forward.h> | #include <LibAccelGfx/Forward.h> | ||||||
| #include <LibGfx/Rect.h> | #include <LibGfx/Rect.h> | ||||||
|  | #include <LibWeb/HTML/FileFilter.h> | ||||||
| #include <LibWeb/Page/Page.h> | #include <LibWeb/Page/Page.h> | ||||||
| #include <LibWeb/PixelUnits.h> | #include <LibWeb/PixelUnits.h> | ||||||
| #include <WebContent/Forward.h> | #include <WebContent/Forward.h> | ||||||
|  | @ -133,7 +134,7 @@ private: | ||||||
|     virtual void page_did_close_top_level_traversable() override; |     virtual void page_did_close_top_level_traversable() override; | ||||||
|     virtual void request_file(Web::FileRequest) override; |     virtual void request_file(Web::FileRequest) override; | ||||||
|     virtual void page_did_request_color_picker(Color current_color) override; |     virtual void page_did_request_color_picker(Color current_color) override; | ||||||
|     virtual void page_did_request_file_picker(Web::HTML::AllowMultipleFiles) override; |     virtual void page_did_request_file_picker(Web::HTML::FileFilter accepted_file_types, Web::HTML::AllowMultipleFiles) override; | ||||||
|     virtual void page_did_request_select_dropdown(Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items) override; |     virtual void page_did_request_select_dropdown(Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items) override; | ||||||
|     virtual void page_did_finish_text_test() override; |     virtual void page_did_finish_text_test() override; | ||||||
|     virtual void page_did_change_theme_color(Gfx::Color color) override; |     virtual void page_did_change_theme_color(Gfx::Color color) override; | ||||||
|  |  | ||||||
|  | @ -6,6 +6,7 @@ | ||||||
| #include <LibWeb/Cookie/ParsedCookie.h> | #include <LibWeb/Cookie/ParsedCookie.h> | ||||||
| #include <LibWeb/CSS/Selector.h> | #include <LibWeb/CSS/Selector.h> | ||||||
| #include <LibWeb/HTML/ActivateTab.h> | #include <LibWeb/HTML/ActivateTab.h> | ||||||
|  | #include <LibWeb/HTML/FileFilter.h> | ||||||
| #include <LibWeb/HTML/SelectedFile.h> | #include <LibWeb/HTML/SelectedFile.h> | ||||||
| #include <LibWeb/HTML/SelectItem.h> | #include <LibWeb/HTML/SelectItem.h> | ||||||
| #include <LibWeb/HTML/WebViewHints.h> | #include <LibWeb/HTML/WebViewHints.h> | ||||||
|  | @ -71,7 +72,7 @@ endpoint WebContentClient | ||||||
|     did_request_fullscreen_window(u64 page_id) => (Gfx::IntRect window_rect) |     did_request_fullscreen_window(u64 page_id) => (Gfx::IntRect window_rect) | ||||||
|     did_request_file(u64 page_id, ByteString path, i32 request_id) =| |     did_request_file(u64 page_id, ByteString path, i32 request_id) =| | ||||||
|     did_request_color_picker(u64 page_id, Color current_color) =| |     did_request_color_picker(u64 page_id, Color current_color) =| | ||||||
|     did_request_file_picker(u64 page_id, Web::HTML::AllowMultipleFiles allow_multiple_files) =| |     did_request_file_picker(u64 page_id, Web::HTML::FileFilter accepted_file_types, Web::HTML::AllowMultipleFiles allow_multiple_files) =| | ||||||
|     did_request_select_dropdown(u64 page_id, Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> items) =| |     did_request_select_dropdown(u64 page_id, Gfx::IntPoint content_position, i32 minimum_width, Vector<Web::HTML::SelectItem> items) =| | ||||||
|     did_finish_handling_input_event(u64 page_id, bool event_was_accepted) =| |     did_finish_handling_input_event(u64 page_id, bool event_was_accepted) =| | ||||||
|     did_change_theme_color(u64 page_id, Gfx::Color color) =| |     did_change_theme_color(u64 page_id, Gfx::Color color) =| | ||||||
|  |  | ||||||
|  | @ -436,15 +436,42 @@ static ErrorOr<TestResult> run_test(HeadlessWebContentView& view, StringView inp | ||||||
|     }; |     }; | ||||||
|     view.on_text_test_finish = {}; |     view.on_text_test_finish = {}; | ||||||
| 
 | 
 | ||||||
|     view.on_request_file_picker = [&](auto allow_multiple_files) { |     view.on_request_file_picker = [&](auto const& accepted_file_types, auto allow_multiple_files) { | ||||||
|         // Create some dummy files for tests.
 |         // Create some dummy files for tests.
 | ||||||
|         Vector<Web::HTML::SelectedFile> selected_files; |         Vector<Web::HTML::SelectedFile> selected_files; | ||||||
|         selected_files.empend("file1"sv, MUST(ByteBuffer::copy("Contents for file1"sv.bytes()))); |  | ||||||
| 
 | 
 | ||||||
|         if (allow_multiple_files == Web::HTML::AllowMultipleFiles::Yes) { |         bool add_txt_files = accepted_file_types.filters.is_empty(); | ||||||
|             selected_files.empend("file2"sv, MUST(ByteBuffer::copy("Contents for file2"sv.bytes()))); |         bool add_cpp_files = false; | ||||||
|             selected_files.empend("file3"sv, MUST(ByteBuffer::copy("Contents for file3"sv.bytes()))); | 
 | ||||||
|             selected_files.empend("file4"sv, MUST(ByteBuffer::copy("Contents for file4"sv.bytes()))); |         for (auto const& filter : accepted_file_types.filters) { | ||||||
|  |             filter.visit( | ||||||
|  |                 [](Web::HTML::FileFilter::FileType) {}, | ||||||
|  |                 [&](Web::HTML::FileFilter::MimeType const& mime_type) { | ||||||
|  |                     if (mime_type.value == "text/plain"sv) | ||||||
|  |                         add_txt_files = true; | ||||||
|  |                 }, | ||||||
|  |                 [&](Web::HTML::FileFilter::Extension const& extension) { | ||||||
|  |                     if (extension.value == "cpp"sv) | ||||||
|  |                         add_cpp_files = true; | ||||||
|  |                 }); | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (add_txt_files) { | ||||||
|  |             selected_files.empend("file1"sv, MUST(ByteBuffer::copy("Contents for file1"sv.bytes()))); | ||||||
|  | 
 | ||||||
|  |             if (allow_multiple_files == Web::HTML::AllowMultipleFiles::Yes) { | ||||||
|  |                 selected_files.empend("file2"sv, MUST(ByteBuffer::copy("Contents for file2"sv.bytes()))); | ||||||
|  |                 selected_files.empend("file3"sv, MUST(ByteBuffer::copy("Contents for file3"sv.bytes()))); | ||||||
|  |                 selected_files.empend("file4"sv, MUST(ByteBuffer::copy("Contents for file4"sv.bytes()))); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         if (add_cpp_files) { | ||||||
|  |             selected_files.empend("file1.cpp"sv, MUST(ByteBuffer::copy("int main() {{ return 1; }}"sv.bytes()))); | ||||||
|  | 
 | ||||||
|  |             if (allow_multiple_files == Web::HTML::AllowMultipleFiles::Yes) { | ||||||
|  |                 selected_files.empend("file2.cpp"sv, MUST(ByteBuffer::copy("int main() {{ return 2; }}"sv.bytes()))); | ||||||
|  |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         view.file_picker_closed(move(selected_files)); |         view.file_picker_closed(move(selected_files)); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Timothy Flynn
						Timothy Flynn