input, change, submit on text/number/range/color/date/file/checkbox/radio/select/form/textarea and form API

This commit is contained in:
Face
2025-08-07 14:05:41 +03:00
parent c3e72093ea
commit d4aa741452
24 changed files with 745 additions and 67 deletions

View File

@@ -34,7 +34,7 @@ class HTMLElement:
func get_preserved_text() -> String:
return text_content
func get_bbcode_formatted_text(parser: HTMLParser = null) -> String:
func get_bbcode_formatted_text(parser: HTMLParser) -> String:
var styles = {}
if parser != null:
styles = parser.get_element_styles_with_inheritance(self, "", [])
@@ -142,8 +142,7 @@ func get_element_styles_with_inheritance(element: HTMLElement, event: String = "
var styles = {}
var class_names = extract_class_names(element)
styles.merge(parse_result.css_parser.stylesheet.get_styles_for_element(element.tag_name, event, class_names, element))
styles.merge(parse_result.css_parser.stylesheet.get_styles_for_element(event, element))
# Apply inline styles (higher priority) - force override CSS rules
var inline_style = element.get_attribute("style")
if inline_style.length() > 0:
@@ -169,8 +168,7 @@ func get_element_styles_internal(element: HTMLElement, event: String = "") -> Di
# Apply CSS rules
if parse_result.css_parser:
var class_names = extract_class_names(element)
styles.merge(parse_result.css_parser.stylesheet.get_styles_for_element(element.tag_name, event, class_names, element))
styles.merge(parse_result.css_parser.stylesheet.get_styles_for_element(event, element))
# Apply inline styles (higher priority) - force override CSS rules
var inline_style = element.get_attribute("style")
@@ -203,7 +201,7 @@ func parse_inline_style_with_event(style_string: String, event: String = "") ->
else:
# Check if this is a CSS class that might have pseudo-class rules
if parse_result.css_parser and parse_result.css_parser.stylesheet:
var pseudo_styles = parse_result.css_parser.stylesheet.get_styles_for_element("", event, [utility_name], null)
var pseudo_styles = parse_result.css_parser.stylesheet.get_styles_for_element(event, null)
if not pseudo_styles.is_empty():
for property in pseudo_styles:
properties[property] = pseudo_styles[property]
@@ -287,7 +285,7 @@ func find_by_id(element_id: String) -> HTMLElement:
return null
func register_dom_node(element: HTMLElement, node: Control) -> void:
func register_dom_node(element: HTMLElement, node) -> void:
var element_id = element.get_id()
if element_id.length() > 0:
parse_result.dom_nodes[element_id] = node

View File

@@ -10,6 +10,7 @@ class EventSubscription:
var lua_api: LuaAPI
var connected_signal: String = ""
var connected_node: Node = null
var callback_func: Callable
var dom_parser: HTMLParser
var event_subscriptions: Dictionary = {}
@@ -489,6 +490,8 @@ func _element_on_event_handler(vm: LuauVM) -> int:
var signal_node = get_dom_node(dom_node, "signal")
var success = LuaEventUtils.connect_element_event(signal_node, event_name, subscription)
if not success:
print("ERROR: Failed to connect ", event_name, " event for ", element_id)
return _handle_subscription_result(vm, subscription, success)
@@ -641,6 +644,11 @@ func _execute_lua_callback(subscription: EventSubscription, args: Array = []) ->
else:
subscription.vm.lua_pop(1)
func _execute_input_event_callback(subscription: EventSubscription, event_data: Dictionary) -> void:
if not event_subscriptions.has(subscription.id):
return
_execute_lua_callback(subscription, [event_data])
# Global input processing
func _input(event: InputEvent) -> void:
if event is InputEventKey:
@@ -699,6 +707,108 @@ func _handle_mousemove_event(mouse_event: InputEventMouseMotion, subscription: E
}
_execute_lua_callback(subscription, [mouse_info])
# Input event handlers
func _on_input_text_changed(new_text: String, subscription: EventSubscription) -> void:
_execute_input_event_callback(subscription, {"value": new_text})
func _on_input_focus_lost(subscription: EventSubscription) -> void:
if not event_subscriptions.has(subscription.id):
return
# Get the current text value from the input node
var dom_node = dom_parser.parse_result.dom_nodes.get(subscription.element_id, null)
if dom_node:
var current_text = ""
if dom_node.has_method("get_text"):
current_text = dom_node.get_text()
elif "text" in dom_node:
current_text = dom_node.text
var event_info = {"value": current_text}
_execute_lua_callback(subscription, [event_info])
func _on_input_value_changed(new_value, subscription: EventSubscription) -> void:
_execute_input_event_callback(subscription, {"value": new_value})
func _on_input_color_changed(new_color: Color, subscription: EventSubscription) -> void:
_execute_input_event_callback(subscription, {"value": "#" + new_color.to_html(false)})
func _on_input_toggled(pressed: bool, subscription: EventSubscription) -> void:
_execute_input_event_callback(subscription, {"value": pressed})
func _on_input_item_selected(index: int, subscription: EventSubscription) -> void:
if not event_subscriptions.has(subscription.id):
return
# Get value from OptionButton
var dom_node = dom_parser.parse_result.dom_nodes.get(subscription.element_id, null)
var value = ""
var text = ""
if dom_node and dom_node is OptionButton:
var option_button = dom_node as OptionButton
text = option_button.get_item_text(index)
# Get actual value attribute (stored as metadata)
var metadata = option_button.get_item_metadata(index)
value = str(metadata) if metadata != null else text
var event_info = {"index": index, "value": value, "text": text}
_execute_lua_callback(subscription, [event_info])
func _on_file_selected(file_path: String, subscription: EventSubscription) -> void:
if not event_subscriptions.has(subscription.id):
return
var dom_node = dom_parser.parse_result.dom_nodes.get(subscription.element_id, null)
if dom_node:
var file_container = dom_node.get_parent() # FileContainer (HBoxContainer)
if file_container:
var input_element = file_container.get_parent() # Input Control
if input_element and input_element.has_method("get_file_info"):
var file_info = input_element.get_file_info()
if not file_info.is_empty():
_execute_lua_callback(subscription, [file_info])
return
# Fallback
var file_name = file_path.get_file()
_execute_lua_callback(subscription, [{"fileName": file_name}])
func _on_date_selected_text(date_text: String, subscription: EventSubscription) -> void:
if not event_subscriptions.has(subscription.id):
return
var event_info = {"value": date_text}
_execute_lua_callback(subscription, [event_info])
func _on_form_submit(subscription: EventSubscription) -> void:
if not event_subscriptions.has(subscription.id):
return
# Find parent form
var form_data = {}
var element = dom_parser.find_by_id(subscription.element_id)
if element:
var form_element = element.parent
while form_element and form_element.tag_name != "form":
form_element = form_element.parent
if form_element:
var form_dom_node = dom_parser.parse_result.dom_nodes.get(form_element.get_attribute("id"), null)
if form_dom_node and form_dom_node.has_method("submit_form"):
form_data = form_dom_node.submit_form()
var event_info = {"data": form_data}
_execute_lua_callback(subscription, [event_info])
func _on_text_submit(text: String, subscription: EventSubscription) -> void:
if not event_subscriptions.has(subscription.id):
return
var event_info = {"value": text}
_execute_lua_callback(subscription, [event_info])
# DOM node utilities
func get_dom_node(node: Node, purpose: String = "general") -> Node:
if not node:
@@ -717,6 +827,10 @@ func get_dom_node(node: Node, purpose: String = "general") -> Node:
return node.get("rich_text_label")
elif node.get_node_or_null("RichTextLabel"):
return node.get_node_or_null("RichTextLabel")
elif node is LineEdit or node is TextEdit or node is SpinBox or node is HSlider:
return node
elif node is CheckBox or node is ColorPickerButton or node is OptionButton:
return node
else:
return node
"text":