Files
leonwww/flumi/Scripts/main.gd

697 lines
24 KiB
GDScript3
Raw Normal View History

class_name Main
2025-07-20 13:45:07 +03:00
extends Control
@onready var website_container: Control = %WebsiteContainer
@onready var tab_container: TabManager = $VBoxContainer/TabContainer
2025-08-12 21:30:41 +03:00
@onready var search_bar: LineEdit = $VBoxContainer/HBoxContainer/LineEdit
const LOADER_CIRCLE = preload("res://Assets/Icons/loader-circle.svg")
2025-07-28 15:22:34 +03:00
const AUTO_SIZING_FLEX_CONTAINER = preload("res://Scripts/AutoSizingFlexContainer.gd")
const P = preload("res://Scenes/Tags/p.tscn")
const IMG = preload("res://Scenes/Tags/img.tscn")
const SEPARATOR = preload("res://Scenes/Tags/separator.tscn")
const PRE = P
const BR = preload("res://Scenes/Tags/br.tscn")
2025-07-22 21:15:57 +03:00
const SPAN = preload("res://Scenes/Tags/span.tscn")
const H1 = P
const H2 = P
const H3 = P
const H4 = P
const H5 = P
const H6 = P
2025-07-23 15:23:32 +03:00
const FORM = preload("res://Scenes/Tags/form.tscn")
const INPUT = preload("res://Scenes/Tags/input.tscn")
const BUTTON = preload("res://Scenes/Tags/button.tscn")
2025-07-25 15:46:18 +03:00
const UL = preload("res://Scenes/Tags/ul.tscn")
const OL = preload("res://Scenes/Tags/ol.tscn")
2025-07-25 17:49:32 +03:00
const SELECT = preload("res://Scenes/Tags/select.tscn")
2025-07-25 18:55:28 +03:00
const TEXTAREA = preload("res://Scenes/Tags/textarea.tscn")
2025-07-28 15:22:34 +03:00
const DIV = preload("res://Scenes/Tags/div.tscn")
2025-08-11 17:08:39 +03:00
const AUDIO = preload("res://Scenes/Tags/audio.tscn")
const POSTPROCESS = preload("res://Scenes/Tags/postprocess.tscn")
2025-08-31 14:17:34 +03:00
const CANVAS = preload("res://Scenes/Tags/canvas.tscn")
2025-07-23 15:23:32 +03:00
const MIN_SIZE = Vector2i(750, 200)
2025-07-31 22:02:03 +03:00
var font_dependent_elements: Array = []
var current_domain = ""
2025-07-31 22:02:03 +03:00
func should_group_as_inline(element: HTMLParser.HTMLElement) -> bool:
if element.tag_name == "input":
var parent = element.parent
while parent:
if parent.tag_name == "form":
return true
parent = parent.parent
return false
return element.is_inline_element()
2025-07-23 15:23:32 +03:00
func _ready():
ProjectSettings.set_setting("display/window/size/min_width", MIN_SIZE.x)
ProjectSettings.set_setting("display/window/size/min_height", MIN_SIZE.y)
DisplayServer.window_set_min_size(MIN_SIZE)
2025-08-22 17:31:54 +03:00
CertificateManager.initialize()
2025-08-29 16:24:53 +03:00
var original_scroll = website_container.get_parent()
if original_scroll:
original_scroll.visible = false
call_deferred("render")
2025-07-20 13:45:07 +03:00
2025-08-15 13:52:01 +03:00
func resolve_url(href: String) -> String:
return URLUtils.resolve_url(current_domain, href)
2025-08-15 13:52:01 +03:00
func handle_link_click(meta: Variant) -> void:
var href = str(meta)
var resolved_url = resolve_url(href)
if GurtProtocol.is_gurt_domain(resolved_url):
_on_search_submitted(resolved_url)
else:
OS.shell_open(resolved_url)
2025-08-12 21:30:41 +03:00
func _on_search_submitted(url: String) -> void:
print("Search submitted: ", url)
search_bar.release_focus()
2025-08-12 21:30:41 +03:00
if GurtProtocol.is_gurt_domain(url):
print("Processing as GURT domain")
var tab = tab_container.tabs[tab_container.active_tab]
tab.start_loading()
2025-08-27 20:23:05 +03:00
var gurt_url = url
if not gurt_url.begins_with("gurt://"):
gurt_url = "gurt://" + gurt_url
2025-08-12 21:30:41 +03:00
2025-08-27 20:23:05 +03:00
await fetch_gurt_content_async(gurt_url, tab, url)
2025-08-12 21:30:41 +03:00
else:
print("Non-GURT URL entered: ", url)
2025-08-27 20:23:05 +03:00
func fetch_gurt_content_async(gurt_url: String, tab: Tab, original_url: String) -> void:
var thread = Thread.new()
var request_data = {"gurt_url": gurt_url}
thread.start(_perform_gurt_request_threaded.bind(request_data))
while thread.is_alive():
await get_tree().process_frame
var result = thread.wait_to_finish()
_handle_gurt_result(result, tab, original_url, gurt_url)
func _perform_gurt_request_threaded(request_data: Dictionary) -> Dictionary:
var gurt_url: String = request_data.gurt_url
var client = GurtProtocolClient.new()
for ca_cert in CertificateManager.trusted_ca_certificates:
client.add_ca_certificate(ca_cert)
if not client.create_client_with_dns(30, GurtProtocol.DNS_SERVER_IP, GurtProtocol.DNS_SERVER_PORT):
client.disconnect()
return {"success": false, "error": "Failed to connect to GURT DNS server"}
var response = client.request(gurt_url, {
"method": "GET"
})
client.disconnect()
if not response or not response.is_success:
var error_msg = "Connection failed"
if response:
error_msg = "GURT %d: %s" % [response.status_code, response.status_message]
elif not response:
error_msg = "Request timed out or connection failed"
return {"success": false, "error": error_msg}
return {"success": true, "html_bytes": response.body}
func _handle_gurt_result(result: Dictionary, tab: Tab, original_url: String, gurt_url: String) -> void:
if not result.success:
print("GURT request failed: ", result.error)
handle_gurt_error(result.error, tab)
return
var html_bytes = result.html_bytes
current_domain = gurt_url
if not search_bar.has_focus():
search_bar.text = original_url # Show the original input in search bar
render_content(html_bytes)
tab.stop_loading()
func handle_gurt_error(error_message: String, tab: Tab) -> void:
var error_html = GurtProtocol.create_error_page(error_message)
render_content(error_html)
const GLOBE_ICON = preload("res://Assets/Icons/globe.svg")
tab.stop_loading()
tab.set_icon(GLOBE_ICON)
2025-08-12 21:30:41 +03:00
func _on_search_focus_entered() -> void:
if not current_domain.is_empty():
search_bar.text = current_domain
2025-08-12 21:30:41 +03:00
func _on_search_focus_exited() -> void:
if not current_domain.is_empty():
var display_text = current_domain
if display_text.begins_with("gurt://"):
display_text = display_text.substr(7)
search_bar.text = display_text
2025-08-12 21:30:41 +03:00
2025-07-28 15:22:34 +03:00
func render() -> void:
2025-08-12 21:30:41 +03:00
render_content(Constants.HTML_CONTENT)
func render_content(html_bytes: PackedByteArray) -> void:
2025-08-29 16:24:53 +03:00
var active_tab = get_active_tab()
var target_container: Control
2025-08-12 21:30:41 +03:00
2025-08-29 16:24:53 +03:00
if active_tab and active_tab.website_container:
target_container = active_tab.website_container
else:
target_container = website_container
2025-08-29 16:24:53 +03:00
if not target_container:
print("Error: No container available for rendering")
return
if active_tab:
var existing_tab_lua_apis = active_tab.lua_apis
for lua_api in existing_tab_lua_apis:
if is_instance_valid(lua_api):
lua_api.kill_script_execution()
remove_child(lua_api)
lua_api.queue_free()
active_tab.lua_apis.clear()
var existing_postprocess = []
for child in get_children():
if child is HTMLPostprocess:
existing_postprocess.append(child)
for postprocess in existing_postprocess:
remove_child(postprocess)
postprocess.queue_free()
if active_tab.background_panel:
var existing_overlay = active_tab.background_panel.get_node_or_null("PostprocessOverlay")
if existing_overlay:
existing_overlay.queue_free()
2025-08-29 16:24:53 +03:00
else:
var existing_lua_apis = []
for child in get_children():
if child is LuaAPI:
existing_lua_apis.append(child)
2025-08-29 16:24:53 +03:00
for lua_api in existing_lua_apis:
lua_api.kill_script_execution()
remove_child(lua_api)
lua_api.queue_free()
var postprocess_nodes: Array[Node] = []
for child in get_children():
if child is HTMLPostprocess:
postprocess_nodes.append(child)
for node in postprocess_nodes:
remove_child(node)
node.queue_free()
var default_panel = website_container.get_parent()
if default_panel and default_panel.has_method("get_node_or_null"):
var existing_overlay = default_panel.get_node_or_null("PostprocessOverlay")
if existing_overlay:
existing_overlay.queue_free()
2025-08-29 16:24:53 +03:00
if target_container.get_parent() and target_container.get_parent().name == "BodyMarginContainer":
var body_margin_container = target_container.get_parent()
var scroll_container = body_margin_container.get_parent()
if scroll_container:
body_margin_container.remove_child(target_container)
scroll_container.remove_child(body_margin_container)
body_margin_container.queue_free()
scroll_container.add_child(target_container)
for child in target_container.get_children():
child.queue_free()
2025-07-31 22:02:03 +03:00
font_dependent_elements.clear()
FontManager.clear_fonts()
FontManager.set_refresh_callback(refresh_fonts)
var parser: HTMLParser = HTMLParser.new(html_bytes)
2025-07-20 13:45:07 +03:00
var parse_result = parser.parse()
parser.process_styles()
if parse_result.external_css and not parse_result.external_css.is_empty():
await parser.process_external_styles(current_domain)
2025-07-31 22:02:03 +03:00
# Process and load all custom fonts defined in <font> tags
parser.process_fonts()
FontManager.load_all_fonts()
2025-07-20 13:45:07 +03:00
if parse_result.errors.size() > 0:
print("Parse errors: " + str(parse_result.errors))
2025-08-29 16:24:53 +03:00
var tab = active_tab
var title = parser.get_title()
tab.set_title(title)
var icon = parser.get_icon()
2025-07-24 13:52:34 +03:00
tab.update_icon_from_url(icon)
var body = parser.find_first("body")
if body:
2025-08-29 16:24:53 +03:00
var background_panel = active_tab.background_panel
StyleManager.apply_body_styles(body, parser, target_container, background_panel)
2025-08-29 16:24:53 +03:00
parser.register_dom_node(body, target_container)
var scripts = parser.find_all("script")
var lua_api = null
if scripts.size() > 0:
lua_api = LuaAPI.new()
add_child(lua_api)
2025-08-29 16:24:53 +03:00
if active_tab:
active_tab.lua_apis.append(lua_api)
2025-07-22 21:15:57 +03:00
var i = 0
2025-08-12 21:30:41 +03:00
if body:
while i < body.children.size():
var element: HTMLParser.HTMLElement = body.children[i]
if should_group_as_inline(element):
# Create an HBoxContainer for consecutive inline elements
var inline_elements: Array[HTMLParser.HTMLElement] = []
2025-08-12 21:30:41 +03:00
while i < body.children.size() and should_group_as_inline(body.children[i]):
inline_elements.append(body.children[i])
i += 1
2025-07-22 21:15:57 +03:00
2025-08-12 21:30:41 +03:00
var hbox = HBoxContainer.new()
hbox.add_theme_constant_override("separation", 4)
2025-08-12 21:30:41 +03:00
for inline_element in inline_elements:
2025-08-29 16:24:53 +03:00
var inline_node = await create_element_node(inline_element, parser, target_container)
2025-08-12 21:30:41 +03:00
if inline_node:
# Input elements register their own DOM nodes in their init() function
if inline_element.tag_name not in ["input", "textarea", "select", "button", "audio"]:
parser.register_dom_node(inline_element, inline_node)
safe_add_child(hbox, inline_node)
# Handle hyperlinks for all inline elements
if contains_hyperlink(inline_element) and inline_node is RichTextLabel:
2025-08-15 13:52:01 +03:00
inline_node.meta_clicked.connect(handle_link_click)
2025-08-12 21:30:41 +03:00
else:
print("Failed to create inline element node: ", inline_element.tag_name)
2025-08-29 16:24:53 +03:00
safe_add_child(target_container, hbox)
2025-08-12 21:30:41 +03:00
continue
2025-08-29 16:24:53 +03:00
var element_node = await create_element_node(element, parser, target_container)
2025-08-12 21:30:41 +03:00
if element_node:
# Input elements register their own DOM nodes in their init() function
2025-08-31 14:17:34 +03:00
if element.tag_name not in ["input", "textarea", "select", "button", "audio", "canvas"]:
2025-08-12 21:30:41 +03:00
parser.register_dom_node(element, element_node)
# ul/ol handle their own adding
if element.tag_name != "ul" and element.tag_name != "ol":
2025-08-29 16:24:53 +03:00
safe_add_child(target_container, element_node)
2025-08-12 21:30:41 +03:00
if contains_hyperlink(element):
if element_node is RichTextLabel:
2025-08-15 13:52:01 +03:00
element_node.meta_clicked.connect(handle_link_click)
2025-08-12 21:30:41 +03:00
elif element_node.has_method("get") and element_node.get("rich_text_label"):
2025-08-15 13:52:01 +03:00
element_node.rich_text_label.meta_clicked.connect(handle_link_click)
2025-08-12 21:30:41 +03:00
else:
print("Couldn't parse unsupported HTML tag \"%s\"" % element.tag_name)
i += 1
2025-08-08 16:51:21 +03:00
if scripts.size() > 0 and lua_api:
parser.process_scripts(lua_api, null)
if parse_result.external_scripts and not parse_result.external_scripts.is_empty():
await parser.process_external_scripts(lua_api, null, current_domain)
2025-08-29 16:24:53 +03:00
var postprocess_element = parser.process_postprocess()
if postprocess_element:
var postprocess_node = POSTPROCESS.instantiate()
add_child(postprocess_node)
await postprocess_node.init(postprocess_element, parser)
2025-08-29 16:24:53 +03:00
active_tab.current_url = current_domain
active_tab.has_content = true
2025-07-28 15:22:34 +03:00
static func safe_add_child(parent: Node, child: Node) -> void:
if child.get_parent():
child.get_parent().remove_child(child)
parent.add_child(child)
2025-07-22 22:14:37 +03:00
func contains_hyperlink(element: HTMLParser.HTMLElement) -> bool:
if element.tag_name == "a":
return true
for child in element.children:
if contains_hyperlink(child):
return true
return false
2025-07-23 15:23:32 +03:00
2025-08-01 21:16:48 +03:00
func is_text_only_element(element: HTMLParser.HTMLElement) -> bool:
if element.children.size() == 0:
var text = element.get_collapsed_text()
return not text.is_empty()
return false
2025-08-29 16:24:53 +03:00
func create_element_node(element: HTMLParser.HTMLElement, parser: HTMLParser, container: Control = null) -> Control:
var styles = parser.get_element_styles_with_inheritance(element, "", [])
var hover_styles = parser.get_element_styles_with_inheritance(element, "hover", [])
2025-07-28 15:22:34 +03:00
var is_flex_container = styles.has("display") and ("flex" in styles["display"])
var is_grid_container = styles.has("display") and ("grid" in styles["display"])
2025-07-28 15:22:34 +03:00
var final_node: Control
var container_for_children: Node
# If this is an inline element AND not a flex or grid container, do NOT recursively add child nodes for its children.
2025-07-28 15:22:34 +03:00
# Only create a node for the outermost inline group; nested inline tags are handled by BBCode.
if element.is_inline_element() and not is_flex_container and not is_grid_container:
2025-08-29 16:24:53 +03:00
final_node = await create_element_node_internal(element, parser, container if container else get_active_website_container())
2025-07-28 15:22:34 +03:00
if not final_node:
return null
final_node = StyleManager.apply_element_styles(final_node, element, parser)
# Flex item properties may still apply
FlexUtils.apply_flex_item_properties(final_node, styles)
2025-07-28 15:22:34 +03:00
return final_node
if is_grid_container:
if element.tag_name == "div":
2025-08-27 20:23:05 +03:00
if BackgroundUtils.needs_background_wrapper(styles) or BackgroundUtils.needs_background_wrapper(hover_styles):
final_node = BackgroundUtils.create_panel_container_with_background(styles, hover_styles)
var grid_container = GridContainer.new()
grid_container.name = "Grid_" + element.tag_name
var vbox = final_node.get_child(0) as VBoxContainer
vbox.add_child(grid_container)
container_for_children = grid_container
else:
final_node = GridContainer.new()
final_node.name = "Grid_" + element.tag_name
container_for_children = final_node
else:
final_node = GridContainer.new()
final_node.name = "Grid_" + element.tag_name
container_for_children = final_node
elif is_flex_container:
2025-07-28 15:22:34 +03:00
# The element's primary identity IS a flex container.
if element.tag_name == "div":
2025-08-27 20:23:05 +03:00
if BackgroundUtils.needs_background_wrapper(styles) or BackgroundUtils.needs_background_wrapper(hover_styles):
final_node = BackgroundUtils.create_panel_container_with_background(styles, hover_styles)
var flex_container = AUTO_SIZING_FLEX_CONTAINER.new()
flex_container.name = "Flex_" + element.tag_name
var vbox = final_node.get_child(0) as VBoxContainer
vbox.add_child(flex_container)
container_for_children = flex_container
2025-08-27 20:23:05 +03:00
FlexUtils.apply_flex_container_properties(flex_container, styles)
else:
final_node = AUTO_SIZING_FLEX_CONTAINER.new()
final_node.name = "Flex_" + element.tag_name
container_for_children = final_node
2025-08-27 20:23:05 +03:00
FlexUtils.apply_flex_container_properties(final_node, styles)
else:
final_node = AUTO_SIZING_FLEX_CONTAINER.new()
final_node.name = "Flex_" + element.tag_name
container_for_children = final_node
2025-08-27 20:23:05 +03:00
FlexUtils.apply_flex_container_properties(final_node, styles)
# For FLEX ul/ol elements, we need to create the li children directly in the flex container
if element.tag_name == "ul" or element.tag_name == "ol":
final_node.flex_direction = FlexContainer.FlexDirection.Column
2025-08-29 16:24:53 +03:00
var active_container = container if container else get_active_website_container()
active_container.add_child(final_node)
var temp_list = UL.instantiate() if element.tag_name == "ul" else OL.instantiate()
2025-08-29 16:24:53 +03:00
active_container.add_child(temp_list)
await temp_list.init(element, parser)
for child in temp_list.get_children():
temp_list.remove_child(child)
container_for_children.add_child(child)
2025-08-29 16:24:53 +03:00
active_container.remove_child(temp_list)
temp_list.queue_free()
2025-07-28 15:22:34 +03:00
# If the element itself has text (like <span style="flex">TEXT</span>)
elif not element.text_content.is_empty():
2025-08-29 16:24:53 +03:00
var new_node = await create_element_node_internal(element, parser, container if container else get_active_website_container())
2025-08-27 20:23:05 +03:00
if new_node:
container_for_children.add_child(new_node)
# For flex divs, we're done - no additional node creation needed
elif element.tag_name == "div":
pass
2025-07-28 15:22:34 +03:00
else:
2025-08-29 16:24:53 +03:00
final_node = await create_element_node_internal(element, parser, container if container else get_active_website_container())
2025-07-28 15:22:34 +03:00
if not final_node:
return null # Unsupported tag
# If final_node is a PanelContainer, children should go to the VBoxContainer inside
if final_node is PanelContainer and final_node.get_child_count() > 0:
container_for_children = final_node.get_child(0) # The VBoxContainer inside
else:
container_for_children = final_node
2025-07-28 15:22:34 +03:00
# Applies background, size, etc. to the FlexContainer (top-level node)
final_node = StyleManager.apply_element_styles(final_node, element, parser)
if is_grid_container:
var grid_container_node = final_node
if final_node is GridContainer:
grid_container_node = final_node
elif final_node is MarginContainer and final_node.get_child_count() > 0:
var first_child = final_node.get_child(0)
if first_child is GridContainer:
grid_container_node = first_child
elif final_node is PanelContainer and final_node.get_child_count() > 0:
var vbox = final_node.get_child(0)
if vbox is VBoxContainer and vbox.get_child_count() > 0:
var potential_grid = vbox.get_child(0)
if potential_grid is GridContainer:
grid_container_node = potential_grid
if grid_container_node is GridContainer:
GridUtils.apply_grid_container_properties(grid_container_node, styles)
FlexUtils.apply_flex_item_properties(final_node, styles)
if not is_grid_container:
GridUtils.apply_grid_item_properties(final_node, styles)
2025-07-28 15:22:34 +03:00
# Skip ul/ol and non-flex forms, they handle their own children
var skip_general_processing = false
if element.tag_name == "ul" or element.tag_name == "ol":
skip_general_processing = true
elif element.tag_name == "form":
skip_general_processing = not is_flex_container and not is_grid_container
if not skip_general_processing:
2025-07-28 15:22:34 +03:00
for child_element in element.children:
# Only add child nodes if the child is NOT an inline element
# UNLESS the parent is a flex or grid container (inline elements become flex/grid items)
if not child_element.is_inline_element() or is_flex_container or is_grid_container:
2025-08-29 16:24:53 +03:00
var child_node = await create_element_node(child_element, parser, container)
2025-07-28 15:22:34 +03:00
if child_node and is_instance_valid(container_for_children):
# Input elements register their own DOM nodes in their init() function
2025-08-11 17:08:39 +03:00
if child_element.tag_name not in ["input", "textarea", "select", "button", "audio"]:
parser.register_dom_node(child_element, child_node)
2025-07-28 15:22:34 +03:00
safe_add_child(container_for_children, child_node)
2025-08-15 13:52:01 +03:00
if contains_hyperlink(child_element):
if child_node is RichTextLabel:
child_node.meta_clicked.connect(handle_link_click)
elif child_node.has_method("get") and child_node.get("rich_text_label"):
child_node.rich_text_label.meta_clicked.connect(handle_link_click)
2025-07-28 15:22:34 +03:00
return final_node
2025-08-29 16:24:53 +03:00
func create_element_node_internal(element: HTMLParser.HTMLElement, parser: HTMLParser, container: Control = null) -> Control:
var node: Control = null
2025-07-23 15:23:32 +03:00
match element.tag_name:
"p":
node = P.instantiate()
node.init(element, parser)
"pre":
node = PRE.instantiate()
node.init(element, parser)
2025-07-28 15:22:34 +03:00
"h1", "h2", "h3", "h4", "h5", "h6":
match element.tag_name:
"h1": node = H1.instantiate()
"h2": node = H2.instantiate()
"h3": node = H3.instantiate()
"h4": node = H4.instantiate()
"h5": node = H5.instantiate()
"h6": node = H6.instantiate()
node.init(element, parser)
"br":
node = BR.instantiate()
node.init(element, parser)
"img":
node = IMG.instantiate()
node.init(element, parser)
"separator":
node = SEPARATOR.instantiate()
node.init(element, parser)
"form":
var form_styles = parser.get_element_styles_with_inheritance(element, "", [])
var is_flex_form = form_styles.has("display") and ("flex" in form_styles["display"])
2025-07-28 15:22:34 +03:00
if is_flex_form:
# Don't create a form node here - return null so general processing takes over
return null
else:
node = FORM.instantiate()
node.init(element, parser)
# Manually process children for non-flex forms
for child_element in element.children:
2025-08-29 16:24:53 +03:00
var child_node = await create_element_node(child_element, parser, container)
if child_node:
safe_add_child(node, child_node)
2025-07-23 15:23:32 +03:00
"input":
node = INPUT.instantiate()
node.init(element, parser)
2025-07-23 15:23:32 +03:00
"button":
node = BUTTON.instantiate()
node.init(element, parser)
2025-07-28 15:22:34 +03:00
"span", "b", "i", "u", "small", "mark", "code", "a":
node = SPAN.instantiate()
2025-08-01 21:16:48 +03:00
node.init(element, parser)
2025-07-25 15:46:18 +03:00
"ul":
node = UL.instantiate()
2025-08-29 16:24:53 +03:00
var ul_container = container if container else website_container
ul_container.add_child(node)
await node.init(element, parser)
2025-07-28 15:22:34 +03:00
return node
2025-07-25 15:46:18 +03:00
"ol":
node = OL.instantiate()
2025-08-29 16:24:53 +03:00
var ol_container = container if container else website_container
ol_container.add_child(node)
await node.init(element, parser)
2025-07-28 15:22:34 +03:00
return node
2025-07-25 15:46:18 +03:00
"li":
node = P.instantiate()
2025-08-08 16:51:21 +03:00
node.init(element, parser)
2025-07-25 17:49:32 +03:00
"select":
node = SELECT.instantiate()
node.init(element, parser)
2025-07-25 18:55:28 +03:00
"textarea":
node = TEXTAREA.instantiate()
node.init(element, parser)
2025-08-11 17:08:39 +03:00
"audio":
node = AUDIO.instantiate()
node.init(element, parser)
2025-08-31 14:17:34 +03:00
"canvas":
node = CANVAS.instantiate()
node.init(element, parser)
2025-07-28 15:22:34 +03:00
"div":
var styles = parser.get_element_styles_with_inheritance(element, "", [])
var hover_styles = parser.get_element_styles_with_inheritance(element, "hover", [])
var is_flex_container = styles.has("display") and ("flex" in styles["display"])
var is_grid_container = styles.has("display") and ("grid" in styles["display"])
# For flex or grid divs, let the general flex/grid container logic handle them
if is_flex_container or is_grid_container:
return null
2025-08-01 21:16:48 +03:00
# Create div container
2025-08-27 20:23:05 +03:00
if BackgroundUtils.needs_background_wrapper(styles) or BackgroundUtils.needs_background_wrapper(hover_styles):
node = BackgroundUtils.create_panel_container_with_background(styles, hover_styles)
else:
2025-08-01 21:16:48 +03:00
node = DIV.instantiate()
node.init(element, parser)
2025-08-01 21:16:48 +03:00
var has_only_text = is_text_only_element(element)
if has_only_text:
var p_node = P.instantiate()
p_node.init(element, parser)
2025-08-12 21:30:41 +03:00
var div_styles = parser.get_element_styles_with_inheritance(element, "", [])
StyleManager.apply_styles_to_label(p_node, div_styles, element, parser)
2025-08-01 21:16:48 +03:00
var container_for_children = node
if node is PanelContainer and node.get_child_count() > 0:
container_for_children = node.get_child(0) # The VBoxContainer inside
safe_add_child(container_for_children, p_node)
2025-07-23 15:23:32 +03:00
_:
return null
return node
2025-07-31 22:02:03 +03:00
func register_font_dependent_element(label: Control, styles: Dictionary, element: HTMLParser.HTMLElement, parser: HTMLParser) -> void:
2025-07-31 22:02:03 +03:00
font_dependent_elements.append({
"label": label,
"styles": styles,
"element": element,
"parser": parser
})
func refresh_fonts(font_name: String) -> void:
# Find all elements that should use this font and refresh them
for element_info in font_dependent_elements:
var label = element_info["label"]
var styles = element_info["styles"]
var element = element_info["element"]
var parser = element_info["parser"]
if styles.has("font-family") and styles["font-family"] == font_name:
if is_instance_valid(label):
StyleManager.apply_styles_to_label(label, styles, element, parser)
func get_current_url() -> String:
return current_domain if not current_domain.is_empty() else ""
func reload_current_page() -> void:
if not current_domain.is_empty():
_on_search_submitted(current_domain)
func navigate_to_url(url: String) -> void:
var resolved_url = resolve_url(url)
_on_search_submitted(resolved_url)
2025-08-29 16:24:53 +03:00
func update_search_bar_from_current_domain() -> void:
if not search_bar.has_focus() and not current_domain.is_empty():
var display_text = current_domain
if display_text.begins_with("gurt://"):
display_text = display_text.substr(7)
search_bar.text = display_text
func get_active_tab() -> Tab:
if tab_container.active_tab >= 0 and tab_container.active_tab < tab_container.tabs.size():
return tab_container.tabs[tab_container.active_tab]
return null
func get_active_website_container() -> Control:
var active_tab = get_active_tab()
if active_tab:
return active_tab.website_container
return website_container # fallback to original container