diff --git a/flumi/Scripts/B9/Lua.gd b/flumi/Scripts/B9/Lua.gd index f4194bc..c8dc9b5 100644 --- a/flumi/Scripts/B9/Lua.gd +++ b/flumi/Scripts/B9/Lua.gd @@ -143,90 +143,107 @@ func _gurt_create_handler(vm: LuauVM) -> int: add_element_methods(vm) return 1 -func add_element_methods(vm: LuauVM) -> void: - vm.lua_pushcallable(_element_set_text_handler, "element.set_text") - vm.lua_setfield(-2, "set_text") - - vm.lua_pushcallable(_element_get_text_handler, "element.get_text") - vm.lua_setfield(-2, "get_text") - - vm.lua_pushcallable(_element_on_event_handler, "element.on") +func add_element_methods(vm: LuauVM, index: String = "element") -> void: + # Add methods directly to element table first + vm.lua_pushcallable(_element_on_event_handler, index + ".on") vm.lua_setfield(-2, "on") - vm.lua_pushcallable(_element_append_handler, "element.append") + vm.lua_pushcallable(_element_append_handler, index + ".append") vm.lua_setfield(-2, "append") - vm.lua_pushcallable(_element_remove_handler, "element.remove") + vm.lua_pushcallable(_element_remove_handler, index + ".remove") vm.lua_setfield(-2, "remove") - vm.lua_pushcallable(_element_get_children_handler, "element.get_children") - vm.lua_setfield(-2, "get_children") + # Create metatable for property access + vm.lua_newtable() # metatable + + # __index method for property getters + vm.lua_pushcallable(_element_index_handler, index + ".__index") + vm.lua_setfield(-2, "__index") + + # __newindex method for property setters + vm.lua_pushcallable(_element_newindex_handler, index + ".__newindex") + vm.lua_setfield(-2, "__newindex") + + # Set metatable on element table + vm.lua_setmetatable(-2) -func _element_get_children_handler(vm: LuauVM) -> int: +# Property access handlers +func _element_index_handler(vm: LuauVM) -> int: vm.luaL_checktype(1, vm.LUA_TTABLE) + var key: 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) - - vm.lua_newtable() - var index = 1 - - if element: - for child in element.children: - vm.lua_newtable() - vm.lua_pushstring(child.tag_name) - vm.lua_setfield(-2, "tag_name") - vm.lua_pushstring(child.get_text_content()) - vm.lua_setfield(-2, "text") + match key: + "text": + var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null) + var text = "" - vm.lua_rawseti(-2, index) - index += 1 - - return 1 + var text_node = get_dom_node(dom_node, "text") + if text_node: + if text_node.has_method("get_text"): + text = text_node.get_text() + else: + text = text_node.text + + vm.lua_pushstring(text) + return 1 + "children": + # 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) + + vm.lua_newtable() + var index = 1 + + if element: + for child in element.children: + vm.lua_newtable() + vm.lua_pushstring(child.tag_name) + vm.lua_setfield(-2, "tagName") + vm.lua_pushstring(child.get_text_content()) + vm.lua_setfield(-2, "text") + + vm.lua_rawseti(-2, index) + index += 1 + + return 1 + _: + # Fall back to checking the original table for methods + vm.lua_pushvalue(1) # Push the original table + vm.lua_pushstring(key) # Push the key + vm.lua_rawget(-2) # Get table[key] without triggering metamethods + vm.lua_remove(-2) # Remove the table, leaving just the result + return 1 -# Element manipulation handlers -func _element_set_text_handler(vm: LuauVM) -> int: +func _element_newindex_handler(vm: LuauVM) -> int: vm.luaL_checktype(1, vm.LUA_TTABLE) - var text: String = vm.luaL_checkstring(2) + var key: String = vm.luaL_checkstring(2) + var value = vm.lua_tovariant(3) vm.lua_getfield(1, "_element_id") var element_id: String = vm.lua_tostring(-1) vm.lua_pop(1) - var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null) - var text_node = get_dom_node(dom_node, "text") - if text_node: - text_node.text = text + match key: + "text": + var text: String = str(value) + var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null) + var text_node = get_dom_node(dom_node, "text") + if text_node: + text_node.text = text + _: + # Ignore unknown properties + pass + return 0 -func _element_get_text_handler(vm: LuauVM) -> int: - vm.luaL_checktype(1, vm.LUA_TTABLE) - - vm.lua_getfield(1, "_element_id") - var element_id: String = vm.lua_tostring(-1) - vm.lua_pop(1) - - var dom_node = dom_parser.parse_result.dom_nodes.get(element_id, null) - var text = "" - - var text_node = get_dom_node(dom_node, "text") - if text_node: - if text_node.has_method("get_text"): - text = text_node.get_text() - else: - text = text_node.text - - vm.lua_pushstring(text) - return 1 - # append() function to add a child element func _element_append_handler(vm: LuauVM) -> int: vm.luaL_checktype(1, vm.LUA_TTABLE) diff --git a/flumi/Scripts/Constants.gd b/flumi/Scripts/Constants.gd index c1477c0..27b017b 100644 --- a/flumi/Scripts/Constants.gd +++ b/flumi/Scripts/Constants.gd @@ -612,16 +612,16 @@ var HTML_CONTENT = """ gurt.log('Starting Lua script execution...') gurt.body:on('keypress', function(el) - typing:set_text(table.tostring(el)) + typing.text = table.tostring(el) end) gurt.body:on('mousemove', function(el) - mouse:set_text(table.tostring(el)) + mouse.text = table.tostring(el) end) -- Test element selection and manipulation local heading = gurt.select('#main-heading') - heading:set_text('Welcome to the New Web!') + heading.text = 'Welcome to the New Web!' local button = gurt.select('#demo-button') local event_log = gurt.select('#event-log') @@ -643,7 +643,7 @@ var HTML_CONTENT = """ end) button:on('mousemove', function(el) - btnmouse:set_text(table.tostring(el)) + btnmouse.text = table.tostring(el) end) if button and event_log then @@ -652,7 +652,7 @@ var HTML_CONTENT = """ local subscription = button:on('click', function() click_count = click_count + 1 local new_text = 'Button clicked ' .. click_count .. ' time(s)!' - event_log:set_text(new_text) + event_log.text = new_text end) heading:on('focusin', function() @@ -690,12 +690,12 @@ var HTML_CONTENT = """ }) gurt.body:append(temp_element) - local test = gurt.set_timeout(function() + local test = gurt.setTimeout(function() print('removed') temp_element:remove() end, 3000) - -- gurt.clear_timeout(test) + -- gurt.clearTimeout(test) @@ -748,7 +748,7 @@ var HTML_CONTENT_ADD_REMOVE = """ end) pop_button:on('click', function() - local items = list:get_children() + local items = list.children local last = items[#items] if last then last:remove() diff --git a/flumi/Scripts/Tags/BaseListContainer.gd b/flumi/Scripts/Tags/BaseListContainer.gd index d981dbb..59421c4 100644 --- a/flumi/Scripts/Tags/BaseListContainer.gd +++ b/flumi/Scripts/Tags/BaseListContainer.gd @@ -279,4 +279,4 @@ func get_marker_text(index: int) -> String: "none": return " " _: - return "•" \ No newline at end of file + return "•" diff --git a/flumi/Scripts/Utils/Lua/Function.gd b/flumi/Scripts/Utils/Lua/Function.gd index c9539df..c3bff96 100644 --- a/flumi/Scripts/Utils/Lua/Function.gd +++ b/flumi/Scripts/Utils/Lua/Function.gd @@ -35,17 +35,17 @@ static func setup_gurt_api(vm: LuauVM, lua_api, dom_parser: HTMLParser) -> void: vm.lua_pushcallable(lua_api._gurt_select_handler, "gurt.select") vm.lua_setfield(-2, "select") - vm.lua_pushcallable(lua_api._gurt_select_all_handler, "gurt.select_all") - vm.lua_setfield(-2, "select_all") + vm.lua_pushcallable(lua_api._gurt_select_all_handler, "gurt.selectAll") + vm.lua_setfield(-2, "selectAll") vm.lua_pushcallable(lua_api._gurt_create_handler, "gurt.create") vm.lua_setfield(-2, "create") - vm.lua_pushcallable(lua_api._gurt_set_timeout_handler, "gurt.set_timeout") - vm.lua_setfield(-2, "set_timeout") + vm.lua_pushcallable(lua_api._gurt_set_timeout_handler, "gurt.setTimeout") + vm.lua_setfield(-2, "setTimeout") - vm.lua_pushcallable(lua_api._gurt_clear_timeout_handler, "gurt.clear_timeout") - vm.lua_setfield(-2, "clear_timeout") + vm.lua_pushcallable(lua_api._gurt_clear_timeout_handler, "gurt.clearTimeout") + vm.lua_setfield(-2, "clearTimeout") # Add body element access var body_element = dom_parser.find_first("body") @@ -54,19 +54,11 @@ static func setup_gurt_api(vm: LuauVM, lua_api, dom_parser: HTMLParser) -> void: vm.lua_pushstring("body") vm.lua_setfield(-2, "_element_id") - # NOTE: same code as add_element_methods, but lazy to handle body.xxxx prop - vm.lua_pushcallable(lua_api._element_set_text_handler, "body.set_text") - vm.lua_setfield(-2, "set_text") - - vm.lua_pushcallable(lua_api._element_get_text_handler, "body.get_text") - vm.lua_setfield(-2, "get_text") + lua_api.add_element_methods(vm) vm.lua_pushcallable(lua_api._body_on_event_handler, "body.on") vm.lua_setfield(-2, "on") - vm.lua_pushcallable(lua_api._element_append_handler, "body.append") - vm.lua_setfield(-2, "append") - vm.lua_setfield(-2, "body") vm.lua_setglobal("gurt") diff --git a/flumi/Scripts/Utils/Lua/Timeout.gd b/flumi/Scripts/Utils/Lua/Timeout.gd index e708e57..7c413ad 100644 --- a/flumi/Scripts/Utils/Lua/Timeout.gd +++ b/flumi/Scripts/Utils/Lua/Timeout.gd @@ -3,7 +3,6 @@ extends RefCounted var active_timeouts: Dictionary = {} var next_timeout_id: int = 1 -var next_callback_ref: int = 1 class TimeoutInfo: var id: int @@ -25,12 +24,23 @@ func set_timeout_handler(vm: LuauVM, parent_node: Node) -> int: var timeout_id = next_timeout_id next_timeout_id += 1 - # Store the callback function in the registry + # Store callback in isolated registry table + vm.lua_pushstring("GURT_TIMEOUTS") + vm.lua_rawget(vm.LUA_REGISTRYINDEX) + if vm.lua_isnil(-1): + vm.lua_pop(1) + vm.lua_newtable() + vm.lua_pushstring("GURT_TIMEOUTS") + vm.lua_pushvalue(-2) + vm.lua_rawset(vm.LUA_REGISTRYINDEX) + + vm.lua_pushinteger(timeout_id) vm.lua_pushvalue(1) - var callback_ref = vm.luaL_ref(vm.LUA_REGISTRYINDEX) + vm.lua_rawset(-3) + vm.lua_pop(1) # Create timeout info - var timeout_info = TimeoutInfo.new(timeout_id, callback_ref, vm, self) + var timeout_info = TimeoutInfo.new(timeout_id, timeout_id, vm, self) # Create and configure timer var timer = Timer.new() @@ -45,7 +55,6 @@ func set_timeout_handler(vm: LuauVM, parent_node: Node) -> int: parent_node.add_child(timer) timer.start() - # Return timeout ID vm.lua_pushinteger(timeout_id) return 1 @@ -60,8 +69,13 @@ func clear_timeout_handler(vm: LuauVM) -> int: timeout_info.timer.queue_free() # Clean up callback reference - vm.lua_pushnil() - vm.lua_rawseti(vm.LUA_REGISTRYINDEX, timeout_info.callback_ref) + vm.lua_pushstring("GURT_TIMEOUTS") + vm.lua_rawget(vm.LUA_REGISTRYINDEX) + if not vm.lua_isnil(-1): + vm.lua_pushinteger(timeout_info.callback_ref) + vm.lua_pushnil() + vm.lua_rawset(-3) + vm.lua_pop(1) # Remove from active timeouts active_timeouts.erase(timeout_id) @@ -73,7 +87,12 @@ func _on_timeout_triggered(timeout_info: TimeoutInfo) -> void: return # Execute the callback - timeout_info.vm.lua_rawgeti(timeout_info.vm.LUA_REGISTRYINDEX, timeout_info.callback_ref) + timeout_info.vm.lua_pushstring("GURT_TIMEOUTS") + timeout_info.vm.lua_rawget(timeout_info.vm.LUA_REGISTRYINDEX) + timeout_info.vm.lua_pushinteger(timeout_info.callback_ref) + timeout_info.vm.lua_rawget(-2) + timeout_info.vm.lua_remove(-2) + if timeout_info.vm.lua_isfunction(-1): if timeout_info.vm.lua_pcall(0, 0, 0) != timeout_info.vm.LUA_OK: print("GURT ERROR in timeout callback: ", timeout_info.vm.lua_tostring(-1)) @@ -83,8 +102,13 @@ func _on_timeout_triggered(timeout_info: TimeoutInfo) -> void: # Clean up timeout timeout_info.timer.queue_free() - timeout_info.vm.lua_pushnil() - timeout_info.vm.lua_rawseti(timeout_info.vm.LUA_REGISTRYINDEX, timeout_info.callback_ref) + timeout_info.vm.lua_pushstring("GURT_TIMEOUTS") + timeout_info.vm.lua_rawget(timeout_info.vm.LUA_REGISTRYINDEX) + if not timeout_info.vm.lua_isnil(-1): + timeout_info.vm.lua_pushinteger(timeout_info.callback_ref) + timeout_info.vm.lua_pushnil() + timeout_info.vm.lua_rawset(-3) + timeout_info.vm.lua_pop(1) active_timeouts.erase(timeout_info.id) func cleanup_all_timeouts(): @@ -97,6 +121,11 @@ func cleanup_all_timeouts(): # Release Lua callback reference if timeout_info.vm and timeout_info.callback_ref: - timeout_info.vm.lua_pushnil() - timeout_info.vm.lua_rawseti(timeout_info.vm.LUA_REGISTRYINDEX, timeout_info.callback_ref) - active_timeouts.clear() \ No newline at end of file + timeout_info.vm.lua_pushstring("GURT_TIMEOUTS") + timeout_info.vm.lua_rawget(timeout_info.vm.LUA_REGISTRYINDEX) + if not timeout_info.vm.lua_isnil(-1): + timeout_info.vm.lua_pushinteger(timeout_info.callback_ref) + timeout_info.vm.lua_pushnil() + timeout_info.vm.lua_rawset(-3) + timeout_info.vm.lua_pop(1) + active_timeouts.clear()