Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for EventCallback #390

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using GoogleMapsComponents.Maps;
using GoogleMapsComponents.Extensions;
using GoogleMapsComponents.Maps;
using GoogleMapsComponents.Maps.Strings;
using GoogleMapsComponents.Serialization;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
Expand All @@ -15,17 +17,6 @@ namespace GoogleMapsComponents;

internal static class Helper
{
private static readonly JsonSerializerOptions Options = new JsonSerializerOptions()
{
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
};

static Helper()
{
Options.Converters.Add(new OneOfConverterFactory());
Options.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
}

internal static Task MyInvokeAsync(
this IJSRuntime jsRuntime,
Expand Down Expand Up @@ -63,144 +54,17 @@ internal static Task MyInvokeAsync(
return default;
}

public static object? DeSerializeObject(JsonElement json, Type type)
{
var obj = json.Deserialize(type, Options);
return obj;
}

public static object? DeSerializeObject(string? json, Type type)
{
if (json == null)
{
return default;
}

var obj = JsonSerializer.Deserialize(json, type, Options);
return obj;
}

public static TObject? DeSerializeObject<TObject>(string? json)
{
if (json == null)
{
return default;
}

var value = JsonSerializer.Deserialize<TObject>(json, Options);
return value;
}

public static string SerializeObject(object obj)
{
var value = JsonSerializer.Serialize(obj, Options);
return value;
}

private static IEnumerable<object> MakeArgJsFriendly(IJSRuntime jsRuntime, IEnumerable<object?> args)
{
var jsFriendlyArgs = args
.Select(arg =>
{
if (arg == null)
{
return arg;
}

if (arg is IOneOf oneof)
{
arg = oneof.Value;
}

var argType = arg.GetType();

switch (arg)
{
case Enum: return GetEnumValue(arg);
case ElementReference _:
case string _:
case int _:
case long _:
case double _:
case float _:
case decimal _:
case DateTime _:
case bool _:
return arg;
case Action action:
return DotNetObjectReference.Create(new JsCallableAction(jsRuntime, action));
default:
{
if (argType.IsGenericType
&& (argType.GetGenericTypeDefinition() == typeof(Action<>)))
{
var genericArguments = argType.GetGenericArguments();

//Debug.WriteLine($"Generic args : {genericArguments.Count()}");

return DotNetObjectReference.Create(new JsCallableAction(jsRuntime, (Delegate)arg, genericArguments));
}

switch (arg)
{
case JsCallableAction _:
return DotNetObjectReference.Create(arg);
case IJsObjectRef jsObjectRef:
{
//Debug.WriteLine("Serialize IJsObjectRef");

var guid = jsObjectRef.Guid;
return SerializeObject(new JsObjectRef1(guid));
}
default:
return SerializeObject(arg);
}
}
}
});

return jsFriendlyArgs;
}

private static string? GetEnumValue(object? enumItem)
{
//what happens if enumItem is null.
//Shouldnt we take 0 value of enum
//Also is it even possible to have null enumItem
//So far looks like only MapLegend Add controll reach here
if (enumItem == null)
{
return null;
}

if (enumItem is not Enum enumItem2)
{
return enumItem.ToString();
}

var memberInfo = enumItem2.GetType().GetMember(enumItem2.ToString());
if (memberInfo.Length == 0)
{
return null;
}

foreach (var attr in memberInfo[0].GetCustomAttributes(false))
{
if (attr is EnumMemberAttribute val)
{
return val.Value;
}
}


return null;
}


internal static async Task<TRes?> MyInvokeAsync<TRes>(
this IJSRuntime jsRuntime,
string identifier,
params object?[] args)
{
var jsFriendlyArgs = MakeArgJsFriendly(jsRuntime, args);
var jsFriendlyArgs = jsRuntime.MakeArgJsFriendly(args);

if (typeof(IJsObjectRef).IsAssignableFrom(typeof(TRes)))
{
Expand All @@ -222,7 +86,7 @@ private static IEnumerable<object> MakeArgJsFriendly(IJSRuntime jsRuntime, IEnum
var typeToken = jo.RootElement.GetProperty("dotnetTypeName").GetString();
if (typeToken != null)
{
result = DeSerializeObject<TRes>(typeToken);
result = JsonExtensions.DeSerializeObject<TRes>(typeToken);
}
else
{
Expand All @@ -248,7 +112,7 @@ internal static async Task<object> MyAddListenerAsync(
string identifier,
params object[] args)
{
var jsFriendlyArgs = MakeArgJsFriendly(jsRuntime, args);
var jsFriendlyArgs = jsRuntime.MakeArgJsFriendly(args);

return await jsRuntime.InvokeAsync<object>(identifier, jsFriendlyArgs);
}
Expand Down Expand Up @@ -299,13 +163,13 @@ internal static async Task<OneOf<T, U>> MyInvokeAsync<T, U>(
json = jsonElement.GetString();
}

var propArray = Helper.DeSerializeObject<Dictionary<string, object>>(json);
var propArray = JsonExtensions.DeSerializeObject<Dictionary<string, object>>(json);
if (propArray?.TryGetValue("dotnetTypeName", out var typeName) ?? false)
{
var asm = typeof(Map).Assembly;
var typeNameString = typeName.ToString();
var type = asm.GetType(typeNameString);
result = Helper.DeSerializeObject(json, type);
result = JsonExtensions.DeSerializeObject(json, type);
}
}

Expand Down Expand Up @@ -341,13 +205,13 @@ internal static async Task<OneOf<T, U, V>> MyInvokeAsync<T, U, V>(
if (resultObject is JsonElement jsonElement)
{
var json = jsonElement.GetString();
var propArray = Helper.DeSerializeObject<Dictionary<string, object>>(json);
var propArray = JsonExtensions.DeSerializeObject<Dictionary<string, object>>(json);
if (propArray?.TryGetValue("dotnetTypeName", out var typeName) ?? false)
{
var asm = typeof(Map).Assembly;
var typeNameString = typeName.ToString();
var type = asm.GetType(typeNameString);
result = Helper.DeSerializeObject(json, type);
result = JsonExtensions.DeSerializeObject(json, type);
}
}

Expand Down
117 changes: 117 additions & 0 deletions GoogleMapsComponents/Extensions/JsArgumentExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using OneOf;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;

namespace GoogleMapsComponents.Extensions;
internal static class JsArgumentExtensions
{
private static string? GetEnumValue(object? enumItem)
{
//what happens if enumItem is null.
//Shouldnt we take 0 value of enum
//Also is it even possible to have null enumItem
//So far looks like only MapLegend Add controll reach here
if (enumItem == null)
{
return null;
}

if (enumItem is not Enum enumItem2)
{
return enumItem.ToString();
}

var memberInfo = enumItem2.GetType().GetMember(enumItem2.ToString());
if (memberInfo.Length == 0)
{
return null;
}

foreach (var attr in memberInfo[0].GetCustomAttributes(false))
{
if (attr is EnumMemberAttribute val)
{
return val.Value;
}
}

return null;
}

internal static DotNetObjectReference<JsAsyncCallableAction<T>> MakeCallbackJsFriendly<T>(this IJSRuntime jsRuntime, EventCallback<T> callback)
{
return DotNetObjectReference.Create(new JsAsyncCallableAction<T>(jsRuntime, callback));
}

internal static IEnumerable<object> MakeArgJsFriendly(this IJSRuntime jsRuntime, IEnumerable<object?> args)
{
var jsFriendlyArgs = args
.Select(arg =>
{
if (arg == null)
{
return arg;
}

if (arg is IOneOf oneof)
{
arg = oneof.Value;
}

var argType = arg.GetType();

switch (arg)
{
case Enum: return GetEnumValue(arg);
case ElementReference _:
case string _:
case int _:
case long _:
case double _:
case float _:
case decimal _:
case DateTime _:
case bool _:
return arg;
case Action action:
return DotNetObjectReference.Create(new JsCallableAction(jsRuntime, action));
case EventCallback callback:
return DotNetObjectReference.Create(new JsAsyncCallableAction(callback));
default:
{
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(Action<>))
{
var genericArguments = argType.GetGenericArguments();

//Debug.WriteLine($"Generic args : {genericArguments.Count()}");

return DotNetObjectReference.Create(new JsCallableAction(jsRuntime, (Delegate)arg, genericArguments));
}

switch (arg)
{
case JsCallableAction _:
return DotNetObjectReference.Create(arg);
case IJsObjectRef jsObjectRef:
{
//Debug.WriteLine("Serialize IJsObjectRef");

var guid = jsObjectRef.Guid;
return JsonExtensions.SerializeObject(new JsObjectRef1(guid));
}
default:
return JsonExtensions.SerializeObject(arg);
}
}
}
});

return jsFriendlyArgs;
}
}
Loading