// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using Microsoft.Maui.Handlers; namespace Microsoft.Maui.Platform; /// /// Linux handler for WebView control using WebKitGTK. /// public partial class WebViewHandler : ViewHandler { /// /// Property mapper for WebView properties. /// public static IPropertyMapper Mapper = new PropertyMapper(ViewHandler.ViewMapper) { [nameof(IWebView.Source)] = MapSource, [nameof(IWebView.UserAgent)] = MapUserAgent, }; /// /// Command mapper for WebView commands. /// public static CommandMapper CommandMapper = new(ViewHandler.ViewCommandMapper) { [nameof(IWebView.GoBack)] = MapGoBack, [nameof(IWebView.GoForward)] = MapGoForward, [nameof(IWebView.Reload)] = MapReload, [nameof(IWebView.Eval)] = MapEval, [nameof(IWebView.EvaluateJavaScriptAsync)] = MapEvaluateJavaScriptAsync, }; public WebViewHandler() : base(Mapper, CommandMapper) { } public WebViewHandler(IPropertyMapper? mapper) : base(mapper ?? Mapper, CommandMapper) { } public WebViewHandler(IPropertyMapper? mapper, CommandMapper? commandMapper) : base(mapper ?? Mapper, commandMapper ?? CommandMapper) { } protected override LinuxWebView CreatePlatformView() { Console.WriteLine("[WebViewHandler] Creating LinuxWebView"); return new LinuxWebView(); } protected override void ConnectHandler(LinuxWebView platformView) { base.ConnectHandler(platformView); platformView.Navigating += OnNavigating; platformView.Navigated += OnNavigated; // Map initial properties if (VirtualView != null) { MapSource(this, VirtualView); MapUserAgent(this, VirtualView); } Console.WriteLine("[WebViewHandler] Handler connected"); } protected override void DisconnectHandler(LinuxWebView platformView) { platformView.Navigating -= OnNavigating; platformView.Navigated -= OnNavigated; base.DisconnectHandler(platformView); Console.WriteLine("[WebViewHandler] Handler disconnected"); } private void OnNavigating(object? sender, WebViewNavigatingEventArgs e) { if (VirtualView == null) return; // Notify the virtual view about navigation starting VirtualView.Navigating(WebNavigationEvent.NewPage, e.Url); } private void OnNavigated(object? sender, WebViewNavigatedEventArgs e) { if (VirtualView == null) return; // Notify the virtual view about navigation completed var result = e.Success ? WebNavigationResult.Success : WebNavigationResult.Failure; VirtualView.Navigated(WebNavigationEvent.NewPage, e.Url, result); } #region Property Mappers public static void MapSource(WebViewHandler handler, IWebView webView) { var source = webView.Source; if (source == null) return; Console.WriteLine($"[WebViewHandler] MapSource: {source.GetType().Name}"); if (source is IUrlWebViewSource urlSource && !string.IsNullOrEmpty(urlSource.Url)) { handler.PlatformView?.LoadUrl(urlSource.Url); } else if (source is IHtmlWebViewSource htmlSource && !string.IsNullOrEmpty(htmlSource.Html)) { handler.PlatformView?.LoadHtml(htmlSource.Html, htmlSource.BaseUrl); } } public static void MapUserAgent(WebViewHandler handler, IWebView webView) { if (handler.PlatformView != null && !string.IsNullOrEmpty(webView.UserAgent)) { handler.PlatformView.UserAgent = webView.UserAgent; Console.WriteLine($"[WebViewHandler] MapUserAgent: {webView.UserAgent}"); } } #endregion #region Command Mappers public static void MapGoBack(WebViewHandler handler, IWebView webView, object? args) { if (handler.PlatformView?.CanGoBack == true) { handler.PlatformView.GoBack(); Console.WriteLine("[WebViewHandler] GoBack"); } } public static void MapGoForward(WebViewHandler handler, IWebView webView, object? args) { if (handler.PlatformView?.CanGoForward == true) { handler.PlatformView.GoForward(); Console.WriteLine("[WebViewHandler] GoForward"); } } public static void MapReload(WebViewHandler handler, IWebView webView, object? args) { handler.PlatformView?.Reload(); Console.WriteLine("[WebViewHandler] Reload"); } public static void MapEval(WebViewHandler handler, IWebView webView, object? args) { if (args is string script) { handler.PlatformView?.Eval(script); Console.WriteLine($"[WebViewHandler] Eval: {script.Substring(0, Math.Min(50, script.Length))}..."); } } public static void MapEvaluateJavaScriptAsync(WebViewHandler handler, IWebView webView, object? args) { if (args is EvaluateJavaScriptAsyncRequest request) { var result = handler.PlatformView?.EvaluateJavaScriptAsync(request.Script); if (result != null) { result.ContinueWith(t => { request.SetResult(t.Result); }); } else { request.SetResult(null); } Console.WriteLine($"[WebViewHandler] EvaluateJavaScriptAsync: {request.Script.Substring(0, Math.Min(50, request.Script.Length))}..."); } } #endregion } /// /// Request object for async JavaScript evaluation. /// public class EvaluateJavaScriptAsyncRequest { public string Script { get; } private readonly TaskCompletionSource _tcs = new(); public EvaluateJavaScriptAsyncRequest(string script) { Script = script; } public Task Task => _tcs.Task; public void SetResult(string? result) { _tcs.TrySetResult(result); } }