diff options
author | DK Liao <dklassic@gmail.com> | 2025-03-10 12:55:38 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-03-10 03:55:38 +0000 |
commit | ce4ba309924ffa35e0dd4309527586b8f0c22b75 (patch) | |
tree | 226f769e796fb9447e6a63c037523ad3dc2b1cfe | |
parent | 34047f8da8e191324121023c7cb040a120e2a523 (diff) | |
download | servo-ce4ba309924ffa35e0dd4309527586b8f0c22b75.tar.gz servo-ce4ba309924ffa35e0dd4309527586b8f0c22b75.zip |
feat: display file chosen for input file (#35789)
Signed-off-by: DK Liao <dklassic@gmail.com>
-rw-r--r-- | components/script/dom/filelist.rs | 21 | ||||
-rw-r--r-- | components/script/dom/htmlinputelement.rs | 29 | ||||
-rw-r--r-- | resources/servo.css | 8 |
3 files changed, 53 insertions, 5 deletions
diff --git a/components/script/dom/filelist.rs b/components/script/dom/filelist.rs index d526b54b99b..8942ec92239 100644 --- a/components/script/dom/filelist.rs +++ b/components/script/dom/filelist.rs @@ -6,6 +6,7 @@ use std::slice::Iter; use dom_struct::dom_struct; +use super::bindings::root::{LayoutDom, ToLayout}; use crate::dom::bindings::codegen::Bindings::FileListBinding::FileListMethods; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; use crate::dom::bindings::root::{Dom, DomRoot}; @@ -69,3 +70,23 @@ impl FileListMethods<crate::DomTypeHolder> for FileList { self.Item(index) } } + +pub(crate) trait LayoutFileListHelpers<'dom> { + fn file_for_layout(&self, index: u32) -> Option<&File>; + fn len(&self) -> usize; +} + +#[allow(unsafe_code)] +impl<'dom> LayoutFileListHelpers<'dom> for LayoutDom<'dom, FileList> { + fn len(&self) -> usize { + self.unsafe_get().list.len() + } + fn file_for_layout(&self, index: u32) -> Option<&File> { + let list = &self.unsafe_get().list; + if (index as usize) < list.len() { + Some(unsafe { list[index as usize].to_layout().unsafe_get() }) + } else { + None + } + } +} diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 66fef852ffd..1cbf386e03e 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -57,7 +57,7 @@ use crate::dom::element::{AttributeMutation, Element, LayoutElementHelpers}; use crate::dom::event::{Event, EventBubbles, EventCancelable}; use crate::dom::eventtarget::EventTarget; use crate::dom::file::File; -use crate::dom::filelist::FileList; +use crate::dom::filelist::{FileList, LayoutFileListHelpers}; use crate::dom::globalscope::GlobalScope; use crate::dom::htmldatalistelement::HTMLDataListElement; use crate::dom::htmlelement::HTMLElement; @@ -90,6 +90,7 @@ use crate::textinput::{ const DEFAULT_SUBMIT_VALUE: &str = "Submit"; const DEFAULT_RESET_VALUE: &str = "Reset"; const PASSWORD_REPLACEMENT_CHAR: char = '●'; +const DEFAULT_FILE_INPUT_VALUE: &str = "No file chosen"; /// <https://html.spec.whatwg.org/multipage/#attr-input-type> #[derive(Clone, Copy, Default, JSTraceable, PartialEq)] @@ -1037,6 +1038,9 @@ impl<'dom> LayoutDom<'dom, HTMLInputElement> { .get_content() } } + fn get_filelist(self) -> Option<LayoutDom<'dom, FileList>> { + unsafe { self.unsafe_get().filelist.get_inner_as_layout() } + } fn placeholder(self) -> &'dom str { unsafe { self.unsafe_get().placeholder.borrow_for_layout() } @@ -1070,8 +1074,27 @@ impl<'dom> LayoutHTMLInputElementHelpers<'dom> for LayoutDom<'dom, HTMLInputElem } match self.input_type() { - InputType::Checkbox | InputType::Radio => "".into(), - InputType::File | InputType::Image => "".into(), + InputType::Checkbox | InputType::Radio | InputType::Image => "".into(), + InputType::File => { + let filelist = self.get_filelist(); + match filelist { + Some(filelist) => { + let length = filelist.len(); + if length == 0 { + return DEFAULT_FILE_INPUT_VALUE.into(); + } + if length == 1 { + match filelist.file_for_layout(0) { + Some(file) => return file.name().to_string().into(), + None => return DEFAULT_FILE_INPUT_VALUE.into(), + } + } + + format!("{} files", length).into() + }, + None => DEFAULT_FILE_INPUT_VALUE.into(), + } + }, InputType::Button => get_raw_attr_value(self, ""), InputType::Submit => get_raw_attr_value(self, DEFAULT_SUBMIT_VALUE), InputType::Reset => get_raw_attr_value(self, DEFAULT_RESET_VALUE), diff --git a/resources/servo.css b/resources/servo.css index ee2aca1f66f..d9f0366c217 100644 --- a/resources/servo.css +++ b/resources/servo.css @@ -74,13 +74,17 @@ input[type="radio"]:checked::before { content: "●"; line-height: 1em; } input[type="file"]::before { content: "Choose File"; + background: lightgrey; + border-top: solid 1px #EEEEEE; + border-left: solid 1px #CCCCCC; + border-right: solid 1px #999999; + border-bottom: solid 1px #999999; } input[type="file"] { - background: lightgrey; text-align: center; - vertical-align: middle; color: black; + border-style: none; } select { |