mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 14:38:11 +00:00
LibWeb: Support displaying HTMLInputElement placeholder values
This adds support for parsing the ::placeholder pseudo-element and injecting an anonymous layout node with that element when the input element's data is empty.
This commit is contained in:
parent
fddbc2e378
commit
4a30446999
5 changed files with 91 additions and 0 deletions
|
@ -1,6 +1,23 @@
|
|||
<html>
|
||||
<head>
|
||||
<style type="text/css">
|
||||
#placeholder1, #placeholder2 {
|
||||
color: red;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
#placeholder1::placeholder {
|
||||
color: green;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>
|
||||
<input type="hidden" id="hidden" value="hidden" /><br />
|
||||
<input type="text" id="text" value="text" /><br />
|
||||
<input type="text" id="placeholder1" placeholder="This placeholder should be green" /><br />
|
||||
<input type="text" id="placeholder2" placeholder="This placeholder should be grey" /><br />
|
||||
<input type="search" id="search" value="search" /><br />
|
||||
<input type="tel" id="tel" value="tel" /><br />
|
||||
<input type="url" id="url" value="url" /><br />
|
||||
|
@ -29,6 +46,8 @@
|
|||
var ids = [
|
||||
"hidden",
|
||||
"text",
|
||||
"placeholder1",
|
||||
"placeholder2",
|
||||
"search",
|
||||
"tel",
|
||||
"url",
|
||||
|
@ -69,3 +88,5 @@
|
|||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -49,6 +49,10 @@ input[type=submit], input[type=button], input[type=reset], input[type=checkbox],
|
|||
cursor: unset;
|
||||
}
|
||||
|
||||
input::placeholder {
|
||||
color: rgb(117, 117, 117);
|
||||
}
|
||||
|
||||
button, input[type=submit], input[type=button], input[type=reset] {
|
||||
padding: 1px 4px;
|
||||
background-color: -libweb-palette-button;
|
||||
|
|
|
@ -317,6 +317,47 @@ WebIDL::ExceptionOr<void> HTMLInputElement::set_value(String value)
|
|||
return {};
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#the-input-element:attr-input-placeholder-3
|
||||
static bool is_allowed_to_have_placeholder(HTML::HTMLInputElement::TypeAttributeState state)
|
||||
{
|
||||
switch (state) {
|
||||
case HTML::HTMLInputElement::TypeAttributeState::Text:
|
||||
case HTML::HTMLInputElement::TypeAttributeState::Search:
|
||||
case HTML::HTMLInputElement::TypeAttributeState::URL:
|
||||
case HTML::HTMLInputElement::TypeAttributeState::Telephone:
|
||||
case HTML::HTMLInputElement::TypeAttributeState::Email:
|
||||
case HTML::HTMLInputElement::TypeAttributeState::Password:
|
||||
case HTML::HTMLInputElement::TypeAttributeState::Number:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// https://html.spec.whatwg.org/multipage/input.html#attr-input-placeholder
|
||||
Optional<String> HTMLInputElement::placeholder_value() const
|
||||
{
|
||||
if (!m_text_node || !m_text_node->data().is_empty())
|
||||
return {};
|
||||
if (!is_allowed_to_have_placeholder(type_state()))
|
||||
return {};
|
||||
if (!has_attribute(HTML::AttributeNames::placeholder))
|
||||
return {};
|
||||
|
||||
auto placeholder = attribute(HTML::AttributeNames::placeholder);
|
||||
|
||||
if (placeholder.contains('\r') || placeholder.contains('\n')) {
|
||||
StringBuilder builder;
|
||||
for (auto ch : placeholder) {
|
||||
if (ch != '\r' && ch != '\n')
|
||||
builder.append(ch);
|
||||
}
|
||||
placeholder = builder.to_string();
|
||||
}
|
||||
|
||||
return placeholder;
|
||||
}
|
||||
|
||||
void HTMLInputElement::create_shadow_tree_if_needed()
|
||||
{
|
||||
if (shadow_root())
|
||||
|
|
|
@ -66,6 +66,8 @@ public:
|
|||
String value() const;
|
||||
WebIDL::ExceptionOr<void> set_value(String);
|
||||
|
||||
Optional<String> placeholder_value() const;
|
||||
|
||||
bool checked() const { return m_checked; }
|
||||
enum class ChangeSource {
|
||||
Programmatic,
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <LibWeb/DOM/ParentNode.h>
|
||||
#include <LibWeb/DOM/ShadowRoot.h>
|
||||
#include <LibWeb/Dump.h>
|
||||
#include <LibWeb/HTML/HTMLInputElement.h>
|
||||
#include <LibWeb/HTML/HTMLProgressElement.h>
|
||||
#include <LibWeb/Layout/InitialContainingBlock.h>
|
||||
#include <LibWeb/Layout/ListItemBox.h>
|
||||
|
@ -292,6 +293,28 @@ void TreeBuilder::create_layout_tree(DOM::Node& dom_node, TreeBuilder::Context&
|
|||
progress.set_pseudo_element_node({}, CSS::Selector::PseudoElement::ProgressValue, progress_value);
|
||||
}
|
||||
}
|
||||
|
||||
if (is<HTML::HTMLInputElement>(dom_node)) {
|
||||
auto& input_element = static_cast<HTML::HTMLInputElement&>(dom_node);
|
||||
|
||||
if (auto placeholder_value = input_element.placeholder_value(); placeholder_value.has_value()) {
|
||||
auto placeholder_style = style_computer.compute_style(input_element, CSS::Selector::PseudoElement::Placeholder);
|
||||
auto placeholder = DOM::Element::create_layout_node_for_display_type(document, placeholder_style->display(), placeholder_style, nullptr);
|
||||
|
||||
auto* text = document.heap().allocate<DOM::Text>(document.realm(), document, *placeholder_value);
|
||||
auto* text_node = document.heap().allocate_without_realm<Layout::TextNode>(document, *text);
|
||||
text_node->set_generated(true);
|
||||
|
||||
push_parent(verify_cast<NodeWithStyle>(*layout_node));
|
||||
push_parent(verify_cast<NodeWithStyle>(*placeholder));
|
||||
insert_node_into_inline_or_block_ancestor(*text_node, text_node->display(), AppendOrPrepend::Append);
|
||||
pop_parent();
|
||||
insert_node_into_inline_or_block_ancestor(*placeholder, placeholder->display(), AppendOrPrepend::Append);
|
||||
pop_parent();
|
||||
|
||||
input_element.set_pseudo_element_node({}, CSS::Selector::PseudoElement::Placeholder, placeholder);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JS::GCPtr<Layout::Node> TreeBuilder::build(DOM::Node& dom_node)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue