mirror of
https://github.com/servo/servo.git
synced 2025-07-16 11:53:39 +01:00
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 -->
This commit is contained in:
commit
0f1f99a4bf
7 changed files with 52 additions and 12 deletions
|
@ -561,7 +561,8 @@ impl<'le> ::selectors::Element for ServoLayoutElement<'le> {
|
||||||
NonTSPseudoClass::Disabled |
|
NonTSPseudoClass::Disabled |
|
||||||
NonTSPseudoClass::Checked |
|
NonTSPseudoClass::Checked |
|
||||||
NonTSPseudoClass::Indeterminate |
|
NonTSPseudoClass::Indeterminate |
|
||||||
NonTSPseudoClass::ReadWrite =>
|
NonTSPseudoClass::ReadWrite |
|
||||||
|
NonTSPseudoClass::PlaceholderShown =>
|
||||||
self.element.get_state_for_layout().contains(pseudo_class.state_flag())
|
self.element.get_state_for_layout().contains(pseudo_class.state_flag())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2222,7 +2222,8 @@ impl<'a> ::selectors::Element for Root<Element> {
|
||||||
NonTSPseudoClass::Disabled |
|
NonTSPseudoClass::Disabled |
|
||||||
NonTSPseudoClass::Checked |
|
NonTSPseudoClass::Checked |
|
||||||
NonTSPseudoClass::Indeterminate |
|
NonTSPseudoClass::Indeterminate |
|
||||||
NonTSPseudoClass::ReadWrite =>
|
NonTSPseudoClass::ReadWrite |
|
||||||
|
NonTSPseudoClass::PlaceholderShown =>
|
||||||
Element::state(self).contains(pseudo_class.state_flag()),
|
Element::state(self).contains(pseudo_class.state_flag()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2493,6 +2494,17 @@ impl Element {
|
||||||
pub fn set_read_write_state(&self, value: bool) {
|
pub fn set_read_write_state(&self, value: bool) {
|
||||||
self.set_state(IN_READ_WRITE_STATE, value)
|
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 {
|
impl Element {
|
||||||
|
|
|
@ -709,6 +709,17 @@ impl HTMLInputElement {
|
||||||
self.value_changed.set(false);
|
self.value_changed.set(false);
|
||||||
self.upcast::<Node>().dirty(NodeDamage::OtherNodeDamage);
|
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 {
|
impl VirtualMethods for HTMLInputElement {
|
||||||
|
@ -757,6 +768,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
self.size.set(size.unwrap_or(DEFAULT_INPUT_SIZE));
|
self.size.set(size.unwrap_or(DEFAULT_INPUT_SIZE));
|
||||||
}
|
}
|
||||||
&atom!("type") => {
|
&atom!("type") => {
|
||||||
|
let el = self.upcast::<Element>();
|
||||||
match mutation {
|
match mutation {
|
||||||
AttributeMutation::Set(_) => {
|
AttributeMutation::Set(_) => {
|
||||||
let new_type = match attr.value().as_atom() {
|
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());
|
let (old_value_mode, old_idl_value) = (self.value_mode(), self.Value());
|
||||||
self.input_type.set(new_type);
|
self.input_type.set(new_type);
|
||||||
|
|
||||||
let el = self.upcast::<Element>();
|
|
||||||
if new_type == InputType::InputText {
|
if new_type == InputType::InputText {
|
||||||
let read_write = !(self.ReadOnly() || el.disabled_state());
|
let read_write = !(self.ReadOnly() || el.disabled_state());
|
||||||
el.set_read_write_state(read_write);
|
el.set_read_write_state(read_write);
|
||||||
|
@ -831,11 +842,14 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
el.set_read_write_state(read_write);
|
el.set_read_write_state(read_write);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.update_placeholder_shown_state();
|
||||||
},
|
},
|
||||||
&atom!("value") if !self.value_changed.get() => {
|
&atom!("value") if !self.value_changed.get() => {
|
||||||
let value = mutation.new_value(attr).map(|value| (**value).to_owned());
|
let value = mutation.new_value(attr).map(|value| (**value).to_owned());
|
||||||
self.textinput.borrow_mut().set_content(
|
self.textinput.borrow_mut().set_content(
|
||||||
value.map_or(DOMString::new(), DOMString::from));
|
value.map_or(DOMString::new(), DOMString::from));
|
||||||
|
self.update_placeholder_shown_state();
|
||||||
},
|
},
|
||||||
&atom!("name") if self.input_type.get() == InputType::InputRadio => {
|
&atom!("name") if self.input_type.get() == InputType::InputRadio => {
|
||||||
self.radio_group_updated(
|
self.radio_group_updated(
|
||||||
|
@ -854,13 +868,15 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&atom!("placeholder") => {
|
&atom!("placeholder") => {
|
||||||
// FIXME(ajeffrey): Should we do in-place mutation of the placeholder?
|
{
|
||||||
let mut placeholder = self.placeholder.borrow_mut();
|
let mut placeholder = self.placeholder.borrow_mut();
|
||||||
placeholder.clear();
|
placeholder.clear();
|
||||||
if let AttributeMutation::Set(_) = mutation {
|
if let AttributeMutation::Set(_) = mutation {
|
||||||
placeholder.extend(
|
placeholder.extend(
|
||||||
attr.value().chars().filter(|&c| c != '\n' && c != '\r'));
|
attr.value().chars().filter(|&c| c != '\n' && c != '\r'));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.update_placeholder_shown_state();
|
||||||
},
|
},
|
||||||
&atom!("readonly") if self.input_type.get() == InputType::InputText => {
|
&atom!("readonly") if self.input_type.get() == InputType::InputText => {
|
||||||
let el = self.upcast::<Element>();
|
let el = self.upcast::<Element>();
|
||||||
|
@ -936,6 +952,7 @@ impl VirtualMethods for HTMLInputElement {
|
||||||
},
|
},
|
||||||
DispatchInput => {
|
DispatchInput => {
|
||||||
self.value_changed.set(true);
|
self.value_changed.set(true);
|
||||||
|
self.update_placeholder_shown_state();
|
||||||
|
|
||||||
if event.IsTrusted() {
|
if event.IsTrusted() {
|
||||||
let window = window_from_node(self);
|
let window = window_from_node(self);
|
||||||
|
|
|
@ -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.
|
/// The length of the content in bytes.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.lines.iter().fold(0, |m, l| {
|
self.lines.iter().fold(0, |m, l| {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
bitflags! {
|
bitflags! {
|
||||||
#[doc = "Event-based element states."]
|
#[doc = "Event-based element states."]
|
||||||
#[derive(HeapSizeOf)]
|
#[derive(HeapSizeOf)]
|
||||||
pub flags ElementState: u8 {
|
pub flags ElementState: u16 {
|
||||||
#[doc = "The mouse is down on this element. \
|
#[doc = "The mouse is down on this element. \
|
||||||
https://html.spec.whatwg.org/multipage/#selector-active \
|
https://html.spec.whatwg.org/multipage/#selector-active \
|
||||||
FIXME(#7333): set/unset this when appropriate"]
|
FIXME(#7333): set/unset this when appropriate"]
|
||||||
|
@ -29,5 +29,7 @@ bitflags! {
|
||||||
const IN_INDETERMINATE_STATE = 0x40,
|
const IN_INDETERMINATE_STATE = 0x40,
|
||||||
#[doc = "https://html.spec.whatwg.org/multipage/#selector-read-write"]
|
#[doc = "https://html.spec.whatwg.org/multipage/#selector-read-write"]
|
||||||
const IN_READ_WRITE_STATE = 0x80,
|
const IN_READ_WRITE_STATE = 0x80,
|
||||||
|
#[doc = "https://html.spec.whatwg.org/multipage/#selector-placeholder-shown"]
|
||||||
|
const IN_PLACEHOLDER_SHOWN_STATE = 0x0100,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -131,7 +131,8 @@ pub enum NonTSPseudoClass {
|
||||||
Indeterminate,
|
Indeterminate,
|
||||||
ServoNonZeroBorder,
|
ServoNonZeroBorder,
|
||||||
ReadWrite,
|
ReadWrite,
|
||||||
ReadOnly
|
ReadOnly,
|
||||||
|
PlaceholderShown,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NonTSPseudoClass {
|
impl NonTSPseudoClass {
|
||||||
|
@ -147,6 +148,7 @@ impl NonTSPseudoClass {
|
||||||
Checked => IN_CHECKED_STATE,
|
Checked => IN_CHECKED_STATE,
|
||||||
Indeterminate => IN_INDETERMINATE_STATE,
|
Indeterminate => IN_INDETERMINATE_STATE,
|
||||||
ReadOnly | ReadWrite => IN_READ_WRITE_STATE,
|
ReadOnly | ReadWrite => IN_READ_WRITE_STATE,
|
||||||
|
PlaceholderShown => IN_PLACEHOLDER_SHOWN_STATE,
|
||||||
|
|
||||||
AnyLink |
|
AnyLink |
|
||||||
Link |
|
Link |
|
||||||
|
@ -179,6 +181,7 @@ impl SelectorImpl for ServoSelectorImpl {
|
||||||
"indeterminate" => Indeterminate,
|
"indeterminate" => Indeterminate,
|
||||||
"read-write" => ReadWrite,
|
"read-write" => ReadWrite,
|
||||||
"read-only" => ReadOnly,
|
"read-only" => ReadOnly,
|
||||||
|
"placeholder-shown" => PlaceholderShown,
|
||||||
"-servo-nonzero-border" => {
|
"-servo-nonzero-border" => {
|
||||||
if !context.in_user_agent_stylesheet {
|
if !context.in_user_agent_stylesheet {
|
||||||
return Err(());
|
return Err(());
|
||||||
|
|
|
@ -352,7 +352,7 @@ impl<'le> TElement for GeckoElement<'le> {
|
||||||
|
|
||||||
fn get_state(&self) -> ElementState {
|
fn get_state(&self) -> ElementState {
|
||||||
unsafe {
|
unsafe {
|
||||||
ElementState::from_bits_truncate(Gecko_ElementState(self.element))
|
ElementState::from_bits_truncate(Gecko_ElementState(self.element) as u16)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue