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
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// This component is using the quilljs project as its editor: https://quilljs.com/

namespace Bit.BlazorUI;
namespace Bit.BlazorUI;

/// <summary>
/// BitMarkdownEditor is a simple editor like GitHub md editor.
/// BitRichTextEditor is a WYSIWYG text editor, utilizing the famous Quill js library (<see href="https://quilljs.com/"/>).
/// </summary>
public partial class BitRichTextEditor : BitComponentBase
{
Expand Down Expand Up @@ -33,6 +31,11 @@ public partial class BitRichTextEditor : BitComponentBase
/// </summary>
[Parameter] public bool FullToolbar { get; set; }

/// <summary>
/// Custom Quill modules to be registered at first render (<see href="https://quilljs.com/docs/guides/building-a-custom-module"/>).
/// </summary>
[Parameter] public IEnumerable<BitRichTextEditorModule>? Modules { get; set; }

/// <summary>
/// Callback for when the editor instance is created and ready to use.
/// </summary>
Expand All @@ -43,6 +46,11 @@ public partial class BitRichTextEditor : BitComponentBase
/// </summary>
[Parameter] public EventCallback OnQuillReady { get; set; }

/// <summary>
/// Callback for when the scripts of the provided Quill Modules are loaded and their api are ready to use.
/// </summary>
[Parameter] public EventCallback OnQuillModulesReady { get; set; }

/// <summary>
/// The placeholder value of the editor.
/// </summary>
Expand Down Expand Up @@ -150,22 +158,45 @@ protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);

if (firstRender)
{
await _js.BitExtrasInitScripts(["_content/Bit.BlazorUI.Extras/quilljs/quill-2.0.3.js"]);
if (firstRender is false) return;

await _js.BitExtrasInitScripts(["_content/Bit.BlazorUI.Extras/quilljs/quill-2.0.3.js"]);

await OnQuillReady.InvokeAsync();
_ = OnQuillReady.InvokeAsync();

var theme = (Theme ?? BitRichTextEditorTheme.Snow).ToString().ToLower();
await _js.BitExtrasInitStylesheets([$"_content/Bit.BlazorUI.Extras/quilljs/quill.{theme}-2.0.3.css"]);
var theme = (Theme ?? BitRichTextEditorTheme.Snow).ToString().ToLower();
await _js.BitExtrasInitStylesheets([$"_content/Bit.BlazorUI.Extras/quilljs/quill.{theme}-2.0.3.css"]);

_dotnetObj = DotNetObjectReference.Create(this);
ElementReference? toolbarRef = ToolbarTemplate is null ? null : _toolbarRef;
await _js.BitRichTextEditorSetup(_Id, _dotnetObj, _editorRef, toolbarRef, theme, Placeholder, ReadOnly, FullToolbar, Styles?.Toolbar, Classes?.Toolbar);
_readyTcs.SetResult();
List<QuillModule> quillModules = [];

await OnEditorReady.InvokeAsync(_Id);
if (Modules is not null)
{
List<string> quillModuleScripts = [];
foreach (var module in Modules)
{
quillModuleScripts.Add(module.Src);
quillModules.Add(new() { Name = module.Name, Config = module.Config });
}

try
{
await _js.BitExtrasInitScripts(quillModuleScripts);

_ = OnQuillModulesReady.InvokeAsync();
}
catch
{
// we need to ignore script load exceptions here, since we can't safely recover from such errors in this state!
// so the developers should make sure the scripts they are providing is correct and has no issue to load.
}
}

_dotnetObj = DotNetObjectReference.Create(this);
ElementReference? toolbarRef = ToolbarTemplate is null ? null : _toolbarRef;
await _js.BitRichTextEditorSetup(_Id, _dotnetObj, _editorRef, toolbarRef, theme, Placeholder, ReadOnly, FullToolbar, Styles?.Toolbar, Classes?.Toolbar, quillModules);
_readyTcs.SetResult();

await OnEditorReady.InvokeAsync(_Id);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,18 @@ namespace BitBlazorUI {
readOnly: boolean,
fullToolbar: boolean,
toolbarStyle: string,
toolbarClass: string) {
toolbarClass: string,
quillModules: QuillModule[]) {

if (!editorContainer) return;

const modules: Record<string, unknown> = {};

modules.toolbar = toolbarContainer || (fullToolbar ? RichTextEditor._toolbarFullOptions : RichTextEditor._toolbarMinOptions);
(quillModules || []).forEach(qm => modules[qm.name] = qm.config);

const quill = new Quill(editorContainer, {
modules: {
toolbar: toolbarContainer || (fullToolbar ? RichTextEditor._toolbarFullOptions : RichTextEditor._toolbarMinOptions)
},
modules,
theme,
placeholder,
readOnly
Expand Down Expand Up @@ -123,4 +127,9 @@ namespace BitBlazorUI {
quill: Quill;
dotnetObj: DotNetObject;
}

interface QuillModule {
name: string;
config: unknown;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ public static ValueTask BitRichTextEditorSetup(this IJSRuntime jsRuntime,
bool readOnly,
bool fullToolbar,
string? toolbarStyle,
string? toolbarClass)
string? toolbarClass,
IEnumerable<QuillModule>? quillModules)
{
return jsRuntime.InvokeVoid("BitBlazorUI.RichTextEditor.setup",
id, dotnetObj, editorContainer, toolbarContainer, theme, placeholder, readOnly, fullToolbar, toolbarStyle, toolbarClass);
id, dotnetObj, editorContainer, toolbarContainer, theme, placeholder, readOnly, fullToolbar, toolbarStyle, toolbarClass, quillModules);
}

public static ValueTask<string> BitRichTextEditorGetText(this IJSRuntime jsRuntime, string id)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
namespace Bit.BlazorUI;

/// <summary>
/// Represents a Quill custom module specifications.
/// </summary>
public class BitRichTextEditorModule
{
/// <summary>
/// The name of the Quill custom module.
/// </summary>
public required string Name { get; set; }

/// <summary>
/// The script src of the Quill custom module to load at first render.
/// </summary>
public required string Src { get; set; }

/// <summary>
/// The configuration object that applies the settings of the Quill custom module.
/// </summary>
public required object Config { get; set; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Bit.BlazorUI;

internal class QuillModule
{
public required string Name { get; set; }
public required object Config { get; set; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,15 @@
</EditorTemplate>
</BitRichTextEditor>
</DemoExample>

<DemoExample Title="Quill custom modules" RazorCode="@example11RazorCode" CsharpCode="@example11CsharpCode" Id="example11">
<div>Using Quill custom modules are as easy as providing a new configuration that provides the name, config, and script src of the module.</div><br />
<div>
The following sample shows how to use the "imageResize" custom module
(<a href="https://github.com/bitignite/quill-image-resize-module">https://github.com/bitignite/quill-image-resize-module</a>).
</div><br />
<BitRichTextEditor FullToolbar Modules="@modules" />
</DemoExample>
</Examples>
</DemoPage>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,22 @@ public partial class BitRichTextEditorDemo
Description = "Custom template for the editor content."
},
new()
{
Name = "FullToolbar",
Type = "bool",
DefaultValue = "false",
Description = "Renders the full toolbar with all of the available features."
},
new()
{
Name = "Modules",
Type = "IEnumerable<BitRichTextEditorModule>?",
DefaultValue = "null",
Description = "Custom Quill modules to be registered at first render (<see href=\"https://quilljs.com/docs/guides/building-a-custom-module\"/>).",
LinkType = LinkType.Link,
Href = "#rich-text-editor-module"
},
new()
{
Name = "OnEditorReady",
Type = "EventCallback<string>",
Expand All @@ -35,6 +51,13 @@ public partial class BitRichTextEditorDemo
Description = "Callback for when the Quill scripts is loaded and the Quill api is ready to use. It allows for custom actions to be performed at that moment."
},
new()
{
Name = "OnQuillModulesReady",
Type = "EventCallback",
DefaultValue = "",
Description = "Callback for when the scripts of the provided Quill Modules are loaded and their api are ready to use."
},
new()
{
Name = "Placeholder",
Type = "string?",
Expand Down Expand Up @@ -70,8 +93,8 @@ public partial class BitRichTextEditorDemo
Type = "BitRichTextEditorTheme?",
DefaultValue = "null",
Description = "The theme of the editor.",
Href = "#rich-text-editor-theme",
LinkType = LinkType.Link,
Href = "#rich-text-editor-theme",
},
new()
{
Expand Down Expand Up @@ -152,6 +175,36 @@ public partial class BitRichTextEditorDemo
Description = "Custom CSS classes/styles for the editor container of the BitRichTextEditor.",
},
]
},
new()
{
Id = "rich-text-editor-module",
Title = "BitRichTextEditorModule",
Description = "Represents a Quill custom module specifications.",
Parameters =
[
new()
{
Name = "Name",
Type = "string",
DefaultValue = "",
Description = "The name of the Quill custom module.",
},
new()
{
Name = "Src",
Type = "string",
DefaultValue = "",
Description = "The script src of the Quill custom module to load at firt render.",
},
new()
{
Name = "Config",
Type = "object",
DefaultValue = "",
Description = "The configuration object that applies the settings of the Quill custom module.",
},
]
}
];

Expand All @@ -171,6 +224,7 @@ public partial class BitRichTextEditorDemo
];



private BitRichTextEditor getEditorRef = default!;
private string? result;
private async Task GetText()
Expand Down Expand Up @@ -206,6 +260,15 @@ private async Task HandleOnQuillReady()
await JSRuntime.InvokeVoidAsync("registerQuillCustomFonts");
}

private List<BitRichTextEditorModule> modules = [
new()
{
Name = "imageResize",
Src = "_content/Bit.BlazorUI.Demo.Client.Core/scripts/quill-image-resize-module.js",
Config = new { displaySize = true }
}
];



private readonly string example1RazorCode = @"
Expand Down Expand Up @@ -392,4 +455,16 @@ private async Task HandleOnQuillReady()
{
await JSRuntime.InvokeVoidAsync(""registerQuillCustomFonts"");
}";

private readonly string example11RazorCode = @"
<BitRichTextEditor FullToolbar Modules=""@modules"" />";
private readonly string example11CsharpCode = @"
private List<BitRichTextEditorModule> modules = [
new()
{
Name = ""imageResize"",
Src = ""/scripts/quill-image-resize-module.js"",
Config = new { displaySize = true }
}
];";
}

Large diffs are not rendered by default.

Loading