diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2016-06-06 23:44:16 -0500 |
---|---|---|
committer | bors-servo <lbergstrom+bors@mozilla.com> | 2016-06-06 23:44:16 -0500 |
commit | 0f1f99a4bf3be2f695b402e8676c3b0b935cbc5b (patch) | |
tree | d714f91f874827e171483b9b5f2a5b07f173074d | |
parent | 1e968b0d3f72199d69f35831bcc9e8ed7d4bbc33 (diff) | |
parent | ff899dc7033449aa01ee61b5e6c28a8760860325 (diff) | |
download | servo-0f1f99a4bf3be2f695b402e8676c3b0b935cbc5b.tar.gz servo-0f1f99a4bf3be2f695b402e8676c3b0b935cbc5b.zip |
Auto merge of #11572 - nox:placeholder-shown, r=SimonSapin
Implement :placeholder-shown (fixes #10561)
<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="35" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/11572)
<!-- Reviewable:end -->
-rw-r--r-- | components/layout/wrapper.rs | 3 | ||||
-rw-r--r-- | components/script/dom/element.rs | 14 | ||||
-rw-r--r-- | components/script/dom/htmlinputelement.rs | 31 | ||||
-rw-r--r-- | components/script/textinput.rs | 5 | ||||
-rw-r--r-- | components/style/element_state.rs | 4 | ||||
-rw-r--r-- | components/style/selector_impl.rs | 5 | ||||
-rw-r--r-- | ports/geckolib/wrapper.rs | 2 |
7 files changed, 52 insertions, 12 deletions
diff --git a/components/layout/wrapper.rs b/components/layout/wrapper.rs index 24c78f190b7..10dde4b2ff0 100644 --- a/components/layout/wrapper.rs +++ b/components/layout/wrapper.rs @@ -561,7 +561,8 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> { NonTSPseudoClass::Disabled | NonTSPseudoClass::Checked | NonTSPseudoClass::Indeterminate | - NonTSPseudoClass::ReadWrite => + NonTSPseudoClass::ReadWrite | + NonTSPseudoClass::PlaceholderShown => self.element.get_state_for_layout().contains(pseudo_class.state_flag()) } } diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs index fc4160f1843..0432be3987c 100644 --- a/components/script/dom/element.rs +++ b/components/script/dom/element.rs @@ -2222,7 +2222,8 @@ impl<'a> ::selectors::Element for Root<Element> { NonTSPseudoClass::Disabled | NonTSPseudoClass::Checked | NonTSPseudoClass::Indeterminate | - NonTSPseudoClass::ReadWrite => + NonTSPseudoClass::ReadWrite | + NonTSPseudoClass::PlaceholderShown => Element::state(self).contains(pseudo_class.state_flag()), } } @@ -2493,6 +2494,17 @@ impl Element { pub fn set_read_write_state(&self, value: bool) { self.set_state(IN_READ_WRITE_STATE, value) } + + pub fn placeholder_shown_state(&self) -> bool { + self.state.get().contains(IN_PLACEHOLDER_SHOWN_STATE) + } + + pub fn set_placeholder_shown_state(&self, value: bool) { + if self.placeholder_shown_state() != value { + self.set_state(IN_PLACEHOLDER_SHOWN_STATE, value); + self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); + } + } } impl Element { diff --git a/components/script/dom/htmlinputelement.rs b/components/script/dom/htmlinputelement.rs index 04fc98a3982..a7bb9846bb9 100644 --- a/components/script/dom/htmlinputelement.rs +++ b/components/script/dom/htmlinputelement.rs @@ -709,6 +709,17 @@ impl HTMLInputElement { self.value_changed.set(false); self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage); } + + fn update_placeholder_shown_state(&self) { + match self.input_type.get() { + InputType::InputText | InputType::InputPassword => {}, + _ => return, + } + let has_placeholder = !self.placeholder.borrow().is_empty(); + let has_value = !self.textinput.borrow().is_empty(); + let el = self.upcast::<Element>(); + el.set_placeholder_shown_state(has_placeholder && !has_value); + } } impl VirtualMethods for HTMLInputElement { @@ -757,6 +768,7 @@ impl VirtualMethods for HTMLInputElement { self.size.set(size.unwrap_or(DEFAULT_INPUT_SIZE)); } &atom!("type") => { + let el = self.upcast::<Element>(); match mutation { AttributeMutation::Set(_) => { let new_type = match attr.value().as_atom() { @@ -774,7 +786,6 @@ impl VirtualMethods for HTMLInputElement { let (old_value_mode, old_idl_value) = (self.value_mode(), self.Value()); self.input_type.set(new_type); - let el = self.upcast::<Element>(); if new_type == InputType::InputText { let read_write = !(self.ReadOnly() || el.disabled_state()); el.set_read_write_state(read_write); @@ -831,11 +842,14 @@ impl VirtualMethods for HTMLInputElement { el.set_read_write_state(read_write); } } + + self.update_placeholder_shown_state(); }, &atom!("value") if !self.value_changed.get() => { let value = mutation.new_value(attr).map(|value| (**value).to_owned()); self.textinput.borrow_mut().set_content( value.map_or(DOMString::new(), DOMString::from)); + self.update_placeholder_shown_state(); }, &atom!("name") if self.input_type.get() == InputType::InputRadio => { self.radio_group_updated( @@ -854,13 +868,15 @@ impl VirtualMethods for HTMLInputElement { } } &atom!("placeholder") => { - // FIXME(ajeffrey): Should we do in-place mutation of the placeholder? - let mut placeholder = self.placeholder.borrow_mut(); - placeholder.clear(); - if let AttributeMutation::Set(_) = mutation { - placeholder.extend( - attr.value().chars().filter(|&c| c != '\n' && c != '\r')); + { + let mut placeholder = self.placeholder.borrow_mut(); + placeholder.clear(); + if let AttributeMutation::Set(_) = mutation { + placeholder.extend( + attr.value().chars().filter(|&c| c != '\n' && c != '\r')); + } } + self.update_placeholder_shown_state(); }, &atom!("readonly") if self.input_type.get() == InputType::InputText => { let el = self.upcast::<Element>(); @@ -936,6 +952,7 @@ impl VirtualMethods for HTMLInputElement { }, DispatchInput => { self.value_changed.set(true); + self.update_placeholder_shown_state(); if event.IsTrusted() { let window = window_from_node(self); diff --git a/components/script/textinput.rs b/components/script/textinput.rs index 5666fa617b4..c724c2691c4 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -549,6 +549,11 @@ impl<T: ClipboardProvider> TextInput<T> { } } + /// Whether the content is empty. + pub fn is_empty(&self) -> bool { + self.lines.len() <= 1 && self.lines.get(0).map_or(true, |line| line.is_empty()) + } + /// The length of the content in bytes. pub fn len(&self) -> usize { self.lines.iter().fold(0, |m, l| { diff --git a/components/style/element_state.rs b/components/style/element_state.rs index f347f7d2164..9b84bde45c1 100644 --- a/components/style/element_state.rs +++ b/components/style/element_state.rs @@ -5,7 +5,7 @@ bitflags! { #[doc = "Event-based element states."] #[derive(HeapSizeOf)] - pub flags ElementState: u8 { + pub flags ElementState: u16 { #[doc = "The mouse is down on this element. \ https://html.spec.whatwg.org/multipage/#selector-active \ FIXME(#7333): set/unset this when appropriate"] @@ -29,5 +29,7 @@ bitflags! { const IN_INDETERMINATE_STATE = 0x40, #[doc = "https://html.spec.whatwg.org/multipage/#selector-read-write"] const IN_READ_WRITE_STATE = 0x80, + #[doc = "https://html.spec.whatwg.org/multipage/#selector-placeholder-shown"] + const IN_PLACEHOLDER_SHOWN_STATE = 0x0100, } } diff --git a/components/style/selector_impl.rs b/components/style/selector_impl.rs index 925ccb816ef..14e6b366690 100644 --- a/components/style/selector_impl.rs +++ b/components/style/selector_impl.rs @@ -131,7 +131,8 @@ pub enum NonTSPseudoClass { Indeterminate, ServoNonZeroBorder, ReadWrite, - ReadOnly + ReadOnly, + PlaceholderShown, } impl NonTSPseudoClass { @@ -147,6 +148,7 @@ impl NonTSPseudoClass { Checked => IN_CHECKED_STATE, Indeterminate => IN_INDETERMINATE_STATE, ReadOnly | ReadWrite => IN_READ_WRITE_STATE, + PlaceholderShown => IN_PLACEHOLDER_SHOWN_STATE, AnyLink | Link | @@ -179,6 +181,7 @@ impl SelectorImpl for ServoSelectorImpl { "indeterminate" => Indeterminate, "read-write" => ReadWrite, "read-only" => ReadOnly, + "placeholder-shown" => PlaceholderShown, "-servo-nonzero-border" => { if !context.in_user_agent_stylesheet { return Err(()); diff --git a/ports/geckolib/wrapper.rs b/ports/geckolib/wrapper.rs index afa6ecfc463..b36e8fd7463 100644 --- a/ports/geckolib/wrapper.rs +++ b/ports/geckolib/wrapper.rs @@ -352,7 +352,7 @@ impl<'le> TElement for GeckoElement<'le> { fn get_state(&self) -> ElementState { unsafe { - ElementState::from_bits_truncate(Gecko_ElementState(self.element)) + ElementState::from_bits_truncate(Gecko_ElementState(self.element) as u16) } } |