browser history and navigation
This commit is contained in:
91
flumi/Scripts/BrowserHistory.gd
Normal file
91
flumi/Scripts/BrowserHistory.gd
Normal file
@@ -0,0 +1,91 @@
|
||||
extends Node
|
||||
|
||||
const HISTORY_FILE_PATH = "user://browser_history.json"
|
||||
const MAX_HISTORY_ENTRIES = 1000
|
||||
|
||||
func get_history_data() -> Array:
|
||||
var history_file = FileAccess.open(HISTORY_FILE_PATH, FileAccess.READ)
|
||||
if not history_file:
|
||||
return []
|
||||
|
||||
var json_string = history_file.get_as_text()
|
||||
history_file.close()
|
||||
|
||||
var json = JSON.new()
|
||||
var parse_result = json.parse(json_string)
|
||||
|
||||
if parse_result != OK:
|
||||
return []
|
||||
|
||||
var history_data = json.data
|
||||
if not history_data is Array:
|
||||
return []
|
||||
|
||||
return history_data
|
||||
|
||||
func save_history_data(history_data: Array):
|
||||
var history_file = FileAccess.open(HISTORY_FILE_PATH, FileAccess.WRITE)
|
||||
if not history_file:
|
||||
push_error("Failed to open history file for writing")
|
||||
return
|
||||
|
||||
var json_string = JSON.stringify(history_data)
|
||||
history_file.store_string(json_string)
|
||||
history_file.close()
|
||||
|
||||
func add_entry(url: String, title: String, icon_url: String = ""):
|
||||
if url.is_empty():
|
||||
return
|
||||
|
||||
var history_data = get_history_data()
|
||||
var timestamp = Time.get_datetime_string_from_system()
|
||||
|
||||
var existing_index = -1
|
||||
for i in range(history_data.size()):
|
||||
if history_data[i].url == url:
|
||||
existing_index = i
|
||||
break
|
||||
|
||||
var entry = {
|
||||
"url": url,
|
||||
"title": title,
|
||||
"timestamp": timestamp,
|
||||
"icon_url": icon_url
|
||||
}
|
||||
|
||||
if existing_index >= 0:
|
||||
history_data.remove_at(existing_index)
|
||||
|
||||
history_data.insert(0, entry)
|
||||
|
||||
if history_data.size() > MAX_HISTORY_ENTRIES:
|
||||
history_data = history_data.slice(0, MAX_HISTORY_ENTRIES)
|
||||
|
||||
save_history_data(history_data)
|
||||
|
||||
func remove_entry(url: String):
|
||||
var history_data = get_history_data()
|
||||
|
||||
for i in range(history_data.size() - 1, -1, -1):
|
||||
if history_data[i].url == url:
|
||||
history_data.remove_at(i)
|
||||
|
||||
save_history_data(history_data)
|
||||
|
||||
func clear_all():
|
||||
save_history_data([])
|
||||
|
||||
func search_history(query: String) -> Array:
|
||||
var history_data = get_history_data()
|
||||
var results = []
|
||||
|
||||
query = query.to_lower()
|
||||
|
||||
for entry in history_data:
|
||||
var title = entry.get("title", "").to_lower()
|
||||
var url = entry.get("url", "").to_lower()
|
||||
|
||||
if title.contains(query) or url.contains(query):
|
||||
results.append(entry)
|
||||
|
||||
return results
|
||||
1
flumi/Scripts/BrowserHistory.gd.uid
Normal file
1
flumi/Scripts/BrowserHistory.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://c8wiwde042pkx
|
||||
4
flumi/Scripts/DevTools.gd
Normal file
4
flumi/Scripts/DevTools.gd
Normal file
@@ -0,0 +1,4 @@
|
||||
extends Control
|
||||
|
||||
func _on_close_button_pressed():
|
||||
Engine.get_main_loop().current_scene._toggle_dev_tools()
|
||||
1
flumi/Scripts/DevTools.gd.uid
Normal file
1
flumi/Scripts/DevTools.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://21a6ds271vmb
|
||||
@@ -1,10 +1,31 @@
|
||||
extends Button
|
||||
|
||||
const HISTORY = preload("res://Scenes/BrowserMenus/history.tscn")
|
||||
|
||||
@onready var tab_container: TabManager = $"../../TabContainer"
|
||||
@onready var main: Main = $"../../../"
|
||||
|
||||
var history_scene: PopupPanel = null
|
||||
|
||||
func _on_pressed() -> void:
|
||||
%OptionsMenu.show()
|
||||
|
||||
func _input(_event: InputEvent) -> void:
|
||||
if _event is InputEventKey and _event.pressed and _event.ctrl_pressed:
|
||||
if _event.keycode == KEY_N:
|
||||
if _event.shift_pressed:
|
||||
# CTRL+SHIFT+N - New incognito window
|
||||
_on_options_menu_id_pressed(2)
|
||||
get_viewport().set_input_as_handled()
|
||||
else:
|
||||
# CTRL+N - New window
|
||||
_on_options_menu_id_pressed(1)
|
||||
get_viewport().set_input_as_handled()
|
||||
elif _event.keycode == KEY_H:
|
||||
# CTRL+H - History
|
||||
_on_options_menu_id_pressed(4)
|
||||
get_viewport().set_input_as_handled()
|
||||
|
||||
func _on_options_menu_id_pressed(id: int) -> void:
|
||||
if id == 0: # new tab
|
||||
tab_container.create_tab()
|
||||
@@ -14,4 +35,21 @@ func _on_options_menu_id_pressed(id: int) -> void:
|
||||
# TODO: handle incognito
|
||||
OS.create_process(OS.get_executable_path(), ["--incognito"])
|
||||
if id == 4: # history
|
||||
modulate = Constants.SECONDARY_COLOR
|
||||
show_history()
|
||||
if id == 10: # exit
|
||||
get_tree().quit()
|
||||
|
||||
func show_history() -> void:
|
||||
if history_scene == null:
|
||||
history_scene = HISTORY.instantiate()
|
||||
history_scene.navigate_to_url.connect(main.navigate_to_url)
|
||||
main.add_child(history_scene)
|
||||
|
||||
history_scene.connect("popup_hide", _on_history_closed)
|
||||
else:
|
||||
history_scene.load_history()
|
||||
history_scene.show()
|
||||
|
||||
func _on_history_closed() -> void:
|
||||
if history_scene:
|
||||
history_scene.hide()
|
||||
|
||||
@@ -41,6 +41,8 @@ var dev_tools_visible: bool = false
|
||||
var lua_apis: Array[LuaAPI] = []
|
||||
var current_url: String = ""
|
||||
var has_content: bool = false
|
||||
var navigation_history: Array[String] = []
|
||||
var history_index: int = -1
|
||||
|
||||
func _ready():
|
||||
add_to_group("tabs")
|
||||
@@ -70,8 +72,11 @@ func update_icon_from_url(icon_url: String) -> void:
|
||||
if icon_url.is_empty():
|
||||
const GLOBE_ICON = preload("res://Assets/Icons/globe.svg")
|
||||
set_icon(GLOBE_ICON)
|
||||
remove_meta("original_icon_url")
|
||||
return
|
||||
|
||||
set_meta("original_icon_url", icon_url)
|
||||
|
||||
var icon_resource = await Network.fetch_image(icon_url)
|
||||
|
||||
if is_instance_valid(self) and icon_resource:
|
||||
@@ -252,3 +257,39 @@ func get_dev_tools_console() -> DevToolsConsole:
|
||||
if dev_tools and dev_tools.has_method("get_console"):
|
||||
return dev_tools.get_console()
|
||||
return null
|
||||
|
||||
func add_to_navigation_history(url: String) -> void:
|
||||
if url.is_empty():
|
||||
return
|
||||
|
||||
# If we're not at the end of history, remove everything after current position
|
||||
if history_index < navigation_history.size() - 1:
|
||||
navigation_history = navigation_history.slice(0, history_index + 1)
|
||||
|
||||
# Don't add duplicate consecutive entries
|
||||
if navigation_history.is_empty() or navigation_history[-1] != url:
|
||||
navigation_history.append(url)
|
||||
history_index = navigation_history.size() - 1
|
||||
|
||||
func can_go_back() -> bool:
|
||||
return history_index > 0
|
||||
|
||||
func can_go_forward() -> bool:
|
||||
return history_index < navigation_history.size() - 1
|
||||
|
||||
func go_back() -> String:
|
||||
if can_go_back():
|
||||
history_index -= 1
|
||||
return navigation_history[history_index]
|
||||
return ""
|
||||
|
||||
func go_forward() -> String:
|
||||
if can_go_forward():
|
||||
history_index += 1
|
||||
return navigation_history[history_index]
|
||||
return ""
|
||||
|
||||
func get_current_history_url() -> String:
|
||||
if history_index >= 0 and history_index < navigation_history.size():
|
||||
return navigation_history[history_index]
|
||||
return ""
|
||||
|
||||
@@ -205,6 +205,8 @@ func set_active_tab(index: int) -> void:
|
||||
main.current_domain = ""
|
||||
main.search_bar.text = ""
|
||||
main.search_bar.grab_focus()
|
||||
|
||||
main.update_navigation_buttons()
|
||||
|
||||
func create_tab() -> void:
|
||||
var index = tabs.size();
|
||||
|
||||
@@ -65,3 +65,21 @@ static func resolve_url(base_url: String, relative_url: String) -> String:
|
||||
result += "/" + "/".join(final_path_parts)
|
||||
|
||||
return result
|
||||
|
||||
static func extract_domain(url: String) -> String:
|
||||
if url.is_empty():
|
||||
return ""
|
||||
|
||||
var clean_url = url
|
||||
if clean_url.begins_with("gurt://"):
|
||||
clean_url = clean_url.substr(7)
|
||||
elif clean_url.begins_with("https://"):
|
||||
clean_url = clean_url.substr(8)
|
||||
elif clean_url.begins_with("http://"):
|
||||
clean_url = clean_url.substr(7)
|
||||
|
||||
var slash_pos = clean_url.find("/")
|
||||
if slash_pos != -1:
|
||||
clean_url = clean_url.substr(0, slash_pos)
|
||||
|
||||
return clean_url
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
extends MarginContainer
|
||||
extends PopupPanel
|
||||
signal navigate_to_url(url: String)
|
||||
|
||||
@onready var history_entry_container: VBoxContainer = $Main/PanelContainer2/ScrollContainer/HistoryEntryContainer
|
||||
@onready var delete_menu: PanelContainer = $Main/DeleteMenu
|
||||
@onready var line_edit: LineEdit = $Main/LineEdit
|
||||
@onready var entries_label: RichTextLabel = $Main/DeleteMenu/HBoxContainer/RichTextLabel
|
||||
@onready var cancel_button: Button = $Main/DeleteMenu/HBoxContainer/CancelButton
|
||||
@onready var delete_button: Button = $Main/DeleteMenu/HBoxContainer/DeleteButton
|
||||
|
||||
var toggled_entries = []
|
||||
var history_entry_scene = preload("res://Scenes/BrowserMenus/history_entry.tscn")
|
||||
|
||||
func _ready():
|
||||
for entry in history_entry_container.get_children():
|
||||
entry.connect("checkbox_toggle", history_toggle.bind(entry))
|
||||
delete_button.pressed.connect(_on_delete_button_pressed)
|
||||
line_edit.text_changed.connect(_on_search_text_changed)
|
||||
load_history()
|
||||
|
||||
func history_toggle(toggled: bool, entry) -> void:
|
||||
print('toggling ', entry, ' to :', toggled)
|
||||
@@ -37,3 +41,80 @@ func _on_cancel_button_pressed() -> void:
|
||||
|
||||
delete_menu.hide()
|
||||
line_edit.show()
|
||||
|
||||
func _on_delete_button_pressed() -> void:
|
||||
var urls_to_delete = []
|
||||
for entry in toggled_entries:
|
||||
if entry.has_meta("history_url"):
|
||||
urls_to_delete.append(entry.get_meta("history_url"))
|
||||
|
||||
for url in urls_to_delete:
|
||||
remove_history_entry(url)
|
||||
|
||||
var entries_to_remove = toggled_entries.duplicate()
|
||||
toggled_entries.clear()
|
||||
|
||||
for entry in entries_to_remove:
|
||||
history_entry_container.remove_child(entry)
|
||||
entry.queue_free()
|
||||
|
||||
delete_menu.hide()
|
||||
line_edit.show()
|
||||
|
||||
func _on_search_text_changed(search_text: String) -> void:
|
||||
filter_history_entries(search_text)
|
||||
|
||||
func load_history():
|
||||
var history_data = BrowserHistory.get_history_data()
|
||||
var existing_entries = history_entry_container.get_children()
|
||||
|
||||
var needs_update = existing_entries.size() != history_data.size()
|
||||
|
||||
if not needs_update and history_data.size() > 0 and existing_entries.size() > 0:
|
||||
var first_entry = existing_entries[0]
|
||||
if first_entry.has_meta("history_url"):
|
||||
var stored_url = first_entry.get_meta("history_url")
|
||||
if stored_url != history_data[0].url:
|
||||
needs_update = true
|
||||
|
||||
if needs_update:
|
||||
clear_displayed_entries()
|
||||
for entry in history_data:
|
||||
add_history_entry_to_display(entry.url, entry.title, entry.timestamp, entry.icon_url)
|
||||
|
||||
show()
|
||||
|
||||
func clear_displayed_entries():
|
||||
for child in history_entry_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
func add_history_entry_to_display(url: String, title_: String, timestamp: String, icon_url: String = ""):
|
||||
var entry_instance = history_entry_scene.instantiate()
|
||||
history_entry_container.add_child(entry_instance)
|
||||
entry_instance.setup_entry(url, title_, timestamp, icon_url)
|
||||
entry_instance.connect("checkbox_toggle", history_toggle.bind(entry_instance))
|
||||
entry_instance.connect("entry_clicked", _on_entry_clicked)
|
||||
entry_instance.set_meta("history_url", url)
|
||||
|
||||
func filter_history_entries(search_text: String):
|
||||
if search_text.is_empty():
|
||||
# Show all entries
|
||||
for child in history_entry_container.get_children():
|
||||
child.visible = true
|
||||
return
|
||||
|
||||
# Filter existing entries by showing/hiding them
|
||||
var query = search_text.to_lower()
|
||||
for child in history_entry_container.get_children():
|
||||
if child.has_method("get_title") and child.has_method("get_url"):
|
||||
var title_ = child.get_title().to_lower()
|
||||
var url = child.get_url().to_lower()
|
||||
child.visible = title_.contains(query) or url.contains(query)
|
||||
else:
|
||||
child.visible = false
|
||||
|
||||
func remove_history_entry(url: String):
|
||||
BrowserHistory.remove_entry(url)
|
||||
|
||||
func _on_entry_clicked(url: String):
|
||||
navigate_to_url.emit(url)
|
||||
|
||||
@@ -1,10 +1,84 @@
|
||||
extends HBoxContainer
|
||||
signal checkbox_toggle
|
||||
signal entry_clicked(url: String)
|
||||
|
||||
@onready var check_box: CheckBox = $CheckBox
|
||||
@onready var time_label: RichTextLabel = $RichTextLabel
|
||||
@onready var icon: TextureRect = $TextureRect
|
||||
@onready var title_label: RichTextLabel = $RichTextLabel2
|
||||
@onready var domain_label: RichTextLabel = $DomainLabel
|
||||
|
||||
var entry_url: String = ""
|
||||
var entry_title: String = ""
|
||||
|
||||
func reset() -> void:
|
||||
check_box.set_pressed_no_signal(false)
|
||||
|
||||
func _on_check_box_toggled(toggled_on: bool) -> void:
|
||||
checkbox_toggle.emit(toggled_on)
|
||||
|
||||
func setup_entry(url: String, title: String, timestamp: String, icon_url: String = ""):
|
||||
entry_url = url
|
||||
entry_title = title
|
||||
|
||||
title_label.text = title if not title.is_empty() else url
|
||||
|
||||
var domain = URLUtils.extract_domain(url)
|
||||
if domain.is_empty():
|
||||
domain = url
|
||||
domain_label.text = domain
|
||||
|
||||
var datetime_dict = Time.get_datetime_dict_from_datetime_string(timestamp, false)
|
||||
if datetime_dict.has("hour") and datetime_dict.has("minute"):
|
||||
var hour = datetime_dict.hour
|
||||
var minute = datetime_dict.minute
|
||||
var am_pm = "AM"
|
||||
|
||||
if hour == 0:
|
||||
hour = 12
|
||||
elif hour > 12:
|
||||
hour -= 12
|
||||
am_pm = "PM"
|
||||
elif hour == 12:
|
||||
am_pm = "PM"
|
||||
|
||||
time_label.text = "%d:%02d%s" % [hour, minute, am_pm]
|
||||
else:
|
||||
time_label.text = ""
|
||||
|
||||
if not icon_url.is_empty():
|
||||
_load_icon(icon_url)
|
||||
else:
|
||||
const GLOBE_ICON = preload("res://Assets/Icons/globe.svg")
|
||||
icon.texture = GLOBE_ICON
|
||||
|
||||
func _load_icon(icon_url: String):
|
||||
if icon_url.is_empty():
|
||||
const GLOBE_ICON = preload("res://Assets/Icons/globe.svg")
|
||||
icon.texture = GLOBE_ICON
|
||||
return
|
||||
|
||||
icon.texture = null
|
||||
|
||||
var icon_resource = await Network.fetch_image(icon_url)
|
||||
|
||||
if is_instance_valid(self) and icon_resource:
|
||||
icon.texture = icon_resource
|
||||
elif is_instance_valid(self):
|
||||
const GLOBE_ICON = preload("res://Assets/Icons/globe.svg")
|
||||
icon.texture = GLOBE_ICON
|
||||
|
||||
func get_title() -> String:
|
||||
return entry_title
|
||||
|
||||
func get_url() -> String:
|
||||
return entry_url
|
||||
|
||||
func _ready():
|
||||
title_label.gui_input.connect(_on_title_clicked)
|
||||
domain_label.gui_input.connect(_on_title_clicked)
|
||||
|
||||
func _on_title_clicked(event: InputEvent):
|
||||
if event is InputEventMouseButton:
|
||||
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
|
||||
entry_clicked.emit(entry_url)
|
||||
|
||||
@@ -4,6 +4,9 @@ extends Control
|
||||
@onready var website_container: Control = %WebsiteContainer
|
||||
@onready var tab_container: TabManager = $VBoxContainer/TabContainer
|
||||
@onready var search_bar: LineEdit = $VBoxContainer/HBoxContainer/LineEdit
|
||||
@onready var back_button: Button = $VBoxContainer/HBoxContainer/BackButton
|
||||
@onready var forward_button: Button = $VBoxContainer/HBoxContainer/ForwardButton
|
||||
@onready var refresh_button: Button = $VBoxContainer/HBoxContainer/RefreshButton
|
||||
|
||||
const LOADER_CIRCLE = preload("res://Assets/Icons/loader-circle.svg")
|
||||
const AUTO_SIZING_FLEX_CONTAINER = preload("res://Scripts/AutoSizingFlexContainer.gd")
|
||||
@@ -63,6 +66,7 @@ func _ready():
|
||||
original_scroll.visible = false
|
||||
|
||||
call_deferred("render")
|
||||
call_deferred("update_navigation_buttons")
|
||||
|
||||
func _input(_event: InputEvent) -> void:
|
||||
if Input.is_action_just_pressed("DevTools"):
|
||||
@@ -87,7 +91,7 @@ func handle_link_click(meta: Variant) -> void:
|
||||
else:
|
||||
OS.shell_open(resolved_url)
|
||||
|
||||
func _on_search_submitted(url: String) -> void:
|
||||
func _on_search_submitted(url: String, add_to_history: bool = true) -> void:
|
||||
print("Search submitted: ", url)
|
||||
|
||||
search_bar.release_focus()
|
||||
@@ -102,11 +106,11 @@ func _on_search_submitted(url: String) -> void:
|
||||
if not gurt_url.begins_with("gurt://"):
|
||||
gurt_url = "gurt://" + gurt_url
|
||||
|
||||
await fetch_gurt_content_async(gurt_url, tab, url)
|
||||
await fetch_gurt_content_async(gurt_url, tab, url, add_to_history)
|
||||
else:
|
||||
print("Non-GURT URL entered: ", url)
|
||||
|
||||
func fetch_gurt_content_async(gurt_url: String, tab: Tab, original_url: String) -> void:
|
||||
func fetch_gurt_content_async(gurt_url: String, tab: Tab, original_url: String, add_to_history: bool = true) -> void:
|
||||
main_navigation_request = NetworkManager.start_request(gurt_url, "GET", false)
|
||||
main_navigation_request.type = NetworkRequest.RequestType.DOC
|
||||
network_start_time = Time.get_ticks_msec()
|
||||
@@ -121,7 +125,7 @@ func fetch_gurt_content_async(gurt_url: String, tab: Tab, original_url: String)
|
||||
|
||||
var result = thread.wait_to_finish()
|
||||
|
||||
_handle_gurt_result(result, tab, original_url, gurt_url)
|
||||
_handle_gurt_result(result, tab, original_url, gurt_url, add_to_history)
|
||||
|
||||
func _perform_gurt_request_threaded(request_data: Dictionary) -> Dictionary:
|
||||
var gurt_url: String = request_data.gurt_url
|
||||
@@ -149,7 +153,7 @@ func _perform_gurt_request_threaded(request_data: Dictionary) -> Dictionary:
|
||||
|
||||
return {"success": true, "html_bytes": response.body}
|
||||
|
||||
func _handle_gurt_result(result: Dictionary, tab: Tab, original_url: String, gurt_url: String) -> void:
|
||||
func _handle_gurt_result(result: Dictionary, tab: Tab, original_url: String, gurt_url: String, add_to_history: bool = true) -> void:
|
||||
if not result.success:
|
||||
print("GURT request failed: ", result.error)
|
||||
handle_gurt_error(result.error, tab)
|
||||
@@ -173,6 +177,11 @@ func _handle_gurt_result(result: Dictionary, tab: Tab, original_url: String, gur
|
||||
main_navigation_request = null
|
||||
|
||||
tab.stop_loading()
|
||||
|
||||
if add_to_history:
|
||||
add_to_history(gurt_url, tab)
|
||||
else:
|
||||
update_navigation_buttons()
|
||||
|
||||
func handle_gurt_error(error_message: String, tab: Tab) -> void:
|
||||
var error_html = GurtProtocol.create_error_page(error_message)
|
||||
@@ -301,6 +310,9 @@ func render_content(html_bytes: PackedByteArray) -> void:
|
||||
var icon = parser.get_icon()
|
||||
tab.update_icon_from_url(icon)
|
||||
|
||||
if not icon.is_empty():
|
||||
tab.set_meta("parsed_icon_url", icon)
|
||||
|
||||
var body = parser.find_first("body")
|
||||
|
||||
if body:
|
||||
@@ -719,9 +731,12 @@ 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)
|
||||
func navigate_to_url(url: String, add_to_history: bool = true) -> void:
|
||||
if url.begins_with("gurt://"):
|
||||
_on_search_submitted(url, add_to_history)
|
||||
else:
|
||||
var resolved_url = resolve_url(url)
|
||||
_on_search_submitted(resolved_url, add_to_history)
|
||||
|
||||
func update_search_bar_from_current_domain() -> void:
|
||||
if not search_bar.has_focus() and not current_domain.is_empty():
|
||||
@@ -746,3 +761,54 @@ func get_dev_tools_console() -> DevToolsConsole:
|
||||
if active_tab:
|
||||
return active_tab.get_dev_tools_console()
|
||||
return null
|
||||
|
||||
func add_to_history(url: String, tab: Tab, add_to_navigation: bool = true):
|
||||
if url.is_empty():
|
||||
return
|
||||
|
||||
var title = "New Tab"
|
||||
var icon_url = ""
|
||||
|
||||
if tab:
|
||||
if add_to_navigation:
|
||||
tab.add_to_navigation_history(url)
|
||||
|
||||
if tab.button and tab.button.text:
|
||||
title = tab.button.text
|
||||
|
||||
if tab.has_meta("parsed_icon_url"):
|
||||
icon_url = tab.get_meta("parsed_icon_url")
|
||||
|
||||
var clean_url = url
|
||||
if clean_url.begins_with("gurt://"):
|
||||
clean_url = clean_url.substr(7)
|
||||
|
||||
BrowserHistory.add_entry(clean_url, title, icon_url)
|
||||
update_navigation_buttons()
|
||||
|
||||
func _on_back_button_pressed() -> void:
|
||||
var active_tab = get_active_tab()
|
||||
if active_tab and active_tab.can_go_back():
|
||||
var url = active_tab.go_back()
|
||||
if not url.is_empty():
|
||||
navigate_to_url(url, false)
|
||||
|
||||
func _on_forward_button_pressed() -> void:
|
||||
var active_tab = get_active_tab()
|
||||
if active_tab and active_tab.can_go_forward():
|
||||
var url = active_tab.go_forward()
|
||||
if not url.is_empty():
|
||||
navigate_to_url(url, false)
|
||||
|
||||
func _on_refresh_button_pressed() -> void:
|
||||
reload_current_page()
|
||||
|
||||
func update_navigation_buttons() -> void:
|
||||
var active_tab = get_active_tab()
|
||||
if active_tab:
|
||||
back_button.disabled = not active_tab.can_go_back()
|
||||
forward_button.disabled = not active_tab.can_go_forward()
|
||||
else:
|
||||
back_button.disabled = true
|
||||
forward_button.disabled = true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user