зеркало из https://github.com/DeGsoft/maui-linux.git
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
This commit is contained in:
Родитель
b60fa6acf8
Коммит
b186254d1f
|
@ -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>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 6.8 KiB |
|
@ -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">
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
html,body{margin:0;padding:10}
|
||||
body,p,h1{font-family:Chalkduster;font-style: italic;}
|
|
@ -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>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 6.8 KiB |
|
@ -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">
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
html,body{margin:0;padding:10}
|
||||
body,p,h1{font-family:Chalkduster;font-style: italic;}
|
|
@ -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>
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 6.8 KiB |
|
@ -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>
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
html,body{margin:0;padding:10}
|
||||
body,p,h1{font-family:Chalkduster;font-style: italic;}
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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">
|
||||
|
|
|
@ -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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче