From 278871d937c3bd6b5cc275fd81fe279c09ed5ef7 Mon Sep 17 00:00:00 2001 From: UnlegitDqrk Date: Tue, 10 Feb 2026 23:13:58 +0100 Subject: [PATCH] Rendering und Lua working, need to work on request method via custom URL implementation --- pom.xml | 9 +- .../webclient/{recode => }/ClientImpl.java | 54 +-- .../webclient/Main.java | 97 ++---- .../webclient/lua/WebLogger.java | 36 ++ .../webclient/lua/hosts/ConsoleHostImpl.java | 37 +++ .../webclient/lua/hosts/UiHostImpl.java | 312 ++++++++++++++++++ .../webclient/network/Promise.java | 59 ---- .../webclient/network/WebClient.java | 172 ---------- .../network/handlers/ServerPacketHandler.java | 43 --- .../webclient/network/type/NTFType.java | 13 - .../network/type/NetTransmitFile.java | 34 -- .../network/type/NetTransmitUnknown.java | 20 -- .../type/application/NetAppstreamFile.java | 25 -- .../network/type/image/NetTransmitIcon.java | 25 -- .../type/text/NetTransmitDocument.java | 23 -- .../type/text/NetTransmitStylesheet.java | 25 -- .../webclient/network/website/WebSite.java | 104 ------ .../webclient/network/website/tab/Tab.java | 19 -- .../webclient/network/website/tab/WebTab.java | 91 ----- .../packetlistener/PacketListener.java | 27 -- .../listeners/WebPacketListener.java | 62 ---- .../webclient/recode/Main.java | 72 ---- .../webclient/recode/ui/TabView.java | 197 ----------- .../webclient/settings/FxEngine.java | 144 ++++++++ .../{recode => }/settings/INSList.java | 4 +- .../webclient/ui/BrowserFrame.java | 14 - .../webclient/{recode => }/ui/BrowserTab.java | 14 +- .../webclient/{recode => }/ui/BrowserUI.java | 21 +- .../webclient/{recode => ui}/FxBootstrap.java | 2 +- .../webclient/ui/MainFrame.java | 70 ---- .../webclient/ui/MenuButton.java | 112 ------- .../webclient/ui/RoundedBorder.java | 44 --- .../webclient/ui/TabView.java | 165 +++++++++ .../webclient/ui/TopBar.java | 83 ----- .../webclient/ui/dom/DOMContainerPanel.java | 52 --- .../webclient/ui/dom/DomSerializer.java | 126 ------- .../webclient/ui/tab/TabButton.java | 35 -- .../webclient/ui/tab/TabButtonView.java | 53 --- 38 files changed, 757 insertions(+), 1738 deletions(-) rename src/main/java/org/openautonomousconnection/webclient/{recode => }/ClientImpl.java (51%) create mode 100644 src/main/java/org/openautonomousconnection/webclient/lua/WebLogger.java create mode 100644 src/main/java/org/openautonomousconnection/webclient/lua/hosts/ConsoleHostImpl.java create mode 100644 src/main/java/org/openautonomousconnection/webclient/lua/hosts/UiHostImpl.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/Promise.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/WebClient.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/handlers/ServerPacketHandler.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/type/NTFType.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/type/NetTransmitFile.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/type/NetTransmitUnknown.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/type/application/NetAppstreamFile.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/type/image/NetTransmitIcon.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/type/text/NetTransmitDocument.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/type/text/NetTransmitStylesheet.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/website/WebSite.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/website/tab/Tab.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/network/website/tab/WebTab.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/packetlistener/PacketListener.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/packetlistener/listeners/WebPacketListener.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/recode/Main.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/recode/ui/TabView.java create mode 100644 src/main/java/org/openautonomousconnection/webclient/settings/FxEngine.java rename src/main/java/org/openautonomousconnection/webclient/{recode => }/settings/INSList.java (77%) delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/BrowserFrame.java rename src/main/java/org/openautonomousconnection/webclient/{recode => }/ui/BrowserTab.java (91%) rename src/main/java/org/openautonomousconnection/webclient/{recode => }/ui/BrowserUI.java (92%) rename src/main/java/org/openautonomousconnection/webclient/{recode => ui}/FxBootstrap.java (93%) delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/MainFrame.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/MenuButton.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/RoundedBorder.java create mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/TabView.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/TopBar.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/dom/DOMContainerPanel.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/dom/DomSerializer.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/tab/TabButton.java delete mode 100644 src/main/java/org/openautonomousconnection/webclient/ui/tab/TabButtonView.java diff --git a/pom.xml b/pom.xml index 9c315a3..a0aaa1e 100644 --- a/pom.xml +++ b/pom.xml @@ -105,11 +105,6 @@ - - org.openautonomousconnection - Protocol - 1.0.0-BETA.7.7 - org.openautonomousconnection OACSwing @@ -124,12 +119,12 @@ org.openautonomousconnection LuaScript - 1.0.0-BETA.1.4 + 1.0.0-BETA.1.5 org.openautonomousconnection InfoNameLib - 1.0.0-BETA.1.1 + 1.0.0-BETA.1.3 org.openjfx diff --git a/src/main/java/org/openautonomousconnection/webclient/recode/ClientImpl.java b/src/main/java/org/openautonomousconnection/webclient/ClientImpl.java similarity index 51% rename from src/main/java/org/openautonomousconnection/webclient/recode/ClientImpl.java rename to src/main/java/org/openautonomousconnection/webclient/ClientImpl.java index 39474ce..51ac346 100644 --- a/src/main/java/org/openautonomousconnection/webclient/recode/ClientImpl.java +++ b/src/main/java/org/openautonomousconnection/webclient/ClientImpl.java @@ -1,24 +1,13 @@ -package org.openautonomousconnection.webclient.recode; +package org.openautonomousconnection.webclient; -import dev.unlegitdqrk.unlegitlibrary.event.EventListener; import dev.unlegitdqrk.unlegitlibrary.event.Listener; -import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.C_PacketSendEvent; -import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.state.ClientConnectedEvent; -import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.state.ClientDisconnectedEvent; -import dev.unlegitdqrk.unlegitlibrary.network.system.utils.TransportProtocol; +import org.openautonomousconnection.infonamelib.OacWebUrlInstaller; +import org.openautonomousconnection.infonamelib.ProtocolHandlerPackages; import org.openautonomousconnection.oacswing.component.OACOptionPane; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket; import org.openautonomousconnection.protocol.side.client.ProtocolClient; import org.openautonomousconnection.protocol.side.client.events.ConnectedToProtocolINSServerEvent; -import org.openautonomousconnection.protocol.side.client.events.ConnectedToProtocolServerEvent; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.WebRequestMethod; import javax.swing.*; -import java.util.List; -import java.util.Map; public class ClientImpl extends ProtocolClient { @Override @@ -65,46 +54,17 @@ public class ClientImpl extends ProtocolClient { return result == 0; } - @Override - public void onResponse(INSResponseStatus status, List records) { - try { - String host = records.getFirst().value; - if (!host.contains(":")) host = host + ":1028"; - String[] split = host.split(":"); - Main.getClient().getClientServerConnection().connect(split[0], Integer.parseInt(split[1])); - } catch (Exception e) { - Main.getClient().getProtocolBridge().getLogger().exception("Failed to connect to Server", e); - OACOptionPane.showMessageDialog(Main.getUi(), "Failed to connect to Server:\n" + e.getMessage(), - "Server Connection", OACOptionPane.ERROR_MESSAGE); - } - - super.onResponse(status, records); - } - @Listener public void onConnected(ConnectedToProtocolINSServerEvent event) { try { - Main.getClient().buildServerConnection(null, true); + buildServerConnection(null, getProtocolBridge().getProtocolValues().ssl); + ProtocolHandlerPackages.installPackage("org.openautonomousconnection.infonamelib"); + OacWebUrlInstaller.installOnce(getProtocolBridge().getProtocolValues().eventManager, this); + SwingUtilities.invokeLater(() -> Main.getUi().openNewTab("web://info.oac/")); } catch (Exception e) { Main.getClient().getProtocolBridge().getLogger().exception("Failed to build Server connection", e); OACOptionPane.showMessageDialog(Main.getUi(), "Failed to connect to build Server connection:\n" + e.getMessage(), "Server Connection", OACOptionPane.ERROR_MESSAGE); } - - Main.getUi().openNewTab("register.oac"); - } - - @Listener - public void onConnected(ConnectedToProtocolServerEvent event) { - try { - this.getClientServerConnection().sendPacket(new WebRequestPacket( - "index.html", - WebRequestMethod.GET, - Map.of(), - null - ), TransportProtocol.TCP); - } catch (Exception e) { - throw new RuntimeException(e); - } } } diff --git a/src/main/java/org/openautonomousconnection/webclient/Main.java b/src/main/java/org/openautonomousconnection/webclient/Main.java index 1f13b71..400030d 100644 --- a/src/main/java/org/openautonomousconnection/webclient/Main.java +++ b/src/main/java/org/openautonomousconnection/webclient/Main.java @@ -1,100 +1,69 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - package org.openautonomousconnection.webclient; import dev.unlegitdqrk.unlegitlibrary.event.EventManager; import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler; -import org.openautonomousconnection.infonamelib.InfoNames; +import lombok.Getter; import org.openautonomousconnection.oacswing.component.design.Design; import org.openautonomousconnection.oacswing.component.design.DesignManager; -import org.openautonomousconnection.oacswing.component.design.OACColor; import org.openautonomousconnection.protocol.ProtocolBridge; import org.openautonomousconnection.protocol.ProtocolValues; import org.openautonomousconnection.protocol.versions.ProtocolVersion; -import org.openautonomousconnection.webclient.network.WebClient; -import org.openautonomousconnection.webclient.network.handlers.ServerPacketHandler; -import org.openautonomousconnection.webclient.packetlistener.listeners.WebPacketListener; -import org.openautonomousconnection.webclient.ui.MainFrame; -import org.openautonomousconnection.webclient.ui.dom.DOMContainerPanel; +import org.openautonomousconnection.webclient.settings.INSList; +import org.openautonomousconnection.webclient.ui.BrowserUI; +import org.openautonomousconnection.webclient.ui.FxBootstrap; -import java.beans.EventHandler; +import javax.swing.*; import java.io.File; public class Main { - public static MainFrame mainFrame; - public static final String DEFAULT_INS = "open-autonomous-connection.org"; + @Getter + private static ClientImpl client; - public static final int DEFAULT_INS_PORT_TCP = 1026; - public static final int DEFAULT_WEB_PORT_TCP = 1028; + private static ProtocolBridge bridge; - private static final ProtocolVersion PROTOCOL_VERSION = ProtocolVersion.PV_1_0_0_BETA; - - public static WebClient client; - - public static ProtocolBridge bridge; - - public static void main(String[] args) { - initProtocol(); - - InfoNames.registerOACInfoNameProtocols(); - - try { - registerEventHandlers(); - } catch (Exception e) { - throw new RuntimeException(e); - } - registerPacketListeners(); - - /* Darkmode, wohoo! */ - initDesigns(); - - DesignManager.setGlobalDesign(Design.DARK); - - mainFrame = new MainFrame(); - - mainFrame.setVisible(true); - } + @Getter + private static BrowserUI ui; private static void initProtocol() { - ProtocolValues values = new ProtocolValues(); - values.packetHandler = new PacketHandler(); values.eventManager = new EventManager(); + values.ssl = true; - client = new WebClient(); + client = new ClientImpl(); try { bridge = new ProtocolBridge( client, values, - PROTOCOL_VERSION, + ProtocolVersion.PV_1_0_0_BETA, new File("logs") - ); + ); - // TODO - client.connectToINSServer(Main.DEFAULT_INS, -1); + client.buildINSConnection(); } catch (Exception e) { throw new RuntimeException(e); } } - private static void registerEventHandlers() throws Exception { - EventManager eventManager = bridge.getProtocolValues().eventManager; + public static void main(String[] args) { + initProtocol(); + FxBootstrap.ensureInitialized(); + DesignManager.setGlobalDesign(Design.DARK); - eventManager.registerListener(new ServerPacketHandler()); + SwingUtilities.invokeLater(() -> { + ui = new BrowserUI(); + ui.setSize(1200, 800); + ui.setLocationRelativeTo(null); + ui.setVisible(true); + + try { + bridge.getProtocolValues().eventManager.registerListener(client); + client.getClientINSConnection().connect(INSList.DEFAULT_INS, INSList.DEFAULT_PORT); + } catch (Exception exception) { + exception.printStackTrace(System.out); + } + }); } - - private static void registerPacketListeners() { - ServerPacketHandler.registerPacketListener(new WebPacketListener()); - } - - private static void initDesigns() { - //TODO - - //DesignManager.getInstance().registerComponent(DOMContainerPanel.class, OACColor.DARK_BACKGROUND); - } -} +} \ No newline at end of file diff --git a/src/main/java/org/openautonomousconnection/webclient/lua/WebLogger.java b/src/main/java/org/openautonomousconnection/webclient/lua/WebLogger.java new file mode 100644 index 0000000..509e8b9 --- /dev/null +++ b/src/main/java/org/openautonomousconnection/webclient/lua/WebLogger.java @@ -0,0 +1,36 @@ +package org.openautonomousconnection.webclient.lua; + +import org.openautonomousconnection.webclient.Main; + +public class WebLogger { + + private final String host; + + public WebLogger(String host) { + this.host = host; + } + + public void log(String string) { + Main.getClient().getProtocolBridge().getLogger().log(host + ": " + string); + } + + public void info(String info) { + Main.getClient().getProtocolBridge().getLogger().info(host + ": " + info); + } + + public void warn(String warn) { + Main.getClient().getProtocolBridge().getLogger().warn(host + ": " + warn); + } + + public void error(String error) { + Main.getClient().getProtocolBridge().getLogger().error(host + ": " + error); + } + + public void exception(String infoLine, Exception exception) { + Main.getClient().getProtocolBridge().getLogger().exception(host + ": " + infoLine, exception); + } + + public void debug(String debug) { + Main.getClient().getProtocolBridge().getLogger().debug(host + ": " + debug); + } +} diff --git a/src/main/java/org/openautonomousconnection/webclient/lua/hosts/ConsoleHostImpl.java b/src/main/java/org/openautonomousconnection/webclient/lua/hosts/ConsoleHostImpl.java new file mode 100644 index 0000000..714ddcd --- /dev/null +++ b/src/main/java/org/openautonomousconnection/webclient/lua/hosts/ConsoleHostImpl.java @@ -0,0 +1,37 @@ +package org.openautonomousconnection.webclient.lua.hosts; + +import org.openautonomousconnection.luascript.hosts.ConsoleHost; +import org.openautonomousconnection.webclient.lua.WebLogger; + +public class ConsoleHostImpl implements ConsoleHost { + private final WebLogger logger; + + public ConsoleHostImpl(WebLogger logger) { + this.logger = logger; + } + + @Override + public void info(String message) { + logger.info(message); + } + + @Override + public void log(String message) { + logger.log(message); + } + + @Override + public void warn(String message) { + logger.warn(message); + } + + @Override + public void error(String message) { + logger.error(message); + } + + @Override + public void exception(String message) { + logger.exception("", new RuntimeException(message)); + } +} diff --git a/src/main/java/org/openautonomousconnection/webclient/lua/hosts/UiHostImpl.java b/src/main/java/org/openautonomousconnection/webclient/lua/hosts/UiHostImpl.java new file mode 100644 index 0000000..c509939 --- /dev/null +++ b/src/main/java/org/openautonomousconnection/webclient/lua/hosts/UiHostImpl.java @@ -0,0 +1,312 @@ +package org.openautonomousconnection.webclient.lua.hosts; + +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import org.openautonomousconnection.luascript.fx.FxDomHost; +import org.openautonomousconnection.luascript.fx.FxThreadBridge; +import org.openautonomousconnection.luascript.hosts.UiHost; +import org.w3c.dom.Element; + +import java.util.Objects; + +/** + * UiHost implementation for JavaFX WebView (no JavaScript). + * + *

Operations are implemented via W3C DOM attributes/text, and best-effort behavior for + * value/style/class using standard attributes.

+ */ +public final class UiHostImpl implements UiHost { + + private final WebEngine engine; + private final WebView view; + private final FxDomHost dom; + + /** + * Creates a new UI host. + * + * @param engine web engine + * @param view web view + * @param dom dom host + */ + public UiHostImpl(WebEngine engine, WebView view, FxDomHost dom) { + this.engine = Objects.requireNonNull(engine, "engine"); + this.view = view; + this.dom = Objects.requireNonNull(dom, "dom"); + } + + @Override + public void alert(String message) { + // No JS: use simple JavaFX dialog-less fallback (log-style). You can replace with real Dialogs later. + // Keeping it deterministic and non-blocking for now. + System.out.println("[ui.alert] " + (message == null ? "" : message)); + } + + @Override + public boolean confirm(String message) { + // No JS: deterministic default (false). Replace with JavaFX dialogs if you want UI interaction. + System.out.println("[ui.confirm] " + (message == null ? "" : message)); + return false; + } + + @Override + public String prompt(String message, String defaultValue) { + // No JS: deterministic default. + System.out.println("[ui.prompt] " + (message == null ? "" : message)); + return defaultValue; + } + + @Override + public void setText(String elementId, String text) { + dom.setTextContent(elementId, text); + } + + @Override + public String getText(String elementId) { + return dom.getTextContent(elementId); + } + + @Override + public void setHtml(String elementId, String html) { + // Without JS, safest is to set textContent (prevents HTML parsing). + // If you need real HTML injection, we must extend DomHost with fragment parsing (not in current API). + dom.setTextContent(elementId, html); + } + + @Override + public String getHtml(String elementId) { + // Without JS, best-effort: return textContent. + return dom.getTextContent(elementId); + } + + @Override + public void setValue(String elementId, String value) { + // Input/textarea value is commonly reflected as attribute "value". + dom.setAttribute(elementId, "value", value == null ? "" : value); + } + + @Override + public String getValue(String elementId) { + String v = dom.getAttribute(elementId, "value"); + return v == null ? "" : v; + } + + @Override + public void setEnabled(String elementId, boolean enabled) { + if (enabled) dom.removeAttribute(elementId, "disabled"); + else dom.setAttribute(elementId, "disabled", "disabled"); + } + + @Override + public void setVisible(String elementId, boolean visible) { + // Best-effort via style attribute + String style = dom.getAttribute(elementId, "style"); + style = style == null ? "" : style; + + style = removeCssProp(style, "display"); + if (!visible) { + style = style.trim(); + if (!style.isEmpty() && !style.endsWith(";")) style += ";"; + style += "display:none;"; + } + + dom.setAttribute(elementId, "style", style); + } + + @Override + public void addClass(String elementId, String className) { + String cls = Objects.requireNonNull(className, "className").trim(); + if (cls.isEmpty()) return; + + FxThreadBridge.runAndWait(() -> { + Element el = dom.byId(elementId); + String c = el.getAttribute("class"); + c = (c == null) ? "" : c.trim(); + + if (c.isEmpty()) { + el.setAttribute("class", cls); + return; + } + + if (!hasClassToken(c, cls)) { + el.setAttribute("class", c + " " + cls); + } + }); + } + + @Override + public void removeClass(String elementId, String className) { + String cls = Objects.requireNonNull(className, "className").trim(); + if (cls.isEmpty()) return; + + FxThreadBridge.runAndWait(() -> { + Element el = dom.byId(elementId); + String c = el.getAttribute("class"); + c = (c == null) ? "" : c.trim(); + if (c.isEmpty()) return; + + String[] parts = c.split("\\s+"); + StringBuilder sb = new StringBuilder(); + for (String p : parts) { + if (p.equals(cls)) continue; + if (!sb.isEmpty()) sb.append(' '); + sb.append(p); + } + el.setAttribute("class", sb.toString()); + }); + } + + @Override + public boolean toggleClass(String elementId, String className) { + if (hasClass(elementId, className)) { + removeClass(elementId, className); + return false; + } + addClass(elementId, className); + return true; + } + + @Override + public boolean hasClass(String elementId, String className) { + String cls = Objects.requireNonNull(className, "className").trim(); + if (cls.isEmpty()) return false; + + return FxThreadBridge.callAndWait(() -> { + Element el = dom.byId(elementId); + String c = el.getAttribute("class"); + c = (c == null) ? "" : c.trim(); + return !c.isEmpty() && hasClassToken(c, cls); + }); + } + + @Override + public void setStyle(String elementId, String property, String value) { + String prop = Objects.requireNonNull(property, "property").trim().toLowerCase(); + if (prop.isEmpty()) return; + + String style = dom.getAttribute(elementId, "style"); + style = style == null ? "" : style; + + style = removeCssProp(style, prop); + String v = value == null ? "" : value.trim(); + + if (!v.isEmpty()) { + style = style.trim(); + if (!style.isEmpty() && !style.endsWith(";")) style += ";"; + style += prop + ":" + v + ";"; + } + dom.setAttribute(elementId, "style", style); + } + + @Override + public String getStyle(String elementId, String property) { + // Best-effort parsing from style attribute. + String prop = Objects.requireNonNull(property, "property").trim().toLowerCase(); + if (prop.isEmpty()) return ""; + + String style = dom.getAttribute(elementId, "style"); + style = style == null ? "" : style; + + for (String part : style.split(";")) { + String p = part.trim(); + if (p.isEmpty()) continue; + int idx = p.indexOf(':'); + if (idx <= 0) continue; + + String k = p.substring(0, idx).trim().toLowerCase(); + if (k.equals(prop)) return p.substring(idx + 1).trim(); + } + return ""; + } + + @Override + public void setAttribute(String elementId, String name, String value) { + dom.setAttribute(elementId, name, value); + } + + @Override + public String getAttribute(String elementId, String name) { + return dom.getAttribute(elementId, name); + } + + @Override + public void removeAttribute(String elementId, String name) { + dom.removeAttribute(elementId, name); + } + + @Override + public void focus(String elementId) { + engine.setJavaScriptEnabled(true); + engine.executeScript( + "document.getElementById('" + elementId + "').focus();" + ); + engine.setJavaScriptEnabled(false); + } + + @Override + public void blur(String elementId) { + engine.setJavaScriptEnabled(true); + engine.executeScript( + "document.getElementById('" + elementId + "').blur();" + ); + engine.setJavaScriptEnabled(false); + } + + @Override + public void scrollIntoView(String elementId) { + engine.setJavaScriptEnabled(true); + engine.executeScript( + "document.getElementById('" + elementId + "').scrollIntoView();" + ); + engine.setJavaScriptEnabled(false); + + } + + @Override + public int viewportWidth() { + return FxThreadBridge.callAndWait(() -> + (int) Math.round(view.getWidth()) + ); + } + + @Override + public int viewportHeight() { + return FxThreadBridge.callAndWait(() -> + (int) Math.round(view.getHeight()) + ); + } + + @Override + public long nowMillis() { + return System.currentTimeMillis(); + } + + private static boolean hasClassToken(String classAttr, String cls) { + String[] parts = classAttr.trim().split("\\s+"); + for (String p : parts) { + if (p.equals(cls)) return true; + } + return false; + } + + private static String removeCssProp(String style, String propLower) { + if (style == null || style.isBlank()) return ""; + StringBuilder sb = new StringBuilder(); + + for (String part : style.split(";")) { + String p = part.trim(); + if (p.isEmpty()) continue; + int idx = p.indexOf(':'); + if (idx <= 0) continue; + + String k = p.substring(0, idx).trim().toLowerCase(); + if (k.equals(propLower)) continue; + + if (!sb.isEmpty()) sb.append(';'); + sb.append(p); + } + + String out = sb.toString().trim(); + if (!out.isEmpty() && !out.endsWith(";")) out += ";"; + return out; + } +} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/Promise.java b/src/main/java/org/openautonomousconnection/webclient/network/Promise.java deleted file mode 100644 index c09b387..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/Promise.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.openautonomousconnection.webclient.network; - -import lombok.Getter; -import lombok.Setter; - -import java.util.concurrent.*; - -/** - * An object that is still waited for to be delivered by the server - * - * @param type of promised object - */ -public class Promise { - @Getter @Setter - private T object; - - public Promise() { - } - - public Promise(T object) { - this.object = object; - } - - public static Promise yieldPromise(int timeout, T reference) { - try (ExecutorService executorService = Executors.newSingleThreadExecutor()) { - Callable task = () -> { - for(int i = 0; i < timeout; i++) { - if(reference == null) { - try { - Thread.sleep(1000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } - - if(reference == null) - throw new TimeoutException(); - - return reference; - }; - - Future future = executorService.submit(task); - - executorService.shutdown(); - - try { - return new Promise<>(future.get()); - } catch (InterruptedException | ExecutionException e) { - throw new RuntimeException(e); - } - } - - } - - private Class getType() { - return this.object.getClass(); - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/WebClient.java b/src/main/java/org/openautonomousconnection/webclient/network/WebClient.java deleted file mode 100644 index 49b5a26..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/WebClient.java +++ /dev/null @@ -1,172 +0,0 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - -package org.openautonomousconnection.webclient.network; - -import dev.unlegitdqrk.unlegitlibrary.network.system.utils.TransportProtocol; -import lombok.Getter; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket; -import org.openautonomousconnection.protocol.side.client.ProtocolClient; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecord; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSResponseStatus; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.WebRequestMethod; -import org.openautonomousconnection.webclient.network.type.NTFType; -import org.openautonomousconnection.webclient.network.type.NetTransmitFile; - -import javax.swing.text.Document; -import java.io.IOException; -import java.net.ConnectException; -import java.net.URL; -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import static org.openautonomousconnection.webclient.Main.*; - -/** - * Uses the OAC-Protocol networking client - * Suppressing "unchecked" warnings because of generic casts - */ -@SuppressWarnings("unchecked") -public class WebClient extends ProtocolClient { - /** - * Global protocol timeout = 30 seconds - */ - public static final int TIMEOUT = 30; - - - /** - * Connect to INServer with URLs (ip based) - * @param ip ip to server - * @param tcpPort tcp ins port - */ - public void connectToINSServer(String ip, int tcpPort) throws NoSuchAlgorithmException, KeyManagementException { - - tcpPort = tcpPort != -1 ? tcpPort : DEFAULT_INS_PORT_TCP; - - // UDP is always preset - - try { - this.buildINSConnection(); - this.getClientINSConnection().connect(ip, tcpPort); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Give promise a non-null reference - * @param type type of file - * @param object serialized object - * @param java object type - */ - public void fulfillPromise(NTFType type, T object) { - if(!this.outstandingPromises.containsKey(type)) - return; - - Object promisedValue = this.outstandingPromises.get(type); - - if(promisedValue != null) - return; - - this.outstandingPromises.replace(type, object); - } - - @Getter - private final Map outstandingPromises = new HashMap<>(); - - /** - * Promise a serialized object that will be delivered as a file by the server - * @param type type of file - * @return object promise - * @param java object type - */ - private Promise> promise(NTFType type) { - NetTransmitFile ntf = NetTransmitFile.of(type, null); - - this.outstandingPromises.put(type, ntf); - - return Promise.yieldPromise(TIMEOUT, ntf); - } - - @Override - public void onResponse(INSResponseStatus insResponseStatus, List list) { - } - - @Override - public boolean trustINS(String caFingerprint) { - //TODO - return true; - } - - @Override - public boolean trustNewINSFingerprint(String oldCAFingerprint, String newCAFingerprint) { - //TODO - return true; - } - - /** - * Send a get request for a file from the currently connected server - * @param type type of file requested (UNKNOWN for files not supported by the protocol) - * @param path path to file - * @param test idfk - * @return resolved file - * @param java object type - */ - public Promise> get(NTFType type, String path, T test) { - try { - this.getClientServerConnection().sendPacket(new WebRequestPacket( - path, - WebRequestMethod.GET, - Map.of(), - null - ), TransportProtocol.TCP); - - } catch (Exception e) { - throw new RuntimeException(e); - } - - return this.promise(type); - } - - // TODO - public void post(String path) { - try { - this.getClientServerConnection().sendPacket(new WebRequestPacket( - path, - WebRequestMethod.POST, - Map.of(), - null - ), TransportProtocol.TCP); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - /** - * Get index.html Document of current site - * @return index.html - */ - public Promise> getIndex() { - try { - this.getClientServerConnection().sendPacket(new WebRequestPacket( - "index.html", - WebRequestMethod.GET, - Map.of(), - null - ), TransportProtocol.TCP); - } catch (Exception e) { - throw new RuntimeException(e); - } - - System.out.println(promise(NTFType.DOCUMENT).getClass().getSimpleName()); - - - - return null;//(Promise>) promise(NTFType.DOCUMENT); - } - -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/handlers/ServerPacketHandler.java b/src/main/java/org/openautonomousconnection/webclient/network/handlers/ServerPacketHandler.java deleted file mode 100644 index b471833..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/handlers/ServerPacketHandler.java +++ /dev/null @@ -1,43 +0,0 @@ -/* Author: Maple - * Jan. 16 2026 - * */ - -package org.openautonomousconnection.webclient.network.handlers; - -import dev.unlegitdqrk.unlegitlibrary.event.EventListener; -import dev.unlegitdqrk.unlegitlibrary.event.Listener; -import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.C_PacketReadEvent; -import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.C_PacketSendEvent; -import dev.unlegitdqrk.unlegitlibrary.network.system.packets.Packet; -import dev.unlegitdqrk.unlegitlibrary.network.system.utils.TransportProtocol; -import org.openautonomousconnection.protocol.packets.OACPacket; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.AuthPacket; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket; -import org.openautonomousconnection.protocol.side.client.events.ConnectedToProtocolINSServerEvent; -import org.openautonomousconnection.webclient.packetlistener.PacketListener; - -import java.util.ArrayList; -import java.util.List; - -public class ServerPacketHandler extends EventListener { - - private static final List listeners = new ArrayList<>(); - - public static void registerPacketListener(PacketListener packetListener) { - listeners.add(packetListener); - } - - @Listener - public void onPacketReceived(C_PacketReadEvent packetReceivedEvent) { - - Packet packet = packetReceivedEvent.getPacket(); - TransportProtocol transport = packetReceivedEvent.getProtocol(); - - switch (packet.getPacketID()) { - case 4 -> listeners - .forEach(l -> l.onAuthPacketReceived((AuthPacket) packet, transport)); - case 9 -> listeners - .forEach(l -> l.onWebResponsePacketReceived((WebResponsePacket) packet, transport));} - - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/type/NTFType.java b/src/main/java/org/openautonomousconnection/webclient/network/type/NTFType.java deleted file mode 100644 index 78e0555..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/type/NTFType.java +++ /dev/null @@ -1,13 +0,0 @@ -/* Author: Maple - * Jan. 17 2026 - * */ - -package org.openautonomousconnection.webclient.network.type; - -public enum NTFType { - UNKNOWN, - STYLESHEET, - DOCUMENT, - ICON, - FILE -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/type/NetTransmitFile.java b/src/main/java/org/openautonomousconnection/webclient/network/type/NetTransmitFile.java deleted file mode 100644 index 09c47e8..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/type/NetTransmitFile.java +++ /dev/null @@ -1,34 +0,0 @@ -/* Author: Maple - * Jan. 17 2026 - * */ - -package org.openautonomousconnection.webclient.network.type; - -import org.openautonomousconnection.webclient.network.type.application.NetAppstreamFile; -import org.openautonomousconnection.webclient.network.type.image.NetTransmitIcon; -import org.openautonomousconnection.webclient.network.type.text.NetTransmitDocument; -import org.openautonomousconnection.webclient.network.type.text.NetTransmitStylesheet; -import org.w3c.dom.Document; -import org.w3c.dom.css.CSSStyleSheet; - -import javax.swing.*; -import java.io.File; - -public interface NetTransmitFile { - T getNtf(); - void setNtf(T ntf); - - @SuppressWarnings("unchecked") - static NetTransmitFile of(NTFType type, T ntf) { - return (NetTransmitFile) switch (type) { - case FILE -> new NetAppstreamFile((File) ntf); - - case ICON -> new NetTransmitIcon((ImageIcon) ntf); - - case DOCUMENT -> new NetTransmitDocument((Document) ntf); - case STYLESHEET -> new NetTransmitStylesheet((CSSStyleSheet) ntf); - - case null, default -> new NetTransmitUnknown(ntf); - }; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/type/NetTransmitUnknown.java b/src/main/java/org/openautonomousconnection/webclient/network/type/NetTransmitUnknown.java deleted file mode 100644 index e4f269a..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/type/NetTransmitUnknown.java +++ /dev/null @@ -1,20 +0,0 @@ -/* Author: Maple - * Jan. 17 2026 - * */ - -package org.openautonomousconnection.webclient.network.type; - -import lombok.Getter; -import lombok.Setter; - -public class NetTransmitUnknown implements NetTransmitFile { - @Getter @Setter - private Object ntf; - - public NetTransmitUnknown() { - } - - public NetTransmitUnknown(Object ntf) { - this.ntf = ntf; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/type/application/NetAppstreamFile.java b/src/main/java/org/openautonomousconnection/webclient/network/type/application/NetAppstreamFile.java deleted file mode 100644 index bca6d00..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/type/application/NetAppstreamFile.java +++ /dev/null @@ -1,25 +0,0 @@ -/* Author: Maple - * Jan. 17 2026 - * */ - -package org.openautonomousconnection.webclient.network.type.application; - -import lombok.Getter; -import lombok.Setter; -import org.openautonomousconnection.webclient.network.type.NetTransmitFile; - -import java.io.File; - -public class NetAppstreamFile implements NetTransmitFile { - @Getter - @Setter - private File ntf; - - public NetAppstreamFile() { - - } - - public NetAppstreamFile(File ntf) { - this.ntf = ntf; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/type/image/NetTransmitIcon.java b/src/main/java/org/openautonomousconnection/webclient/network/type/image/NetTransmitIcon.java deleted file mode 100644 index 740d77d..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/type/image/NetTransmitIcon.java +++ /dev/null @@ -1,25 +0,0 @@ -/* Author: Maple - * Jan. 17 2026 - * */ - -package org.openautonomousconnection.webclient.network.type.image; - -import lombok.Getter; -import lombok.Setter; -import org.openautonomousconnection.webclient.network.type.NetTransmitFile; - -import javax.swing.*; - -public class NetTransmitIcon implements NetTransmitFile { - @Getter - @Setter - private ImageIcon ntf; - - public NetTransmitIcon() { - - } - - public NetTransmitIcon(ImageIcon ntf) { - this.ntf = ntf; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/type/text/NetTransmitDocument.java b/src/main/java/org/openautonomousconnection/webclient/network/type/text/NetTransmitDocument.java deleted file mode 100644 index 76a293b..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/type/text/NetTransmitDocument.java +++ /dev/null @@ -1,23 +0,0 @@ -/* Author: Maple - * Jan. 17 2026 - * */ - -package org.openautonomousconnection.webclient.network.type.text; - -import lombok.Getter; -import lombok.Setter; -import org.openautonomousconnection.webclient.network.type.NetTransmitFile; -import org.w3c.dom.Document; - -public class NetTransmitDocument implements NetTransmitFile { - @Getter @Setter - private Document ntf; - - public NetTransmitDocument() { - - } - - public NetTransmitDocument(Document ntf) { - this.ntf = ntf; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/type/text/NetTransmitStylesheet.java b/src/main/java/org/openautonomousconnection/webclient/network/type/text/NetTransmitStylesheet.java deleted file mode 100644 index 92fbfb7..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/type/text/NetTransmitStylesheet.java +++ /dev/null @@ -1,25 +0,0 @@ -/* Author: Maple - * Jan. 17 2026 - * */ - -package org.openautonomousconnection.webclient.network.type.text; - -import lombok.Getter; -import lombok.Setter; -import org.openautonomousconnection.webclient.network.type.NetTransmitFile; -import org.w3c.dom.css.CSSStyleSheet; - -public class NetTransmitStylesheet implements NetTransmitFile { - @Getter - @Setter - private CSSStyleSheet ntf; - - public NetTransmitStylesheet() { - - } - - public NetTransmitStylesheet(CSSStyleSheet ntf) { - this.ntf = ntf; - } - -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/website/WebSite.java b/src/main/java/org/openautonomousconnection/webclient/network/website/WebSite.java deleted file mode 100644 index 3776daa..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/website/WebSite.java +++ /dev/null @@ -1,104 +0,0 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - -package org.openautonomousconnection.webclient.network.website; - -import lombok.Getter; -import lombok.Setter; -import org.openautonomousconnection.webclient.Main; -import org.openautonomousconnection.webclient.network.Promise; -import org.openautonomousconnection.webclient.network.type.NTFType; -import org.openautonomousconnection.webclient.network.type.NetTransmitFile; -import org.w3c.dom.Document; - -import javax.annotation.Nullable; -import javax.swing.*; -import java.net.URL; -import java.util.Objects; - -/** - * Contains data about a site - * Suppressing "unchecked" warnings because of generic casts - */ -@SuppressWarnings("unchecked") -public final class WebSite { - @Getter - private final URL infoName; - - @Getter @Setter - private Document dom; - - /** - * - */ - public WebSite(URL infoName) { - this.infoName = infoName; - } - - /** - * Send new get request - */ - public Document requestNewDom() { - Document test = null; - - Promise> promise = (Promise>) - Main.client.get(NTFType.DOCUMENT, this.infoName.getPath().toString(), test); - return promise.getObject().getNtf(); - } - - /** - * Get favicon of site by attempting to retrieve the favicon.ico - * - * @return retrieved icon or null - */ - public Icon getFavIcon() { - return getFavIcon(this.infoName); - } - - /** - * Get favicon of site by attempting to retrieve the favicon.ico - * - * @param infoName info name that leads to the site with the favicon - * @return retrieved icon or null - */ - public static @Nullable Icon getFavIcon(URL infoName) { - ImageIcon test = null; - - Promise> promise = (Promise>) - Main.client.get(NTFType.ICON, infoName.getPath().toString(), test); - - return promise.getObject().getNtf(); - } - -// /** -// * Get HTML text (dom) of site -// * -// * @param infoName that leads to the target OAC page -// * @return html document -// */ -// public static Document getDom(InfoName infoName) { -// Main.client.getDocument(); -// } - - @Override - public boolean equals(Object obj) { - if (obj == this) return true; - if (obj == null || obj.getClass() != this.getClass()) return false; - var that = (WebSite) obj; - return Objects.equals(this.infoName, that.infoName); - } - - @Override - public int hashCode() { - return Objects.hash(infoName); - } - - @Override - public String toString() { - return "WebSite{" + - "infoName=" + this.infoName + - ", dom=" + this.dom + - '}'; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/website/tab/Tab.java b/src/main/java/org/openautonomousconnection/webclient/network/website/tab/Tab.java deleted file mode 100644 index aceceea..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/website/tab/Tab.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.openautonomousconnection.webclient.network.website.tab; - -import org.openautonomousconnection.webclient.network.website.WebSite; - -import javax.swing.*; -import java.net.URL; - -public interface Tab { - Icon getFavicon(); - void setFavicon(Icon favicon); - - URL getInfoName(); - void setInfoName(URL infoName); - - WebSite getWebSite(); - void setWebSite(WebSite webSite); - - void refresh() throws Exception; -} diff --git a/src/main/java/org/openautonomousconnection/webclient/network/website/tab/WebTab.java b/src/main/java/org/openautonomousconnection/webclient/network/website/tab/WebTab.java deleted file mode 100644 index 4a9d9c4..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/network/website/tab/WebTab.java +++ /dev/null @@ -1,91 +0,0 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - -package org.openautonomousconnection.webclient.network.website.tab; - -import lombok.Getter; -import lombok.Setter; -import org.openautonomousconnection.webclient.network.WebClient; -import org.openautonomousconnection.webclient.network.website.WebSite; - -import javax.swing.*; -import java.net.URL; -import java.util.Objects; - -import static org.openautonomousconnection.webclient.Main.DEFAULT_WEB_PORT_TCP; - -public final class WebTab implements Tab { - @Getter @Setter - private URL infoName; - - @Getter @Setter - private Icon favicon; - - @Getter @Setter - private WebSite webSite; - - private WebClient client; - - public WebTab(URL infoName, Icon favicon) throws Exception { - refresh(); - - this.infoName = infoName; - this.favicon = favicon; - this.webSite = new WebSite(infoName); - } - - public WebTab(URL infoName) throws Exception { - refresh(); - - this.infoName = infoName; - this.favicon = WebSite.getFavIcon(infoName); - this.webSite = new WebSite(infoName); - } - - public WebTab(WebSite webSite) throws Exception { - refresh(); - - this.infoName = webSite.getInfoName(); - this.favicon = webSite.getFavIcon(); - this.webSite = webSite; - } - - public void refresh() throws Exception { - - if (client.getClientServerConnection().isConnected()) client.getClientServerConnection().disconnect(); - int port = infoName.getPort() == -1 ? DEFAULT_WEB_PORT_TCP : infoName.getPort(); - client.buildServerConnection(null, true); - - try { - client.getClientServerConnection().connect(infoName.getHost(), port); - } catch (Exception e) { - throw new RuntimeException(e); - } - - this.webSite.requestNewDom(); - this.favicon = this.webSite.getFavIcon(); - } - - @Override - public boolean equals(Object o) { - if (o == null || getClass() != o.getClass()) return false; - WebTab webTab = (WebTab) o; - return Objects.equals(infoName, webTab.infoName) && Objects.equals(favicon, webTab.favicon) && Objects.equals(webSite, webTab.webSite) && Objects.equals(client, webTab.client); - } - - @Override - public int hashCode() { - return Objects.hash(infoName, favicon, webSite, client); - } - - @Override - public String toString() { - return "WebTab{" + - "infoName=" + infoName + - ", favicon=" + favicon + - ", webSite=" + webSite + - ", client=" + client + - '}'; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/packetlistener/PacketListener.java b/src/main/java/org/openautonomousconnection/webclient/packetlistener/PacketListener.java deleted file mode 100644 index 06f2660..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/packetlistener/PacketListener.java +++ /dev/null @@ -1,27 +0,0 @@ -/* Author: Maple - * Jan. 16 2026 - * */ - -package org.openautonomousconnection.webclient.packetlistener; - -import dev.unlegitdqrk.unlegitlibrary.network.system.utils.TransportProtocol; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.AuthPacket; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket; - -import java.util.concurrent.TransferQueue; - -public abstract class PacketListener { - - public void onAuthPacketReceived(AuthPacket authPacket, TransportProtocol transport) { - } - - public void onAuthPacketSent(AuthPacket authPacket, TransportProtocol transport) { - } - - public void onWebResponsePacketReceived(WebResponsePacket webResponsePacket, TransportProtocol transport) { - } - - public void onWebRequestPacketSent(WebRequestPacket webRequestPacket, TransportProtocol transport) { - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/packetlistener/listeners/WebPacketListener.java b/src/main/java/org/openautonomousconnection/webclient/packetlistener/listeners/WebPacketListener.java deleted file mode 100644 index 8cf7965..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/packetlistener/listeners/WebPacketListener.java +++ /dev/null @@ -1,62 +0,0 @@ -/* Author: Maple - * Jan. 16 2026 - * */ - -package org.openautonomousconnection.webclient.packetlistener.listeners; - -import dev.unlegitdqrk.unlegitlibrary.network.system.utils.TransportProtocol; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket; -import org.openautonomousconnection.webclient.Main; -import org.openautonomousconnection.webclient.network.type.NTFType; -import org.openautonomousconnection.webclient.network.type.NetTransmitFile; -import org.openautonomousconnection.webclient.network.type.image.NetTransmitIcon; -import org.openautonomousconnection.webclient.network.type.text.NetTransmitDocument; -import org.openautonomousconnection.webclient.packetlistener.PacketListener; -import org.openautonomousconnection.webclient.ui.dom.DomSerializer; -import org.w3c.dom.Document; - -import javax.swing.*; - -public class WebPacketListener extends PacketListener { - @Override - public void onWebResponsePacketReceived(WebResponsePacket packet, TransportProtocol transport) { - NTFType type = NTFType.UNKNOWN; - - NetTransmitFile file = null; - - /* - full list of content types at https://repo.open-autonomous-connection.org/open-autonomous-connection/WebServer/src/branch/master/src/main/java/org/openautonomousconnection/webserver/ContentTypeResolver.java - */ - switch (packet.getContentType()) { - case "text/html": - type = NTFType.DOCUMENT; - - // body is sent as byte array (string) - - String htmlText = new String(packet.getBody()); - - Document dom = DomSerializer.fromString(Main.mainFrame.getDomContainerPanel().getWebEngine(), htmlText); - - file = new NetTransmitDocument(); - break; - - case "image/png": // TODO: Implement - break; - - case "image/ico": // the server doesn't implement this yet, so favicons won't work at this moment - type = NTFType.ICON; - - ImageIcon icon = new ImageIcon(packet.getBody()); - - file = new NetTransmitIcon(icon); - break; - - // the same as application/octet-stream - default: - break; //TODO: stream files - - } - - Main.client.fulfillPromise(type, file); - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/recode/Main.java b/src/main/java/org/openautonomousconnection/webclient/recode/Main.java deleted file mode 100644 index b717d0a..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/recode/Main.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.openautonomousconnection.webclient.recode; - -import dev.unlegitdqrk.unlegitlibrary.event.EventManager; -import dev.unlegitdqrk.unlegitlibrary.network.system.packets.PacketHandler; -import lombok.Getter; -import org.openautonomousconnection.infonamelib.InfoNames; -import org.openautonomousconnection.oacswing.component.OACOptionPane; -import org.openautonomousconnection.oacswing.component.design.Design; -import org.openautonomousconnection.oacswing.component.design.DesignManager; -import org.openautonomousconnection.protocol.ProtocolBridge; -import org.openautonomousconnection.protocol.ProtocolValues; -import org.openautonomousconnection.protocol.versions.ProtocolVersion; -import org.openautonomousconnection.webclient.recode.settings.INSList; -import org.openautonomousconnection.webclient.recode.ui.BrowserUI; - -import javax.swing.*; -import java.io.File; - -public class Main { - @Getter - private static ClientImpl client; - private static ProtocolBridge bridge; - - @Getter - private static BrowserUI ui; - - private static void initProtocol() { - InfoNames.registerOACInfoNameProtocols(); - - ProtocolValues values = new ProtocolValues(); - - values.packetHandler = new PacketHandler(); - values.eventManager = new EventManager(); - - client = new ClientImpl(); - - try { - bridge = new ProtocolBridge( - client, - values, - ProtocolVersion.PV_1_0_0_BETA, - new File("logs") - ); - - client.buildINSConnection(); - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public static void main(String[] args) { - initProtocol(); - FxBootstrap.ensureInitialized(); - DesignManager.setGlobalDesign(Design.DARK); - - SwingUtilities.invokeLater(() -> { - ui = new BrowserUI(); - ui.setSize(1200, 800); - ui.setLocationRelativeTo(null); - ui.setVisible(true); - - try { - bridge.getProtocolValues().eventManager.registerListener(client); - client.getClientINSConnection().connect(INSList.DEFAULT_INS, INSList.DEFAULT_PORT); - } catch (Exception exception) { - client.getProtocolBridge().getLogger().exception("Failed to connect to INS", exception); - OACOptionPane.showMessageDialog(Main.getUi(), "Failed to connect to INS Server:\n" + exception.getMessage(), - "INS Connection", OACOptionPane.ERROR_MESSAGE); - } - }); - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/recode/ui/TabView.java b/src/main/java/org/openautonomousconnection/webclient/recode/ui/TabView.java deleted file mode 100644 index 737adfd..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/recode/ui/TabView.java +++ /dev/null @@ -1,197 +0,0 @@ -package org.openautonomousconnection.webclient.recode.ui; - -import dev.unlegitdqrk.unlegitlibrary.event.EventListener; -import dev.unlegitdqrk.unlegitlibrary.event.Listener; -import dev.unlegitdqrk.unlegitlibrary.network.system.client.events.packets.C_PacketReadEvent; -import dev.unlegitdqrk.unlegitlibrary.network.system.utils.TransportProtocol; -import javafx.application.Platform; -import javafx.embed.swing.JFXPanel; -import javafx.scene.Scene; -import javafx.scene.web.WebEngine; -import javafx.scene.web.WebHistory; -import javafx.scene.web.WebView; -import org.openautonomousconnection.infonamelib.InfoNames; -import org.openautonomousconnection.oacswing.component.OACOptionPane; -import org.openautonomousconnection.oacswing.component.OACPanel; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebRequestPacket; -import org.openautonomousconnection.protocol.packets.v1_0_0.beta.web.WebResponsePacket; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.INSRecordType; -import org.openautonomousconnection.protocol.versions.v1_0_0.beta.WebRequestMethod; -import org.openautonomousconnection.webclient.recode.Main; - -import javax.swing.*; -import java.awt.*; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.Consumer; - -/** - * A Swing panel that embeds a JavaFX WebView. - * The JavaFX scene is initialized on first addNotify(). - */ -public final class TabView extends OACPanel { - - private final AtomicBoolean initialized = new AtomicBoolean(false); - - private JFXPanel fxPanel; - private WebView webView; - private WebEngine engine; - - private final Consumer onLocationChanged; - - /** - * Creates a new tab view. - * - * @param onLocationChanged callback invoked when the WebEngine location changes - */ - public TabView(Consumer onLocationChanged) { - super(); - this.onLocationChanged = Objects.requireNonNull(onLocationChanged, "onLocationChanged"); - setLayout(new BorderLayout()); - Main.getClient().getProtocolBridge().getProtocolValues().eventManager.registerListener(new TabListener(this)); - } - - @Override - public void addNotify() { - super.addNotify(); - - if (!initialized.compareAndSet(false, true)) { - return; - } - - fxPanel = new JFXPanel(); - add(fxPanel, BorderLayout.CENTER); - - Platform.runLater(() -> { - webView = new WebView(); - webView.setContextMenuEnabled(false); - webView.getEngine().setJavaScriptEnabled(false); - engine = webView.getEngine(); - - engine.locationProperty().addListener((obs, oldV, newV) -> { - if (newV != null) { - onLocationChanged.accept(newV); - } - }); - - fxPanel.setScene(new Scene(webView)); - }); - } - - /** - * Loads a URL in this tab. - * - * @param url URL to load - */ - public void load(String url) { - String[] parts = url.split("\\."); - if (parts.length < 2 || parts.length > 3) { - throw new IllegalArgumentException( - "Invalid INS address format: " + url + - " (expected name.tln or sub.name.tln)" - ); - } - - String tln = parts[parts.length - 1]; - String name = parts[parts.length - 2]; - String sub = (parts.length == 3) ? parts[0] : null; - - try { - Main.getClient().sendINSQuery(tln, name, sub, INSRecordType.A); - } catch (Exception e) { - Main.getClient().getProtocolBridge().getLogger().exception("Failed to send INS Query", e); - OACOptionPane.showMessageDialog(Main.getUi(), "Failed to send INS Query:\n" + e.getMessage(), - "INS Connection", OACOptionPane.ERROR_MESSAGE); - return; - } - } - - public static class TabListener extends EventListener { - private TabView view; - - public TabListener(TabView view) { - this.view = view; - } - - @Listener - public void onListen(C_PacketReadEvent event) { - if (event.getPacket() instanceof WebResponsePacket response) { - view.parseHtml(new String(response.getBody())); - } - } - } - - public void parseHtml(String html) { - Platform.runLater(() -> { - if (engine != null) engine.loadContent(html); - }); - } - - /** - * Reloads the current page. - */ - public void reload() { - Platform.runLater(() -> { - if (engine != null) { - engine.reload(); - } - }); - } - - /** - * Navigates one step back in history if possible. - */ - public void back() { - Platform.runLater(() -> { - if (engine == null) return; - WebHistory h = engine.getHistory(); - if (h.getCurrentIndex() > 0) { - h.go(-1); - } - }); - } - - /** - * Navigates one step forward in history if possible. - */ - public void forward() { - Platform.runLater(() -> { - if (engine == null) return; - WebHistory h = engine.getHistory(); - if (h.getCurrentIndex() < h.getEntries().size() - 1) { - h.go(1); - } - }); - } - - /** - * Returns the current location (best-effort, may be null until initialized). - * - * @return current location or null - */ - public String getEngineLocation() { - // No blocking: best-effort for UI sync. - return engine != null ? engine.getLocation() : null; - } - - /** - * Disposes JavaFX scene references (best-effort). - */ - public void dispose() { - Platform.runLater(() -> { - if (engine != null) { - try { - engine.load(null); - } catch (Exception ignored) { - // Best-effort cleanup. - } - } - engine = null; - webView = null; - if (fxPanel != null) { - fxPanel.setScene(null); - } - }); - } -} \ No newline at end of file diff --git a/src/main/java/org/openautonomousconnection/webclient/settings/FxEngine.java b/src/main/java/org/openautonomousconnection/webclient/settings/FxEngine.java new file mode 100644 index 0000000..40f0cf6 --- /dev/null +++ b/src/main/java/org/openautonomousconnection/webclient/settings/FxEngine.java @@ -0,0 +1,144 @@ +package org.openautonomousconnection.webclient.settings; + +import javafx.concurrent.Worker; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebView; +import org.luaj.vm2.Globals; +import org.openautonomousconnection.luascript.fx.FxDomHost; +import org.openautonomousconnection.luascript.fx.FxEventHost; +import org.openautonomousconnection.luascript.fx.FxWebViewResourceHost; +import org.openautonomousconnection.luascript.hosts.HostServices; +import org.openautonomousconnection.luascript.runtime.LuaRuntime; +import org.openautonomousconnection.luascript.security.LuaExecutionPolicy; +import org.openautonomousconnection.luascript.utils.LuaGlobalsFactory; +import org.openautonomousconnection.webclient.lua.WebLogger; +import org.openautonomousconnection.webclient.lua.hosts.ConsoleHostImpl; +import org.openautonomousconnection.webclient.lua.hosts.UiHostImpl; + +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * JavaFX WebView integration entry point for LuaScript (no JavaScript). + * + *

Hard rule: every HTML script tag is treated as Lua.

+ */ +public final class FxEngine implements AutoCloseable { + + private final WebEngine engine; + private final WebView webView; + private final LuaExecutionPolicy policy; + private final WebLogger logger; + + private final AtomicBoolean bootstrapped = new AtomicBoolean(false); + + private LuaRuntime runtime; + + /** + * Creates an integration engine with default UI execution policy. + * + * @param engine web engine + * @param webView web view + */ + public FxEngine(WebEngine engine, WebView webView, WebLogger logger) { + this(engine, webView, LuaExecutionPolicy.uiDefault(), logger); + } + + /** + * Creates an integration engine with a custom execution policy. + * + * @param engine web engine + * @param webView web view + * @param policy execution policy + */ + public FxEngine(WebEngine engine, WebView webView, LuaExecutionPolicy policy, WebLogger logger) { + this.engine = Objects.requireNonNull(engine, "engine"); + this.webView = webView; + this.policy = Objects.requireNonNull(policy, "policy"); + this.logger = logger; + } + + /** + * Installs a load hook that bootstraps Lua when a page finished loading. + */ + public void install() { + engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> { + if (newState == Worker.State.SUCCEEDED) { + bootstrapped.set(false); + bootstrap(); + } else if (newState == Worker.State.CANCELLED || newState == Worker.State.FAILED) { + bootstrapped.set(false); + closeRuntimeQuietly(); + } + }); + } + + /** + * Bootstraps Lua for the currently loaded document. + */ + public void bootstrap() { + if (!bootstrapped.compareAndSet(false, true)) return; + + closeRuntimeQuietly(); + + // DOM host must exist before event/UI tables, and must ensure stable ids. + FxDomHost dom = new FxDomHost(engine); + dom.ensureAllElementsHaveId(); + + // Create per-page globals; harden sandbox in production. + Globals globals = LuaGlobalsFactory.create( + new LuaGlobalsFactory.Options() + .enableDebug(false) + .sandbox(true) + ); + + // Create runtime first (router lives inside it). + ConsoleHostImpl console = new ConsoleHostImpl(logger); + UiHostImpl uiHost = new UiHostImpl(engine, webView, dom); + FxWebViewResourceHost resourceHost = new FxWebViewResourceHost(engine); + + // runtime depends on services; events depends on runtime router. + // We'll create eventHost after runtime, then build HostServices with it. + LuaRuntime rt = new LuaRuntime(globals, new HostServices.Default(uiHost, dom, null, resourceHost, console), policy); + + FxEventHost eventHost = new FxEventHost(dom, rt.eventRouter()); + + // Rebuild services including eventHost and reinstall tables. + HostServices services = new HostServices.Default(uiHost, dom, eventHost, resourceHost, console); + + // Replace runtime with correct services (clean and deterministic). + rt.close(); + rt = new LuaRuntime(globals, services, policy); + + rt.installStdTables(true); + rt.bootstrapFromDom(); + + this.runtime = rt; + } + + /** + * Returns active runtime or null if not bootstrapped. + * + * @return runtime or null + */ + public LuaRuntime runtimeOrNull() { + return runtime; + } + + @Override + public void close() { + closeRuntimeQuietly(); + } + + private void closeRuntimeQuietly() { + LuaRuntime rt = this.runtime; + this.runtime = null; + if (rt != null) { + try { + rt.close(); + } catch (Exception ignored) { + // Best-effort shutdown. + } + } + } +} \ No newline at end of file diff --git a/src/main/java/org/openautonomousconnection/webclient/recode/settings/INSList.java b/src/main/java/org/openautonomousconnection/webclient/settings/INSList.java similarity index 77% rename from src/main/java/org/openautonomousconnection/webclient/recode/settings/INSList.java rename to src/main/java/org/openautonomousconnection/webclient/settings/INSList.java index c110ea1..e6cd6be 100644 --- a/src/main/java/org/openautonomousconnection/webclient/recode/settings/INSList.java +++ b/src/main/java/org/openautonomousconnection/webclient/settings/INSList.java @@ -1,6 +1,4 @@ -package org.openautonomousconnection.webclient.recode.settings; - -import javafx.embed.swing.JFXPanel; +package org.openautonomousconnection.webclient.settings; import java.util.HashMap; diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/BrowserFrame.java b/src/main/java/org/openautonomousconnection/webclient/ui/BrowserFrame.java deleted file mode 100644 index 37cdeab..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/BrowserFrame.java +++ /dev/null @@ -1,14 +0,0 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - -package org.openautonomousconnection.webclient.ui; - -import org.openautonomousconnection.oacswing.component.OACFrame; - -public abstract class BrowserFrame extends OACFrame { - - protected BrowserFrame() { - } - -} diff --git a/src/main/java/org/openautonomousconnection/webclient/recode/ui/BrowserTab.java b/src/main/java/org/openautonomousconnection/webclient/ui/BrowserTab.java similarity index 91% rename from src/main/java/org/openautonomousconnection/webclient/recode/ui/BrowserTab.java rename to src/main/java/org/openautonomousconnection/webclient/ui/BrowserTab.java index 942daae..6c1f03d 100644 --- a/src/main/java/org/openautonomousconnection/webclient/recode/ui/BrowserTab.java +++ b/src/main/java/org/openautonomousconnection/webclient/ui/BrowserTab.java @@ -1,6 +1,4 @@ -package org.openautonomousconnection.webclient.recode.ui; - -import org.openautonomousconnection.webclient.recode.Main; +package org.openautonomousconnection.webclient.ui; import java.util.Objects; import java.util.function.Consumer; @@ -22,7 +20,7 @@ public class BrowserTab { */ public BrowserTab(String initialUrl, Consumer onLocationChange) { this.key = Objects.requireNonNull(initialUrl, "initialUrl"); // placeholder key overwritten by BrowserUI - this.view = new TabView(onLocationChange); + this.view = new TabView(onLocationChange, initialUrl); } /** @@ -41,8 +39,8 @@ public class BrowserTab { * * @param url URL */ - public void load(String url) { - view.load(url); + public void loadUrl(String url) { + view.loadUrl(url); } /** @@ -125,8 +123,8 @@ public class BrowserTab { } @Override - public void load(String url) { - fixedView.load(url); + public void loadUrl(String url) { + fixedView.loadUrl(url); } @Override diff --git a/src/main/java/org/openautonomousconnection/webclient/recode/ui/BrowserUI.java b/src/main/java/org/openautonomousconnection/webclient/ui/BrowserUI.java similarity index 92% rename from src/main/java/org/openautonomousconnection/webclient/recode/ui/BrowserUI.java rename to src/main/java/org/openautonomousconnection/webclient/ui/BrowserUI.java index 0e99536..e14eb14 100644 --- a/src/main/java/org/openautonomousconnection/webclient/recode/ui/BrowserUI.java +++ b/src/main/java/org/openautonomousconnection/webclient/ui/BrowserUI.java @@ -1,4 +1,4 @@ -package org.openautonomousconnection.webclient.recode.ui; +package org.openautonomousconnection.webclient.ui; import org.openautonomousconnection.oacswing.component.OACButton; import org.openautonomousconnection.oacswing.component.OACFrame; @@ -109,7 +109,7 @@ public class BrowserUI extends OACFrame { if (tab != null) tab.reload(); }); - newTabButton.addActionListener(e -> openNewTab("info.oac")); + newTabButton.addActionListener(e -> openNewTab("web://info.oac/")); closeTabButton.addActionListener(e -> closeCurrentTab()); // Create first tab @@ -143,7 +143,7 @@ public class BrowserUI extends OACFrame { getTitleBar().getTabs().setSelectedIndex(idx); // Navigate - tab.load(url); + tab.loadUrl(url); // Show content cardLayout.show(pageHost, key); @@ -165,7 +165,7 @@ public class BrowserUI extends OACFrame { String url = normalizeUrl(input); addressField.setText(url); - tab.load(url); + tab.loadUrl(url); } /** @@ -187,7 +187,7 @@ public class BrowserUI extends OACFrame { // If no tabs left, open a new one if (getTitleBar().getTabs().getTabCount() == 0) { - openNewTab("info.oac"); + openNewTab("web://info.oac/"); return; } @@ -225,8 +225,13 @@ public class BrowserUI extends OACFrame { private static String normalizeUrl(String input) { String s = input == null ? "" : input.trim(); - if (s.isEmpty()) return "info.oac"; - if (s.startsWith("web://")) return s; - return "web://" + s; + if (s.isEmpty()) return "web://info.oac/"; + if (s.startsWith("web://")) { + // Ensure trailing slash for "host only" URLs + String rest = s.substring("web://".length()); + if (!rest.contains("/")) return s + "/"; + return s; + } + return "web://" + s + (s.contains("/") ? "" : "/"); } } \ No newline at end of file diff --git a/src/main/java/org/openautonomousconnection/webclient/recode/FxBootstrap.java b/src/main/java/org/openautonomousconnection/webclient/ui/FxBootstrap.java similarity index 93% rename from src/main/java/org/openautonomousconnection/webclient/recode/FxBootstrap.java rename to src/main/java/org/openautonomousconnection/webclient/ui/FxBootstrap.java index 7a602f6..cacddcd 100644 --- a/src/main/java/org/openautonomousconnection/webclient/recode/FxBootstrap.java +++ b/src/main/java/org/openautonomousconnection/webclient/ui/FxBootstrap.java @@ -1,4 +1,4 @@ -package org.openautonomousconnection.webclient.recode; +package org.openautonomousconnection.webclient.ui; import javafx.application.Platform; import javafx.embed.swing.JFXPanel; diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/MainFrame.java b/src/main/java/org/openautonomousconnection/webclient/ui/MainFrame.java deleted file mode 100644 index bb5f172..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/MainFrame.java +++ /dev/null @@ -1,70 +0,0 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - -package org.openautonomousconnection.webclient.ui; - -import lombok.Getter; -import org.openautonomousconnection.webclient.network.website.tab.WebTab; -import org.openautonomousconnection.webclient.ui.dom.DOMContainerPanel; - -import java.awt.*; -import java.net.URL; - -public final class MainFrame extends BrowserFrame { - @Getter - private WebTab openWebTab; - - @Getter - private final DOMContainerPanel domContainerPanel; - - public MainFrame() { - super(); - - this.setSize(800, 600); - - try { - // TODO this.openTab = new Tab(URI.create("web://127.0.0.1").toURL()); - } catch (Exception e) { - throw new RuntimeException(e); - } - - this.domContainerPanel = new DOMContainerPanel(); - this.add(this.domContainerPanel, BorderLayout.CENTER); - } - - private void init() { - this.open(this.openWebTab); - } - - public void setOpenWebTab(int index) { - //TODO - } - - public void setOpenWebTab(WebTab webTab) { - //TODO -// for(TabButton button : this.getTopBar().getTabButtons()) -// if(button.getTab().equals(tab)) { -// this.openTab = button.getTab(); -// button.grabFocus(); -// } - } - - public void open(URL url) throws Exception { - //TODO -// TabButton button = new TabButton(url); -// -// this.getTopBar().addButton(button); -// -// button.grabFocus(); - } - - public void open(WebTab webTab) { - //TODO -// TabButton button = new TabButton(tab); -// -// this.getTopBar().addButton(button); -// -// button.grabFocus(); - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/MenuButton.java b/src/main/java/org/openautonomousconnection/webclient/ui/MenuButton.java deleted file mode 100644 index c25f269..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/MenuButton.java +++ /dev/null @@ -1,112 +0,0 @@ -/* Author: Maple - * Jan. 18 2026 - * */ - -package org.openautonomousconnection.webclient.ui; - -import lombok.Getter; -import org.openautonomousconnection.webclient.Main; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; -import java.awt.event.MouseEvent; -import java.awt.event.MouseListener; - -public class MenuButton extends JButton { - @Getter - private ClickAction clickAction; - - public MenuButton(Icon icon, ClickAction clickAction) { - this.setIcon(icon); - - this.clickAction = clickAction; - - this.init(); - } - - public MenuButton(String text, ClickAction clickAction) { - this.setText(text); - - this.clickAction = clickAction; - - this.init(); - } - - private void init() { - this.setBackground(Color.gray); - - this.setForeground(Color.lightGray); - - this.setBorderPainted(false); - - this.addActionListener(e -> { - - - switch (this.clickAction) { - case CLOSE -> Main.mainFrame.dispose(); - case MINIMIZE -> Main.mainFrame.setState(JFrame.ICONIFIED); - case MAXIMIZE -> { - if(Main.mainFrame.getExtendedState() == JFrame.NORMAL) { - this.setText("(_)"); - - Main.mainFrame.setExtendedState( - Main.mainFrame.getExtendedState() | JFrame.MAXIMIZED_BOTH - ); - } - else { - this.setText("[]"); - Main.mainFrame.setExtendedState(JFrame.NORMAL); - } - } - } - }); - - this.addFocusListener(new FocusListener() { - @Override - public void focusGained(FocusEvent e) { - setBorderPainted(false); -// setBackground(Color.getHSBColor(0.65f, 0.5f, 0.6f)); - } - - @Override - public void focusLost(FocusEvent e) { -// setBackground(Color.gray); - } - }); - - this.addMouseListener(new MouseListener() { - @Override - public void mouseClicked(MouseEvent e) { - - } - - @Override - public void mousePressed(MouseEvent e) { - - } - - @Override - public void mouseReleased(MouseEvent e) { - - } - - @Override - public void mouseEntered(MouseEvent e) { - setBackground(Color.getHSBColor(0.65f, 0.3f, 0.5f)); - } - - @Override - public void mouseExited(MouseEvent e) { - setBackground(Color.gray); - } - }); - } - - public enum ClickAction { - CLOSE, - MINIMIZE, - MAXIMIZE - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/RoundedBorder.java b/src/main/java/org/openautonomousconnection/webclient/ui/RoundedBorder.java deleted file mode 100644 index 1369e3c..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/RoundedBorder.java +++ /dev/null @@ -1,44 +0,0 @@ -/* Author: Maple - * Jan. 19 2026 - * */ - -package org.openautonomousconnection.webclient.ui; - -import javax.swing.border.Border; -import java.awt.*; -import java.awt.geom.RoundRectangle2D; - -public class RoundedBorder implements Border { - - private final int radius; - - public RoundedBorder(int radius) { - this.radius = radius; - } - - @Override - public Insets getBorderInsets(Component c) { - return new Insets(radius, radius, radius, radius); - } - - @Override - public boolean isBorderOpaque() { - return false; - } - - @Override - public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { - Graphics2D g2 = (Graphics2D) g.create(); - g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, - RenderingHints.VALUE_ANTIALIAS_ON); - - g2.setColor(c.getForeground()); - g2.draw(new RoundRectangle2D.Double( - x, y, - width - 1, height - 1, - radius, radius - )); - - g2.dispose(); - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/TabView.java b/src/main/java/org/openautonomousconnection/webclient/ui/TabView.java new file mode 100644 index 0000000..02b58c9 --- /dev/null +++ b/src/main/java/org/openautonomousconnection/webclient/ui/TabView.java @@ -0,0 +1,165 @@ +package org.openautonomousconnection.webclient.ui; + +import javafx.application.Platform; +import javafx.embed.swing.JFXPanel; +import javafx.scene.Scene; +import javafx.scene.web.WebEngine; +import javafx.scene.web.WebHistory; +import javafx.scene.web.WebView; +import org.openautonomousconnection.oacswing.component.OACPanel; +import org.openautonomousconnection.webclient.lua.WebLogger; +import org.openautonomousconnection.webclient.settings.FxEngine; + +import java.awt.*; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.Consumer; + +/** + * A Swing panel that embeds a JavaFX WebView and runs LuaScript (no JavaScript). + * + *

Loads "web://" URLs so JavaFX can request subresources (CSS, images, href navigations) + * through URLConnection (mapped to OAC WebRequestPacket).

+ */ +public final class TabView extends OACPanel { + + private final AtomicBoolean initialized = new AtomicBoolean(false); + + private JFXPanel fxPanel; + private WebView webView; + private WebEngine engine; + + private final Consumer onLocationChanged; + private final WebLogger webLogger; + + private volatile FxEngine luaEngine; + + /** + * Creates a new tab view. + * + * @param onLocationChanged callback invoked when the WebEngine location changes + * @param url callback invoked on URL changes + */ + public TabView(Consumer onLocationChanged, String url) { + super(); + this.onLocationChanged = Objects.requireNonNull(onLocationChanged, "onLocationChanged"); + this.webLogger = new WebLogger(url); + setLayout(new BorderLayout()); + } + + @Override + public void addNotify() { + super.addNotify(); + + if (!initialized.compareAndSet(false, true)) { + return; + } + + fxPanel = new JFXPanel(); + add(fxPanel, BorderLayout.CENTER); + + Platform.runLater(() -> { + webView = new WebView(); + webView.setContextMenuEnabled(false); + + engine = webView.getEngine(); + engine.setJavaScriptEnabled(false); + + engine.locationProperty().addListener((obs, oldV, newV) -> { + if (newV != null) { + onLocationChanged.accept(newV); + } + }); + + // Proper Lua integration from your library + luaEngine = new FxEngine(engine, webView, webLogger); + luaEngine.install(); + + fxPanel.setScene(new Scene(webView)); + }); + } + + /** + * Loads a normalized URL (expected: web://...). + * + * @param url URL to load + */ + public void loadUrl(String url) { + String u = Objects.requireNonNull(url, "url").trim(); + if (u.isEmpty()) return; + + Platform.runLater(() -> { + if (engine != null) { + engine.load(u); + } + }); + } + + /** + * Reloads the current page. + */ + public void reload() { + Platform.runLater(() -> { + if (engine != null) engine.reload(); + }); + } + + /** + * Navigates one step back in history if possible. + */ + public void back() { + Platform.runLater(() -> { + if (engine == null) return; + WebHistory h = engine.getHistory(); + if (h.getCurrentIndex() > 0) h.go(-1); + }); + } + + /** + * Navigates one step forward in history if possible. + */ + public void forward() { + Platform.runLater(() -> { + if (engine == null) return; + WebHistory h = engine.getHistory(); + if (h.getCurrentIndex() < h.getEntries().size() - 1) h.go(1); + }); + } + + /** + * Returns current engine location. + * + * @return location or null + */ + public String getEngineLocation() { + return engine != null ? engine.getLocation() : null; + } + + /** + * Disposes resources. + */ + public void dispose() { + FxEngine le = luaEngine; + luaEngine = null; + if (le != null) { + try { + le.close(); + } catch (Exception ignored) { + } + } + + Platform.runLater(() -> { + if (engine != null) { + try { + engine.load(null); + } catch (Exception ignored) { + } + } + engine = null; + webView = null; + if (fxPanel != null) { + fxPanel.setScene(null); + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/TopBar.java b/src/main/java/org/openautonomousconnection/webclient/ui/TopBar.java deleted file mode 100644 index c00d611..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/TopBar.java +++ /dev/null @@ -1,83 +0,0 @@ -/* Author: Maple - * Jan. 18 2026 - * */ - -package org.openautonomousconnection.webclient.ui; - -import lombok.Getter; -import org.openautonomousconnection.webclient.Main; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.MouseAdapter; -import java.awt.event.MouseEvent; -import java.awt.event.MouseMotionAdapter; - -@Deprecated(forRemoval = true) -public class TopBar extends JPanel { - @Getter - private MenuButton closeButton, minimizeButton, maximizeButton; - - @Getter - private JPanel buttonPanel; - - private Point dragOffset; - - public TopBar() { - this.setPreferredSize(new Dimension(0, 40)); - - this.buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT)); - - this.closeButton = new MenuButton("X", MenuButton.ClickAction.CLOSE); - this.minimizeButton = new MenuButton("-", MenuButton.ClickAction.MINIMIZE); - this.maximizeButton = new MenuButton("[]", MenuButton.ClickAction.MAXIMIZE); - - this.buttonPanel.add(this.closeButton); - this.buttonPanel.add(this.minimizeButton); - this.buttonPanel.add(this.maximizeButton); - - this.init(); - } - - private void init() { - this.addMouseListener(new MouseAdapter() { - @Override - public void mousePressed(MouseEvent e) { - Point mouseOnScreen = e.getLocationOnScreen(); - Point frameLocation = Main.mainFrame.getLocation(); - - dragOffset = new Point( - mouseOnScreen.x - frameLocation.x, - mouseOnScreen.y - frameLocation.y - ); - } - - @Override - public void mouseReleased(MouseEvent e) { - dragOffset = null; - } - }); - - this.addMouseMotionListener(new MouseMotionAdapter() { - @Override - public void mouseDragged(MouseEvent e) { - if (dragOffset != null) { - Point mouseOnScreen = e.getLocationOnScreen(); - - int newX = mouseOnScreen.x - dragOffset.x; - int newY = mouseOnScreen.y - dragOffset.y; - - Main.mainFrame.setLocation(newX, newY); - } - } - }); - } - - public void initButtonPanel(String alignment) { - this.setLayout(new BorderLayout()); - - this.add(this.buttonPanel, alignment); - - this.repaint(); - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/dom/DOMContainerPanel.java b/src/main/java/org/openautonomousconnection/webclient/ui/dom/DOMContainerPanel.java deleted file mode 100644 index 90d4488..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/dom/DOMContainerPanel.java +++ /dev/null @@ -1,52 +0,0 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - -package org.openautonomousconnection.webclient.ui.dom; - -import javafx.application.Platform; -import javafx.embed.swing.JFXPanel; -import javafx.scene.Scene; -import javafx.scene.web.WebEngine; -import javafx.scene.web.WebView; -import lombok.Getter; -import org.openautonomousconnection.oacswing.component.OACPanel; -import org.w3c.dom.Document; - -import javax.swing.*; -import java.awt.*; - -public class DOMContainerPanel extends OACPanel { - @Getter - private final JFXPanel dom; - - @Getter - private WebView webView; - - @Getter - private WebEngine webEngine; - - public void loadContent(String html) { - this.webEngine.loadContent(html); - } - - public void loadContent(Document html) { - this.loadContent(DomSerializer.toString(html)); - } - - public DOMContainerPanel() { - this.setBackground(Color.LIGHT_GRAY); - - //TODO: Turn this into designable OAC-JFXpanel - this.dom = new JFXPanel(); - - Platform.runLater(() -> { - this.webView = new WebView(); - this.webEngine = this.webView.getEngine(); - this.webEngine.setJavaScriptEnabled(false); - this.dom.setScene(new Scene(this.webView)); - }); - - this.add(this.dom); - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/dom/DomSerializer.java b/src/main/java/org/openautonomousconnection/webclient/ui/dom/DomSerializer.java deleted file mode 100644 index 37658d3..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/dom/DomSerializer.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.openautonomousconnection.webclient.ui.dom; - -import org.w3c.dom.Document; - -import javax.xml.transform.OutputKeys; -import javax.xml.transform.Transformer; -import javax.xml.transform.TransformerFactory; -import javax.xml.transform.dom.DOMSource; -import javax.xml.transform.stream.StreamResult; -import java.io.StringWriter; -import javafx.application.Platform; -import javafx.scene.web.WebEngine; - -import java.util.Objects; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.TimeUnit; - -/** - * Serializes a W3C DOM Document to an HTML string. - * - *

Works with JavaFX WebEngine DOM.

- */ -public final class DomSerializer { - - private DomSerializer() { - } - - /** - * Converts a DOM {@link Document} to a string. - * - * @param document DOM document - * @return serialized HTML - */ - public static String toString(Document document) { - if (document == null) { - throw new IllegalArgumentException("document is null"); - } - - try { - TransformerFactory tf = TransformerFactory.newInstance(); - Transformer transformer = tf.newTransformer(); - - transformer.setOutputProperty(OutputKeys.METHOD, "html"); - transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); - transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); - transformer.setOutputProperty(OutputKeys.INDENT, "no"); - - StringWriter writer = new StringWriter(); - transformer.transform( - new DOMSource(document), - new StreamResult(writer) - ); - return writer.toString(); - } catch (Exception e) { - throw new RuntimeException("Failed to serialize DOM document", e); - } - } - - /** - * Loads an HTML string into a JavaFX {@link WebEngine} and returns the resulting DOM {@link Document}. - * - *

No JavaScript required. Parsing is done by WebKit.

- * - * @param engine JavaFX WebEngine (must not be null) - * @param html HTML source - * @return parsed DOM document - */ - public static Document fromString(WebEngine engine, String html) { - Objects.requireNonNull(engine, "engine"); - Objects.requireNonNull(html, "html"); - - if (!Platform.isFxApplicationThread()) { - final Document[] result = new Document[1]; - final RuntimeException[] error = new RuntimeException[1]; - - CountDownLatch latch = new CountDownLatch(1); - Platform.runLater(() -> { - try { - result[0] = fromString(engine, html); - } catch (RuntimeException e) { - error[0] = e; - } finally { - latch.countDown(); - } - }); - - try { - if (!latch.await(5, TimeUnit.SECONDS)) { - throw new RuntimeException("Timed out while parsing HTML"); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("Interrupted while parsing HTML", e); - } - - if (error[0] != null) throw error[0]; - return result[0]; - } - - CountDownLatch latch = new CountDownLatch(1); - - engine.getLoadWorker().stateProperty().addListener((obs, o, n) -> { - switch (n) { - case SUCCEEDED, FAILED, CANCELLED -> latch.countDown(); - } - }); - - engine.loadContent(html, "text/html"); - - try { - if (!latch.await(5, TimeUnit.SECONDS)) { - throw new RuntimeException("Timed out while parsing HTML"); - } - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - throw new RuntimeException("Interrupted while parsing HTML", e); - } - - Document doc = engine.getDocument(); - if (doc == null) { - throw new IllegalStateException("WebEngine did not produce a DOM document"); - } - - return doc; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/tab/TabButton.java b/src/main/java/org/openautonomousconnection/webclient/ui/tab/TabButton.java deleted file mode 100644 index 32ed24a..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/tab/TabButton.java +++ /dev/null @@ -1,35 +0,0 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - -package org.openautonomousconnection.webclient.ui.tab; - -import lombok.Getter; -import lombok.NonNull; -import lombok.Setter; -import org.openautonomousconnection.oacswing.component.OACButton; -import org.openautonomousconnection.webclient.network.website.tab.WebTab; - -import javax.swing.*; -import java.net.URI; -import java.net.URL; - -/** - * Button that contains Tab data - */ -@Getter @Setter -public class TabButton extends OACButton { - private WebTab webTab; - - public TabButton(@NonNull String infoName) throws Exception { - this(URI.create(infoName).toURL()); - } - - public TabButton(@NonNull URL infoName) throws Exception { - this.webTab = new WebTab(infoName); - } - - public TabButton(@NonNull WebTab webTab) { - this.webTab = webTab; - } -} diff --git a/src/main/java/org/openautonomousconnection/webclient/ui/tab/TabButtonView.java b/src/main/java/org/openautonomousconnection/webclient/ui/tab/TabButtonView.java deleted file mode 100644 index aa6938d..0000000 --- a/src/main/java/org/openautonomousconnection/webclient/ui/tab/TabButtonView.java +++ /dev/null @@ -1,53 +0,0 @@ -/* Author: Maple - * Dec. 12 2025 - * */ - -package org.openautonomousconnection.webclient.ui.tab; - -import lombok.Getter; -import org.openautonomousconnection.oacswing.component.OACTitleBar; - -import java.awt.*; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -/** - * View at the top of the screen that contains the tabs - * @deprecated the OAC-Swing library's solution fits better and works globally - */ -@Deprecated(forRemoval = true, since = "1.0.0-BETA.1.4") -public class TabButtonView extends OACTitleBar { - @Getter - private final List tabButtons; - - public TabButtonView() { - this(new ArrayList<>()); - } - - /** - * Constructor with preset buttons - * @param tabButtons already created buttons - */ - public TabButtonView(Collection tabButtons) { - super(null); - this.tabButtons = (List) tabButtons; - - FlowLayout layoutStyle = new FlowLayout(FlowLayout.RIGHT, 0, 0); - - this.setLayout(layoutStyle); - - this.setBackground(Color.gray); - } - - public void addButton(TabButton tabButton) { - this.tabButtons.add(tabButton); - } - - public TabButton getButton(int index) { - return this.tabButtons.get(index); - } - - - -}