Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/BootstrapBlazor.Server/BootstrapBlazor.Server.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
<PackageReference Include="BootstrapBlazor.Topology" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.UniverIcon" Version="9.0.1" />
<PackageReference Include="BootstrapBlazor.UniverSheet" Version="9.0.5" />
<PackageReference Include="BootstrapBlazor.Vditor" Version="9.0.0" />
<PackageReference Include="BootstrapBlazor.VideoPlayer" Version="9.0.3" />
<PackageReference Include="BootstrapBlazor.WinBox" Version="9.0.7" />
<PackageReference Include="Longbow.Logging" Version="9.0.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

<h3>@Localizer["Header"]</h3>
<h4>@Localizer["Tip"]</h4>

<PackageTips Name="BootstrapBlazor.CherryMarkdown" />

<p>@((MarkupString)Localizer["MarkdownsNote"].Value)</p>

<Pre class="no-highlight">builder.Services.Configure&lt;HubOptions&gt;(option => option.MaximumReceiveMessageSize = null);</Pre>
Expand Down
54 changes: 54 additions & 0 deletions src/BootstrapBlazor.Server/Components/Samples/Vditors.razor
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
@page "/vditor"
@inject IOptionsMonitor<WebsiteOptions> WebsiteOption

<h3>@Localizer["VditorTitle"]</h3>
Comment on lines +1 to +4
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Remove unused injected service

Since WebsiteOption is not used, removing it will eliminate unnecessary warnings and dependencies.

Suggested change
@page "/vditor"
@inject IOptionsMonitor<WebsiteOptions> WebsiteOption
<h3>@Localizer["VditorTitle"]</h3>
@page "/vditor"
<h3>@Localizer["VditorTitle"]</h3>


<h4>@Localizer["VditorSubTitle"]</h4>

<PackageTips Name="BootstrapBlazor.Vditor" />

<p>@((MarkupString)Localizer["MarkdownsNote"].Value)</p>

<Pre class="no-highlight">builder.Services.Configure&lt;HubOptions&gt;(option => option.MaximumReceiveMessageSize = null);</Pre>

<DemoBlock Title="@Localizer["BaseUsageTitle"]" Introduction="@Localizer["BaseUsageIntro"]" Name="Normal">
<section ignore class="row g-3">
<div class="col-12">
<BootstrapInputGroup>
<BootstrapInputGroupLabel DisplayText="Mode"></BootstrapInputGroupLabel>
<Segmented Value="_mode" OnValueChanged="OnModeChanged">
@foreach (var item in Enum.GetValues(typeof(VditorMode)).Cast<VditorMode>())
{
<SegmentedItem Value="@item" Text="@item.ToString()" />
}
</Segmented>
</BootstrapInputGroup>
</div>
<div class="col-12">
<Button Text="GetValue" OnClick="OnTriggerGetValueAsync" IsDisabled="_isDisabled"></Button>
<Button Text="InsertValue" OnClick="OnTriggerInsertValueAsync" IsDisabled="_isDisabled"></Button>
<Button Text="GetHtml" OnClick="OnTriggerGetHtmlAsync" IsDisabled="_isDisabled"></Button>
<Button Text="GetSelection" OnClick="OnTriggerGetSelectionAsync" IsDisabled="_isDisabled"></Button>
<Button Text="Enable" OnClick="OnTriggerEnableAsync" IsDisabled="!_isDisabled"></Button>
<Button Text="Disable" OnClick="OnTriggerDisableAsync" IsDisabled="_isDisabled"></Button>
<Button Text="Focus" OnClick="OnTriggerFocusAsync" IsDisabled="_isDisabled"></Button>
<Button Text="Blur" OnClick="OnTriggerBlurAsync" IsDisabled="_isDisabled"></Button>
</div>
</section>
<Vditor Value="@_vditorValueString" Options="_vditorOptions" @ref="_vditor"
OnRenderedAsync="OnRenderAsync"
OnFocusAsync="OnFocusAsync" OnBlurAsync="OnBlurAsync"
OnEscapeAsync="OnEscapeAsync" OnCtrlEnterAsync="OnCtrlEnterAsync"
OnSelectAsync="OnSelectAsync" OnInputAsync="OnInputAsync"></Vditor>
<section ignore class="mt-3">
<p>
<textarea class="form-control" rows="6" disabled="disabled">@_vditorValueString</textarea>
</p>
<p>
<textarea class="form-control" rows="6" disabled="disabled"> @_htmlString</textarea>
</p>
Comment on lines +47 to +49
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Remove leading space before binding

The whitespace before @_htmlString causes an extra space in the rendered textarea. Remove it or use >@(_htmlString) for correct output.

Suggested change
<p>
<textarea class="form-control" rows="6" disabled="disabled"> @_htmlString</textarea>
</p>
<p>
<textarea class="form-control" rows="6" disabled="disabled">@_htmlString</textarea>
</p>

<ConsoleLogger @ref="_logger"></ConsoleLogger>
</section>
</DemoBlock>

<AttributeTable Items="GetAttributes()" />
195 changes: 195 additions & 0 deletions src/BootstrapBlazor.Server/Components/Samples/Vditors.razor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
// 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([email protected]) Website: https://www.blazor.zone

namespace BootstrapBlazor.Server.Components.Samples;

/// <summary>
/// Vditors 组件示例代码
/// </summary>
public partial class Vditors
{
[Inject]
[NotNull]
private IStringLocalizer<Vditors>? Localizer { get; set; }

private VditorOptions _vditorOptions = new()
{
Height = "500px"
};

private Vditor _vditor = default!;
private string? _htmlString;
private string _vditorValueString = "## 所见即所得(WYSIWYG)\n所见即所得模式对不熟悉 Markdown 的用户较为友好,熟悉 Markdown 的话也可以无缝使用。";
private VditorMode _mode = VditorMode.WYSIWYG;
private ConsoleLogger _logger = default!;

private async Task OnModeChanged(VditorMode mode)
{
_mode = mode;
_vditorOptions.Mode = mode;
if (mode == VditorMode.WYSIWYG)
{
_vditorValueString = "## 所见即所得(WYSIWYG)\n所见即所得模式对不熟悉 Markdown 的用户较为友好,熟悉 Markdown 的话也可以无缝使用。";
}
else if (mode == VditorMode.IR)
{
_vditorValueString = "## 即时渲染(IR)\n即时渲染模式对熟悉 Typora 的用户应该不会感到陌生,理论上这是最优雅的 Markdown 编辑方式。";
}
else if (mode == VditorMode.SV)
{
_vditorValueString = "## 分屏预览(SV)\n传统的分屏预览模式适合大屏下的 Markdown 编辑。";
}

_htmlString = await _vditor.GetHtmlAsync();
StateHasChanged();
}

private Task OnRenderAsync()
{
_logger.Log($"Trigger OnRenderAsync");
return Task.CompletedTask;
}

private Task OnFocusAsync(string value)
{
_logger.Log($"Trigger OnFocusAsync");
return Task.CompletedTask;
}

private async Task OnBlurAsync(string value)
{
_vditorValueString = value;
_logger.Log($"Trigger OnBlurAsync");

_htmlString = await _vditor.GetHtmlAsync();
StateHasChanged();
}

private Task OnEscapeAsync(string value)
{
_logger.Log($"Trigger OnEscapeAsync");
return Task.CompletedTask;
}

private Task OnSelectAsync(string value)
{
_logger.Log($"Trigger OnSelectAsync");
return Task.CompletedTask;
}

private async Task OnInputAsync(string value)
{
_vditorValueString = value;
_htmlString = await _vditor.GetHtmlAsync();

_logger.Log($"Trigger OnInputAsync");
StateHasChanged();
}

private async Task OnCtrlEnterAsync(string value)
{
_vditorValueString = value;
_htmlString = await _vditor.GetHtmlAsync();

_logger.Log($"Trigger OnCtrlEnterAsync");
StateHasChanged();
}

private async Task OnTriggerGetValueAsync()
{
_vditorValueString = await _vditor.GetValueAsync() ?? "";
}

private async Task OnTriggerInsertValueAsync()
{
await _vditor.InsertValueAsync("光标处插入当前值");
}

private async Task OnTriggerGetHtmlAsync()
{
_htmlString = await _vditor.GetHtmlAsync();
}

private async Task OnTriggerGetSelectionAsync()
{
var selection = await _vditor.GetSelectionAsync() ?? "";
_logger.Log($"Trigger OnTriggerGetSelectionAsync: {selection}");
}

private bool _isDisabled = false;
private async Task OnTriggerEnableAsync()
{
await _vditor.EnableAsync();
_isDisabled = false;
}

private async Task OnTriggerDisableAsync()
{
await _vditor.DisableAsync();
_isDisabled = true;
}

private async Task OnTriggerFocusAsync()
{
await _vditor.FocusAsync();
}

private async Task OnTriggerBlurAsync()
{
await _vditor.BlurAsync();
}

private static AttributeItem[] GetAttributes() =>
[
new()
{
Name = "EditorSettings",
Description = "编辑器设置",
Type = "EditorSettings",
ValueList = " — ",
DefaultValue = " — "
},
new()
{
Name = "ToolbarSettings",
Description = "工具栏设置",
Type = "ToolbarSettings",
ValueList = " — ",
DefaultValue = " — "
},
new()
{
Name = "Value",
Description = "组件值",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new()
{
Name = "Html",
Description = "组件 Html 代码",
Type = "string",
ValueList = " — ",
DefaultValue = " — "
},
new()
{
Name = "OnFileUpload",
Description = "文件上传回调方法",
Type = "Func<CherryMarkdownUploadFile, Task<string>>",
ValueList = " — ",
DefaultValue = " — "
},
new()
{
Name = "IsViewer",
Description = "组件是否为浏览器模式",
Type = "bool",
ValueList = "true/false",
DefaultValue = "false"
}
];
}
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,12 @@ void AddForm(DemoMenuItem item)
{
Text = Localizer["ValidateForm"],
Url = "validate-form"
},
new()
{
IsNew = true,
Text = Localizer["Vditor"],
Url = "vditor"
}
};
AddBadge(item);
Expand Down
9 changes: 8 additions & 1 deletion src/BootstrapBlazor.Server/Locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -4948,7 +4948,8 @@
"ButtonUpload": "ButtonUpload",
"AvatarUpload": "AvatarUpload",
"CardUpload": "CardUpload",
"DropUpload": "DropUpload"
"DropUpload": "DropUpload",
"Vditor": "Vditor Markdown"
},
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
"TablesHeaderTitle": "Header grouping function",
Expand Down Expand Up @@ -7190,5 +7191,11 @@
"AudioDevicePauseText": "Pause",
"AudioDeviceResumeText": "Resume",
"AudioDeviceDownloadText": "Download"
},
"BootstrapBlazor.Server.Components.Samples.Vditors": {
"VditorTitle": "Vditor Markdown",
"VditorSubTitle": "Vditor is a browser-based Markdown editor that supports WYSIWYG, instant rendering (similar to Typora), and split-screen preview mode.",
"BaseUsageTitle": "Basic usage",
"BaseUsageIntro": "Set the content displayed by the component by setting the <code>Value</code> value, and set the component configuration information by setting the <code>Options</code> parameter"
}
}
9 changes: 8 additions & 1 deletion src/BootstrapBlazor.Server/Locales/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -4948,7 +4948,8 @@
"ButtonUpload": "按钮上传组件 ButtonUpload",
"AvatarUpload": "头像上传组件 AvatarUpload",
"CardUpload": "卡片上传组件 CardUpload",
"DropUpload": "拖动上传组件 DropUpload"
"DropUpload": "拖动上传组件 DropUpload",
"Vditor": "富文本框 Vditor Markdown"
},
"BootstrapBlazor.Server.Components.Samples.Table.TablesHeader": {
"TablesHeaderTitle": "表头分组功能",
Expand Down Expand Up @@ -7190,5 +7191,11 @@
"AudioDevicePauseText": "暂停",
"AudioDeviceResumeText": "恢复",
"AudioDeviceDownloadText": "下载"
},
"BootstrapBlazor.Server.Components.Samples.Vditors": {
"VditorTitle": "Vditor Markdown 富文本编辑框",
"VditorSubTitle": "Vditor 是一款浏览器端的 Markdown 编辑器,支持所见即所得、即时渲染(类似 Typora)和分屏预览模式",
"BaseUsageTitle": "基本用法",
"BaseUsageIntro": "通过设置 <code>Value</code> 值设置组件显示的内容,通过 <code>Options</code> 参数设置组件配置信息"
}
}
3 changes: 2 additions & 1 deletion src/BootstrapBlazor.Server/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,8 @@
"video-device": "VideoDevices",
"audio-device": "AudioDevices",
"fullscreen-button": "FullScreenButtons",
"meet": "Meets"
"meet": "Meets",
"vditor": "Vditors"
},
"video": {
"table": "BV1ap4y1x7Qn?p=1",
Expand Down
19 changes: 19 additions & 0 deletions test/UnitTest/Performance/RecordTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,25 @@ public void With_Ok()
Assert.NotEqual(foo3, foo2);
}

[Fact]
public void Height_Ok()
{
var dummy1 = new Dummy { Height = 100 };
var dummy2 = new Dummy { Height = 100 };

Assert.Equal(dummy1, dummy2);

dummy2.Width = 100;
Assert.NotEqual(dummy1, dummy2);
}

struct Dummy
{
public int Height { get; set; }

public int Width { get; set; }
}

record Foo
{
public Foo(string name) { Name = name; }
Expand Down