mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 06:32:44 +00:00 
			
		
		
		
	LibWeb: Add input number up down UI buttons
This commit is contained in:
		
							parent
							
								
									234d084876
								
							
						
					
					
						commit
						f8509e2183
					
				
					 4 changed files with 83 additions and 31 deletions
				
			
		|  | @ -5,7 +5,7 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline | ||||||
|         frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 200x25.84375] |         frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 200x25.84375] | ||||||
|       BlockContainer <input> at (11,11) content-size 200x25.84375 inline-block [BFC] children: not-inline |       BlockContainer <input> at (11,11) content-size 200x25.84375 inline-block [BFC] children: not-inline | ||||||
|         Box <div> at (13,12) content-size 196x23.84375 flex-container(row) [FFC] children: not-inline |         Box <div> at (13,12) content-size 196x23.84375 flex-container(row) [FFC] children: not-inline | ||||||
|           BlockContainer <div> at (14,13) content-size 0x21.84375 flex-item [BFC] children: inline |           BlockContainer <div> at (14,13) content-size 194x21.84375 flex-item [BFC] children: inline | ||||||
|             TextNode <#text> |             TextNode <#text> | ||||||
| 
 | 
 | ||||||
| ViewportPaintable (Viewport<#document>) [0,0 800x600] | ViewportPaintable (Viewport<#document>) [0,0 800x600] | ||||||
|  | @ -13,4 +13,4 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600] | ||||||
|     PaintableWithLines (BlockContainer<BODY>) [9,9 782x29.84375] |     PaintableWithLines (BlockContainer<BODY>) [9,9 782x29.84375] | ||||||
|       PaintableWithLines (BlockContainer<INPUT>) [10,10 202x27.84375] |       PaintableWithLines (BlockContainer<INPUT>) [10,10 202x27.84375] | ||||||
|         PaintableBox (Box<DIV>) [11,11 200x25.84375] |         PaintableBox (Box<DIV>) [11,11 200x25.84375] | ||||||
|           PaintableWithLines (BlockContainer<DIV>) [13,12 2x23.84375] |           PaintableWithLines (BlockContainer<DIV>) [13,12 196x23.84375] | ||||||
|  |  | ||||||
|  | @ -1,22 +1,22 @@ | ||||||
| Viewport <#document> at (0,0) content-size 800x600 children: not-inline | Viewport <#document> at (0,0) content-size 800x600 children: not-inline | ||||||
|   BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline |   BlockContainer <html> at (0,0) content-size 800x41.84375 [BFC] children: not-inline | ||||||
|     BlockContainer <body> at (8,8) content-size 784x21.46875 children: inline |     BlockContainer <body> at (8,8) content-size 784x25.84375 children: inline | ||||||
|       line 0 width: 191.875, height: 21.46875, bottom: 21.46875, baseline: 13.53125 |       line 0 width: 202, height: 25.84375, bottom: 25.84375, baseline: 16.921875 | ||||||
|         frag 0 from BlockContainer start: 0, length: 0, rect: [9,9 189.875x19.46875] |         frag 0 from BlockContainer start: 0, length: 0, rect: [9,9 200x23.84375] | ||||||
|       BlockContainer <input#foo> at (9,9) content-size 189.875x19.46875 inline-block [BFC] children: not-inline |       BlockContainer <input#foo> at (9,9) content-size 200x23.84375 inline-block [BFC] children: not-inline | ||||||
|         Box <div> at (11,10) content-size 185.875x17.46875 flex-container(row) [FFC] children: not-inline |         Box <div> at (11,10) content-size 196x21.84375 flex-container(row) [FFC] children: not-inline | ||||||
|           BlockContainer <div> at (11,10) content-size 49.734375x17.46875 flex-item [BFC] children: inline |           BlockContainer <div> at (11,10) content-size 196x21.84375 flex-item [BFC] children: inline | ||||||
|             line 0 width: 49.734375, height: 17.46875, bottom: 17.46875, baseline: 13.53125 |             line 0 width: 62.171875, height: 21.84375, bottom: 21.84375, baseline: 16.921875 | ||||||
|               frag 0 from TextNode start: 0, length: 4, rect: [11,10 49.734375x17.46875] |               frag 0 from TextNode start: 0, length: 4, rect: [11,10 62.171875x21.84375] | ||||||
|                 "PASS" |                 "PASS" | ||||||
|             TextNode <#text> |             TextNode <#text> | ||||||
|       TextNode <#text> |       TextNode <#text> | ||||||
|       TextNode <#text> |       TextNode <#text> | ||||||
| 
 | 
 | ||||||
| ViewportPaintable (Viewport<#document>) [0,0 800x600] | ViewportPaintable (Viewport<#document>) [0,0 800x600] | ||||||
|   PaintableWithLines (BlockContainer<HTML>) [0,0 800x600] |   PaintableWithLines (BlockContainer<HTML>) [0,0 800x41.84375] | ||||||
|     PaintableWithLines (BlockContainer<BODY>) [8,8 784x21.46875] |     PaintableWithLines (BlockContainer<BODY>) [8,8 784x25.84375] | ||||||
|       PaintableWithLines (BlockContainer<INPUT>#foo) [8,8 191.875x21.46875] |       PaintableWithLines (BlockContainer<INPUT>#foo) [8,8 202x25.84375] | ||||||
|         PaintableBox (Box<DIV>) [9,9 189.875x19.46875] |         PaintableBox (Box<DIV>) [9,9 200x23.84375] | ||||||
|           PaintableWithLines (BlockContainer<DIV>) [11,10 49.734375x17.46875] |           PaintableWithLines (BlockContainer<DIV>) [11,10 196x21.84375] | ||||||
|             TextPaintable (TextNode<#text>) |             TextPaintable (TextNode<#text>) | ||||||
|  |  | ||||||
|  | @ -1,4 +1,11 @@ | ||||||
| <input id="foo"> | <!DOCTYPE html><html><head><style> | ||||||
|  | * { | ||||||
|  |     font: 20px 'SerenitySans'; | ||||||
|  | } | ||||||
|  | input { | ||||||
|  |     width: 200px; | ||||||
|  | } | ||||||
|  | </style></head><body><input id="foo"> | ||||||
| <script> | <script> | ||||||
|     let foo = document.getElementById("foo"); |     let foo = document.getElementById("foo"); | ||||||
|     foo.value = "FAIL"; |     foo.value = "FAIL"; | ||||||
|  |  | ||||||
|  | @ -7,11 +7,13 @@ | ||||||
|  * SPDX-License-Identifier: BSD-2-Clause |  * SPDX-License-Identifier: BSD-2-Clause | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
|  | #include <LibJS/Runtime/NativeFunction.h> | ||||||
| #include <LibWeb/CSS/StyleValues/DisplayStyleValue.h> | #include <LibWeb/CSS/StyleValues/DisplayStyleValue.h> | ||||||
| #include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h> | #include <LibWeb/CSS/StyleValues/IdentifierStyleValue.h> | ||||||
| #include <LibWeb/DOM/Document.h> | #include <LibWeb/DOM/Document.h> | ||||||
| #include <LibWeb/DOM/ElementFactory.h> | #include <LibWeb/DOM/ElementFactory.h> | ||||||
| #include <LibWeb/DOM/Event.h> | #include <LibWeb/DOM/Event.h> | ||||||
|  | #include <LibWeb/DOM/IDLEventListener.h> | ||||||
| #include <LibWeb/DOM/ShadowRoot.h> | #include <LibWeb/DOM/ShadowRoot.h> | ||||||
| #include <LibWeb/HTML/BrowsingContext.h> | #include <LibWeb/HTML/BrowsingContext.h> | ||||||
| #include <LibWeb/HTML/EventNames.h> | #include <LibWeb/HTML/EventNames.h> | ||||||
|  | @ -563,8 +565,10 @@ void HTMLInputElement::create_shadow_tree_if_needed() | ||||||
| void HTMLInputElement::create_text_input_shadow_tree() | void HTMLInputElement::create_text_input_shadow_tree() | ||||||
| { | { | ||||||
|     auto shadow_root = heap().allocate<DOM::ShadowRoot>(realm(), document(), *this, Bindings::ShadowRootMode::Closed); |     auto shadow_root = heap().allocate<DOM::ShadowRoot>(realm(), document(), *this, Bindings::ShadowRootMode::Closed); | ||||||
|  |     set_shadow_root(shadow_root); | ||||||
|  | 
 | ||||||
|     auto initial_value = m_value; |     auto initial_value = m_value; | ||||||
|     auto element = DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); |     auto element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML)); | ||||||
|     MUST(element->set_attribute(HTML::AttributeNames::style, R"~~~( |     MUST(element->set_attribute(HTML::AttributeNames::style, R"~~~( | ||||||
|         display: flex; |         display: flex; | ||||||
|         height: 100%; |         height: 100%; | ||||||
|  | @ -572,37 +576,78 @@ void HTMLInputElement::create_text_input_shadow_tree() | ||||||
|         white-space: pre; |         white-space: pre; | ||||||
|         border: none; |         border: none; | ||||||
|         padding: 1px 2px; |         padding: 1px 2px; | ||||||
| )~~~"_string)); |     )~~~"_string)); | ||||||
|  |     MUST(shadow_root->append_child(element)); | ||||||
| 
 | 
 | ||||||
|     m_placeholder_element = heap().allocate<PlaceholderElement>(realm(), document()); |     m_placeholder_element = heap().allocate<PlaceholderElement>(realm(), document()); | ||||||
|     MUST(m_placeholder_element->style_for_bindings()->set_property(CSS::PropertyID::Height, "1lh"sv)); |     MUST(m_placeholder_element->set_attribute(HTML::AttributeNames::style, R"~~~( | ||||||
|  |         flex: 1; | ||||||
|  |         height: 1lh; | ||||||
|  |     )~~~"_string)); | ||||||
|  |     MUST(element->append_child(*m_placeholder_element)); | ||||||
| 
 | 
 | ||||||
|     m_placeholder_text_node = heap().allocate<DOM::Text>(realm(), document(), initial_value); |     m_placeholder_text_node = heap().allocate<DOM::Text>(realm(), document(), initial_value); | ||||||
|     m_placeholder_text_node->set_data(attribute(HTML::AttributeNames::placeholder).value_or(String {})); |     m_placeholder_text_node->set_data(attribute(HTML::AttributeNames::placeholder).value_or(String {})); | ||||||
|     m_placeholder_text_node->set_editable_text_node_owner(Badge<HTMLInputElement> {}, *this); |     m_placeholder_text_node->set_editable_text_node_owner(Badge<HTMLInputElement> {}, *this); | ||||||
|     MUST(m_placeholder_element->append_child(*m_placeholder_text_node)); |     MUST(m_placeholder_element->append_child(*m_placeholder_text_node)); | ||||||
|     MUST(element->append_child(*m_placeholder_element)); |  | ||||||
| 
 | 
 | ||||||
|     m_inner_text_element = DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML).release_value_but_fixme_should_propagate_errors(); |     m_inner_text_element = MUST(DOM::create_element(document(), HTML::TagNames::div, Namespace::HTML)); | ||||||
|     MUST(m_inner_text_element->style_for_bindings()->set_property(CSS::PropertyID::Height, "1lh"sv)); |     MUST(m_inner_text_element->set_attribute(HTML::AttributeNames::style, R"~~~( | ||||||
|  |         flex: 1; | ||||||
|  |         height: 1lh; | ||||||
|  |     )~~~"_string)); | ||||||
|  |     MUST(element->append_child(*m_inner_text_element)); | ||||||
| 
 | 
 | ||||||
|     m_text_node = heap().allocate<DOM::Text>(realm(), document(), move(initial_value)); |     m_text_node = heap().allocate<DOM::Text>(realm(), document(), move(initial_value)); | ||||||
|     if (m_type == TypeAttributeState::FileUpload) { |     if (type_state() == TypeAttributeState::FileUpload) { | ||||||
|         // NOTE: file upload state is mutable, but we don't allow the text node to be modifed
 |         // NOTE: file upload state is mutable, but we don't allow the text node to be modifed
 | ||||||
|         m_text_node->set_always_editable(false); |         m_text_node->set_always_editable(false); | ||||||
|     } else { |     } else { | ||||||
|         handle_readonly_attribute(attribute(HTML::AttributeNames::readonly)); |         handle_readonly_attribute(attribute(HTML::AttributeNames::readonly)); | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     m_text_node->set_editable_text_node_owner(Badge<HTMLInputElement> {}, *this); |     m_text_node->set_editable_text_node_owner(Badge<HTMLInputElement> {}, *this); | ||||||
| 
 |     if (type_state() == TypeAttributeState::Password) | ||||||
|     if (m_type == TypeAttributeState::Password) |  | ||||||
|         m_text_node->set_is_password_input({}, true); |         m_text_node->set_is_password_input({}, true); | ||||||
| 
 |  | ||||||
|     MUST(m_inner_text_element->append_child(*m_text_node)); |     MUST(m_inner_text_element->append_child(*m_text_node)); | ||||||
|     MUST(element->append_child(*m_inner_text_element)); | 
 | ||||||
|     MUST(shadow_root->append_child(element)); |     if (type_state() == TypeAttributeState::Number) { | ||||||
|     set_shadow_root(shadow_root); |         // Up button
 | ||||||
|  |         auto up_button = MUST(DOM::create_element(document(), HTML::TagNames::button, Namespace::HTML)); | ||||||
|  |         // FIXME: This cursor property doesn't work
 | ||||||
|  |         MUST(up_button->set_attribute(HTML::AttributeNames::style, R"~~~( | ||||||
|  |             padding: 0; | ||||||
|  |             cursor: default; | ||||||
|  |         )~~~"_string)); | ||||||
|  |         MUST(up_button->set_inner_html("<svg style=\"width: 1em; height: 1em;\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z\" /></svg>"sv)); | ||||||
|  |         MUST(element->append_child(up_button)); | ||||||
|  | 
 | ||||||
|  |         auto up_callback_function = JS::NativeFunction::create( | ||||||
|  |             realm(), [this](JS::VM&) { | ||||||
|  |                 (void)step_up(); | ||||||
|  |                 return JS::js_undefined(); | ||||||
|  |             }, | ||||||
|  |             0, "", &realm()); | ||||||
|  |         auto up_callback = realm().heap().allocate_without_realm<WebIDL::CallbackType>(*up_callback_function, Bindings::host_defined_environment_settings_object(realm())); | ||||||
|  |         up_button->add_event_listener_without_options("click"_fly_string, DOM::IDLEventListener::create(realm(), up_callback)); | ||||||
|  | 
 | ||||||
|  |         // Down button
 | ||||||
|  |         auto down_button = MUST(DOM::create_element(document(), HTML::TagNames::button, Namespace::HTML)); | ||||||
|  |         MUST(down_button->set_attribute(HTML::AttributeNames::style, R"~~~( | ||||||
|  |             padding: 0; | ||||||
|  |             cursor: default; | ||||||
|  |         )~~~"_string)); | ||||||
|  |         MUST(down_button->set_inner_html("<svg style=\"width: 1em; height: 1em;\" xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\"><path fill=\"currentColor\" d=\"M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z\" /></svg>"sv)); | ||||||
|  |         MUST(element->append_child(down_button)); | ||||||
|  | 
 | ||||||
|  |         auto down_callback_function = JS::NativeFunction::create( | ||||||
|  |             realm(), [this](JS::VM&) { | ||||||
|  |                 (void)step_down(); | ||||||
|  |                 return JS::js_undefined(); | ||||||
|  |             }, | ||||||
|  |             0, "", &realm()); | ||||||
|  |         auto down_callback = realm().heap().allocate_without_realm<WebIDL::CallbackType>(*down_callback_function, Bindings::host_defined_environment_settings_object(realm())); | ||||||
|  |         down_button->add_event_listener_without_options("click"_fly_string, DOM::IDLEventListener::create(realm(), down_callback)); | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void HTMLInputElement::create_color_input_shadow_tree() | void HTMLInputElement::create_color_input_shadow_tree() | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Bastiaan van der Plaat
						Bastiaan van der Plaat