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 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"; /// #[derive(Clone, Copy, Default, JSTraceable, PartialEq)] @@ -1037,6 +1038,9 @@ impl<'dom> LayoutDom<'dom, HTMLInputElement> { .get_content() } } + fn get_filelist(self) -> Option> { + 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 {