getAttribute, setAttribute

This commit is contained in:
Face
2025-08-05 18:35:13 +03:00
parent ba2f49559e
commit 92b7976256
11 changed files with 283 additions and 21 deletions

View File

@@ -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)

View File

@@ -590,7 +590,7 @@ var HTML_CONTENT3 = """<head>
</body>
""".to_utf8_buffer()
var HTML_CONTENT = """
var HTML_CONTENTvvv = """
<head>
<title>Lua API Demo</title>
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
@@ -796,3 +796,189 @@ var HTML_CONTENT_ADD_REMOVE = """<head>
</ul>
</body>
""".to_utf8_buffer()
var HTML_CONTENT = """<head>
<title>Button getAttribute/setAttribute Demo</title>
<icon src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/cf/Lua-Logo.svg/256px-Lua-Logo.svg.png">
<meta name="theme-color" content="#3b82f6">
<meta name="description" content="Demonstrating getAttribute and setAttribute with button controls">
<style>
body { bg-[#f8fafc] p-6 }
h1 { text-[#3b82f6] text-3xl font-bold text-center }
h2 { text-[#1e40af] text-xl font-semibold }
.container { bg-[#ffffff] p-6 rounded-lg shadow-lg max-w-4xl mx-auto }
.button-group { flex gap-3 justify-center items-center flex-wrap }
.control-button { px-4 py-2 rounded-lg font-medium cursor-pointer transition-colors }
.enable-btn { bg-[#10b981] text-white hover:bg-[#059669] }
.disable-btn { bg-[#ef4444] text-white hover:bg-[#dc2626] }
.toggle-btn { bg-[#8b5cf6] text-white hover:bg-[#7c3aed] }
.status-btn { bg-[#6b7280] text-white hover:bg-[#4b5563] }
.demo-buttons { bg-[#f1f5f9] p-4 rounded-lg }
.status-display { bg-[#e0e7ff] p-3 rounded-md text-[#3730a3] font-mono }
.info-box { bg-[#fef3c7] border border-[#f59e0b] p-4 rounded-lg }
.target-button { bg-[#3b82f6] text-white px-6 py-3 rounded-lg font-semibold hover:bg-[#2563eb] }
.target-button[disabled] { bg-[#9ca3af] text-[#6b7280] cursor-not-allowed }
</style>
<script>
local targetButton = gurt.select('#target-button')
local enableBtn = gurt.select('#enable-btn')
local disableBtn = gurt.select('#disable-btn')
local toggleBtn = gurt.select('#toggle-btn')
local statusBtn = gurt.select('#status-btn')
local statusDisplay = gurt.select('#status-display')
local infoBox = gurt.select('#info-box')
local clickCounter = gurt.select('#click-counter')
gurt.log('Button attribute demo script started.')
local clickCount = 0
-- Function to update the status display
local function updateStatus()
local disabled = targetButton:getAttribute('disabled')
local type = targetButton:getAttribute('type')
local style = targetButton:getAttribute('style')
local id = targetButton:getAttribute('id')
local dataValue = targetButton:getAttribute('data-value')
local status = 'Status: ' .. (disabled and 'DISABLED' or 'ENABLED') .. '\\n'
status = status .. 'Type: ' .. (type or 'button') .. '\\n'
status = status .. 'ID: ' .. (id or 'none') .. '\\n'
status = status .. 'Data Value: ' .. (dataValue or 'none') .. '\\n'
status = status .. 'Click Count: ' .. clickCount
statusDisplay.text = status
-- Update info box with current state
if disabled then
infoBox.text = '🔒 Target button is currently DISABLED. It cannot be clicked and appears grayed out.'
else
infoBox.text = '✅ Target button is currently ENABLED. Click it to see the counter increase!'
end
end
-- Target button click handler
targetButton:on('click', function()
clickCount = clickCount + 1
clickCounter.text = 'Button clicked ' .. clickCount .. ' times!'
gurt.log('Target button clicked! Count:', clickCount)
updateStatus()
end)
-- Enable button functionality
enableBtn:on('click', function()
targetButton:setAttribute('disabled', '') -- Remove disabled attribute
targetButton:setAttribute('data-value', 'enabled')
gurt.log('Target button enabled via setAttribute')
updateStatus()
end)
-- Disable button functionality
disableBtn:on('click', function()
targetButton:setAttribute('disabled', 'true')
targetButton:setAttribute('data-value', 'disabled')
gurt.log('Target button disabled via setAttribute')
updateStatus()
end)
-- Toggle button functionality
toggleBtn:on('click', function()
local currentlyDisabled = targetButton:getAttribute('disabled')
if currentlyDisabled then
-- Currently disabled, so enable it
targetButton:setAttribute('disabled', '')
targetButton:setAttribute('data-value', 'toggled-enabled')
gurt.log('Target button toggled to enabled state')
else
-- Currently enabled, so disable it
targetButton:setAttribute('disabled', 'true')
targetButton:setAttribute('data-value', 'toggled-disabled')
gurt.log('Target button toggled to disabled state')
end
updateStatus()
end)
-- Status check button
statusBtn:on('click', function()
local disabled = targetButton:getAttribute('disabled')
local type = targetButton:getAttribute('type')
local dataValue = targetButton:getAttribute('data-value')
gurt.log('=== BUTTON STATUS CHECK ===')
gurt.log('Disabled attribute:', disabled or 'not set')
gurt.log('Type attribute:', type or 'not set')
gurt.log('Data-value attribute:', dataValue or 'not set')
gurt.log('Click count:', clickCount)
gurt.log('===========================')
-- Demonstrate style setAttribute
local randomColors = {'bg-red-500', 'bg-green-500', 'bg-purple-500', 'bg-orange-500', 'bg-pink-500'}
local randomColor = randomColors[math.random(1, #randomColors)]
if not disabled then
targetButton:setAttribute('style', 'target-button ' .. randomColor .. ' text-white px-6 py-3 rounded-lg font-semibold hover:opacity-75')
gurt.setTimeout(function()
targetButton:setAttribute('style', 'target-button bg-[#3b82f6] text-white px-6 py-3 rounded-lg font-semibold hover:bg-[#2563eb]')
end, 1000)
end
end)
-- Initialize status display
updateStatus()
-- Set initial attributes to demonstrate the methods
targetButton:setAttribute('type', 'button')
targetButton:setAttribute('data-value', 'initial')
-- Update status after setting initial attributes
gurt.setTimeout(function()
updateStatus()
end, 100)
</script>
</head>
<body>
<h1>🔘 Button getAttribute & setAttribute Demo</h1>
<div style="container mt-6">
<div style="info-box mb-6">
<p id="info-box">✅ Target button is currently ENABLED. Click it to see the counter increase!</p>
</div>
<h2>Target Button</h2>
<div style="demo-buttons mb-6 text-center">
<button id="target-button" style="target-button">🎯 Click Me!</button>
<p id="click-counter" style="mt-3 text-lg font-semibold text-[#374151]">Button clicked 0 times!</p>
</div>
<h2>Control Buttons</h2>
<div style="button-group mb-6">
<button id="enable-btn" style="control-button enable-btn">🟢 Enable Button</button>
<button id="disable-btn" style="control-button disable-btn">🔴 Disable Button</button>
<button id="toggle-btn" style="control-button toggle-btn">🔄 Toggle State</button>
<button id="status-btn" style="control-button status-btn">📊 Check Status</button>
</div>
<h2>Current Attributes</h2>
<div style="status-display mb-6">
<pre id="status-display">Loading status...</pre>
</div>
<div style="bg-[#e0f2fe] p-4 rounded-lg">
<h3 style="text-[#0277bd] font-semibold mb-2">How It Works:</h3>
<ul style="text-[#01579b] space-y-1">
<li><strong>Enable:</strong> Uses <code>setAttribute('disabled', '')</code> to remove the disabled attribute</li>
<li><strong>Disable:</strong> Uses <code>setAttribute('disabled', 'true')</code> to add the disabled attribute</li>
<li><strong>Toggle:</strong> Uses <code>getAttribute('disabled')</code> to check current state, then toggles it</li>
<li><strong>Status:</strong> Uses <code>getAttribute()</code> to read multiple attributes and displays them</li>
<li><strong>Bonus:</strong> Also demonstrates setting custom data attributes and style changes</li>
</ul>
</div>
</div>
</body>
""".to_utf8_buffer()

View File

@@ -1,4 +1,4 @@
extends Control
func init(_element: HTMLParser.HTMLElement) -> void:
func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void:
pass

View File

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

View File

@@ -1,5 +1,5 @@
class_name HTMLDiv
extends VBoxContainer
func init(_element: HTMLParser.HTMLElement):
func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null):
pass

View File

@@ -1,4 +1,4 @@
extends VBoxContainer
func init(_element: HTMLParser.HTMLElement) -> void:
func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void:
pass

View File

@@ -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 <img/> tag without \"src\" attribute.")

View File

@@ -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():

View File

@@ -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

View File

@@ -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":

View File

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