DNS record management, CSS grid, Regex, location.query
This commit is contained in:
84
flumi/Scripts/Utils/GridUtils.gd
Normal file
84
flumi/Scripts/Utils/GridUtils.gd
Normal file
@@ -0,0 +1,84 @@
|
||||
class_name GridUtils
|
||||
extends RefCounted
|
||||
|
||||
static func apply_grid_container_properties(node: GridContainer, styles: Dictionary) -> void:
|
||||
if styles.has("grid-template-columns"):
|
||||
var cols = styles["grid-template-columns"]
|
||||
if cols is int:
|
||||
node.columns = cols
|
||||
elif cols is String:
|
||||
var parts = cols.split(" ")
|
||||
node.columns = parts.size()
|
||||
|
||||
if styles.has("gap"):
|
||||
var gap_value = parse_grid_value(styles["gap"])
|
||||
if gap_value is int or gap_value is float:
|
||||
node.add_theme_constant_override("h_separation", int(gap_value))
|
||||
node.add_theme_constant_override("v_separation", int(gap_value))
|
||||
|
||||
if styles.has("column-gap"):
|
||||
var gap_value = parse_grid_value(styles["column-gap"])
|
||||
if gap_value is int or gap_value is float:
|
||||
node.add_theme_constant_override("h_separation", int(gap_value))
|
||||
|
||||
if styles.has("row-gap"):
|
||||
var gap_value = parse_grid_value(styles["row-gap"])
|
||||
if gap_value is int or gap_value is float:
|
||||
node.add_theme_constant_override("v_separation", int(gap_value))
|
||||
|
||||
static func apply_grid_item_properties(node: Control, styles: Dictionary) -> void:
|
||||
var grid_properties: Dictionary = node.get_meta("grid_properties", {})
|
||||
var changed = false
|
||||
|
||||
if styles.has("grid-column"):
|
||||
grid_properties["grid-column"] = styles["grid-column"]
|
||||
changed = true
|
||||
|
||||
if styles["grid-column"].begins_with("span "):
|
||||
var span_count = styles["grid-column"].substr(5).to_int()
|
||||
if span_count > 1:
|
||||
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
node.set_meta("grid_column_span", span_count)
|
||||
elif styles["grid-column"] == "1 / -1":
|
||||
# Full span
|
||||
node.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
node.set_meta("grid_column_span", -1)
|
||||
|
||||
if styles.has("grid-row"):
|
||||
grid_properties["grid-row"] = styles["grid-row"]
|
||||
changed = true
|
||||
|
||||
if changed:
|
||||
node.set_meta("grid_properties", grid_properties)
|
||||
|
||||
static func parse_grid_value(val):
|
||||
if val is float or val is int:
|
||||
return val
|
||||
|
||||
if val is String:
|
||||
var s_val = val.strip_edges()
|
||||
if s_val.is_valid_float():
|
||||
return s_val.to_float()
|
||||
if s_val.ends_with("px"):
|
||||
return s_val.trim_suffix("px").to_float()
|
||||
if s_val == "auto":
|
||||
return "auto"
|
||||
|
||||
return null
|
||||
|
||||
static func get_grid_item_span(span_property: String) -> Dictionary:
|
||||
var result = {"start": -1, "end": -1, "span": 1}
|
||||
|
||||
if span_property.begins_with("span "):
|
||||
var span_count = span_property.substr(5).to_int()
|
||||
result["span"] = max(1, span_count)
|
||||
elif span_property == "1 / -1":
|
||||
# Full span
|
||||
result["span"] = -1
|
||||
else:
|
||||
var parts = span_property.split(" / ")
|
||||
if parts.size() == 2:
|
||||
result["start"] = parts[0].to_int()
|
||||
result["end"] = parts[1].to_int()
|
||||
|
||||
return result
|
||||
1
flumi/Scripts/Utils/GridUtils.gd.uid
Normal file
1
flumi/Scripts/Utils/GridUtils.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://4p5lrhmdwgrj
|
||||
@@ -341,32 +341,72 @@ static func _find_input_control_with_file_info(node: Node) -> Node:
|
||||
|
||||
return null
|
||||
|
||||
static func _get_select_value(element: HTMLParser.HTMLElement, dom_node: Node) -> String:
|
||||
if dom_node is OptionButton:
|
||||
var option_button = dom_node as OptionButton
|
||||
var selected_index = option_button.selected
|
||||
if selected_index >= 0 and selected_index < option_button.get_item_count():
|
||||
var metadata = option_button.get_item_metadata(selected_index)
|
||||
if metadata:
|
||||
return str(metadata)
|
||||
else:
|
||||
return option_button.get_item_text(selected_index)
|
||||
return ""
|
||||
|
||||
static func _set_select_value(element: HTMLParser.HTMLElement, dom_node: Node, value: Variant) -> void:
|
||||
if dom_node is OptionButton:
|
||||
var option_button = dom_node as OptionButton
|
||||
var target_value = str(value)
|
||||
|
||||
# Find the correct index to select
|
||||
var selected_index = -1
|
||||
|
||||
# Find option with matching value
|
||||
for i in range(option_button.get_item_count()):
|
||||
var metadata = option_button.get_item_metadata(i)
|
||||
var option_value = str(metadata) if metadata else option_button.get_item_text(i)
|
||||
if option_value == target_value:
|
||||
selected_index = i
|
||||
break
|
||||
|
||||
# If no matching value found, try to find by text
|
||||
if selected_index == -1:
|
||||
for i in range(option_button.get_item_count()):
|
||||
if option_button.get_item_text(i) == target_value:
|
||||
selected_index = i
|
||||
break
|
||||
|
||||
# Use call_deferred to set the property on main thread
|
||||
if selected_index != -1:
|
||||
option_button.call_deferred("set", "selected", selected_index)
|
||||
|
||||
static func _set_input_value(element: HTMLParser.HTMLElement, dom_node: Node, value: Variant) -> void:
|
||||
var input_type = element.get_attribute("type").to_lower()
|
||||
|
||||
match input_type:
|
||||
"checkbox", "radio":
|
||||
if dom_node is CheckBox:
|
||||
dom_node.button_pressed = bool(value)
|
||||
dom_node.call_deferred("set", "button_pressed", bool(value))
|
||||
"color":
|
||||
if dom_node is ColorPickerButton:
|
||||
var color_value = str(value)
|
||||
if color_value.begins_with("#"):
|
||||
dom_node.color = Color.from_string(color_value, Color.WHITE)
|
||||
var color = Color.from_string(color_value, Color.WHITE)
|
||||
dom_node.call_deferred("set", "color", color)
|
||||
"range":
|
||||
if dom_node is HSlider:
|
||||
dom_node.value = float(value)
|
||||
dom_node.call_deferred("set", "value", float(value))
|
||||
"number":
|
||||
if dom_node is SpinBox:
|
||||
dom_node.value = float(value)
|
||||
dom_node.call_deferred("set", "value", float(value))
|
||||
"date":
|
||||
if dom_node is DateButton and dom_node.has_method("set_date_from_string"):
|
||||
dom_node.set_date_from_string(str(value))
|
||||
dom_node.call_deferred("set_date_from_string", str(value))
|
||||
_: # text, password, email, etc.
|
||||
if dom_node is LineEdit:
|
||||
dom_node.text = str(value)
|
||||
dom_node.call_deferred("set", "text", str(value))
|
||||
elif dom_node is TextEdit:
|
||||
dom_node.text = str(value)
|
||||
dom_node.call_deferred("set", "text", str(value))
|
||||
|
||||
# Helper functions
|
||||
static func find_element_by_id(element_id: String, dom_parser: HTMLParser) -> HTMLParser.HTMLElement:
|
||||
@@ -931,7 +971,7 @@ static func _element_index_wrapper(vm: LuauVM) -> int:
|
||||
|
||||
match key:
|
||||
"value":
|
||||
if lua_api and tag_name == "input":
|
||||
if lua_api and (tag_name == "input" or tag_name == "select"):
|
||||
vm.lua_getfield(1, "_element_id")
|
||||
var element_id: String = vm.lua_tostring(-1)
|
||||
vm.lua_pop(1)
|
||||
@@ -940,8 +980,13 @@ static func _element_index_wrapper(vm: LuauVM) -> int:
|
||||
var dom_node = lua_api.dom_parser.parse_result.dom_nodes.get(element_id, null)
|
||||
|
||||
if element and dom_node:
|
||||
var input_value = _get_input_value(element, dom_node)
|
||||
vm.lua_pushstring(str(input_value))
|
||||
var value_result: String
|
||||
if tag_name == "input":
|
||||
value_result = str(_get_input_value(element, dom_node))
|
||||
elif tag_name == "select":
|
||||
value_result = _get_select_value(element, dom_node)
|
||||
|
||||
vm.lua_pushstring(value_result)
|
||||
return 1
|
||||
|
||||
# Fallback to empty string
|
||||
@@ -1225,7 +1270,7 @@ static func _element_newindex_wrapper(vm: LuauVM) -> int:
|
||||
|
||||
match key:
|
||||
"value":
|
||||
if tag_name == "input":
|
||||
if tag_name == "input" or tag_name == "select":
|
||||
vm.lua_getfield(1, "_element_id")
|
||||
var element_id: String = vm.lua_tostring(-1)
|
||||
vm.lua_pop(1)
|
||||
@@ -1234,10 +1279,12 @@ static func _element_newindex_wrapper(vm: LuauVM) -> int:
|
||||
var dom_node = lua_api.dom_parser.parse_result.dom_nodes.get(element_id, null)
|
||||
|
||||
if element and dom_node:
|
||||
# Update the HTML element's value attribute
|
||||
element.set_attribute("value", str(value))
|
||||
|
||||
_set_input_value(element, dom_node, value)
|
||||
if tag_name == "input":
|
||||
element.set_attribute("value", str(value))
|
||||
_set_input_value(element, dom_node, value)
|
||||
elif tag_name == "select":
|
||||
element.set_attribute("value", str(value))
|
||||
_set_select_value(element, dom_node, value)
|
||||
return 0
|
||||
"text":
|
||||
var text: String = str(value) # Convert value to string
|
||||
|
||||
@@ -25,7 +25,7 @@ static func connect_element_event(signal_node: Node, event_name: String, subscri
|
||||
elif signal_node is Control:
|
||||
var wrapper = func(event: InputEvent):
|
||||
LuaAudioUtils.mark_user_event()
|
||||
subscription.lua_api._on_gui_input_click(subscription, event)
|
||||
subscription.lua_api._on_gui_input_click(event, subscription)
|
||||
signal_node.gui_input.connect(wrapper)
|
||||
subscription.connected_signal = "gui_input"
|
||||
subscription.connected_node = signal_node
|
||||
|
||||
142
flumi/Scripts/Utils/Lua/Regex.gd
Normal file
142
flumi/Scripts/Utils/Lua/Regex.gd
Normal file
@@ -0,0 +1,142 @@
|
||||
class_name LuaRegexUtils
|
||||
extends RefCounted
|
||||
|
||||
static func regex_new_handler(vm: LuauVM) -> int:
|
||||
var pattern: String = vm.luaL_checkstring(1)
|
||||
var regex = RegEx.new()
|
||||
var result = regex.compile(pattern)
|
||||
|
||||
if result != OK:
|
||||
vm.luaL_error("Invalid regex pattern: " + pattern)
|
||||
return 0
|
||||
|
||||
vm.lua_newtable()
|
||||
vm.lua_pushobject(regex)
|
||||
vm.lua_setfield(-2, "_regex")
|
||||
|
||||
vm.lua_pushcallable(regex_match_handler, "regex:match")
|
||||
vm.lua_setfield(-2, "match")
|
||||
|
||||
vm.lua_pushcallable(regex_test_handler, "regex:test")
|
||||
vm.lua_setfield(-2, "test")
|
||||
|
||||
return 1
|
||||
|
||||
static func regex_match_handler(vm: LuauVM) -> int:
|
||||
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||
var subject: String = vm.luaL_checkstring(2)
|
||||
|
||||
vm.lua_getfield(1, "_regex")
|
||||
var regex: RegEx = vm.lua_toobject(-1) as RegEx
|
||||
vm.lua_pop(1)
|
||||
|
||||
if not regex:
|
||||
vm.luaL_error("Invalid regex object")
|
||||
return 0
|
||||
|
||||
var result = regex.search(subject)
|
||||
if not result:
|
||||
vm.lua_pushnil()
|
||||
return 1
|
||||
|
||||
vm.lua_newtable()
|
||||
|
||||
vm.lua_pushstring(result.get_string())
|
||||
vm.lua_rawseti(-2, 1)
|
||||
|
||||
for i in range(1, result.get_group_count()):
|
||||
var group = result.get_string(i)
|
||||
vm.lua_pushstring(group)
|
||||
vm.lua_rawseti(-2, i + 1)
|
||||
|
||||
return 1
|
||||
|
||||
static func regex_test_handler(vm: LuauVM) -> int:
|
||||
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||
var subject: String = vm.luaL_checkstring(2)
|
||||
|
||||
vm.lua_getfield(1, "_regex")
|
||||
var regex: RegEx = vm.lua_toobject(-1) as RegEx
|
||||
vm.lua_pop(1)
|
||||
|
||||
if not regex:
|
||||
vm.luaL_error("Invalid regex object")
|
||||
return 0
|
||||
|
||||
var result = regex.search(subject)
|
||||
vm.lua_pushboolean(result != null)
|
||||
return 1
|
||||
|
||||
static func string_replace_handler(vm: LuauVM) -> int:
|
||||
var subject: String = vm.luaL_checkstring(1)
|
||||
|
||||
if vm.lua_istable(2):
|
||||
vm.lua_getfield(2, "_regex")
|
||||
var regex: RegEx = vm.lua_toobject(-1) as RegEx
|
||||
vm.lua_pop(1)
|
||||
|
||||
if not regex:
|
||||
vm.luaL_error("Invalid regex object")
|
||||
return 0
|
||||
|
||||
var replacement: String = vm.luaL_checkstring(3)
|
||||
var result = regex.sub(subject, replacement, false)
|
||||
vm.lua_pushstring(result)
|
||||
else:
|
||||
var search: String = vm.luaL_checkstring(2)
|
||||
var replacement: String = vm.luaL_checkstring(3)
|
||||
|
||||
var pos = subject.find(search)
|
||||
if pos >= 0:
|
||||
var result = subject.substr(0, pos) + replacement + subject.substr(pos + search.length())
|
||||
vm.lua_pushstring(result)
|
||||
else:
|
||||
vm.lua_pushstring(subject)
|
||||
|
||||
return 1
|
||||
|
||||
static func string_replace_all_handler(vm: LuauVM) -> int:
|
||||
var subject: String = vm.luaL_checkstring(1)
|
||||
|
||||
if vm.lua_istable(2):
|
||||
vm.lua_getfield(2, "_regex")
|
||||
var regex: RegEx = vm.lua_toobject(-1) as RegEx
|
||||
vm.lua_pop(1)
|
||||
|
||||
if not regex:
|
||||
vm.luaL_error("Invalid regex object")
|
||||
return 0
|
||||
|
||||
var replacement: String = vm.luaL_checkstring(3)
|
||||
var result = regex.sub(subject, replacement, true)
|
||||
vm.lua_pushstring(result)
|
||||
else:
|
||||
var search: String = vm.luaL_checkstring(2)
|
||||
var replacement: String = vm.luaL_checkstring(3)
|
||||
var result = subject.replace(search, replacement)
|
||||
vm.lua_pushstring(result)
|
||||
|
||||
return 1
|
||||
|
||||
static func setup_regex_api(vm: LuauVM) -> void:
|
||||
vm.lua_newtable()
|
||||
|
||||
vm.lua_pushcallable(regex_new_handler, "Regex.new")
|
||||
vm.lua_setfield(-2, "new")
|
||||
|
||||
vm.lua_setglobal("Regex")
|
||||
|
||||
vm.lua_getglobal("string")
|
||||
if vm.lua_isnil(-1):
|
||||
vm.lua_pop(1)
|
||||
vm.lua_newtable()
|
||||
vm.lua_setglobal("string")
|
||||
vm.lua_getglobal("string")
|
||||
|
||||
vm.lua_pushcallable(string_replace_handler, "string.replace")
|
||||
vm.lua_setfield(-2, "replace")
|
||||
|
||||
vm.lua_pushcallable(string_replace_all_handler, "string.replaceAll")
|
||||
vm.lua_setfield(-2, "replaceAll")
|
||||
|
||||
vm.lua_pop(1)
|
||||
1
flumi/Scripts/Utils/Lua/Regex.gd.uid
Normal file
1
flumi/Scripts/Utils/Lua/Regex.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c23cbsiegb0rq
|
||||
@@ -315,6 +315,15 @@ func _setup_threaded_gurt_api():
|
||||
lua_vm.lua_pushstring(current_href)
|
||||
lua_vm.lua_setfield(-2, "href")
|
||||
|
||||
lua_vm.lua_newtable()
|
||||
lua_vm.lua_pushcallable(lua_api._gurt_location_query_get_handler, "gurt.location.query.get")
|
||||
lua_vm.lua_setfield(-2, "get")
|
||||
lua_vm.lua_pushcallable(lua_api._gurt_location_query_has_handler, "gurt.location.query.has")
|
||||
lua_vm.lua_setfield(-2, "has")
|
||||
lua_vm.lua_pushcallable(lua_api._gurt_location_query_getAll_handler, "gurt.location.query.getAll")
|
||||
lua_vm.lua_setfield(-2, "getAll")
|
||||
lua_vm.lua_setfield(-2, "query")
|
||||
|
||||
lua_vm.lua_setfield(-2, "location")
|
||||
|
||||
var body_element = dom_parser.find_first("body")
|
||||
@@ -345,6 +354,7 @@ func _setup_additional_lua_apis():
|
||||
LuaWebSocketUtils.setup_websocket_api(lua_vm)
|
||||
LuaAudioUtils.setup_audio_api(lua_vm)
|
||||
LuaCrumbsUtils.setup_crumbs_api(lua_vm)
|
||||
LuaRegexUtils.setup_regex_api(lua_vm)
|
||||
|
||||
func _table_tostring_handler(vm: LuauVM) -> int:
|
||||
vm.luaL_checktype(1, vm.LUA_TTABLE)
|
||||
|
||||
Reference in New Issue
Block a user