user domains API, .value on input, fix flex sizing
This commit is contained in:
@@ -88,7 +88,7 @@ func _resort() -> void:
|
||||
|
||||
if not auto_size_width:
|
||||
available_width = calculate_available_dimension(true)
|
||||
elif flex_wrap == FlexContainer.FlexWrap.Wrap:
|
||||
elif flex_wrap != FlexContainer.FlexWrap.NoWrap:
|
||||
available_width = get_parent_or_fallback_size(true)
|
||||
|
||||
if not auto_size_height:
|
||||
|
||||
@@ -170,7 +170,7 @@ func get_element_styles_with_inheritance(element: HTMLElement, event: String = "
|
||||
styles[property] = inline_parsed[property]
|
||||
|
||||
# Inherit certain properties from parent elements
|
||||
var inheritable_properties = ["width", "height", "font-size", "color", "font-family", "cursor", "font-bold", "font-italic", "underline"]
|
||||
var inheritable_properties = ["font-size", "color", "font-family", "cursor", "font-bold", "font-italic", "underline"]
|
||||
var parent_element = element.parent
|
||||
while parent_element:
|
||||
var parent_styles = get_element_styles_internal(parent_element, event)
|
||||
|
||||
@@ -663,10 +663,7 @@ func _handle_text_setting(operation: Dictionary):
|
||||
var text_node = get_dom_node(dom_node, "text")
|
||||
if text_node:
|
||||
if text_node is RichTextLabel:
|
||||
var formatted_text = element.get_bbcode_formatted_text(dom_parser)
|
||||
formatted_text = "[font_size=24]%s[/font_size]" % formatted_text
|
||||
|
||||
text_node.text = formatted_text
|
||||
StyleManager.apply_styles_to_label(text_node, dom_parser.get_element_styles_with_inheritance(element, "", []), element, dom_parser, text)
|
||||
text_node.call_deferred("_auto_resize_to_content")
|
||||
elif text_node.has_method("set_text"):
|
||||
text_node.set_text(text)
|
||||
@@ -677,10 +674,7 @@ func _handle_text_setting(operation: Dictionary):
|
||||
else:
|
||||
var rich_text_label = _find_rich_text_label_recursive(dom_node)
|
||||
if rich_text_label:
|
||||
var formatted_text = element.get_bbcode_formatted_text(dom_parser)
|
||||
formatted_text = "[font_size=24]%s[/font_size]" % formatted_text
|
||||
|
||||
rich_text_label.text = formatted_text
|
||||
StyleManager.apply_styles_to_label(rich_text_label, dom_parser.get_element_styles_with_inheritance(element, "", []), element, dom_parser, text)
|
||||
rich_text_label.call_deferred("_auto_resize_to_content")
|
||||
|
||||
func _find_rich_text_label_recursive(node: Node) -> RichTextLabel:
|
||||
|
||||
@@ -60,55 +60,24 @@ static func apply_element_styles(node: Control, element: HTMLParser.HTMLElement,
|
||||
if styles.has("height"):
|
||||
height = parse_size(styles["height"])
|
||||
|
||||
# Skip width/height inheritance for buttons when inheriting from auto-sized containers
|
||||
var skip_sizing = SizingUtils.should_skip_sizing(node, element, parser)
|
||||
|
||||
if (width != null or height != null) and not skip_sizing:
|
||||
# FlexContainers handle percentage sizing differently than regular controls
|
||||
if node is FlexContainer:
|
||||
if width != null:
|
||||
if SizingUtils.is_percentage(width):
|
||||
# For FlexContainers with percentage width, use proportion sizing
|
||||
var percentage_value = float(width.replace("%", "")) / 100.0
|
||||
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
node.size_flags_stretch_ratio = percentage_value
|
||||
else:
|
||||
node.custom_minimum_size.x = width
|
||||
node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
node.set_meta("size_flags_horizontal_set", true)
|
||||
|
||||
if height != null:
|
||||
if SizingUtils.is_percentage(height):
|
||||
node.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
else:
|
||||
node.custom_minimum_size.y = height
|
||||
node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||
node.set_meta("size_flags_vertical_set", true)
|
||||
|
||||
node.set_meta("size_flags_set_by_style_manager", true)
|
||||
elif node is VBoxContainer or node is HBoxContainer or node is Container:
|
||||
# Hcontainer nodes (like ul, ol)
|
||||
SizingUtils.apply_container_dimension_sizing(node, width, height, styles)
|
||||
elif node is HTMLP:
|
||||
# Only apply sizing if element has explicit size, otherwise preserve natural sizing
|
||||
var element_styles = parser.get_element_styles_internal(element, "")
|
||||
if element_styles.has("width") or element_styles.has("height"):
|
||||
var orig_h_flag = node.size_flags_horizontal
|
||||
var orig_v_flag = node.size_flags_vertical
|
||||
SizingUtils.apply_regular_control_sizing(node, width, height, styles)
|
||||
if not element_styles.has("width"):
|
||||
node.size_flags_horizontal = orig_h_flag
|
||||
if not element_styles.has("height"):
|
||||
node.size_flags_vertical = orig_v_flag
|
||||
else:
|
||||
if element.tag_name == "img" and SizingUtils.is_percentage(width) and SizingUtils.is_percentage(height):
|
||||
if width != null:
|
||||
if width is String and width == "100%":
|
||||
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
node.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
# Clear any hardcoded sizing
|
||||
node.custom_minimum_size = Vector2.ZERO
|
||||
node.custom_minimum_size.x = 0
|
||||
else:
|
||||
# regular controls
|
||||
SizingUtils.apply_regular_control_sizing(node, width, height, styles)
|
||||
node.custom_minimum_size.x = width
|
||||
node.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
|
||||
|
||||
if height != null:
|
||||
if height is String and height == "100%":
|
||||
node.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
||||
node.custom_minimum_size.y = 0
|
||||
else:
|
||||
node.custom_minimum_size.y = height
|
||||
node.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
|
||||
|
||||
apply_element_centering(node, styles)
|
||||
|
||||
@@ -539,7 +508,7 @@ static func apply_body_styles(body: HTMLParser.HTMLElement, parser: HTMLParser,
|
||||
original_parent.move_child(margin_container, container_index)
|
||||
margin_container.add_child(website_container)
|
||||
|
||||
var padding_val = parse_size(styles["padding"])
|
||||
var padding_val = parse_size(styles["padding"] if styles.has("padding") else 0)
|
||||
|
||||
margin_container.add_theme_constant_override("margin_left", padding_val)
|
||||
margin_container.add_theme_constant_override("margin_right", padding_val)
|
||||
|
||||
@@ -61,7 +61,7 @@ static func apply_flex_container_properties(node, styles: Dictionary) -> void:
|
||||
|
||||
if styles.has("width"):
|
||||
var width_val = styles["width"]
|
||||
if width_val == "full":
|
||||
if width_val == "full" or width_val == "100%":
|
||||
# For flex containers, w-full should expand to fill parent
|
||||
node.set_meta("should_fill_horizontal", true)
|
||||
elif typeof(width_val) == TYPE_STRING and width_val.ends_with("%"):
|
||||
@@ -79,6 +79,7 @@ static func apply_flex_container_properties(node, styles: Dictionary) -> void:
|
||||
node.set_meta("custom_css_height", SizingUtils.parse_size_value(height_val))
|
||||
if styles.has("background-color"):
|
||||
node.set_meta("custom_css_background_color", styles["background-color"])
|
||||
|
||||
node.update_layout()
|
||||
|
||||
static func apply_flex_item_properties(node: Control, styles: Dictionary) -> void:
|
||||
|
||||
@@ -290,6 +290,84 @@ static func render_new_element(element: HTMLParser.HTMLElement, parent_node: Nod
|
||||
|
||||
main_scene.safe_add_child(container_node, element_node)
|
||||
|
||||
static func _get_input_value(element: HTMLParser.HTMLElement, dom_node: Node) -> Variant:
|
||||
var input_type = element.get_attribute("type").to_lower()
|
||||
|
||||
match input_type:
|
||||
"checkbox", "radio":
|
||||
if dom_node is CheckBox:
|
||||
return dom_node.button_pressed
|
||||
return false
|
||||
"color":
|
||||
if dom_node is ColorPickerButton:
|
||||
return "#" + dom_node.color.to_html(false)
|
||||
return "#ffffff"
|
||||
"range":
|
||||
if dom_node is HSlider:
|
||||
return dom_node.value
|
||||
return 0.0
|
||||
"number":
|
||||
if dom_node is SpinBox:
|
||||
return dom_node.value
|
||||
return 0.0
|
||||
"file":
|
||||
# For file inputs, need to find the input control that has get_file_info method
|
||||
var input_control = _find_input_control_with_file_info(dom_node)
|
||||
if input_control:
|
||||
var file_info = input_control.get_file_info()
|
||||
return file_info.get("fileName", "")
|
||||
return ""
|
||||
"date":
|
||||
if dom_node is DateButton:
|
||||
if dom_node.has_method("get_date_text"):
|
||||
return dom_node.get_date_text()
|
||||
return ""
|
||||
_: # text, password, email, etc.
|
||||
if dom_node is LineEdit:
|
||||
return dom_node.text
|
||||
elif dom_node is TextEdit:
|
||||
return dom_node.text
|
||||
return ""
|
||||
|
||||
static func _find_input_control_with_file_info(node: Node) -> Node:
|
||||
if node and node.has_method("get_file_info"):
|
||||
return node
|
||||
|
||||
var current = node
|
||||
while current:
|
||||
current = current.get_parent()
|
||||
if current and current.has_method("get_file_info"):
|
||||
return current
|
||||
|
||||
return null
|
||||
|
||||
static func _set_input_value(element: HTMLParser.HTMLElement, dom_node: Node, value: Variant) -> void:
|
||||
var input_type = element.get_attribute("type").to_lower()
|
||||
|
||||
match input_type:
|
||||
"checkbox", "radio":
|
||||
if dom_node is CheckBox:
|
||||
dom_node.button_pressed = bool(value)
|
||||
"color":
|
||||
if dom_node is ColorPickerButton:
|
||||
var color_value = str(value)
|
||||
if color_value.begins_with("#"):
|
||||
dom_node.color = Color.from_string(color_value, Color.WHITE)
|
||||
"range":
|
||||
if dom_node is HSlider:
|
||||
dom_node.value = float(value)
|
||||
"number":
|
||||
if dom_node is SpinBox:
|
||||
dom_node.value = float(value)
|
||||
"date":
|
||||
if dom_node is DateButton and dom_node.has_method("set_date_from_string"):
|
||||
dom_node.set_date_from_string(str(value))
|
||||
_: # text, password, email, etc.
|
||||
if dom_node is LineEdit:
|
||||
dom_node.text = str(value)
|
||||
elif dom_node is TextEdit:
|
||||
dom_node.text = str(value)
|
||||
|
||||
# Helper functions
|
||||
static func find_element_by_id(element_id: String, dom_parser: HTMLParser) -> HTMLParser.HTMLElement:
|
||||
if element_id == "body":
|
||||
@@ -852,6 +930,23 @@ static func _element_index_wrapper(vm: LuauVM) -> int:
|
||||
return LuaAudioUtils.handle_dom_audio_index(vm, element_id, key)
|
||||
|
||||
match key:
|
||||
"value":
|
||||
if lua_api and tag_name == "input":
|
||||
vm.lua_getfield(1, "_element_id")
|
||||
var element_id: String = vm.lua_tostring(-1)
|
||||
vm.lua_pop(1)
|
||||
|
||||
var element = lua_api.dom_parser.find_by_id(element_id) if element_id != "body" else lua_api.dom_parser.find_first("body")
|
||||
var dom_node = lua_api.dom_parser.parse_result.dom_nodes.get(element_id, null)
|
||||
|
||||
if element and dom_node:
|
||||
var input_value = _get_input_value(element, dom_node)
|
||||
vm.lua_pushstring(str(input_value))
|
||||
return 1
|
||||
|
||||
# Fallback to empty string
|
||||
vm.lua_pushstring("")
|
||||
return 1
|
||||
"text":
|
||||
if lua_api:
|
||||
# Get element ID and find the element
|
||||
@@ -929,12 +1024,10 @@ static func _element_index_wrapper(vm: LuauVM) -> int:
|
||||
return 1
|
||||
|
||||
static func _add_classlist_support(vm: LuauVM, lua_api: LuaAPI) -> void:
|
||||
# Create classList table with threaded methods
|
||||
vm.lua_newtable()
|
||||
|
||||
# Store the element_id in the classList table
|
||||
vm.lua_getfield(-2, "_element_id") # Get element_id from parent element
|
||||
vm.lua_setfield(-2, "_element_id") # Store it in classList table
|
||||
vm.lua_getfield(-2, "_element_id")
|
||||
vm.lua_setfield(-2, "_element_id")
|
||||
|
||||
# Add classList methods
|
||||
vm.lua_pushcallable(LuaDOMUtils._classlist_add_wrapper, "classList.add")
|
||||
@@ -961,12 +1054,11 @@ static func _add_classlist_support(vm: LuauVM, lua_api: LuaAPI) -> void:
|
||||
vm.lua_setfield(-2, "classList")
|
||||
|
||||
static func _classlist_add_wrapper(vm: LuauVM) -> int:
|
||||
# Get lua_api from VM metadata
|
||||
var lua_api = vm.get_meta("lua_api") as LuaAPI
|
||||
if not lua_api:
|
||||
return 0
|
||||
|
||||
vm.luaL_checktype(1, vm.LUA_TTABLE) # classList table
|
||||
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||
var cls: String = vm.luaL_checkstring(2)
|
||||
|
||||
# Get element_id from classList table
|
||||
@@ -1132,6 +1224,21 @@ static func _element_newindex_wrapper(vm: LuauVM) -> int:
|
||||
return LuaAudioUtils.handle_dom_audio_newindex(vm, element_id, key, value)
|
||||
|
||||
match key:
|
||||
"value":
|
||||
if tag_name == "input":
|
||||
vm.lua_getfield(1, "_element_id")
|
||||
var element_id: String = vm.lua_tostring(-1)
|
||||
vm.lua_pop(1)
|
||||
|
||||
var element = lua_api.dom_parser.find_by_id(element_id) if element_id != "body" else lua_api.dom_parser.find_first("body")
|
||||
var dom_node = lua_api.dom_parser.parse_result.dom_nodes.get(element_id, null)
|
||||
|
||||
if element and dom_node:
|
||||
# Update the HTML element's value attribute
|
||||
element.set_attribute("value", str(value))
|
||||
|
||||
_set_input_value(element, dom_node, value)
|
||||
return 0
|
||||
"text":
|
||||
var text: String = str(value) # Convert value to string
|
||||
|
||||
|
||||
@@ -53,18 +53,6 @@ func _ready():
|
||||
ProjectSettings.set_setting("display/window/size/min_width", MIN_SIZE.x)
|
||||
ProjectSettings.set_setting("display/window/size/min_height", MIN_SIZE.y)
|
||||
DisplayServer.window_set_min_size(MIN_SIZE)
|
||||
|
||||
get_viewport().size_changed.connect(_on_viewport_size_changed)
|
||||
|
||||
func _on_viewport_size_changed():
|
||||
recalculate_percentage_elements(website_container)
|
||||
|
||||
func recalculate_percentage_elements(node: Node):
|
||||
if node is Control and node.has_meta("needs_percentage_recalc"):
|
||||
SizingUtils.apply_container_percentage_sizing(node)
|
||||
|
||||
for child in node.get_children():
|
||||
recalculate_percentage_elements(child)
|
||||
|
||||
var current_domain = "" # Store current domain for display
|
||||
|
||||
@@ -267,9 +255,6 @@ static func safe_add_child(parent: Node, child: Node) -> void:
|
||||
child.get_parent().remove_child(child)
|
||||
parent.add_child(child)
|
||||
|
||||
if child.has_meta("container_percentage_width") or child.has_meta("container_percentage_height"):
|
||||
SizingUtils.apply_container_percentage_sizing(child)
|
||||
child.set_meta("needs_percentage_recalc", true)
|
||||
|
||||
func contains_hyperlink(element: HTMLParser.HTMLElement) -> bool:
|
||||
if element.tag_name == "a":
|
||||
@@ -290,6 +275,7 @@ func is_text_only_element(element: HTMLParser.HTMLElement) -> bool:
|
||||
|
||||
func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser) -> Control:
|
||||
var styles = parser.get_element_styles_with_inheritance(element, "", [])
|
||||
var hover_styles = parser.get_element_styles_with_inheritance(element, "hover", [])
|
||||
var is_flex_container = styles.has("display") and ("flex" in styles["display"])
|
||||
|
||||
var final_node: Control
|
||||
@@ -308,10 +294,22 @@ func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser) ->
|
||||
|
||||
if is_flex_container:
|
||||
# The element's primary identity IS a flex container.
|
||||
# We create it directly.
|
||||
final_node = AUTO_SIZING_FLEX_CONTAINER.new()
|
||||
final_node.name = "Flex_" + element.tag_name
|
||||
container_for_children = final_node
|
||||
if element.tag_name == "div":
|
||||
if BackgroundUtils.needs_background_wrapper(styles) or hover_styles.size() > 0:
|
||||
final_node = BackgroundUtils.create_panel_container_with_background(styles, hover_styles)
|
||||
var flex_container = AUTO_SIZING_FLEX_CONTAINER.new()
|
||||
flex_container.name = "Flex_" + element.tag_name
|
||||
var vbox = final_node.get_child(0) as VBoxContainer
|
||||
vbox.add_child(flex_container)
|
||||
container_for_children = flex_container
|
||||
else:
|
||||
final_node = AUTO_SIZING_FLEX_CONTAINER.new()
|
||||
final_node.name = "Flex_" + element.tag_name
|
||||
container_for_children = final_node
|
||||
else:
|
||||
final_node = AUTO_SIZING_FLEX_CONTAINER.new()
|
||||
final_node.name = "Flex_" + element.tag_name
|
||||
container_for_children = final_node
|
||||
|
||||
# For FLEX ul/ol elements, we need to create the li children directly in the flex container
|
||||
if element.tag_name == "ul" or element.tag_name == "ol":
|
||||
@@ -353,11 +351,20 @@ func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser) ->
|
||||
# Apply flex CONTAINER properties if it's a flex container
|
||||
if is_flex_container:
|
||||
var flex_container_node = final_node
|
||||
# If the node was wrapped in a MarginContainer, get the inner FlexContainer
|
||||
if final_node is MarginContainer and final_node.get_child_count() > 0:
|
||||
|
||||
if final_node is FlexContainer:
|
||||
# Direct FlexContainer
|
||||
flex_container_node = final_node
|
||||
elif final_node is MarginContainer and final_node.get_child_count() > 0:
|
||||
var first_child = final_node.get_child(0)
|
||||
if first_child is FlexContainer:
|
||||
flex_container_node = first_child
|
||||
elif final_node is PanelContainer and final_node.get_child_count() > 0:
|
||||
var vbox = final_node.get_child(0)
|
||||
if vbox is VBoxContainer and vbox.get_child_count() > 0:
|
||||
var potential_flex = vbox.get_child(0)
|
||||
if potential_flex is FlexContainer:
|
||||
flex_container_node = potential_flex
|
||||
|
||||
if flex_container_node is FlexContainer:
|
||||
FlexUtils.apply_flex_container_properties(flex_container_node, styles)
|
||||
@@ -476,7 +483,7 @@ func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLP
|
||||
var hover_styles = parser.get_element_styles_with_inheritance(element, "hover", [])
|
||||
var is_flex_container = styles.has("display") and ("flex" in styles["display"])
|
||||
|
||||
# For flex divs, don't create div scene - the AutoSizingFlexContainer handles it
|
||||
# For flex divs, let the general flex container logic handle them
|
||||
if is_flex_container:
|
||||
return null
|
||||
|
||||
|
||||
Reference in New Issue
Block a user