diff --git a/flumi/Scripts/B9/Lua.gd b/flumi/Scripts/B9/Lua.gd index ee11acd..0b9e210 100644 --- a/flumi/Scripts/B9/Lua.gd +++ b/flumi/Scripts/B9/Lua.gd @@ -154,6 +154,12 @@ func add_element_methods(vm: LuauVM, index: String = "element") -> void: vm.lua_pushcallable(_element_remove_handler, index + ".remove") vm.lua_setfield(-2, "remove") + vm.lua_pushcallable(_element_get_attribute_handler, index + ".getAttribute") + vm.lua_setfield(-2, "getAttribute") + + vm.lua_pushcallable(_element_set_attribute_handler, index + ".setAttribute") + vm.lua_setfield(-2, "setAttribute") + # Create metatable for property access vm.lua_newtable() # metatable @@ -352,6 +358,67 @@ func _element_remove_handler(vm: LuauVM) -> int: return 0 +# getAttribute() function to get element attribute +func _element_get_attribute_handler(vm: LuauVM) -> int: + vm.luaL_checktype(1, vm.LUA_TTABLE) + var attribute_name: String = vm.luaL_checkstring(2) + + vm.lua_getfield(1, "_element_id") + var element_id: String = vm.lua_tostring(-1) + vm.lua_pop(1) + + # Find the element + var element: HTMLParser.HTMLElement = null + if element_id == "body": + element = dom_parser.find_first("body") + else: + element = dom_parser.find_by_id(element_id) + + if not element: + vm.lua_pushnil() + return 1 + + # Get the attribute value + var attribute_value = element.get_attribute(attribute_name) + if attribute_value.is_empty(): + vm.lua_pushnil() + else: + vm.lua_pushstring(attribute_value) + + return 1 + +# setAttribute() function to set element attribute +func _element_set_attribute_handler(vm: LuauVM) -> int: + vm.luaL_checktype(1, vm.LUA_TTABLE) + var attribute_name: String = vm.luaL_checkstring(2) + var attribute_value: String = vm.luaL_checkstring(3) + + vm.lua_getfield(1, "_element_id") + var element_id: String = vm.lua_tostring(-1) + vm.lua_pop(1) + + # Find the element + var element: HTMLParser.HTMLElement = null + if element_id == "body": + element = dom_parser.find_first("body") + else: + element = dom_parser.find_by_id(element_id) + + if not element: + return 0 + + if attribute_value == "": + element.attributes.erase(attribute_name) + else: + element.set_attribute(attribute_name, attribute_value) + + # Trigger visual update by calling init() again + var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null) + if dom_node and dom_node.has_method("init"): + dom_node.init(element, dom_parser) + + return 0 + func _element_classlist_add_wrapper(vm: LuauVM) -> int: return LuaClassListUtils.element_classlist_add_handler(vm, dom_parser) diff --git a/flumi/Scripts/Constants.gd b/flumi/Scripts/Constants.gd index dce64bd..67f6d3e 100644 --- a/flumi/Scripts/Constants.gd +++ b/flumi/Scripts/Constants.gd @@ -590,7 +590,7 @@ var HTML_CONTENT3 = """ """.to_utf8_buffer() -var HTML_CONTENT = """ +var HTML_CONTENTvvv = """ Lua API Demo @@ -796,3 +796,189 @@ var HTML_CONTENT_ADD_REMOVE = """ """.to_utf8_buffer() + +var HTML_CONTENT = """ + Button getAttribute/setAttribute Demo + + + + + + + + + + +

🔘 Button getAttribute & setAttribute Demo

+ +
+
+

✅ Target button is currently ENABLED. Click it to see the counter increase!

+
+ +

Target Button

+
+ +

Button clicked 0 times!

+
+ +

Control Buttons

+
+ + + + +
+ +

Current Attributes

+
+
Loading status...
+
+ +
+

How It Works:

+
    +
  • Enable: Uses setAttribute('disabled', '') to remove the disabled attribute
  • +
  • Disable: Uses setAttribute('disabled', 'true') to add the disabled attribute
  • +
  • Toggle: Uses getAttribute('disabled') to check current state, then toggles it
  • +
  • Status: Uses getAttribute() to read multiple attributes and displays them
  • +
  • Bonus: Also demonstrates setting custom data attributes and style changes
  • +
+
+
+ +""".to_utf8_buffer() diff --git a/flumi/Scripts/Tags/br.gd b/flumi/Scripts/Tags/br.gd index d590451..80b5b27 100644 --- a/flumi/Scripts/Tags/br.gd +++ b/flumi/Scripts/Tags/br.gd @@ -1,4 +1,4 @@ extends Control -func init(_element: HTMLParser.HTMLElement) -> void: +func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void: pass diff --git a/flumi/Scripts/Tags/button.gd b/flumi/Scripts/Tags/button.gd index eab12b4..3245d27 100644 --- a/flumi/Scripts/Tags/button.gd +++ b/flumi/Scripts/Tags/button.gd @@ -8,8 +8,7 @@ func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void: current_element = element current_parser = parser var button_node: Button = $ButtonNode - if element.has_attribute("disabled"): - button_node.disabled = true + button_node.disabled = element.has_attribute("disabled") var button_text = element.text_content.strip_edges() if button_text.length() == 0: diff --git a/flumi/Scripts/Tags/div.gd b/flumi/Scripts/Tags/div.gd index bd8a823..1455830 100644 --- a/flumi/Scripts/Tags/div.gd +++ b/flumi/Scripts/Tags/div.gd @@ -1,5 +1,5 @@ class_name HTMLDiv extends VBoxContainer -func init(_element: HTMLParser.HTMLElement): +func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null): pass diff --git a/flumi/Scripts/Tags/form.gd b/flumi/Scripts/Tags/form.gd index fd81a25..4c888c9 100644 --- a/flumi/Scripts/Tags/form.gd +++ b/flumi/Scripts/Tags/form.gd @@ -1,4 +1,4 @@ extends VBoxContainer -func init(_element: HTMLParser.HTMLElement) -> void: +func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void: pass diff --git a/flumi/Scripts/Tags/img.gd b/flumi/Scripts/Tags/img.gd index f89b735..4375b22 100644 --- a/flumi/Scripts/Tags/img.gd +++ b/flumi/Scripts/Tags/img.gd @@ -1,6 +1,6 @@ extends TextureRect -func init(element: HTMLParser.HTMLElement) -> void: +func init(element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void: var src = element.get_attribute("src") if !src: return print("Ignoring tag without \"src\" attribute.") diff --git a/flumi/Scripts/Tags/input.gd b/flumi/Scripts/Tags/input.gd index 70c25e3..8ba7a18 100644 --- a/flumi/Scripts/Tags/input.gd +++ b/flumi/Scripts/Tags/input.gd @@ -128,6 +128,12 @@ func init(element: HTMLParser.HTMLElement, parser: HTMLParser = null) -> void: setup_text_input(line_edit, placeholder, value, minlength, maxlength, pattern) apply_input_styles(element, parser) + + # Handle disabled and readonly attributes + if element.has_attribute("disabled"): + active_child.set("disabled", true) + if element.has_attribute("readonly") and active_child.has_method("set_editable"): + active_child.set_editable(false) func remove_unused_children(keep_child_name: String) -> void: for child in get_children(): diff --git a/flumi/Scripts/Tags/select.gd b/flumi/Scripts/Tags/select.gd index 86afae7..5d8a6fb 100644 --- a/flumi/Scripts/Tags/select.gd +++ b/flumi/Scripts/Tags/select.gd @@ -2,7 +2,7 @@ extends Control const BROWSER_TEXT = preload("res://Scenes/Styles/BrowserText.tres") -func init(element: HTMLParser.HTMLElement) -> void: +func init(element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void: var option_button: OptionButton = $OptionButton var selected_index = -1 @@ -20,14 +20,11 @@ func init(element: HTMLParser.HTMLElement) -> void: option_button.set_item_metadata(option_index, option_value) # Check if this option is selected - var is_selected = child_element.get_attribute("selected") - if is_selected.length() > 0 and selected_index == -1: + if child_element.has_attribute("selected") and selected_index == -1: selected_index = option_index # Check if this option is disabled - var is_disabled = child_element.get_attribute("disabled") - if is_disabled.length() > 0: - option_button.set_item_disabled(option_index, true) + option_button.set_item_disabled(option_index, child_element.has_attribute("disabled")) option_index += 1 diff --git a/flumi/Scripts/Tags/separator.gd b/flumi/Scripts/Tags/separator.gd index b2da732..1d9c2d0 100644 --- a/flumi/Scripts/Tags/separator.gd +++ b/flumi/Scripts/Tags/separator.gd @@ -2,7 +2,7 @@ extends Control var separator_node: Separator -func init(element: HTMLParser.HTMLElement) -> void: +func init(element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void: var direction = element.get_attribute("direction") if direction == "vertical": diff --git a/flumi/Scripts/Tags/textarea.gd b/flumi/Scripts/Tags/textarea.gd index 210aed4..3091860 100644 --- a/flumi/Scripts/Tags/textarea.gd +++ b/flumi/Scripts/Tags/textarea.gd @@ -2,7 +2,7 @@ extends Control const BROWSER_TEXT = preload("res://Scenes/Styles/BrowserText.tres") -func init(element: HTMLParser.HTMLElement) -> void: +func init(element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void: var text_edit: TextEdit = $TextEdit var placeholder = element.get_attribute("placeholder") @@ -37,12 +37,7 @@ func init(element: HTMLParser.HTMLElement) -> void: # Sync Control size with TextEdit custom_minimum_size = text_edit.custom_minimum_size - # Set readonly state - if readonly.length() > 0: - text_edit.editable = false - - # Set disabled state - if disabled.length() > 0: + if element.has_attribute("disabled"): text_edit.editable = false var stylebox = StyleBoxFlat.new() stylebox.bg_color = Color(0.8, 0.8, 0.8, 1.0) @@ -58,10 +53,22 @@ func init(element: HTMLParser.HTMLElement) -> void: text_edit.add_theme_stylebox_override("normal", stylebox) text_edit.add_theme_stylebox_override("focus", stylebox) text_edit.add_theme_stylebox_override("readonly", stylebox) + else: + text_edit.remove_theme_stylebox_override("normal") + text_edit.remove_theme_stylebox_override("focus") + text_edit.remove_theme_stylebox_override("readonly") + + if element.has_attribute("readonly"): + text_edit.editable = false + else: + text_edit.editable = true # Handle maxlength if maxlength.length() > 0 and maxlength.is_valid_int(): var max_len = maxlength.to_int() + # Disconnect existing signal if connected to prevent duplicates + if text_edit.text_changed.is_connected(_on_text_changed): + text_edit.text_changed.disconnect(_on_text_changed) text_edit.text_changed.connect(_on_text_changed.bind(max_len)) func _on_text_changed(max_length: int) -> void: