mirror of
https://github.com/csd4ni3l/browser.git
synced 2026-01-01 04:03:43 +01:00
add tab support by having separate renderers and http clients, make link clicking open a new tab, add better default headers, fix style elements showing as text, fix crash if there are no needs but needs_render is True, fix view-source scheme not working,
This commit is contained in:
@@ -28,7 +28,7 @@ class HTTPClient():
|
||||
self.response_headers = {}
|
||||
self.response_http_version = None
|
||||
self.response_status = None
|
||||
self.nodes = []
|
||||
self.nodes = None
|
||||
self.css_rules = []
|
||||
self.content_response = ""
|
||||
self.view_source = False
|
||||
@@ -71,7 +71,7 @@ class HTTPClient():
|
||||
if "Host" not in self.request_headers:
|
||||
self.request_headers["Host"] = self.host
|
||||
|
||||
cache_filename = f"{self.scheme}_{self.host}_{self.port}_{self.path.replace('/', '_')}.json"
|
||||
cache_filename = f"{self.scheme}_{self.host}_{self.port}_{self.path.replace('/', '_')}.html"
|
||||
if os.path.exists(f"html_cache/{cache_filename}"):
|
||||
threading.Thread(target=self.parse, daemon=True).start()
|
||||
return
|
||||
@@ -190,7 +190,14 @@ class HTTPClient():
|
||||
def parse(self):
|
||||
self.css_rules = []
|
||||
|
||||
html_cache_filename = f"{self.scheme}_{self.host}_{self.port}_{self.path.replace('/', '_')}.json"
|
||||
html_cache_filename = f"{self.scheme}_{self.host}_{self.port}_{self.path.replace('/', '_')}.html"
|
||||
|
||||
if html_cache_filename in os.listdir("html_cache"):
|
||||
with open(f"html_cache/{html_cache_filename}", "r") as file:
|
||||
self.content_response = file.read()
|
||||
else:
|
||||
with open(f"html_cache/{html_cache_filename}", "w") as file:
|
||||
file.write(self.content_response)
|
||||
|
||||
original_scheme = self.scheme
|
||||
original_host = self.host
|
||||
@@ -198,15 +205,8 @@ class HTTPClient():
|
||||
original_path = self.path
|
||||
original_response = self.content_response
|
||||
|
||||
if html_cache_filename in os.listdir("html_cache"):
|
||||
with open(f"html_cache/{html_cache_filename}", "r") as file:
|
||||
self.nodes = HTML.from_json(ujson.load(file))
|
||||
else:
|
||||
self.nodes = HTML(self.content_response).parse()
|
||||
with open(f"html_cache/{html_cache_filename}", "w") as file:
|
||||
json_list = HTML.to_json(self.nodes)
|
||||
file.write(ujson.dumps(json_list))
|
||||
|
||||
self.nodes = HTML(self.content_response).parse()
|
||||
|
||||
css_links = [
|
||||
node.attributes["href"]
|
||||
for node in tree_to_list(self.nodes, [])
|
||||
|
||||
@@ -36,7 +36,8 @@ class HTML():
|
||||
for c in self.raw_html:
|
||||
if c == "<":
|
||||
in_tag = True
|
||||
if text: self.add_text(text) # start of new tag means before everything was content/text
|
||||
if (not self.unfinished or not self.unfinished[-1].tag == "style") and text:
|
||||
self.add_text(text) # start of new tag means before everything was content/text
|
||||
text = ""
|
||||
elif c == ">":
|
||||
in_tag = False
|
||||
@@ -173,6 +174,9 @@ def get_inline_styles(node):
|
||||
|
||||
for node in node.children:
|
||||
if isinstance(node, Element) and node.tag == "style":
|
||||
if not node.children:
|
||||
continue
|
||||
|
||||
if isinstance(node.children[0], Text):
|
||||
all_rules.extend(CSSParser(node.children[0].text).parse()) # node's first children will just be a text element that contains the css
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import arcade, pyglet, platform
|
||||
from utils.constants import BLOCK_ELEMENTS, token_pattern, emoji_pattern, INHERITED_PROPERTIES
|
||||
from utils.utils import get_color_from_name, hex_to_rgb
|
||||
|
||||
from http_client.connection import HTTPClient, resolve_url
|
||||
from http_client.html_parser import CSSParser, Text, Element, style, cascade_priority, replace_symbols, tree_to_list
|
||||
from http_client.connection import HTTPClient
|
||||
from http_client.html_parser import CSSParser, Text, Element, style, cascade_priority
|
||||
|
||||
from pyglet.font.base import Font as BaseFont
|
||||
|
||||
@@ -245,11 +245,11 @@ def paint_tree(layout_object, display_list):
|
||||
paint_tree(child, display_list)
|
||||
|
||||
class Renderer():
|
||||
def __init__(self, http_client: HTTPClient, view_class):
|
||||
def __init__(self, http_client: HTTPClient, window):
|
||||
self.content = ''
|
||||
self.request_scheme = 'http'
|
||||
self.view_class = view_class
|
||||
self.window: arcade.Window = view_class.window
|
||||
self.window: arcade.Window = window
|
||||
self.current_window_size = self.window.size
|
||||
self.http_client = http_client
|
||||
|
||||
self.scroll_y = 0
|
||||
@@ -261,10 +261,6 @@ class Renderer():
|
||||
self.widgets: list[pyglet.text.Label] = []
|
||||
self.text_to_create = []
|
||||
|
||||
self.window.on_mouse_scroll = self.on_mouse_scroll
|
||||
self.window.on_mouse_press = self.on_mouse_press
|
||||
self.window.on_resize = self.on_resize
|
||||
|
||||
self.batch = pyglet.graphics.Batch()
|
||||
|
||||
def hide_out_of_bounds_labels(self):
|
||||
@@ -279,8 +275,8 @@ class Renderer():
|
||||
widget.visible = True
|
||||
|
||||
def on_resize(self, width, height):
|
||||
if self.http_client.css_rules:
|
||||
self.http_client.needs_render = True
|
||||
self.current_window_size = self.window.size
|
||||
self.http_client.needs_render = True
|
||||
|
||||
def on_mouse_scroll(self, x, y, scroll_x, scroll_y):
|
||||
if not self.allow_scroll:
|
||||
@@ -289,40 +285,11 @@ class Renderer():
|
||||
old_y = self.scroll_y
|
||||
self.scroll_y = max(0, min(abs(self.scroll_y - (scroll_y * self.scroll_y_speed)), abs(self.smallest_y) - (self.window.height * 0.925) + 5)) # flip scroll direction
|
||||
|
||||
|
||||
for widget in self.widgets:
|
||||
widget.y += (self.scroll_y - old_y)
|
||||
|
||||
self.hide_out_of_bounds_labels()
|
||||
|
||||
def on_mouse_press(self, x: int, y: int, button: int, modifiers: int):
|
||||
if not self.document:
|
||||
return
|
||||
|
||||
y -= self.scroll_y
|
||||
|
||||
objs = [
|
||||
obj for obj in tree_to_list(self.document, [])
|
||||
if obj.x <= x < obj.x + obj.width
|
||||
and ((self.window.height * 0.925) - obj.y - obj.height) <= y < ((self.window.height * 0.925) - obj.y)
|
||||
]
|
||||
|
||||
if not objs:
|
||||
return
|
||||
|
||||
|
||||
elt = objs[-1].node
|
||||
|
||||
while elt:
|
||||
if isinstance(elt, Text):
|
||||
pass
|
||||
elif elt.tag == "a" and "href" in elt.attributes:
|
||||
url = resolve_url(self.http_client.scheme, self.http_client.host, self.http_client.port, self.http_client.path, elt.attributes["href"])
|
||||
self.http_client.get_request(url, self.http_client.request_headers)
|
||||
self.view_class.search_bar.text = url
|
||||
|
||||
elt = elt.parent
|
||||
|
||||
def add_text(self, x, y, text, font, color, multiline=False):
|
||||
self.widgets.append(
|
||||
pyglet.text.Label(
|
||||
@@ -331,6 +298,7 @@ class Renderer():
|
||||
italic=font.italic,
|
||||
weight=font.weight,
|
||||
font_size=font.size,
|
||||
width=self.window.width * 0.5 if multiline else None,
|
||||
multiline=multiline,
|
||||
color=color,
|
||||
x=x,
|
||||
@@ -369,19 +337,21 @@ class Renderer():
|
||||
self.smallest_y = 0
|
||||
|
||||
if self.http_client.view_source or self.http_client.scheme == "file":
|
||||
self.add_text(x=HSTEP, y=0, text=self.http_client.content_response, font=pyglet.font.load("Roboto", 16), multiline=True)
|
||||
self.add_text(x=HSTEP, y=self.window.height * 0.05, text=self.http_client.content_response, font=pyglet.font.load("Roboto", 16), color=arcade.color.BLACK, multiline=True)
|
||||
|
||||
elif self.http_client.scheme == "http" or self.http_client.scheme == "https":
|
||||
style(self.http_client.nodes, sorted(self.http_client.css_rules + CSSParser(open("assets/css/browser.css").read()).parse(), key=cascade_priority))
|
||||
if self.http_client.nodes:
|
||||
style(self.http_client.nodes, sorted(self.http_client.css_rules + CSSParser(open("assets/css/browser.css").read()).parse(), key=cascade_priority))
|
||||
|
||||
self.document = DocumentLayout(self.http_client.nodes)
|
||||
self.document.layout()
|
||||
self.cmds = []
|
||||
paint_tree(self.document, self.cmds)
|
||||
|
||||
for cmd in self.cmds:
|
||||
if isinstance(cmd, DrawText):
|
||||
self.add_text(cmd.left, cmd.top, cmd.text, cmd.font, cmd.color)
|
||||
elif isinstance(cmd, DrawRect):
|
||||
self.add_background(cmd.left, cmd.top, cmd.width, cmd.height, cmd.color)
|
||||
self.document = DocumentLayout(self.http_client.nodes)
|
||||
self.document.layout()
|
||||
self.cmds = []
|
||||
paint_tree(self.document, self.cmds)
|
||||
|
||||
for cmd in self.cmds:
|
||||
if isinstance(cmd, DrawText):
|
||||
self.add_text(cmd.left, cmd.top, cmd.text, cmd.font, cmd.color)
|
||||
elif isinstance(cmd, DrawRect):
|
||||
self.add_background(cmd.left, cmd.top, cmd.width, cmd.height, cmd.color)
|
||||
|
||||
self.hide_out_of_bounds_labels()
|
||||
self.hide_out_of_bounds_labels()
|
||||
Reference in New Issue
Block a user