-
-
Notifications
You must be signed in to change notification settings - Fork 382
Expand file tree
/
Copy pathContextMenuTrigger.cs
More file actions
161 lines (139 loc) · 5.81 KB
/
ContextMenuTrigger.cs
File metadata and controls
161 lines (139 loc) · 5.81 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the Apache 2.0 License
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang(argo@live.ca) Website: https://www.blazor.zone
using Microsoft.AspNetCore.Components.Rendering;
using Microsoft.AspNetCore.Components.Web;
namespace BootstrapBlazor.Components;
/// <summary>
/// <para lang="zh">ContextMenuTrigger 组件</para>
/// <para lang="en">A component that defines a trigger that shows a <see cref="ContextMenu"/></para>
/// </summary>
public class ContextMenuTrigger : BootstrapComponentBase
{
/// <summary>
/// <inheritdoc cref="ContextMenu.ChildContent" />
/// </summary>
[Parameter]
public RenderFragment? ChildContent { get; set; }
/// <summary>
/// <para lang="zh">获得/设置 包裹组件 TagName 默认为 div</para>
/// <para lang="en">The HTML tag name to use for the trigger. Default is <div></para>
/// </summary>
[Parameter]
public string WrapperTag { get; set; } = "div";
/// <summary>
/// <para lang="zh">获得/设置 上下文数据</para>
/// <para lang="en">Gets or sets the context data</para>
/// </summary>
[Parameter]
public object? ContextItem { get; set; }
[CascadingParameter]
[NotNull]
private ContextMenuZone? ContextMenuZone { get; set; }
/// <summary>
/// <para lang="zh">触摸事件触发菜单的超时时间(毫秒)。默认值为 <see cref="ContextMenuOptions.OnTouchDelay"/> 毫秒。必须大于 0</para>
/// <para lang="en">The timeout duration for touch events to trigger the context menu (in milliseconds). Default is <see cref="ContextMenuOptions.OnTouchDelay"/> milliseconds. Must be greater than 0</para>
/// </summary>
[Parameter]
public int? OnTouchDelay { get; set; }
/// <summary>
/// <para lang="zh">标记滚动时上下文菜单是否应不可见。默认值为 false。</para>
/// <para lang="en">Flags whether the context menu should be invisible while scrolling. Default is false.</para>
/// </summary>
[Parameter]
public bool IsInvisibleWhenTouchMove { get; set; }
[Inject, NotNull]
private IOptionsMonitor<BootstrapBlazorOptions>? Options { get; set; }
private string? ClassString => CssBuilder.Default()
.AddClassFromAttributes(AdditionalAttributes)
.Build();
/// <summary>
/// <inheritdoc/>
/// </summary>
protected override void OnParametersSet()
{
base.OnParametersSet();
OnTouchDelay ??= Options.CurrentValue.ContextMenuOptions.OnTouchDelay;
}
/// <summary>
/// <inheritdoc/>
/// </summary>
protected override void BuildRenderTree(RenderTreeBuilder builder)
{
builder.OpenElement(0, WrapperTag);
builder.AddMultipleAttributes(10, AdditionalAttributes);
builder.AddAttribute(20, "class", ClassString);
builder.AddAttribute(30, "oncontextmenu", EventCallback.Factory.Create<MouseEventArgs>(this, OnContextMenu));
builder.AddAttribute(35, "ontouchstart", EventCallback.Factory.Create<TouchEventArgs>(this, OnTouchStart));
builder.AddAttribute(36, "ontouchend", EventCallback.Factory.Create<TouchEventArgs>(this, OnTouchEnd));
if (IsInvisibleWhenTouchMove)
{
builder.AddAttribute(37, "ontouchmove", EventCallback.Factory.Create<TouchEventArgs>(this, OnTouchMove));
}
builder.AddEventPreventDefaultAttribute(40, "oncontextmenu", true);
builder.AddContent(50, ChildContent);
builder.CloseElement();
}
/// <summary>
/// <para lang="zh">点击 ContextMenu 菜单项时触发</para>
/// <para lang="en">Triggered when a context menu item is clicked</para>
/// </summary>
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicMethods, typeof(MouseEventArgs))]
public Task OnContextMenu(MouseEventArgs args) => ContextMenuZone.OnContextMenu(args, ContextItem);
/// <summary>
/// <para lang="zh">是否触摸</para>
/// <para lang="en">Indicates whether a touch event is started</para>
/// </summary>
public bool IsTouchStarted { get; private set; }
/// <summary>
/// <para lang="zh">触摸定时器工作指示</para>
/// <para lang="en">Indicates whether the touch timer is working</para>
/// </summary>
private bool IsBusy { get; set; }
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(TouchEventArgs))]
[DynamicDependency(DynamicallyAccessedMemberTypes.PublicProperties, typeof(TouchPoint))]
private async Task OnTouchStart(TouchEventArgs e)
{
if (!IsBusy)
{
IsBusy = true;
IsTouchStarted = true;
// 延时保持 TouchStart 状态
// Delay to maintain TouchStart state
if (OnTouchDelay.HasValue)
{
await Task.Delay(OnTouchDelay.Value);
}
if (IsTouchStarted)
{
var args = new MouseEventArgs()
{
ClientX = e.Touches[0].ClientX,
ClientY = e.Touches[0].ClientY,
ScreenX = e.Touches[0].ScreenX,
ScreenY = e.Touches[0].ScreenY,
};
await OnContextMenu(args);
// 延时防止重复激活菜单功能
// Delay to prevent repeated activation of menu functions
if (OnTouchDelay.HasValue)
{
await Task.Delay(OnTouchDelay.Value);
}
}
IsBusy = false;
}
}
private void OnTouchMove()
{
if (IsInvisibleWhenTouchMove)
{
IsTouchStarted = false;
}
}
private void OnTouchEnd()
{
IsTouchStarted = false;
}
}