// 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.Controls; using Microsoft.Maui.Handlers; using Microsoft.Maui.Platform; namespace Microsoft.Maui.Platform.Linux.Handlers; /// /// Handler for WebView control on Linux using WebKitGTK. /// public partial class WebViewHandler : ViewHandler { public static IPropertyMapper Mapper = new PropertyMapper(ViewHandler.ViewMapper) { [nameof(IWebView.Source)] = MapSource, [nameof(IWebView.UserAgent)] = MapUserAgent, }; 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 = null, CommandMapper? commandMapper = null) : base(mapper ?? Mapper, commandMapper ?? CommandMapper) { } protected override SkiaWebView CreatePlatformView() { return new SkiaWebView(); } protected override void ConnectHandler(SkiaWebView platformView) { base.ConnectHandler(platformView); platformView.Navigating += OnNavigating; platformView.Navigated += OnNavigated; } protected override void DisconnectHandler(SkiaWebView platformView) { platformView.Navigating -= OnNavigating; platformView.Navigated -= OnNavigated; base.DisconnectHandler(platformView); } private void OnNavigating(object? sender, Microsoft.Maui.Platform.WebNavigatingEventArgs e) { IWebView virtualView = VirtualView; IWebViewController? controller = virtualView as IWebViewController; if (controller != null) { var args = new Microsoft.Maui.Controls.WebNavigatingEventArgs( WebNavigationEvent.NewPage, null, e.Url); controller.SendNavigating(args); } } private void OnNavigated(object? sender, Microsoft.Maui.Platform.WebNavigatedEventArgs e) { IWebView virtualView = VirtualView; IWebViewController? controller = virtualView as IWebViewController; if (controller != null) { WebNavigationResult result = e.Success ? WebNavigationResult.Success : WebNavigationResult.Failure; var args = new Microsoft.Maui.Controls.WebNavigatedEventArgs( WebNavigationEvent.NewPage, null, e.Url, result); controller.SendNavigated(args); } } public static void MapSource(WebViewHandler handler, IWebView webView) { Console.WriteLine("[WebViewHandler] MapSource called"); if (handler.PlatformView == null) { Console.WriteLine("[WebViewHandler] PlatformView is null!"); return; } var source = webView.Source; Console.WriteLine($"[WebViewHandler] Source type: {source?.GetType().Name ?? "null"}"); if (source is UrlWebViewSource urlSource) { Console.WriteLine($"[WebViewHandler] Loading URL: {urlSource.Url}"); handler.PlatformView.Source = urlSource.Url ?? ""; } else if (source is HtmlWebViewSource htmlSource) { Console.WriteLine($"[WebViewHandler] Loading HTML ({htmlSource.Html?.Length ?? 0} chars)"); Console.WriteLine($"[WebViewHandler] HTML preview: {htmlSource.Html?.Substring(0, Math.Min(100, htmlSource.Html?.Length ?? 0))}..."); handler.PlatformView.Html = htmlSource.Html ?? ""; } else { Console.WriteLine("[WebViewHandler] Unknown source type or null"); } } public static void MapGoBack(WebViewHandler handler, IWebView webView, object? args) { handler.PlatformView?.GoBack(); } public static void MapGoForward(WebViewHandler handler, IWebView webView, object? args) { handler.PlatformView?.GoForward(); } public static void MapReload(WebViewHandler handler, IWebView webView, object? args) { handler.PlatformView?.Reload(); } public static void MapUserAgent(WebViewHandler handler, IWebView webView) { if (handler.PlatformView != null && !string.IsNullOrEmpty(webView.UserAgent)) { handler.PlatformView.UserAgent = webView.UserAgent; } } public static void MapEval(WebViewHandler handler, IWebView webView, object? args) { if (args is string script) { handler.PlatformView?.Eval(script); } } public static void MapEvaluateJavaScriptAsync(WebViewHandler handler, IWebView webView, object? args) { // Handle EvaluateJavaScriptAsyncRequest from Microsoft.Maui.Platform namespace 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); } } else if (args is string script) { // Direct script string handler.PlatformView?.EvaluateJavaScriptAsync(script); } } } /// /// Request object for async JavaScript evaluation (matches Microsoft.Maui.Platform.EvaluateJavaScriptAsyncRequest). /// public class EvaluateJavaScriptAsyncRequest { public string Script { get; } private readonly System.Threading.Tasks.TaskCompletionSource _tcs = new(); public EvaluateJavaScriptAsyncRequest(string script) { Script = script; } public System.Threading.Tasks.Task Task => _tcs.Task; public void SetResult(string? result) { _tcs.TrySetResult(result); } }