mirror of
https://github.com/SerenityOS/serenity
synced 2024-07-21 18:15:58 +00:00
LibWeb: Add textarea placeholder
This commit is contained in:
parent
091faf1aae
commit
52397d01bd
|
@ -1,5 +1,8 @@
|
|||
<!doctype html>
|
||||
<textarea>
|
||||
<textarea cols="80" rows="5">
|
||||
This is some text
|
||||
inside a <textarea>
|
||||
</textarea>
|
||||
<textarea placeholder="Textarea placeholder!" cols="80" rows="5"></textarea>
|
||||
<textarea placeholder="Textarea placeholder!
|
||||
That is multiline!" cols="80" rows="5"></textarea>
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
|
||||
BlockContainer <html> at (0,0) content-size 800x56.9375 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 784x40.9375 children: inline
|
||||
line 0 width: 403.75, height: 40.9375, bottom: 40.9375, baseline: 13.53125
|
||||
frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 191.875x34.9375]
|
||||
frag 1 from TextNode start: 0, length: 1, rect: [206,8 8x17.46875]
|
||||
BlockContainer <html> at (0,0) content-size 800x65.6875 [BFC] children: not-inline
|
||||
BlockContainer <body> at (8,8) content-size 784x49.6875 children: inline
|
||||
line 0 width: 502, height: 49.6875, bottom: 49.6875, baseline: 16.921875
|
||||
frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 240x43.6875]
|
||||
frag 1 from TextNode start: 0, length: 1, rect: [254,8 10x21.84375]
|
||||
" "
|
||||
frag 2 from BlockContainer start: 0, length: 0, rect: [217,11 191.875x34.9375]
|
||||
frag 2 from BlockContainer start: 0, length: 0, rect: [267,11 240x43.6875]
|
||||
TextNode <#text>
|
||||
BlockContainer <textarea> at (11,11) content-size 191.875x34.9375 inline-block [BFC] children: not-inline
|
||||
BlockContainer <div> at (11,11) content-size 191.875x17.46875 children: not-inline
|
||||
BlockContainer <div> at (11,11) content-size 191.875x17.46875 children: inline
|
||||
line 0 width: 152.203125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||
frag 0 from TextNode start: 0, length: 17, rect: [11,11 152.203125x17.46875]
|
||||
BlockContainer <textarea> at (11,11) content-size 240x43.6875 inline-block [BFC] children: not-inline
|
||||
BlockContainer <div> at (11,11) content-size 240x21.84375 children: not-inline
|
||||
BlockContainer <div> at (11,11) content-size 240x21.84375 children: inline
|
||||
line 0 width: 190.265625, height: 21.84375, bottom: 21.84375, baseline: 16.921875
|
||||
frag 0 from TextNode start: 0, length: 17, rect: [11,11 190.265625x21.84375]
|
||||
"Bonjour mon amis!"
|
||||
TextNode <#text>
|
||||
TextNode <#text>
|
||||
BlockContainer <textarea> at (217,11) content-size 191.875x34.9375 inline-block [BFC] children: not-inline
|
||||
BlockContainer <div> at (217,11) content-size 191.875x17.46875 children: not-inline
|
||||
BlockContainer <div> at (217,11) content-size 191.875x17.46875 children: inline
|
||||
line 0 width: 142.140625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
|
||||
frag 0 from TextNode start: 0, length: 19, rect: [217,11 142.140625x17.46875]
|
||||
BlockContainer <textarea> at (267,11) content-size 240x43.6875 inline-block [BFC] children: not-inline
|
||||
BlockContainer <div> at (267,11) content-size 240x21.84375 children: not-inline
|
||||
BlockContainer <div> at (267,11) content-size 240x21.84375 children: inline
|
||||
line 0 width: 177.6875, height: 21.84375, bottom: 21.84375, baseline: 16.921875
|
||||
frag 0 from TextNode start: 0, length: 19, rect: [267,11 177.6875x21.84375]
|
||||
"Well hello friends!"
|
||||
TextNode <#text>
|
||||
TextNode <#text>
|
||||
|
||||
ViewportPaintable (Viewport<#document>) [0,0 800x600]
|
||||
PaintableWithLines (BlockContainer<HTML>) [0,0 800x56.9375]
|
||||
PaintableWithLines (BlockContainer<BODY>) [8,8 784x40.9375]
|
||||
PaintableWithLines (BlockContainer<TEXTAREA>) [8,8 197.875x40.9375]
|
||||
PaintableWithLines (BlockContainer<DIV>) [11,11 191.875x17.46875]
|
||||
PaintableWithLines (BlockContainer<DIV>) [11,11 191.875x17.46875]
|
||||
PaintableWithLines (BlockContainer<HTML>) [0,0 800x65.6875]
|
||||
PaintableWithLines (BlockContainer<BODY>) [8,8 784x49.6875]
|
||||
PaintableWithLines (BlockContainer<TEXTAREA>) [8,8 246x49.6875]
|
||||
PaintableWithLines (BlockContainer<DIV>) [11,11 240x21.84375]
|
||||
PaintableWithLines (BlockContainer<DIV>) [11,11 240x21.84375]
|
||||
TextPaintable (TextNode<#text>)
|
||||
TextPaintable (TextNode<#text>)
|
||||
PaintableWithLines (BlockContainer<TEXTAREA>) [214,8 197.875x40.9375]
|
||||
PaintableWithLines (BlockContainer<DIV>) [217,11 191.875x17.46875]
|
||||
PaintableWithLines (BlockContainer<DIV>) [217,11 191.875x17.46875]
|
||||
PaintableWithLines (BlockContainer<TEXTAREA>) [264,8 246x49.6875]
|
||||
PaintableWithLines (BlockContainer<DIV>) [267,11 240x21.84375]
|
||||
PaintableWithLines (BlockContainer<DIV>) [267,11 240x21.84375]
|
||||
TextPaintable (TextNode<#text>)
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
<!doctype html>
|
||||
<body>
|
||||
<!DOCTYPE html><html><head><style>
|
||||
* {
|
||||
font: 20px 'SerenitySans';
|
||||
}
|
||||
</style></head><body>
|
||||
<textarea>Bonjour mon amis!</textarea>
|
||||
<script>
|
||||
const textarea = document.createElement("textarea");
|
||||
textarea.innerText = "Well hello friends!";
|
||||
document.body.appendChild(textarea);
|
||||
</script>
|
||||
</body>
|
||||
|
|
|
@ -43,7 +43,7 @@ textarea {
|
|||
height: attr(rows lh, 2lh);
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
input::placeholder, textarea::placeholder {
|
||||
color: GrayText;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,8 @@ void HTMLTextAreaElement::initialize(JS::Realm& realm)
|
|||
void HTMLTextAreaElement::visit_edges(Cell::Visitor& visitor)
|
||||
{
|
||||
Base::visit_edges(visitor);
|
||||
visitor.visit(m_placeholder_element);
|
||||
visitor.visit(m_placeholder_text_node);
|
||||
visitor.visit(m_inner_text_element);
|
||||
visitor.visit(m_text_node);
|
||||
}
|
||||
|
@ -86,6 +88,8 @@ void HTMLTextAreaElement::reset_algorithm()
|
|||
m_dirty = false;
|
||||
// and set the raw value of element to its child text content.
|
||||
m_raw_value = child_text_content();
|
||||
|
||||
update_placeholder_visibility();
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::form_associated_element_was_inserted()
|
||||
|
@ -181,9 +185,22 @@ void HTMLTextAreaElement::create_shadow_tree_if_needed()
|
|||
return;
|
||||
|
||||
auto shadow_root = heap().allocate<DOM::ShadowRoot>(realm(), document(), *this, Bindings::ShadowRootMode::Closed);
|
||||
set_shadow_root(shadow_root);
|
||||
|
||||
auto element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML));
|
||||
MUST(shadow_root->append_child(element));
|
||||
|
||||
m_placeholder_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML));
|
||||
m_placeholder_element->set_use_pseudo_element(CSS::Selector::PseudoElement::Type::Placeholder);
|
||||
MUST(element->append_child(*m_placeholder_element));
|
||||
|
||||
m_placeholder_text_node = heap().allocate<DOM::Text>(realm(), document(), String {});
|
||||
m_placeholder_text_node->set_data(get_attribute(HTML::AttributeNames::placeholder).value_or(String {}));
|
||||
m_placeholder_text_node->set_editable_text_node_owner(Badge<HTMLTextAreaElement> {}, *this);
|
||||
MUST(m_placeholder_element->append_child(*m_placeholder_text_node));
|
||||
|
||||
m_inner_text_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML));
|
||||
MUST(element->append_child(*m_inner_text_element));
|
||||
|
||||
m_text_node = heap().allocate<DOM::Text>(realm(), document(), String {});
|
||||
m_text_node->set_always_editable(true);
|
||||
|
@ -191,11 +208,23 @@ void HTMLTextAreaElement::create_shadow_tree_if_needed()
|
|||
// NOTE: If `children_changed()` was called before now, `m_raw_value` will hold the text content.
|
||||
// Otherwise, it will get filled in whenever that does get called.
|
||||
m_text_node->set_text_content(m_raw_value);
|
||||
|
||||
MUST(m_inner_text_element->append_child(*m_text_node));
|
||||
MUST(element->append_child(*m_inner_text_element));
|
||||
MUST(shadow_root->append_child(element));
|
||||
set_shadow_root(shadow_root);
|
||||
|
||||
update_placeholder_visibility();
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::update_placeholder_visibility()
|
||||
{
|
||||
if (!m_placeholder_element)
|
||||
return;
|
||||
if (!m_text_node)
|
||||
return;
|
||||
auto placeholder_text = get_attribute(AttributeNames::placeholder);
|
||||
if (placeholder_text.has_value() && m_text_node->data().is_empty()) {
|
||||
MUST(m_placeholder_element->style_for_bindings()->set_property(CSS::PropertyID::Display, "block"sv));
|
||||
} else {
|
||||
MUST(m_placeholder_element->style_for_bindings()->set_property(CSS::PropertyID::Display, "none"sv));
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element:children-changed-steps
|
||||
|
@ -207,6 +236,16 @@ void HTMLTextAreaElement::children_changed()
|
|||
m_raw_value = child_text_content();
|
||||
if (m_text_node)
|
||||
m_text_node->set_text_content(m_raw_value);
|
||||
update_placeholder_visibility();
|
||||
}
|
||||
}
|
||||
|
||||
void HTMLTextAreaElement::attribute_changed(FlyString const& name, Optional<String> const& value)
|
||||
{
|
||||
HTMLElement::attribute_changed(name, value);
|
||||
if (name == HTML::AttributeNames::placeholder) {
|
||||
if (m_placeholder_text_node)
|
||||
m_placeholder_text_node->set_data(value.value_or(String {}));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,6 +253,8 @@ void HTMLTextAreaElement::did_edit_text_node(Badge<Web::HTML::BrowsingContext>)
|
|||
{
|
||||
// A textarea element's dirty value flag must be set to true whenever the user interacts with the control in a way that changes the raw value.
|
||||
m_dirty = true;
|
||||
|
||||
update_placeholder_visibility();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -56,6 +56,8 @@ public:
|
|||
virtual bool is_auto_capitalize_inheriting() const override { return true; }
|
||||
|
||||
// ^HTMLElement
|
||||
virtual void attribute_changed(FlyString const&, Optional<String> const&) override;
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/forms.html#category-label
|
||||
virtual bool is_labelable() const override { return true; }
|
||||
|
||||
|
@ -94,6 +96,10 @@ private:
|
|||
|
||||
void create_shadow_tree_if_needed();
|
||||
|
||||
void update_placeholder_visibility();
|
||||
JS::GCPtr<DOM::Element> m_placeholder_element;
|
||||
JS::GCPtr<DOM::Text> m_placeholder_text_node;
|
||||
|
||||
JS::GCPtr<DOM::Element> m_inner_text_element;
|
||||
JS::GCPtr<DOM::Text> m_text_node;
|
||||
|
||||
|
|
Loading…
Reference in a new issue