fix event reg on Lua added elements, add classList.contains, item and length

This commit is contained in:
Face
2025-08-19 09:47:58 +03:00
parent 1761b05899
commit dacda095d5
4 changed files with 143 additions and 5 deletions

View File

@@ -20,6 +20,7 @@ TODO:
11. **< table >** component. [🔗 Related Godot proposal](https://github.com/godotengine/godot-proposals/issues/97)
12. **< canvas >** component should be theoretically impossible by exposing Godot `_draw()` APIs to Lua.
13. `grid` display property for CSS, using `GridContainer` in Godot.
14. Position `absolute` can be achieved by wrapping inside a Control node with a 0,0 size (so it's ignored by the layout), and moving the inner child according to CSS.
Issues:
1. **< br />** counts as 1 element in **WebsiteContainer**, therefore despite being (0,0) in size, it counts as double in spacing

View File

@@ -8,6 +8,7 @@ local domainsList = gurt.select('#domains-list')
local tldSelector = gurt.select('#tld-selector')
local loadingElement = gurt.select('#tld-loading')
local displayElement = gurt.select('#invite-code-display')
local options
displayElement:hide()
@@ -49,18 +50,23 @@ local function renderTLDSelector()
['data-tld'] = tld
})
tldSelector:append(option)
option:on('click', function()
-- Clear previous selection
local options = gurt.selectAll('.tld-option')
if not options then
options = gurt.selectAll('.tld-option')
end
for j = 1, #options do
options[j].classList:remove('tld-selected')
if options[j].classList:contains('tld-selected') then
options[j].classList:remove('tld-selected')
end
end
-- Select this option
option.classList:add('tld-selected')
end)
tldSelector:append(option)
i = i + 1
end, 16)
end

View File

@@ -23,6 +23,7 @@ var next_callback_ref: int = 1
var element_id_counter: int = 1
var element_id_registry: Dictionary = {}
var pending_event_registrations: Array = []
func _init():
timeout_manager = LuaTimeoutManager.new()
@@ -729,6 +730,19 @@ func _register_event_on_main_thread(element_id: String, event_name: String, call
# This runs on the main thread - safe to access DOM nodes
var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null)
if not dom_node:
var pending_registration = {
"element_id": element_id,
"event_name": event_name,
"callback_ref": callback_ref,
"subscription_id": subscription_id if subscription_id != -1 else next_subscription_id
}
if subscription_id == -1:
next_subscription_id += 1
pending_event_registrations.append(pending_registration)
call_deferred("_process_pending_event_registrations")
return
# Use provided subscription_id or generate a new one
@@ -750,6 +764,29 @@ func _register_event_on_main_thread(element_id: String, event_name: String, call
var signal_node = get_dom_node(dom_node, "signal")
LuaEventUtils.connect_element_event(signal_node, event_name, subscription)
func _process_pending_event_registrations():
var i = 0
while i < pending_event_registrations.size():
var registration = pending_event_registrations[i]
var element_id = registration.element_id
var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null)
if dom_node:
pending_event_registrations.remove_at(i)
_register_event_on_main_thread(
registration.element_id,
registration.event_name,
registration.callback_ref,
registration.subscription_id
)
else:
i += 1
if pending_event_registrations.size() > 0:
call_deferred("_process_pending_event_registrations")
func _unsubscribe_event_on_main_thread(subscription_id: int):
# This runs on the main thread - safe to cleanup event subscriptions
var subscription = event_subscriptions.get(subscription_id, null)

View File

@@ -268,6 +268,8 @@ static func render_new_element(element: HTMLParser.HTMLElement, parent_node: Nod
if not main_scene:
return
var element_id = element.get_attribute("id")
# Create the visual node for the element
var element_node = await main_scene.create_element_node(element, dom_parser)
if not element_node:
@@ -279,7 +281,6 @@ static func render_new_element(element: HTMLParser.HTMLElement, parent_node: Nod
# Register the DOM node
dom_parser.register_dom_node(element, element_node)
# Add to parent - handle body special case
var container_node = parent_node
if parent_node is MarginContainer and parent_node.get_child_count() > 0:
@@ -945,6 +946,17 @@ static func _add_classlist_support(vm: LuauVM, lua_api: LuaAPI) -> void:
vm.lua_pushcallable(LuaDOMUtils._classlist_toggle_wrapper, "classList.toggle")
vm.lua_setfield(-2, "toggle")
vm.lua_pushcallable(LuaDOMUtils._classlist_contains_wrapper, "classList.contains")
vm.lua_setfield(-2, "contains")
vm.lua_pushcallable(LuaDOMUtils._classlist_item_wrapper, "classList.item")
vm.lua_setfield(-2, "item")
vm.lua_newtable()
vm.lua_pushcallable(LuaDOMUtils._classlist_index_wrapper, "classList.__index")
vm.lua_setfield(-2, "__index")
vm.lua_setmetatable(-2)
# Set classList on the element
vm.lua_setfield(-2, "classList")
@@ -1017,6 +1029,88 @@ static func _classlist_toggle_wrapper(vm: LuauVM) -> int:
emit_dom_operation(lua_api, operation)
return 0
static func _classlist_contains_wrapper(vm: LuauVM) -> int:
var start_time = Time.get_ticks_msec()
var lua_api = vm.get_meta("lua_api") as LuaAPI
if not lua_api:
vm.lua_pushboolean(false)
return 1
vm.luaL_checktype(1, vm.LUA_TTABLE)
var cls: String = vm.luaL_checkstring(2)
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")
if element:
var current_style = element.get_attribute("style", "")
var style_classes = CSSParser.smart_split_utility_classes(current_style) if current_style.length() > 0 else []
var has_class = cls in style_classes
vm.lua_pushboolean(has_class)
return 1
vm.lua_pushboolean(false)
return 1
static func _classlist_item_wrapper(vm: LuauVM) -> int:
var lua_api = vm.get_meta("lua_api") as LuaAPI
if not lua_api:
vm.lua_pushnil()
return 1
vm.luaL_checktype(1, vm.LUA_TTABLE)
var index: int = vm.luaL_checkint(2) - 1 # Convert from 1-based to 0-based indexing
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")
if element:
var current_style = element.get_attribute("style", "")
var style_classes = CSSParser.smart_split_utility_classes(current_style) if current_style.length() > 0 else []
if index >= 0 and index < style_classes.size():
vm.lua_pushstring(style_classes[index])
return 1
vm.lua_pushnil()
return 1
static func _classlist_index_wrapper(vm: LuauVM) -> int:
vm.luaL_checktype(1, vm.LUA_TTABLE)
var key: String = vm.luaL_checkstring(2)
if key == "length":
var lua_api = vm.get_meta("lua_api") as LuaAPI
if not lua_api:
vm.lua_pushinteger(0)
return 1
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")
if element:
var current_style = element.get_attribute("style", "")
var style_classes = CSSParser.smart_split_utility_classes(current_style) if current_style.length() > 0 else []
vm.lua_pushinteger(style_classes.size())
return 1
vm.lua_pushinteger(0)
return 1
vm.lua_pushvalue(1)
vm.lua_pushstring(key)
vm.lua_rawget(-2)
vm.lua_remove(-2)
return 1
static func _element_newindex_wrapper(vm: LuauVM) -> int:
# Get lua_api from VM metadata
var lua_api = vm.get_meta("lua_api") as LuaAPI