diff options
author | E.Z. Hart <hartez@users.noreply.github.com> | 2016-08-03 15:22:14 -0600 |
---|---|---|
committer | Jason Smith <jason.smith@xamarin.com> | 2016-08-03 14:22:14 -0700 |
commit | b186254d1f4a0547c67f4fd30669df9d4cf36b65 (patch) | |
tree | 6278a0f3217c726aed4e29c2027b10eb61522aeb | |
parent | b60fa6acf84d897d6283310e58b1c6c6365c391c (diff) | |
download | xamarin-forms-b186254d1f4a0547c67f4fd30669df9d4cf36b65.tar.gz xamarin-forms-b186254d1f4a0547c67f4fd30669df9d4cf36b65.tar.bz2 xamarin-forms-b186254d1f4a0547c67f4fd30669df9d4cf36b65.zip |
Enable WebView to render local HTML files on WinRT platforms (#277)
* Enable WebView to render local HTML files on WinRT platforms
* Add test to demonstrate that the solution works even if
<head> isn't in the HTML string
16 files changed, 240 insertions, 8 deletions
diff --git a/Xamarin.Forms.ControlGallery.WP8/local.html b/Xamarin.Forms.ControlGallery.WP8/local.html index b1998a12..6ef9746b 100644 --- a/Xamarin.Forms.ControlGallery.WP8/local.html +++ b/Xamarin.Forms.ControlGallery.WP8/local.html @@ -4,7 +4,7 @@ </head> <body> <h1>Xamarin.Forms</h1> -<p>This is a local iOS Html page</p> +<p>This is a local HTML page</p> </body> </html>
\ No newline at end of file diff --git a/Xamarin.Forms.ControlGallery.Windows/WebImages/XamarinLogo.png b/Xamarin.Forms.ControlGallery.Windows/WebImages/XamarinLogo.png Binary files differnew file mode 100644 index 00000000..361e2782 --- /dev/null +++ b/Xamarin.Forms.ControlGallery.Windows/WebImages/XamarinLogo.png diff --git a/Xamarin.Forms.ControlGallery.Windows/Xamarin.Forms.ControlGallery.Windows.csproj b/Xamarin.Forms.ControlGallery.Windows/Xamarin.Forms.ControlGallery.Windows.csproj index c93c45b9..aa8f862f 100644 --- a/Xamarin.Forms.ControlGallery.Windows/Xamarin.Forms.ControlGallery.Windows.csproj +++ b/Xamarin.Forms.ControlGallery.Windows/Xamarin.Forms.ControlGallery.Windows.csproj @@ -189,7 +189,10 @@ <Content Include="Assets\SplashScreen.scale-100.png" /> <Content Include="Assets\StoreLogo.scale-100.png" /> <Content Include="coffee.png" /> + <Content Include="default.css" /> + <Content Include="local.html" /> <Content Include="toolbar_close.png" /> + <Content Include="WebImages\XamarinLogo.png" /> </ItemGroup> <ItemGroup> <ApplicationDefinition Include="App.xaml"> diff --git a/Xamarin.Forms.ControlGallery.Windows/default.css b/Xamarin.Forms.ControlGallery.Windows/default.css new file mode 100644 index 00000000..9e32b419 --- /dev/null +++ b/Xamarin.Forms.ControlGallery.Windows/default.css @@ -0,0 +1,2 @@ +html,body{margin:0;padding:10} +body,p,h1{font-family:Chalkduster;font-style: italic;}
\ No newline at end of file diff --git a/Xamarin.Forms.ControlGallery.Windows/local.html b/Xamarin.Forms.ControlGallery.Windows/local.html new file mode 100644 index 00000000..6ef9746b --- /dev/null +++ b/Xamarin.Forms.ControlGallery.Windows/local.html @@ -0,0 +1,10 @@ +<html> +<head> +<link rel="stylesheet" href="default.css"> +</head> +<body> +<h1>Xamarin.Forms</h1> +<p>This is a local HTML page</p> + +</body> +</html>
\ No newline at end of file diff --git a/Xamarin.Forms.ControlGallery.WindowsPhone/WebImages/XamarinLogo.png b/Xamarin.Forms.ControlGallery.WindowsPhone/WebImages/XamarinLogo.png Binary files differnew file mode 100644 index 00000000..361e2782 --- /dev/null +++ b/Xamarin.Forms.ControlGallery.WindowsPhone/WebImages/XamarinLogo.png diff --git a/Xamarin.Forms.ControlGallery.WindowsPhone/Xamarin.Forms.ControlGallery.WindowsPhone.csproj b/Xamarin.Forms.ControlGallery.WindowsPhone/Xamarin.Forms.ControlGallery.WindowsPhone.csproj index 16a042b0..a8565433 100644 --- a/Xamarin.Forms.ControlGallery.WindowsPhone/Xamarin.Forms.ControlGallery.WindowsPhone.csproj +++ b/Xamarin.Forms.ControlGallery.WindowsPhone/Xamarin.Forms.ControlGallery.WindowsPhone.csproj @@ -166,7 +166,10 @@ <Content Include="Assets\StoreLogo.scale-240.png" /> <Content Include="Assets\WideLogo.scale-240.png" /> <Content Include="coffee.png" /> + <Content Include="default.css" /> + <Content Include="local.html" /> <Content Include="toolbar_close.png" /> + <Content Include="WebImages\XamarinLogo.png" /> </ItemGroup> <ItemGroup> <ApplicationDefinition Include="App.xaml"> diff --git a/Xamarin.Forms.ControlGallery.WindowsPhone/default.css b/Xamarin.Forms.ControlGallery.WindowsPhone/default.css new file mode 100644 index 00000000..9e32b419 --- /dev/null +++ b/Xamarin.Forms.ControlGallery.WindowsPhone/default.css @@ -0,0 +1,2 @@ +html,body{margin:0;padding:10} +body,p,h1{font-family:Chalkduster;font-style: italic;}
\ No newline at end of file diff --git a/Xamarin.Forms.ControlGallery.WindowsPhone/local.html b/Xamarin.Forms.ControlGallery.WindowsPhone/local.html new file mode 100644 index 00000000..6ef9746b --- /dev/null +++ b/Xamarin.Forms.ControlGallery.WindowsPhone/local.html @@ -0,0 +1,10 @@ +<html> +<head> +<link rel="stylesheet" href="default.css"> +</head> +<body> +<h1>Xamarin.Forms</h1> +<p>This is a local HTML page</p> + +</body> +</html>
\ No newline at end of file diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/WebImages/XamarinLogo.png b/Xamarin.Forms.ControlGallery.WindowsUniversal/WebImages/XamarinLogo.png Binary files differnew file mode 100644 index 00000000..361e2782 --- /dev/null +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/WebImages/XamarinLogo.png diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj b/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj index d5339b71..a4952000 100644 --- a/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/Xamarin.Forms.ControlGallery.WindowsUniversal.csproj @@ -117,8 +117,11 @@ </ItemGroup> <ItemGroup> <Content Include="coffee.png" /> + <Content Include="default.css" /> <Content Include="invalidimage.jpg" /> + <Content Include="local.html" /> <Content Include="toolbar_close.png" /> + <Content Include="WebImages\XamarinLogo.png" /> <None Include="project.json" /> <Content Include="..\Xamarin.Forms.ControlGallery.WP8\bank.png"> <Link>bank.png</Link> diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/default.css b/Xamarin.Forms.ControlGallery.WindowsUniversal/default.css new file mode 100644 index 00000000..9e32b419 --- /dev/null +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/default.css @@ -0,0 +1,2 @@ +html,body{margin:0;padding:10} +body,p,h1{font-family:Chalkduster;font-style: italic;}
\ No newline at end of file diff --git a/Xamarin.Forms.ControlGallery.WindowsUniversal/local.html b/Xamarin.Forms.ControlGallery.WindowsUniversal/local.html new file mode 100644 index 00000000..6ef9746b --- /dev/null +++ b/Xamarin.Forms.ControlGallery.WindowsUniversal/local.html @@ -0,0 +1,10 @@ +<html> +<head> +<link rel="stylesheet" href="default.css"> +</head> +<body> +<h1>Xamarin.Forms</h1> +<p>This is a local HTML page</p> + +</body> +</html>
\ No newline at end of file diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla32033.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla32033.cs new file mode 100644 index 00000000..2576525a --- /dev/null +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Bugzilla32033.cs @@ -0,0 +1,141 @@ +using Xamarin.Forms.CustomAttributes; +using Xamarin.Forms.Internals; + +namespace Xamarin.Forms.Controls +{ + [Preserve (AllMembers = true)] + [Issue (IssueTracker.Bugzilla, 32033, "WebView on Windows does not display local HTML files", PlatformAffected.WinRT)] + public class Bugzilla32033 : TestNavigationPage + { + protected override void Init () + { + PushAsync(Menu()); + } + + ContentPage Menu() + { + var page = new ContentPage(); + + var layout = new StackLayout(); + + var buttonLocal = new Button() {Text = "Local HTML file"}; + buttonLocal.Clicked += (sender, args) => Navigation.PushAsync(LocalUrl()); + + var buttonHtmlString = new Button() {Text = "HTML string with links/refs to local files"}; + buttonHtmlString.Clicked += (sender, args) => Navigation.PushAsync(HtmlString()); + + var buttonHtmlStringNoHead = new Button() {Text = "HTML string with links/refs to local files (no <head>)"}; + buttonHtmlStringNoHead.Clicked += (sender, args) => Navigation.PushAsync(HtmlStringNoHead()); + + layout.Children.Add(buttonLocal); + layout.Children.Add(buttonHtmlString); + layout.Children.Add(buttonHtmlStringNoHead); + + page.Content = layout; + + return page; + } + + static ContentPage LocalUrl() + { + var page = new ContentPage(); + + var instructions = new Label + { + Text = @"The WebView below should contain the heading 'Xamarin Forms' and text reading 'This is a local HTML page'. All text should be italicized." + }; + + var webView = new WebView + { + WidthRequest = 300, + HeightRequest = 500, + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill, + Source = new UrlWebViewSource() { Url = "local.html" } + }; + + var layout = new StackLayout { Children = { instructions, webView } }; + page.Content = layout; + + return page; + } + + static ContentPage HtmlString() + { + var page = new ContentPage(); + + var instructions = new Label + { + Text = +@"The WebView below should contain the heading 'Xamarin Forms', display the Xamarin logo, and have a link labeled 'next page'. +Clicking that link should navigate to a page with the heading 'Xamarin Forms' and text reading 'This is a local HTML page'. All text on both pages should be italicized." + }; + + var webView = new WebView + { + WidthRequest = 300, + HeightRequest = 500, + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill, + Source = new HtmlWebViewSource + { + Html = @"<html> +<head> +<link rel=""stylesheet"" href=""default.css""> +</head> +<body> +<h1>Xamarin.Forms</h1> +<p>The CSS and image are loaded from local files!</p> +<img src='WebImages/XamarinLogo.png'/> +<p><a href=""local.html"">next page</a></p> +</body> +</html>" + } + }; + + + var layout = new StackLayout {HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, Children = { instructions, webView } }; + page.Content = layout; + + return page; + } + + // This test verifies that the <base> injection solution works even if the HTML string doesn't explicitly include a <head> section + static ContentPage HtmlStringNoHead() + { + var page = new ContentPage(); + + var instructions = new Label + { + Text = +@"The WebView below should contain the heading 'Xamarin Forms', display the Xamarin logo, and have a link labeled 'next page'. +Clicking that link should navigate to a page with the heading 'Xamarin Forms' and text reading 'This is a local HTML page'. " + }; + + var webView = new WebView + { + WidthRequest = 300, + HeightRequest = 500, + HorizontalOptions = LayoutOptions.Fill, + VerticalOptions = LayoutOptions.Fill, + Source = new HtmlWebViewSource + { + Html = @"<html> +<body> +<h1>Xamarin.Forms</h1> +<p>The CSS and image are loaded from local files!</p> +<img src='WebImages/XamarinLogo.png'/> +<p><a href=""local.html"">next page</a></p> +</body> +</html>" + } + }; + + + var layout = new StackLayout {HorizontalOptions = LayoutOptions.Fill, VerticalOptions = LayoutOptions.Fill, Children = { instructions, webView } }; + page.Content = layout; + + return page; + } + } +}
\ No newline at end of file diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems index 4fdb18fd..8d1e0b40 100644 --- a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems +++ b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems @@ -46,6 +46,7 @@ <Compile Include="$(MSBuildThisFileDirectory)Bugzilla31333.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Bugzilla31366.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Bugzilla31964.cs" /> + <Compile Include="$(MSBuildThisFileDirectory)Bugzilla32033.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Bugzilla32034.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Bugzilla32776.cs" /> <Compile Include="$(MSBuildThisFileDirectory)Bugzilla32842.xaml.cs"> diff --git a/Xamarin.Forms.Platform.WinRT/WebViewRenderer.cs b/Xamarin.Forms.Platform.WinRT/WebViewRenderer.cs index 78d69abd..e3fcb898 100644 --- a/Xamarin.Forms.Platform.WinRT/WebViewRenderer.cs +++ b/Xamarin.Forms.Platform.WinRT/WebViewRenderer.cs @@ -1,8 +1,14 @@ using System; +using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; +using System.Threading.Tasks; using Windows.UI.Core; +using Windows.UI.WebUI; using Windows.UI.Xaml.Controls; +using Windows.Web.Http; using Xamarin.Forms.Internals; +using static System.String; #if WINDOWS_UWP @@ -16,19 +22,59 @@ namespace Xamarin.Forms.Platform.WinRT { WebNavigationEvent _eventState; bool _updating; + const string LocalScheme = "ms-appx-web:///"; + + // Script to insert a <base> tag into an HTML document + const string BaseInsertionScript = @" +var head = document.getElementsByTagName('head')[0]; +var bases = head.getElementsByTagName('base'); +if(bases.length == 0){ + head.innerHTML = 'baseTag' + head.innerHTML; +}"; public void LoadHtml(string html, string baseUrl) { - /* - * FIXME: If baseUrl is a file URL, set the Base property to its path. - * Otherwise, it doesn't seem as if WebBrowser can handle it. - */ - Control.NavigateToString(html); + if (IsNullOrEmpty(baseUrl)) + { + baseUrl = LocalScheme; + } + + // Generate a base tag for the document + var baseTag = $"<base href=\"{baseUrl}\"></base>"; + + string htmlWithBaseTag; + + // Set up an internal WebView we can use to load and parse the original HTML string + var internalWebView = new Windows.UI.Xaml.Controls.WebView(); + + // When the 'navigation' to the original HTML string is done, we can modify it to include our <base> tag + internalWebView.NavigationCompleted += async (sender, args) => + { + // Generate a version of the <base> script with the correct <base> tag + var script = BaseInsertionScript.Replace("baseTag", baseTag); + + // Run it and retrieve the updated HTML from our WebView + await sender.InvokeScriptAsync("eval", new[] { script }); + htmlWithBaseTag = await sender.InvokeScriptAsync("eval", new[] { "document.documentElement.outerHTML;" }); + + // Set the HTML for the 'real' WebView to the updated HTML + Control.NavigateToString(!IsNullOrEmpty(htmlWithBaseTag) ? htmlWithBaseTag : html); + }; + + // Kick off the initial navigation + internalWebView.NavigateToString(html); } public void LoadUrl(string url) { - Control.Source = new Uri(url); + Uri uri = new Uri(url, UriKind.RelativeOrAbsolute); + + if (!uri.IsAbsoluteUri) + { + uri = new Uri(LocalScheme + url, UriKind.RelativeOrAbsolute); + } + + Control.Source = uri; } protected override void Dispose(bool disposing) @@ -165,7 +211,6 @@ namespace Xamarin.Forms.Platform.WinRT _eventState = WebNavigationEvent.NewPage; } - // Nasty hack because we cant bind this because OneWayToSource isn't a thing in WP8, yay void UpdateCanGoBackForward() { Element.CanGoBack = Control.CanGoBack; |