Add support for passing parameters to UI event handlers (e.g., which key was pressed)
This commit is contained in:
parent
23f7120b75
commit
04c582647a
|
|
@ -91,7 +91,16 @@ function applyAttribute(componentId: string, toDomElement: Element, attributeNod
|
||||||
|
|
||||||
switch (attributeName) {
|
switch (attributeName) {
|
||||||
case 'onclick':
|
case 'onclick':
|
||||||
toDomElement.addEventListener('click', () => raiseEvent(componentId, attributeNodeIndex, 'click'));
|
toDomElement.addEventListener('click', () => raiseEvent(componentId, attributeNodeIndex, 'mouse', { Type: 'click' }));
|
||||||
|
break;
|
||||||
|
case 'onkeypress':
|
||||||
|
toDomElement.addEventListener('keypress', evt => {
|
||||||
|
// This does not account for special keys nor cross-browser differences. So far it's
|
||||||
|
// just to establish that we can pass parameters when raising events.
|
||||||
|
// We use C#-style PascalCase on the eventInfo to simplify deserialization, but this could
|
||||||
|
// change if we introduced a richer JSON library on the .NET side.
|
||||||
|
raiseEvent(componentId, attributeNodeIndex, 'keyboard', { Type: evt.type, Key: (evt as any).key });
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
// Treat as a regular string-valued attribute
|
// Treat as a regular string-valued attribute
|
||||||
|
|
@ -103,7 +112,7 @@ function applyAttribute(componentId: string, toDomElement: Element, attributeNod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function raiseEvent(componentId: string, uiTreeNodeIndex: number, eventName: string) {
|
function raiseEvent(componentId: string, uiTreeNodeIndex: number, eventInfoType: EventInfoType, eventInfo: any) {
|
||||||
if (!raiseEventMethod) {
|
if (!raiseEventMethod) {
|
||||||
raiseEventMethod = platform.findMethod(
|
raiseEventMethod = platform.findMethod(
|
||||||
'Microsoft.Blazor.Browser', 'Microsoft.Blazor.Browser', 'Events', 'RaiseEvent'
|
'Microsoft.Blazor.Browser', 'Microsoft.Blazor.Browser', 'Events', 'RaiseEvent'
|
||||||
|
|
@ -114,7 +123,9 @@ function raiseEvent(componentId: string, uiTreeNodeIndex: number, eventName: str
|
||||||
// it first if necessary. Until then we have to send it as a string.
|
// it first if necessary. Until then we have to send it as a string.
|
||||||
platform.callMethod(raiseEventMethod, null, [
|
platform.callMethod(raiseEventMethod, null, [
|
||||||
platform.toDotNetString(componentId),
|
platform.toDotNetString(componentId),
|
||||||
platform.toDotNetString(uiTreeNodeIndex.toString())
|
platform.toDotNetString(uiTreeNodeIndex.toString()),
|
||||||
|
platform.toDotNetString(eventInfoType),
|
||||||
|
platform.toDotNetString(JSON.stringify(eventInfo))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,3 +141,5 @@ function clearElement(element: Element) {
|
||||||
element.removeChild(childNode);
|
element.removeChild(childNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type EventInfoType = 'mouse' | 'keyboard';
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ namespace Microsoft.Blazor.Browser
|
||||||
return _uITreeBuilder.GetNodes();
|
return _uITreeBuilder.GetNodes();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RaiseEvent(int uiTreeNodeIndex)
|
public void RaiseEvent(int uiTreeNodeIndex, UIEventInfo eventInfo)
|
||||||
{
|
{
|
||||||
var nodes = _uITreeBuilder.GetNodes();
|
var nodes = _uITreeBuilder.GetNodes();
|
||||||
var eventHandler = nodes.Array[nodes.Offset + uiTreeNodeIndex].AttributeEventHandlerValue;
|
var eventHandler = nodes.Array[nodes.Offset + uiTreeNodeIndex].AttributeEventHandlerValue;
|
||||||
|
|
@ -82,7 +82,7 @@ namespace Microsoft.Blazor.Browser
|
||||||
throw new ArgumentException($"Cannot raise event because the specified {nameof(UITreeNode)} at index {uiTreeNodeIndex} does not have any {nameof(UITreeNode.AttributeEventHandlerValue)}.");
|
throw new ArgumentException($"Cannot raise event because the specified {nameof(UITreeNode)} at index {uiTreeNodeIndex} does not have any {nameof(UITreeNode.AttributeEventHandlerValue)}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
eventHandler.Invoke();
|
eventHandler.Invoke(eventInfo);
|
||||||
RenderToDOM();
|
RenderToDOM();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,36 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using Microsoft.Blazor.Browser.Interop;
|
||||||
|
using Microsoft.Blazor.UITree;
|
||||||
|
using System;
|
||||||
|
|
||||||
namespace Microsoft.Blazor.Browser
|
namespace Microsoft.Blazor.Browser
|
||||||
{
|
{
|
||||||
// Invoked by the Microsoft.Blazor.Browser.JS code when a DOM event occurs
|
// Invoked by the Microsoft.Blazor.Browser.JS code when a DOM event occurs
|
||||||
internal static class Events
|
internal static class Events
|
||||||
{
|
{
|
||||||
public static void RaiseEvent(string domComponentID, string uiTreeNodeIndex)
|
public static void RaiseEvent(string domComponentID, string uiTreeNodeIndex, string eventInfoType, string eventInfoJson)
|
||||||
{
|
{
|
||||||
// We're receiving the uiTreeNodeIndex as a string only because there's not
|
// We're receiving the uiTreeNodeIndex as a string only because there's not
|
||||||
// yet a way to pass ints (or construct boxed ones) from JS with the current Mono
|
// yet a way to pass ints (or construct boxed ones) from JS with the current Mono
|
||||||
// runtime. When there's a supported way to do that, this can be simplified.
|
// runtime. When there's a supported way to do that, this can be simplified.
|
||||||
var renderState = DOMComponentRenderState.FindByDOMComponentID(domComponentID);
|
var renderState = DOMComponentRenderState.FindByDOMComponentID(domComponentID);
|
||||||
renderState.RaiseEvent(int.Parse(uiTreeNodeIndex));
|
var eventInfo = ParseEventInfo(eventInfoType, eventInfoJson);
|
||||||
|
renderState.RaiseEvent(int.Parse(uiTreeNodeIndex), eventInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static UIEventInfo ParseEventInfo(string eventInfoType, string eventInfoJson)
|
||||||
|
{
|
||||||
|
switch (eventInfoType)
|
||||||
|
{
|
||||||
|
case "mouse":
|
||||||
|
return Json.Deserialize<UIMouseEventInfo>(eventInfoJson);
|
||||||
|
case "keyboard":
|
||||||
|
return Json.Deserialize<UIKeyboardEventInfo>(eventInfoJson);
|
||||||
|
default:
|
||||||
|
throw new ArgumentException($"Unsupported value '{eventInfoType}'.", nameof(eventInfoType));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,5 +6,5 @@ namespace Microsoft.Blazor.UITree
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handles an event raised for a <see cref="UITreeNode"/>.
|
/// Handles an event raised for a <see cref="UITreeNode"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public delegate void UIEventHandler();
|
public delegate void UIEventHandler(UIEventInfo eventInfo);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,34 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
namespace Microsoft.Blazor.UITree
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Supplies information about an event that is being raised.
|
||||||
|
/// </summary>
|
||||||
|
public class UIEventInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the type of the event.
|
||||||
|
/// </summary>
|
||||||
|
public string Type { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supplies information about a mouse event that is being raised.
|
||||||
|
/// </summary>
|
||||||
|
public class UIMouseEventInfo : UIEventInfo
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supplies information about a keyboard event that is being raised.
|
||||||
|
/// </summary>
|
||||||
|
public class UIKeyboardEventInfo : UIEventInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// If applicable, gets or sets the key that produced the event.
|
||||||
|
/// </summary>
|
||||||
|
public string Key { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -60,6 +60,23 @@ namespace Microsoft.Blazor.E2ETest.Tests
|
||||||
appElement.FindElement(By.TagName("p")).Text);
|
appElement.FindElement(By.TagName("p")).Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void CanTriggerKeyPressEvents()
|
||||||
|
{
|
||||||
|
var appElement = MountTestComponent<KeyPressEventComponent>();
|
||||||
|
|
||||||
|
Assert.Empty(appElement.FindElements(By.TagName("li")));
|
||||||
|
|
||||||
|
appElement.FindElement(By.TagName("input")).SendKeys("a");
|
||||||
|
Assert.Collection(appElement.FindElements(By.TagName("li")),
|
||||||
|
li => Assert.Equal("a", li.Text));
|
||||||
|
|
||||||
|
appElement.FindElement(By.TagName("input")).SendKeys("b");
|
||||||
|
Assert.Collection(appElement.FindElements(By.TagName("li")),
|
||||||
|
li => Assert.Equal("a", li.Text),
|
||||||
|
li => Assert.Equal("b", li.Text));
|
||||||
|
}
|
||||||
|
|
||||||
private IWebElement MountTestComponent<TComponent>() where TComponent: IComponent
|
private IWebElement MountTestComponent<TComponent>() where TComponent: IComponent
|
||||||
{
|
{
|
||||||
var componentTypeName = typeof(TComponent).FullName;
|
var componentTypeName = typeof(TComponent).FullName;
|
||||||
|
|
|
||||||
|
|
@ -136,7 +136,7 @@ namespace Microsoft.Blazor.Test
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var builder = new UITreeBuilder();
|
var builder = new UITreeBuilder();
|
||||||
UIEventHandler eventHandler = () => { };
|
UIEventHandler eventHandler = eventInfo => { };
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
builder.OpenElement("myelement"); // 0: <myelement
|
builder.OpenElement("myelement"); // 0: <myelement
|
||||||
|
|
@ -180,7 +180,7 @@ namespace Microsoft.Blazor.Test
|
||||||
// Act/Assert
|
// Act/Assert
|
||||||
Assert.Throws<InvalidOperationException>(() =>
|
Assert.Throws<InvalidOperationException>(() =>
|
||||||
{
|
{
|
||||||
builder.AddAttribute("name", () => { });
|
builder.AddAttribute("name", eventInfo => { });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -210,7 +210,7 @@ namespace Microsoft.Blazor.Test
|
||||||
{
|
{
|
||||||
builder.OpenElement("some element");
|
builder.OpenElement("some element");
|
||||||
builder.AddText("hello");
|
builder.AddText("hello");
|
||||||
builder.AddAttribute("name", () => { });
|
builder.AddAttribute("name", eventInfo => { });
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ namespace BasicTestApp
|
||||||
builder.CloseElement();
|
builder.CloseElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnButtonClicked()
|
private void OnButtonClicked(UIEventInfo eventInfo)
|
||||||
{
|
{
|
||||||
currentCount++;
|
currentCount++;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
// 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 Microsoft.Blazor.Components;
|
||||||
|
using Microsoft.Blazor.UITree;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace BasicTestApp
|
||||||
|
{
|
||||||
|
public class KeyPressEventComponent : IComponent
|
||||||
|
{
|
||||||
|
private List<string> keysPressed = new List<string>();
|
||||||
|
|
||||||
|
public void BuildUITree(UITreeBuilder builder)
|
||||||
|
{
|
||||||
|
builder.AddText("Type here:");
|
||||||
|
builder.OpenElement("input");
|
||||||
|
builder.AddAttribute("onkeypress", OnKeyPressed);
|
||||||
|
builder.CloseElement();
|
||||||
|
|
||||||
|
builder.OpenElement("ul");
|
||||||
|
foreach (var key in keysPressed)
|
||||||
|
{
|
||||||
|
builder.OpenElement("li");
|
||||||
|
builder.AddText(key);
|
||||||
|
builder.CloseElement();
|
||||||
|
}
|
||||||
|
builder.CloseElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnKeyPressed(UIEventInfo eventInfo)
|
||||||
|
{
|
||||||
|
keysPressed.Add(((UIKeyboardEventInfo)eventInfo).Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue