Skip to content

Commit 379986b

Browse files
authored
feat(Vditor): add Vditor component (#466)
* chore: 增加组件资源 * feat: 增加 Vditor 组件 * chore: 增加 Vditor 工程 * feat: 完善组件功能 * fix: 修复插入值逻辑 * refactor: 更新获得选择值方法名称 * refactor: 更正 disabled 方法名
1 parent 71806c3 commit 379986b

16 files changed

Lines changed: 18803 additions & 0 deletions

BootstrapBlazor.Extensions.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.JitsiMeet",
190190
EndProject
191191
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.PdfViewer", "src\components\BootstrapBlazor.PdfViewer\BootstrapBlazor.PdfViewer.csproj", "{4757B038-70E4-40B0-9B73-700EE5632B07}"
192192
EndProject
193+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BootstrapBlazor.Vditor", "src\components\BootstrapBlazor.Vditor\BootstrapBlazor.Vditor.csproj", "{D417E1B9-D146-4983-81D0-79F3193B322B}"
194+
EndProject
193195
Global
194196
GlobalSection(SolutionConfigurationPlatforms) = preSolution
195197
Debug|Any CPU = Debug|Any CPU
@@ -516,6 +518,10 @@ Global
516518
{4757B038-70E4-40B0-9B73-700EE5632B07}.Debug|Any CPU.Build.0 = Debug|Any CPU
517519
{4757B038-70E4-40B0-9B73-700EE5632B07}.Release|Any CPU.ActiveCfg = Release|Any CPU
518520
{4757B038-70E4-40B0-9B73-700EE5632B07}.Release|Any CPU.Build.0 = Release|Any CPU
521+
{D417E1B9-D146-4983-81D0-79F3193B322B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
522+
{D417E1B9-D146-4983-81D0-79F3193B322B}.Debug|Any CPU.Build.0 = Debug|Any CPU
523+
{D417E1B9-D146-4983-81D0-79F3193B322B}.Release|Any CPU.ActiveCfg = Release|Any CPU
524+
{D417E1B9-D146-4983-81D0-79F3193B322B}.Release|Any CPU.Build.0 = Release|Any CPU
519525
EndGlobalSection
520526
GlobalSection(SolutionProperties) = preSolution
521527
HideSolutionNode = FALSE
@@ -605,6 +611,7 @@ Global
605611
{F3043A78-1942-4524-BDC4-7E88F56DF3D5} = {FF1089BE-C704-4374-B629-C57C08E1798F}
606612
{08458CA3-BF81-48E8-870D-9389DC037808} = {FF1089BE-C704-4374-B629-C57C08E1798F}
607613
{4757B038-70E4-40B0-9B73-700EE5632B07} = {FF1089BE-C704-4374-B629-C57C08E1798F}
614+
{D417E1B9-D146-4983-81D0-79F3193B322B} = {FF1089BE-C704-4374-B629-C57C08E1798F}
608615
EndGlobalSection
609616
GlobalSection(ExtensibilityGlobals) = postSolution
610617
SolutionGuid = {D5EB1960-6F30-4CE1-B375-EAE1F787D6FF}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<Project Sdk="Microsoft.NET.Sdk.Razor">
2+
3+
<PropertyGroup>
4+
<Version>9.0.0</Version>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<PackageTags>Bootstrap Blazor WebAssembly wasm UI Components Vditor Markdown</PackageTags>
9+
<Description>Bootstrap UI components extensions of Vditor Markdown</Description>
10+
</PropertyGroup>
11+
12+
<ItemGroup>
13+
<PackageReference Include="BootstrapBlazor" Version="$(BBVersion)" />
14+
</ItemGroup>
15+
16+
<ItemGroup>
17+
<Using Include="Microsoft.JSInterop" />
18+
</ItemGroup>
19+
20+
</Project>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
@namespace BootstrapBlazor.Components
2+
@inherits ValidateBase<string>
3+
@attribute [JSModuleAutoLoader("./_content/BootstrapBlazor.Vditor/Vditor.razor.js", JSObjectReference = true)]
4+
5+
<div @attributes="@AdditionalAttributes" class="@ClassString" id="@Id"></div>
Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
// Copyright (c) Argo Zhang (argo@163.com). All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
// Website: https://www.blazor.zone or https://argozhang.github.io/
4+
5+
using Microsoft.AspNetCore.Components;
6+
7+
namespace BootstrapBlazor.Components;
8+
9+
/// <summary>
10+
/// Vditor markdown component
11+
/// </summary>
12+
public partial class Vditor
13+
{
14+
/// <summary>
15+
/// 获得/设置 组件 <see cref="VditorOptions"/> 实例 默认 null
16+
/// </summary>
17+
[Parameter]
18+
public VditorOptions? Options { get; set; }
19+
20+
/// <summary>
21+
/// 获得/设置 组件渲染完毕回调方法 默认 null
22+
/// </summary>
23+
[Parameter]
24+
public Func<Task>? OnRenderedAsync { get; set; }
25+
26+
/// <summary>
27+
/// 获得/设置 组件输入时回调方法 高频触发 默认 null
28+
/// </summary>
29+
[Parameter]
30+
public Func<string, Task>? OnInputAsync { get; set; }
31+
32+
/// <summary>
33+
/// 获得/设置 组件获得焦点时回调方法 默认 null
34+
/// </summary>
35+
[Parameter]
36+
public Func<string, Task>? OnFocusAsync { get; set; }
37+
38+
/// <summary>
39+
/// 获得/设置 组件失去焦点时回调方法 默认 null
40+
/// </summary>
41+
[Parameter]
42+
public Func<string, Task>? OnBlurAsync { get; set; }
43+
44+
/// <summary>
45+
/// 获得/设置 组件选择内容时回调方法 默认 null
46+
/// </summary>
47+
[Parameter]
48+
public Func<string, Task>? OnSelectAsync { get; set; }
49+
50+
/// <summary>
51+
/// 获得/设置 组件按 ESC 案件时回调方法 默认 null
52+
/// </summary>
53+
[Parameter]
54+
public Func<string, Task>? OnEscapeAsync { get; set; }
55+
56+
/// <summary>
57+
/// 获得/设置 组件按 Ctrl + Enter 组合案件时回调方法 默认 null
58+
/// </summary>
59+
[Parameter]
60+
public Func<string, Task>? OnCtrlEnterAsync { get; set; }
61+
62+
private string? ClassString => CssBuilder.Default("bb-vditor")
63+
.AddClassFromAttributes(AdditionalAttributes)
64+
.Build();
65+
66+
private string? _lastValue;
67+
private IJSObjectReference? _vditor;
68+
69+
/// <summary>
70+
/// <inheritdoc/>
71+
/// </summary>
72+
/// <param name="firstRender"></param>
73+
/// <returns></returns>
74+
protected override async Task OnAfterRenderAsync(bool firstRender)
75+
{
76+
await base.OnAfterRenderAsync(firstRender);
77+
78+
if (firstRender)
79+
{
80+
_lastValue = Value;
81+
return;
82+
}
83+
84+
if (_lastValue != Value)
85+
{
86+
_lastValue = Value;
87+
if (_vditor != null)
88+
{
89+
await _vditor.InvokeVoidAsync("setValue", Value, true);
90+
}
91+
}
92+
}
93+
94+
/// <summary>
95+
/// <inheritdoc/>
96+
/// </summary>
97+
/// <returns></returns>
98+
protected override async Task InvokeInitAsync()
99+
{
100+
_vditor = await InvokeAsync<IJSObjectReference>("init", Id, Interop, new
101+
{
102+
Options,
103+
Value
104+
});
105+
}
106+
107+
/// <summary>
108+
/// 重新设置编辑器方法
109+
/// </summary>
110+
/// <param name="value"></param>
111+
/// <param name="options"></param>
112+
/// <returns></returns>
113+
public async Task Reset(string value, VditorOptions options)
114+
{
115+
if (!string.IsNullOrEmpty(value))
116+
{
117+
Value = value;
118+
}
119+
_vditor = await InvokeAsync<IJSObjectReference>("reset", Id, Value, Options);
120+
}
121+
122+
/// <summary>
123+
/// 在焦点处插入内容,并默认进行 Markdown 渲染
124+
/// </summary>
125+
/// <param name="value">要插入的 markdown 值</param>
126+
/// <param name="render">是否渲染</param>
127+
public async ValueTask InsertValueAsync(string? value, bool render = true)
128+
{
129+
if (_vditor != null)
130+
{
131+
await _vditor.InvokeVoidAsync("insertValue", value, render);
132+
}
133+
}
134+
135+
/// <summary>
136+
/// 获取编辑器的 markdown 内容
137+
/// </summary>
138+
public async ValueTask<string?> GetValueAsync()
139+
{
140+
string? ret = null;
141+
if (_vditor != null)
142+
{
143+
ret = await _vditor.InvokeAsync<string?>("getValue");
144+
}
145+
return ret;
146+
}
147+
148+
/// <summary>
149+
/// 获取 markdown 渲染后的 HTML
150+
/// </summary>
151+
public async ValueTask<string?> GetHtmlAsync()
152+
{
153+
string? ret = null;
154+
if (_vditor != null)
155+
{
156+
ret = await _vditor.InvokeAsync<string?>("getHTML");
157+
}
158+
return ret;
159+
}
160+
161+
/// <summary>
162+
/// 返回选中的字符串
163+
/// </summary>
164+
public async ValueTask<string?> GetSelectionAsync()
165+
{
166+
string? ret = null;
167+
if (_vditor != null)
168+
{
169+
ret = await _vditor.InvokeAsync<string?>("getSelection");
170+
}
171+
return ret;
172+
}
173+
174+
/// <summary>
175+
/// 解除编辑器禁用
176+
/// </summary>
177+
public async ValueTask EnableAsync()
178+
{
179+
if (_vditor != null)
180+
{
181+
await _vditor.InvokeVoidAsync("enable");
182+
}
183+
}
184+
185+
/// <summary>
186+
/// 禁用编辑器
187+
/// </summary>
188+
public async ValueTask DisableAsync()
189+
{
190+
if (_vditor != null)
191+
{
192+
await _vditor.InvokeVoidAsync("disabled");
193+
}
194+
}
195+
196+
/// <summary>
197+
/// 聚焦编辑器
198+
/// </summary>
199+
public async ValueTask FocusAsync()
200+
{
201+
if (_vditor != null)
202+
{
203+
await _vditor.InvokeVoidAsync("focus");
204+
}
205+
}
206+
207+
/// <summary>
208+
/// 让编辑器失去焦点
209+
/// </summary>
210+
public async ValueTask BlurAsync()
211+
{
212+
if (_vditor != null)
213+
{
214+
await _vditor.InvokeAsync<string?>("blur");
215+
}
216+
}
217+
218+
/// <summary>
219+
/// 客户端渲染完毕回调方法由 JavaScript 调用
220+
/// </summary>
221+
/// <returns></returns>
222+
[JSInvokable]
223+
public async Task TriggerRenderedAsync()
224+
{
225+
if (OnRenderedAsync != null)
226+
{
227+
await OnRenderedAsync();
228+
}
229+
}
230+
231+
/// <summary>
232+
/// 组件录入时回调方法由 JavaScript 调用
233+
/// </summary>
234+
/// <param name="value"></param>
235+
/// <returns></returns>
236+
[JSInvokable]
237+
public async Task TriggerInputAsync(string value)
238+
{
239+
if (OnInputAsync != null)
240+
{
241+
_lastValue = value;
242+
CurrentValue = value;
243+
await OnInputAsync(value);
244+
}
245+
}
246+
247+
/// <summary>
248+
/// 触发 Value 值改变回调方法由 JavaScript 调用
249+
/// </summary>
250+
/// <param name="value"></param>
251+
/// <returns></returns>
252+
[JSInvokable]
253+
public async Task TriggerFocusAsync(string value)
254+
{
255+
if (OnFocusAsync != null)
256+
{
257+
await OnFocusAsync(value);
258+
}
259+
}
260+
261+
/// <summary>
262+
/// 触发 Value 值改变回调方法由 JavaScript 调用
263+
/// </summary>
264+
/// <param name="value"></param>
265+
/// <returns></returns>
266+
[JSInvokable]
267+
public async Task TriggerBlurAsync(string value)
268+
{
269+
if (OnBlurAsync != null)
270+
{
271+
_lastValue = value;
272+
CurrentValue = value;
273+
await OnBlurAsync(value);
274+
}
275+
}
276+
277+
/// <summary>
278+
/// 触发 Value 值改变回调方法由 JavaScript 调用
279+
/// </summary>
280+
/// <param name="value"></param>
281+
/// <returns></returns>
282+
[JSInvokable]
283+
public async Task TriggerSelectAsync(string value)
284+
{
285+
if (OnSelectAsync != null)
286+
{
287+
await OnSelectAsync(value);
288+
}
289+
}
290+
291+
/// <summary>
292+
/// 触发 Value 值改变回调方法由 JavaScript 调用
293+
/// </summary>
294+
/// <param name="value"></param>
295+
/// <returns></returns>
296+
[JSInvokable]
297+
public async Task TriggerEscapeAsync(string value)
298+
{
299+
if (OnEscapeAsync != null)
300+
{
301+
_lastValue = value;
302+
CurrentValue = value;
303+
await OnEscapeAsync(value);
304+
}
305+
}
306+
307+
/// <summary>
308+
/// 触发 Value 值改变回调方法由 JavaScript 调用
309+
/// </summary>
310+
/// <param name="value"></param>
311+
/// <returns></returns>
312+
[JSInvokable]
313+
public async Task TriggerCtrlEnterAsync(string value)
314+
{
315+
if (OnCtrlEnterAsync != null)
316+
{
317+
_lastValue = value;
318+
CurrentValue = value;
319+
await OnCtrlEnterAsync(value);
320+
}
321+
}
322+
323+
/// <summary>
324+
/// <inheritdoc/>
325+
/// </summary>
326+
/// <param name="disposing"></param>
327+
/// <returns></returns>
328+
protected override async ValueTask DisposeAsync(bool disposing)
329+
{
330+
if (disposing)
331+
{
332+
if (_vditor != null)
333+
{
334+
await _vditor.DisposeAsync();
335+
_vditor = null;
336+
}
337+
338+
await base.DisposeAsync(disposing);
339+
}
340+
}
341+
}

0 commit comments

Comments
 (0)