aspnetcore/src/Components/Shared/src/WebEventData.cs

135 lines
5.5 KiB
C#

// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text.Json;
using Microsoft.AspNetCore.Components.RenderTree;
namespace Microsoft.AspNetCore.Components.Web
{
internal class WebEventData
{
// This class represents the second half of parsing incoming event data,
// once the type of the eventArgs becomes known.
public static WebEventData Parse(string eventDescriptorJson, string eventArgsJson)
{
WebEventDescriptor eventDescriptor;
try
{
eventDescriptor = Deserialize<WebEventDescriptor>(eventDescriptorJson);
}
catch (Exception e)
{
throw new InvalidOperationException("Error parsing the event descriptor", e);
}
return Parse(
eventDescriptor,
eventArgsJson);
}
public static WebEventData Parse(WebEventDescriptor eventDescriptor, string eventArgsJson)
{
return new WebEventData(
eventDescriptor.BrowserRendererId,
eventDescriptor.EventHandlerId,
InterpretEventFieldInfo(eventDescriptor.EventFieldInfo),
ParseEventArgsJson(eventDescriptor.EventHandlerId, eventDescriptor.EventArgsType, eventArgsJson));
}
private WebEventData(int browserRendererId, ulong eventHandlerId, EventFieldInfo eventFieldInfo, EventArgs eventArgs)
{
BrowserRendererId = browserRendererId;
EventHandlerId = eventHandlerId;
EventFieldInfo = eventFieldInfo;
EventArgs = eventArgs;
}
public int BrowserRendererId { get; }
public ulong EventHandlerId { get; }
public EventFieldInfo EventFieldInfo { get; }
public EventArgs EventArgs { get; }
private static EventArgs ParseEventArgsJson(ulong eventHandlerId, string eventArgsType, string eventArgsJson)
{
try
{
return eventArgsType switch
{
"change" => DeserializeChangeEventArgs(eventArgsJson),
"clipboard" => Deserialize<UIClipboardEventArgs>(eventArgsJson),
"drag" => Deserialize<UIDragEventArgs>(eventArgsJson),
"error" => Deserialize<UIErrorEventArgs>(eventArgsJson),
"focus" => Deserialize<UIFocusEventArgs>(eventArgsJson),
"keyboard" => Deserialize<UIKeyboardEventArgs>(eventArgsJson),
"mouse" => Deserialize<UIMouseEventArgs>(eventArgsJson),
"pointer" => Deserialize<UIPointerEventArgs>(eventArgsJson),
"progress" => Deserialize<UIProgressEventArgs>(eventArgsJson),
"touch" => Deserialize<UITouchEventArgs>(eventArgsJson),
"unknown" => EventArgs.Empty,
"wheel" => Deserialize<UIWheelEventArgs>(eventArgsJson),
_ => throw new InvalidOperationException($"Unsupported event type '{eventArgsType}'. EventId: '{eventHandlerId}'."),
};
}
catch (Exception e)
{
throw new InvalidOperationException($"There was an error parsing the event arguments. EventId: '{eventHandlerId}'.", e);
}
}
private static T Deserialize<T>(string json) => JsonSerializer.Deserialize<T>(json, JsonSerializerOptionsProvider.Options);
private static EventFieldInfo InterpretEventFieldInfo(EventFieldInfo fieldInfo)
{
// The incoming field value can be either a bool or a string, but since the .NET property
// type is 'object', it will deserialize initially as a JsonElement
if (fieldInfo?.FieldValue is JsonElement attributeValueJsonElement)
{
switch (attributeValueJsonElement.ValueKind)
{
case JsonValueKind.True:
case JsonValueKind.False:
return new EventFieldInfo
{
ComponentId = fieldInfo.ComponentId,
FieldValue = attributeValueJsonElement.GetBoolean()
};
default:
return new EventFieldInfo
{
ComponentId = fieldInfo.ComponentId,
FieldValue = attributeValueJsonElement.GetString()
};
}
}
return null;
}
private static ChangeEventArgs DeserializeChangeEventArgs(string eventArgsJson)
{
var changeArgs = Deserialize<ChangeEventArgs>(eventArgsJson);
var jsonElement = (JsonElement)changeArgs.Value;
switch (jsonElement.ValueKind)
{
case JsonValueKind.Null:
changeArgs.Value = null;
break;
case JsonValueKind.String:
changeArgs.Value = jsonElement.GetString();
break;
case JsonValueKind.True:
case JsonValueKind.False:
changeArgs.Value = jsonElement.GetBoolean();
break;
default:
throw new ArgumentException($"Unsupported {nameof(ChangeEventArgs)} value {jsonElement}.");
}
return changeArgs;
}
}
}