mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 06:02:44 +00:00 
			
		
		
		
	LibWeb: Start implementing <input type=text> using a shadow DOM
Text <input> fields will now generate a basic shadow DOM and attach it to the input element. The shadow DOM contains a <div> with some inline style, and an always- editable text node inside it. Accessing the "value" attribute on such an input element will get/set the value from that text node. This is really cool, although not super stable since HTML editing is not super stable. But it's a start! :^)
This commit is contained in:
		
							parent
							
								
									e4e325ff61
								
							
						
					
					
						commit
						29a2aac89a
					
				
					 4 changed files with 58 additions and 3 deletions
				
			
		|  | @ -194,3 +194,10 @@ ul, | |||
| ol { | ||||
|     padding-left: 20px; | ||||
| } | ||||
| 
 | ||||
| /* FIXME: This is a temporary hack until we can render a native-looking frame for these. */ | ||||
| input[type=text] { | ||||
|     border: 1px solid black; | ||||
|     min-width: 80px; | ||||
|     min-height: 16px; | ||||
| } | ||||
|  |  | |||
|  | @ -27,10 +27,13 @@ | |||
| #include <LibGfx/FontDatabase.h> | ||||
| #include <LibWeb/DOM/Document.h> | ||||
| #include <LibWeb/DOM/Event.h> | ||||
| #include <LibWeb/DOM/ShadowRoot.h> | ||||
| #include <LibWeb/DOM/Text.h> | ||||
| #include <LibWeb/HTML/EventNames.h> | ||||
| #include <LibWeb/HTML/HTMLFormElement.h> | ||||
| #include <LibWeb/HTML/HTMLInputElement.h> | ||||
| #include <LibWeb/InProcessWebView.h> | ||||
| #include <LibWeb/Layout/BlockBox.h> | ||||
| #include <LibWeb/Layout/ButtonBox.h> | ||||
| #include <LibWeb/Layout/CheckBox.h> | ||||
| #include <LibWeb/Page/Frame.h> | ||||
|  | @ -74,8 +77,10 @@ RefPtr<Layout::Node> HTMLInputElement::create_layout_node() | |||
|     if (type() == "checkbox") | ||||
|         return adopt(*new Layout::CheckBox(document(), *this, move(style))); | ||||
| 
 | ||||
|     // FIXME: Implement <input type=text> in terms of LibWeb primitives.
 | ||||
|     return nullptr; | ||||
|     create_shadow_tree_if_needed(); | ||||
|     auto layout_node = adopt(*new Layout::BlockBox(document(), this, move(style))); | ||||
|     layout_node->set_inline(true); | ||||
|     return layout_node; | ||||
| } | ||||
| 
 | ||||
| void HTMLInputElement::set_checked(bool checked) | ||||
|  | @ -94,4 +99,39 @@ bool HTMLInputElement::enabled() const | |||
|     return !has_attribute(HTML::AttributeNames::disabled); | ||||
| } | ||||
| 
 | ||||
| String HTMLInputElement::value() const | ||||
| { | ||||
|     if (m_text_node) | ||||
|         return m_text_node->data(); | ||||
|     return default_value(); | ||||
| } | ||||
| 
 | ||||
| void HTMLInputElement::set_value(String value) | ||||
| { | ||||
|     if (m_text_node) { | ||||
|         m_text_node->set_data(move(value)); | ||||
|         return; | ||||
|     } | ||||
|     set_attribute(HTML::AttributeNames::value, move(value)); | ||||
| } | ||||
| 
 | ||||
| void HTMLInputElement::create_shadow_tree_if_needed() | ||||
| { | ||||
|     if (shadow_root()) | ||||
|         return; | ||||
| 
 | ||||
|     // FIXME: This assumes that we want a text box. Is that always true?
 | ||||
|     auto shadow_root = adopt(*new DOM::ShadowRoot(document(), *this)); | ||||
|     auto initial_value = attribute(HTML::AttributeNames::value); | ||||
|     if (initial_value.is_null()) | ||||
|         initial_value = String::empty(); | ||||
|     auto element = document().create_element(HTML::TagNames::div); | ||||
|     element->set_attribute(HTML::AttributeNames::style, "white-space: pre"); | ||||
|     m_text_node = adopt(*new DOM::Text(document(), initial_value)); | ||||
|     m_text_node->set_always_editable(true); | ||||
|     element->append_child(*m_text_node); | ||||
|     shadow_root->append_child(move(element)); | ||||
|     set_shadow_root(move(shadow_root)); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -40,9 +40,12 @@ public: | |||
|     virtual RefPtr<Layout::Node> create_layout_node() override; | ||||
| 
 | ||||
|     String type() const { return attribute(HTML::AttributeNames::type); } | ||||
|     String value() const { return attribute(HTML::AttributeNames::value); } | ||||
|     String default_value() const { return attribute(HTML::AttributeNames::value); } | ||||
|     String name() const { return attribute(HTML::AttributeNames::name); } | ||||
| 
 | ||||
|     String value() const; | ||||
|     void set_value(String); | ||||
| 
 | ||||
|     bool checked() const { return m_checked; } | ||||
|     void set_checked(bool); | ||||
| 
 | ||||
|  | @ -51,6 +54,9 @@ public: | |||
|     void did_click_button(Badge<Layout::ButtonBox>); | ||||
| 
 | ||||
| private: | ||||
|     void create_shadow_tree_if_needed(); | ||||
| 
 | ||||
|     RefPtr<DOM::Text> m_text_node; | ||||
|     bool m_checked { false }; | ||||
| }; | ||||
| 
 | ||||
|  |  | |||
|  | @ -11,6 +11,8 @@ interface HTMLInputElement : HTMLElement { | |||
|     [Reflect=dirname] attribute DOMString dirName; | ||||
|     [Reflect=value] attribute DOMString defaultValue; | ||||
| 
 | ||||
|     [LegacyNullToEmptyString] attribute DOMString value; | ||||
| 
 | ||||
|     attribute boolean checked; | ||||
| 
 | ||||
|     [Reflect] attribute boolean disabled; | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling