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
+
+
+
+
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: