!2788 feat(#I57PKH): markdown support validate

* doc: 更新示例
* refactor: 重构代码
* feat: Markdown 增加 SetValue 方法
* doc: 增加 Markdown 客户端验证示例
* style: 增加 Validate 样式
* chore: bump version 6.1.6
* feat: Markdown 组件支持 Validate
This commit is contained in:
Argo 2022-05-16 13:00:11 +00:00
parent 71c55f481d
commit 469d7afd68
9 changed files with 82 additions and 87 deletions

View File

@ -1359,6 +1359,9 @@
"BrowserButtonText2": "Insert a picture",
"BrowserButtonText3": "The cursor moves to the end",
"BrowserText": "coconut palm",
"ValidateTitle": "Validate",
"ValidateIntro": "Check data validity and prompt automatically based on custom validation rules",
"SubmitText": "Save",
"P7": "Set the <code>markdown</code> editor to browse-only mode, <code>IsViewer='true'</code>",
"Att1": "Control height",
"Att2": "The minimum height of the control",

View File

@ -1361,6 +1361,9 @@
"BrowserButtonText3": "光标移动到最后",
"BrowserText": "椰子树",
"P7": "设置<code>Markdown</code> 编辑器为纯浏览模式,<code>IsViewer='true'</code>",
"ValidateTitle": "客户端验证",
"ValidateIntro": "根据自定义验证规则进行数据有效性检查并自动提示",
"SubmitText": "提交",
"MarkdownString": "测试",
"Att1": "控件高度",
"Att2": "控件最小高度",

View File

@ -39,7 +39,7 @@
<DemoBlock Title="@Localizer["Block1Title"]" Introduction="@Localizer["Block1Intro"]" Name="Normal">
<p>@((MarkupString)Localizer["P5"].Value)</p>
<div style="width: 100%; height: 300px;">
<Markdown Language="@Language" Value="@MarkdownString" OnValueChanged="OnValueChanged" Html="@HtmlString" OnHtmlChanged="OnHtmlChanged" />
<Markdown Language="@Language" @bind-Value="@MarkdownString" @bind-Html="@HtmlString" />
</div>
<div class="mt-3">
<textarea class="form-control" rows="6" disabled="disabled">
@ -55,7 +55,7 @@
<DemoBlock Title="@Localizer["Block2Title"]" Introduction="@Localizer["Block2Intro"]" Name="Async">
<Button Text="@Localizer["ButtonText"]" IsAsync="true" OnClick="GetAsyncString" Icon="fa fa-fa" class="mb-3" />
<Markdown Value="@AsyncValue"></Markdown>
<Markdown Value="@AsyncValue" @ref="MarkdownSetValue"></Markdown>
</DemoBlock>
<DemoBlock Title="@Localizer["Block3Title"]" Introduction="@Localizer["Block3Intro"]" Name="CommonProperty">
@ -85,4 +85,17 @@
</div>
</DemoBlock>
<DemoBlock Title="@Localizer["ValidateTitle"]" Introduction="@Localizer["ValidateIntro"]" Name="Validate">
<ValidateForm Model="@Model">
<div class="row g-3 form-inline">
<div class="col-12">
<Markdown @bind-Value="Model.Name"></Markdown>
</div>
<div class="col-12">
<Button ButtonType="ButtonType.Submit" Icon="fa fa-fw fa-save" Text="@Localizer["SubmitText"]" />
</div>
</div>
</ValidateForm>
</DemoBlock>
<AttributeTable Items="GetAttributes()"></AttributeTable>

View File

@ -33,12 +33,20 @@ console.log('test');
[NotNull]
private Markdown? Markdown { get; set; }
[NotNull]
private Markdown? MarkdownSetValue { get; set; }
[NotNull]
private Foo? Model { get; set; }
/// <summary>
/// OnInitializedAsync 方法
/// </summary>
/// <returns></returns>
protected override async Task OnInitializedAsync()
{
Model = new() { Name = "Name", Education = EnumEducation.Primary, DateTime = DateTime.Now };
Language = CultureInfo.CurrentUICulture.Name;
MarkdownString = $"### {Localizer["MarkdownString"]}";
Version = await VersionManager.GetVersionAsync("bootstrapblazor.markdown");
@ -48,20 +56,7 @@ console.log('test');
{
await Task.Delay(600);
AsyncValue = $"### {DateTime.Now}";
}
private Task OnValueChanged(string value)
{
MarkdownString = value;
StateHasChanged();
return Task.CompletedTask;
}
private Task OnHtmlChanged(string value)
{
HtmlString = value;
StateHasChanged();
return Task.CompletedTask;
await MarkdownSetValue.SetValue(AsyncValue);
}
private IEnumerable<AttributeItem> GetAttributes() => new AttributeItem[]

View File

@ -3,7 +3,7 @@
<Import Project="..\..\..\bundleconfig.props" />
<PropertyGroup>
<Version>6.1.5</Version>
<Version>6.1.6</Version>
</PropertyGroup>
<PropertyGroup>

View File

@ -11,3 +11,11 @@
border-radius: unset;
white-space: pre-wrap;
}
.is-invalid > .toastui-editor-defaultUI {
border: 1px solid var(--bs-danger);
}
.is-valid > .toastui-editor-defaultUI {
border: 1px solid var(--bs-success);
}

View File

@ -1,4 +1,4 @@
@namespace BootstrapBlazor.Components
@inherits BootstrapComponentBase
@inherits ValidateBase<string>
<div @attributes="@AdditionalAttributes" @ref="MarkdownElement" />
<div @attributes="@AdditionalAttributes" id="@Id" class="@GetClassString()" @ref="MarkdownElement" />

View File

@ -54,30 +54,6 @@ public partial class Markdown : IAsyncDisposable
[Parameter]
public string? Placeholder { get; set; }
private string? _value;
/// <summary>
/// 获得/设置 组件值
/// </summary>
[Parameter]
public string? Value
{
get => _value;
set
{
if (_value != value)
{
_value = value;
IsRender = true;
}
}
}
/// <summary>
/// 获得/设置 组件值回调
/// </summary>
[Parameter]
public Func<string?, Task>? OnValueChanged { get; set; }
/// <summary>
/// 获得/设置 组件 Html 代码
/// </summary>
@ -88,7 +64,7 @@ public partial class Markdown : IAsyncDisposable
/// 获得/设置 组件 Html 代码回调
/// </summary>
[Parameter]
public Func<string?, Task>? OnHtmlChanged { get; set; }
public EventCallback<string> HtmlChanged { get; set; }
/// <summary>
/// 获取/设置 组件是否为浏览器模式
@ -108,13 +84,18 @@ public partial class Markdown : IAsyncDisposable
[Parameter]
public bool EnableHighlight { get; set; } = false;
private readonly MarkdownOption _markdownOption = new();
private bool IsRender { get; set; }
private MarkdownOption Option { get; } = new();
[NotNull]
private JSModule<Markdown>? Module { get; set; }
/// <summary>
/// 获得 组件样式
/// </summary>
protected string? GetClassString() => CssBuilder.Default()
.AddClass(CssClass).AddClass(ValidCss)
.Build();
/// <summary>
/// OnInitialized 方法
/// </summary>
@ -122,16 +103,16 @@ public partial class Markdown : IAsyncDisposable
{
base.OnInitialized();
_markdownOption.PreviewStyle = PreviewStyle.ToDescriptionString();
_markdownOption.InitialEditType = InitialEditType.ToDescriptionString();
_markdownOption.Language = Language;
_markdownOption.Placeholder = Placeholder;
_markdownOption.Height = $"{Height}px";
_markdownOption.MinHeight = $"{MinHeight}px";
_markdownOption.InitialValue = Value ?? "";
_markdownOption.Viewer = IsViewer;
_markdownOption.Theme = IsDark ? "dark" : "light";
_markdownOption.EnableHighlight = EnableHighlight;
Option.PreviewStyle = PreviewStyle.ToDescriptionString();
Option.InitialEditType = InitialEditType.ToDescriptionString();
Option.Language = Language;
Option.Placeholder = Placeholder;
Option.Height = $"{Height}px";
Option.MinHeight = $"{MinHeight}px";
Option.InitialValue = Value ?? "";
Option.Viewer = IsViewer;
Option.Theme = IsDark ? "dark" : "light";
Option.EnableHighlight = EnableHighlight;
}
/// <summary>
@ -145,14 +126,8 @@ public partial class Markdown : IAsyncDisposable
if (firstRender)
{
IsRender = false;
Module = await JSRuntime.LoadModule<Markdown>("./_content/BootstrapBlazor.Markdown/js/bootstrap.blazor.markdown.min.js", this, false);
await Module.InvokeVoidAsync("bb_markdown", MarkdownElement, _markdownOption, nameof(Update));
}
if (IsRender)
{
await Module.InvokeVoidAsync("bb_markdown", MarkdownElement, Value ?? "", "setMarkdown");
await Module.InvokeVoidAsync("bb_markdown", MarkdownElement, Option, nameof(Update));
}
}
@ -166,28 +141,35 @@ public partial class Markdown : IAsyncDisposable
{
if (vals.Length == 2)
{
var hasChanged = !EqualityComparer<string>.Default.Equals(vals[0], Value);
if (hasChanged)
{
_value = vals[0];
if (OnValueChanged != null)
{
await OnValueChanged(Value);
}
}
CurrentValueAsString = vals[0];
hasChanged = !EqualityComparer<string>.Default.Equals(vals[1], Html);
var hasChanged = !EqualityComparer<string>.Default.Equals(vals[1], Html);
if (hasChanged)
{
Html = vals[1];
if (OnHtmlChanged != null)
if (HtmlChanged.HasDelegate)
{
await OnHtmlChanged(Html);
await HtmlChanged.InvokeAsync(Html);
}
}
if (ValidateForm != null)
{
StateHasChanged();
}
}
}
/// <summary>
/// 设置 Value 方法
/// </summary>
/// <returns></returns>
public new ValueTask SetValue(string value)
{
CurrentValueAsString = value;
return Module.InvokeVoidAsync("bb_markdown", MarkdownElement, Value ?? "", "setMarkdown");
}
/// <summary>
/// 执行方法
/// </summary>
@ -200,7 +182,7 @@ public partial class Markdown : IAsyncDisposable
/// Dispose 方法
/// </summary>
/// <param name="disposing"></param>
protected virtual async ValueTask DisposeAsync(bool disposing)
protected override async ValueTask DisposeAsyncCore(bool disposing)
{
if (disposing)
{
@ -210,13 +192,4 @@ public partial class Markdown : IAsyncDisposable
}
}
}
/// <summary>
/// Dispose 方法
/// </summary>
public async ValueTask DisposeAsync()
{
await DisposeAsync(true);
GC.SuppressFinalize(this);
}
}

File diff suppressed because one or more lines are too long