mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 15:12:45 +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 { | ol { | ||||||
|     padding-left: 20px; |     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 <LibGfx/FontDatabase.h> | ||||||
| #include <LibWeb/DOM/Document.h> | #include <LibWeb/DOM/Document.h> | ||||||
| #include <LibWeb/DOM/Event.h> | #include <LibWeb/DOM/Event.h> | ||||||
|  | #include <LibWeb/DOM/ShadowRoot.h> | ||||||
|  | #include <LibWeb/DOM/Text.h> | ||||||
| #include <LibWeb/HTML/EventNames.h> | #include <LibWeb/HTML/EventNames.h> | ||||||
| #include <LibWeb/HTML/HTMLFormElement.h> | #include <LibWeb/HTML/HTMLFormElement.h> | ||||||
| #include <LibWeb/HTML/HTMLInputElement.h> | #include <LibWeb/HTML/HTMLInputElement.h> | ||||||
| #include <LibWeb/InProcessWebView.h> | #include <LibWeb/InProcessWebView.h> | ||||||
|  | #include <LibWeb/Layout/BlockBox.h> | ||||||
| #include <LibWeb/Layout/ButtonBox.h> | #include <LibWeb/Layout/ButtonBox.h> | ||||||
| #include <LibWeb/Layout/CheckBox.h> | #include <LibWeb/Layout/CheckBox.h> | ||||||
| #include <LibWeb/Page/Frame.h> | #include <LibWeb/Page/Frame.h> | ||||||
|  | @ -74,8 +77,10 @@ RefPtr<Layout::Node> HTMLInputElement::create_layout_node() | ||||||
|     if (type() == "checkbox") |     if (type() == "checkbox") | ||||||
|         return adopt(*new Layout::CheckBox(document(), *this, move(style))); |         return adopt(*new Layout::CheckBox(document(), *this, move(style))); | ||||||
| 
 | 
 | ||||||
|     // FIXME: Implement <input type=text> in terms of LibWeb primitives.
 |     create_shadow_tree_if_needed(); | ||||||
|     return nullptr; |     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) | void HTMLInputElement::set_checked(bool checked) | ||||||
|  | @ -94,4 +99,39 @@ bool HTMLInputElement::enabled() const | ||||||
|     return !has_attribute(HTML::AttributeNames::disabled); |     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; |     virtual RefPtr<Layout::Node> create_layout_node() override; | ||||||
| 
 | 
 | ||||||
|     String type() const { return attribute(HTML::AttributeNames::type); } |     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 name() const { return attribute(HTML::AttributeNames::name); } | ||||||
| 
 | 
 | ||||||
|  |     String value() const; | ||||||
|  |     void set_value(String); | ||||||
|  | 
 | ||||||
|     bool checked() const { return m_checked; } |     bool checked() const { return m_checked; } | ||||||
|     void set_checked(bool); |     void set_checked(bool); | ||||||
| 
 | 
 | ||||||
|  | @ -51,6 +54,9 @@ public: | ||||||
|     void did_click_button(Badge<Layout::ButtonBox>); |     void did_click_button(Badge<Layout::ButtonBox>); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|  |     void create_shadow_tree_if_needed(); | ||||||
|  | 
 | ||||||
|  |     RefPtr<DOM::Text> m_text_node; | ||||||
|     bool m_checked { false }; |     bool m_checked { false }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -11,6 +11,8 @@ interface HTMLInputElement : HTMLElement { | ||||||
|     [Reflect=dirname] attribute DOMString dirName; |     [Reflect=dirname] attribute DOMString dirName; | ||||||
|     [Reflect=value] attribute DOMString defaultValue; |     [Reflect=value] attribute DOMString defaultValue; | ||||||
| 
 | 
 | ||||||
|  |     [LegacyNullToEmptyString] attribute DOMString value; | ||||||
|  | 
 | ||||||
|     attribute boolean checked; |     attribute boolean checked; | ||||||
| 
 | 
 | ||||||
|     [Reflect] attribute boolean disabled; |     [Reflect] attribute boolean disabled; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling