Add netstandard1.0 (PCL) support

This commit is contained in:
Frank A. Krueger 2018-03-09 12:56:32 -08:00
parent 00d14adcf1
commit a0e45ab61a
No known key found for this signature in database
GPG Key ID: 0471C67474FFE664
6 changed files with 195 additions and 123 deletions

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection;
namespace Ooui namespace Ooui
{ {
@ -21,7 +22,7 @@ namespace Ooui
public IReadOnlyList<Message> StateMessages { public IReadOnlyList<Message> StateMessages {
get { get {
lock (stateMessages) { lock (stateMessages) {
return new List<Message> (stateMessages).AsReadOnly (); return new ReadOnlyList<Message> (stateMessages);
} }
} }
} }
@ -242,7 +243,7 @@ namespace Ooui
public override bool CanConvert (Type objectType) public override bool CanConvert (Type objectType)
{ {
return typeof (EventTarget).IsAssignableFrom (objectType); return typeof (EventTarget).GetTypeInfo ().IsAssignableFrom (objectType.GetTypeInfo ());
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -11,7 +12,7 @@ namespace Ooui
public IReadOnlyList<Node> Children { public IReadOnlyList<Node> Children {
get { get {
lock (children) { lock (children) {
return new List<Node> (children).AsReadOnly (); return new ReadOnlyList<Node> (children);
} }
} }
} }
@ -35,7 +36,7 @@ namespace Ooui
protected Node (string tagName) protected Node (string tagName)
: base (tagName) : base (tagName)
{ {
} }
public override EventTarget GetElementById (string id) public override EventTarget GetElementById (string id)
@ -84,7 +85,7 @@ namespace Ooui
return null; return null;
lock (children) { lock (children) {
if (!children.Remove (child)) { if (!children.Remove (child)) {
throw new ArgumentException ("Child not contained in this element", nameof(child)); throw new ArgumentException ("Child not contained in this element", nameof (child));
} }
} }
child.MessageSent -= HandleChildMessageSent; child.MessageSent -= HandleChildMessageSent;
@ -130,8 +131,8 @@ namespace Ooui
case MessageType.Call when message.Key == "removeChild" && message.Value is Array ma && ma.Length == 1: case MessageType.Call when message.Key == "removeChild" && message.Value is Array ma && ma.Length == 1:
UpdateStateMessages (state => { UpdateStateMessages (state => {
var mchild = ma.GetValue (0); var mchild = ma.GetValue (0);
Node nextChild = null; Node nextChild = null;
for (var i = 0; i < state.Count; ) { for (var i = 0; i < state.Count;) {
var x = state[i]; var x = state[i];
if (x.Key == "insertBefore" && x.Value is Array xa && xa.Length == 2 && ReferenceEquals (xa.GetValue (0), mchild)) { if (x.Key == "insertBefore" && x.Value is Array xa && xa.Length == 2 && ReferenceEquals (xa.GetValue (0), mchild)) {
// Remove any inserts for this node // Remove any inserts for this node
@ -200,4 +201,28 @@ namespace Ooui
public abstract void WriteOuterHtml (System.Xml.XmlWriter w); public abstract void WriteOuterHtml (System.Xml.XmlWriter w);
} }
class ReadOnlyList<T> : IReadOnlyList<T>
{
readonly List<T> list;
public ReadOnlyList (List<T> items)
{
list = new List<T> (items);
}
T IReadOnlyList<T>.this[int index] => list[index];
int IReadOnlyCollection<T>.Count => list.Count;
IEnumerator<T> IEnumerable<T>.GetEnumerator ()
{
return ((IEnumerable<T>)list).GetEnumerator ();
}
IEnumerator IEnumerable.GetEnumerator ()
{
return ((IEnumerable)list).GetEnumerator ();
}
}
} }

View File

@ -8,12 +8,18 @@
<PackageProjectUrl>https://github.com/praeclarum/Ooui</PackageProjectUrl> <PackageProjectUrl>https://github.com/praeclarum/Ooui</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/praeclarum/Ooui/blob/master/LICENSE</PackageLicenseUrl> <PackageLicenseUrl>https://github.com/praeclarum/Ooui/blob/master/LICENSE</PackageLicenseUrl>
<RepositoryUrl>https://github.com/praeclarum/Ooui.git</RepositoryUrl> <RepositoryUrl>https://github.com/praeclarum/Ooui.git</RepositoryUrl>
<TargetFramework>netstandard2.0</TargetFramework> <TargetFrameworks>netstandard2.0;netstandard1.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" $(TargetFramework) == 'netstandard1.0' ">
<DefineConstants>PCL</DefineConstants>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="10.0.2" /> <PackageReference Include="Newtonsoft.Json" Version="10.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<EmbeddedResource Include="Client.js" /> <EmbeddedResource Include="Client.js" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -7,131 +7,139 @@ namespace Ooui
{ {
static class Platform static class Platform
{ {
static readonly Assembly iosAssembly; #if PCL
static readonly Type iosUIViewControllerType;
static readonly Type iosUIApplicationType;
static readonly Type iosUIWebViewType;
static readonly Type iosNSUrl;
static readonly Type iosNSUrlRequest;
static readonly Assembly androidAssembly; public static void OpenBrowser (string url, object presenter)
static readonly Type androidActivityType; {
static readonly Type androidWebViewType; }
static Platform () #else
{
var asms = AppDomain.CurrentDomain.GetAssemblies ().ToDictionary (
x => x.GetName ().Name);
asms.TryGetValue ("Xamarin.iOS", out iosAssembly); static readonly Assembly iosAssembly;
if (iosAssembly != null) { static readonly Type iosUIViewControllerType;
iosUIViewControllerType = iosAssembly.GetType ("UIKit.UIViewController"); static readonly Type iosUIApplicationType;
iosUIApplicationType = iosAssembly.GetType ("UIKit.UIApplication"); static readonly Type iosUIWebViewType;
iosUIWebViewType = iosAssembly.GetType ("UIKit.UIWebView"); static readonly Type iosNSUrl;
iosNSUrl = iosAssembly.GetType ("Foundation.NSUrl"); static readonly Type iosNSUrlRequest;
iosNSUrlRequest = iosAssembly.GetType ("Foundation.NSUrlRequest");
}
asms.TryGetValue ("Mono.Android", out androidAssembly); static readonly Assembly androidAssembly;
if (androidAssembly != null) { static readonly Type androidActivityType;
androidActivityType = androidAssembly.GetType ("Android.App.Activity"); static readonly Type androidWebViewType;
androidWebViewType = androidAssembly.GetType ("Android.Webkit.WebView");
}
}
public static void OpenBrowser (string url, object presenter) static Platform ()
{ {
if (iosAssembly != null) { var asms = AppDomain.CurrentDomain.GetAssemblies ().ToDictionary (
OpenBrowserOniOS (url, presenter); x => x.GetName ().Name);
}
else if (androidAssembly != null) {
OpenBrowserOnAndroid (url, presenter);
}
else {
StartBrowserProcess (url);
}
}
static void OpenBrowserOnAndroid (string url, object presenter) asms.TryGetValue ("Xamarin.iOS", out iosAssembly);
{ if (iosAssembly != null) {
var presenterType = GetObjectType (presenter); iosUIViewControllerType = iosAssembly.GetType ("UIKit.UIViewController");
iosUIApplicationType = iosAssembly.GetType ("UIKit.UIApplication");
iosUIWebViewType = iosAssembly.GetType ("UIKit.UIWebView");
iosNSUrl = iosAssembly.GetType ("Foundation.NSUrl");
iosNSUrlRequest = iosAssembly.GetType ("Foundation.NSUrlRequest");
}
object presenterWebView = null; asms.TryGetValue ("Mono.Android", out androidAssembly);
if (presenter != null && androidWebViewType.IsAssignableFrom (presenterType)) { if (androidAssembly != null) {
presenterWebView = presenter; androidActivityType = androidAssembly.GetType ("Android.App.Activity");
} androidWebViewType = androidAssembly.GetType ("Android.Webkit.WebView");
}
}
if (presenterWebView == null) { public static void OpenBrowser (string url, object presenter)
throw new ArgumentException ("Presenter must be a WebView", nameof(presenter)); {
} if (iosAssembly != null) {
OpenBrowserOniOS (url, presenter);
}
else if (androidAssembly != null) {
OpenBrowserOnAndroid (url, presenter);
}
else {
StartBrowserProcess (url);
}
}
var m = androidWebViewType.GetMethod ("LoadUrl", BindingFlags.Public|BindingFlags.Instance, null, CallingConventions.Any, new Type[] { typeof(string) }, null); static void OpenBrowserOnAndroid (string url, object presenter)
m.Invoke (presenterWebView, new object[] { url }); {
} var presenterType = GetObjectType (presenter);
static void OpenBrowserOniOS (string url, object presenter) object presenterWebView = null;
{ if (presenter != null && androidWebViewType.IsAssignableFrom (presenterType)) {
var presenterType = GetObjectType (presenter); presenterWebView = presenter;
}
// if (presenterWebView == null) {
// Find a presenter view controller throw new ArgumentException ("Presenter must be a WebView", nameof (presenter));
// 1. Try the given presenter }
// 2. Find the key window vc
// 3. Create a window?
//
object presenterViewController = null;
if (presenter != null && iosUIViewControllerType.IsAssignableFrom (presenterType)) {
presenterViewController = presenter;
}
if (presenterViewController == null) { var m = androidWebViewType.GetMethod ("LoadUrl", BindingFlags.Public | BindingFlags.Instance, null, CallingConventions.Any, new Type[] { typeof (string) }, null);
var app = iosUIApplicationType.GetProperty ("SharedApplication").GetValue (null, null); m.Invoke (presenterWebView, new object[] { url });
var window = iosUIApplicationType.GetProperty ("KeyWindow").GetValue (app, null); }
if (window != null) {
var rvc = window.GetType ().GetProperty ("RootViewController").GetValue (window, null);
if (rvc != null) {
var pvc = rvc.GetType ().GetProperty ("PresentedViewController").GetValue (rvc, null);
presenterViewController = pvc ?? rvc;
}
}
}
if (presenterViewController == null) { static void OpenBrowserOniOS (string url, object presenter)
throw new InvalidOperationException ("Cannot find a view controller from which to present"); {
} var presenterType = GetObjectType (presenter);
// //
// Create the browser // Find a presenter view controller
// // 1. Try the given presenter
var browserVC = Activator.CreateInstance (iosUIViewControllerType); // 2. Find the key window vc
var browserV = Activator.CreateInstance (iosUIWebViewType); // 3. Create a window?
//
object presenterViewController = null;
if (presenter != null && iosUIViewControllerType.IsAssignableFrom (presenterType)) {
presenterViewController = presenter;
}
var nsUrl = iosNSUrl.GetMethod ("FromString").Invoke (null, new object[] { url }); if (presenterViewController == null) {
var nsUrlRequest = iosNSUrlRequest.GetMethod ("FromUrl").Invoke (null, new object[] { nsUrl }); var app = iosUIApplicationType.GetProperty ("SharedApplication").GetValue (null, null);
iosUIWebViewType.GetMethod ("LoadRequest").Invoke (browserV, new object[] { nsUrlRequest }); var window = iosUIApplicationType.GetProperty ("KeyWindow").GetValue (app, null);
iosUIViewControllerType.GetProperty ("View").SetValue (browserVC, browserV, null); if (window != null) {
var rvc = window.GetType ().GetProperty ("RootViewController").GetValue (window, null);
if (rvc != null) {
var pvc = rvc.GetType ().GetProperty ("PresentedViewController").GetValue (rvc, null);
presenterViewController = pvc ?? rvc;
}
}
}
var m = iosUIViewControllerType.GetMethod ("PresentViewController"); if (presenterViewController == null) {
throw new InvalidOperationException ("Cannot find a view controller from which to present");
}
// Console.WriteLine (presenterViewController); //
// Console.WriteLine (browserVC); // Create the browser
m.Invoke (presenterViewController, new object[] { browserVC, false, null }); //
} var browserVC = Activator.CreateInstance (iosUIViewControllerType);
var browserV = Activator.CreateInstance (iosUIWebViewType);
static Type GetObjectType (object o) var nsUrl = iosNSUrl.GetMethod ("FromString").Invoke (null, new object[] { url });
{ var nsUrlRequest = iosNSUrlRequest.GetMethod ("FromUrl").Invoke (null, new object[] { nsUrl });
var t = typeof (object); iosUIWebViewType.GetMethod ("LoadRequest").Invoke (browserV, new object[] { nsUrlRequest });
if (o is IReflectableType rt) { iosUIViewControllerType.GetProperty ("View").SetValue (browserVC, browserV, null);
t = rt.GetTypeInfo ().AsType ();
}
else if (o != null) {
t = o.GetType ();
}
return t;
}
static Process StartBrowserProcess (string url) var m = iosUIViewControllerType.GetMethod ("PresentViewController");
{
// Console.WriteLine (presenterViewController);
// Console.WriteLine (browserVC);
m.Invoke (presenterViewController, new object[] { browserVC, false, null });
}
static Type GetObjectType (object o)
{
var t = typeof (object);
if (o is IReflectableType rt) {
t = rt.GetTypeInfo ().AsType ();
}
else if (o != null) {
t = o.GetType ();
}
return t;
}
static void StartBrowserProcess (string url)
{
// var vs = Environment.GetEnvironmentVariables (); // var vs = Environment.GetEnvironmentVariables ();
// foreach (System.Collections.DictionaryEntry kv in vs) { // foreach (System.Collections.DictionaryEntry kv in vs) {
// System.Console.WriteLine($"K={kv.Key}, V={kv.Value}"); // System.Console.WriteLine($"K={kv.Key}, V={kv.Value}");
@ -139,9 +147,14 @@ namespace Ooui
// Console.WriteLine ($"Process.Start {cmd} {args}"); // Console.WriteLine ($"Process.Start {cmd} {args}");
return Environment.OSVersion.Platform == PlatformID.Unix if (Environment.OSVersion.Platform == PlatformID.Unix) {
? Process.Start ("open", url) Process.Start ("open", url);
: Process.Start (new ProcessStartInfo (url) { UseShellExecute = true }); }
else {
Process.Start (new ProcessStartInfo (url) { UseShellExecute = true });
}
} }
#endif
} }
} }

View File

@ -412,8 +412,19 @@ namespace Ooui
return null; return null;
if (val is string s) if (val is string s)
return s; return s;
if (val is int i)
return i + units;
if (val is double d)
return d.ToString (System.Globalization.CultureInfo.InvariantCulture) + units;
if (val is float f)
return f.ToString (System.Globalization.CultureInfo.InvariantCulture) + units;
#if !PCL
if (val is IConvertible c) if (val is IConvertible c)
return c.ToString (System.Globalization.CultureInfo.InvariantCulture) + units; return c.ToString (System.Globalization.CultureInfo.InvariantCulture) + units;
#endif
return val.ToString (); return val.ToString ();
} }
@ -431,8 +442,17 @@ namespace Ooui
return num; return num;
} }
if (v is int i)
return i;
if (v is double d)
return d;
if (v is float f)
return f;
#if !PCL
if (v is IConvertible c) if (v is IConvertible c)
return c.ToDouble (System.Globalization.CultureInfo.InvariantCulture); return c.ToDouble (System.Globalization.CultureInfo.InvariantCulture);
#endif
return 0; return 0;
} }

View File

@ -6,12 +6,17 @@ using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Net; using System.Net;
#if !PCL
using System.Net.WebSockets; using System.Net.WebSockets;
#endif
namespace Ooui namespace Ooui
{ {
public static class UI public static class UI
{ {
#if !PCL
static readonly ManualResetEvent started = new ManualResetEvent (false); static readonly ManualResetEvent started = new ManualResetEvent (false);
[ThreadStatic] [ThreadStatic]
@ -22,12 +27,6 @@ namespace Ooui
static readonly Dictionary<string, RequestHandler> publishedPaths = static readonly Dictionary<string, RequestHandler> publishedPaths =
new Dictionary<string, RequestHandler> (); new Dictionary<string, RequestHandler> ();
static readonly Dictionary<string, Style> styles =
new Dictionary<string, Style> ();
static readonly StyleSelectors rules = new StyleSelectors ();
public static StyleSelectors Styles => rules;
static readonly byte[] clientJsBytes; static readonly byte[] clientJsBytes;
static readonly string clientJsEtag; static readonly string clientJsEtag;
@ -809,6 +808,14 @@ namespace Ooui
} }
} }
#endif
static readonly Dictionary<string, Style> styles =
new Dictionary<string, Style> ();
static readonly StyleSelectors rules = new StyleSelectors ();
public static StyleSelectors Styles => rules;
public class StyleSelectors public class StyleSelectors
{ {
public Style this[string selector] { public Style this[string selector] {