getAttribute, setAttribute
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
extends Control
|
||||
|
||||
func init(_element: HTMLParser.HTMLElement) -> void:
|
||||
func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void:
|
||||
pass
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
class_name HTMLDiv
|
||||
extends VBoxContainer
|
||||
|
||||
func init(_element: HTMLParser.HTMLElement):
|
||||
func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null):
|
||||
pass
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
extends VBoxContainer
|
||||
|
||||
func init(_element: HTMLParser.HTMLElement) -> void:
|
||||
func init(_element: HTMLParser.HTMLElement, _parser: HTMLParser = null) -> void:
|
||||
pass
|
||||
|
||||
@@ -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.")
|
||||
|
||||
|
||||
@@ -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():
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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":
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user