281 lines
7.7 KiB
Plaintext
281 lines
7.7 KiB
Plaintext
@namespace Oqtane.Modules.Controls
|
|
@inherits ModuleControlBase
|
|
@inject IStringLocalizer<RichTextEditor> Localizer
|
|
|
|
<div class="row" style="margin-bottom: 50px;">
|
|
<div class="col">
|
|
<TabStrip>
|
|
<TabPanel Name="Rich" Heading="Rich Text Editor" ResourceKey="RichTextEditor">
|
|
@if (_richfilemanager)
|
|
{
|
|
<FileManager @ref="_fileManager" Filter="@Constants.ImageFiles" />
|
|
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
|
|
<br />
|
|
}
|
|
<div class="d-flex justify-content-center mb-2">
|
|
@if (AllowRawHtml)
|
|
{
|
|
<button type="button" class="btn btn-secondary" @onclick="RefreshRichText">@Localizer["SynchronizeContent"]</button>@((MarkupString)" ")
|
|
}
|
|
@if (AllowFileManagement)
|
|
{
|
|
<button type="button" class="btn btn-primary" @onclick="InsertRichImage">@Localizer["InsertImage"]</button>
|
|
}
|
|
@if (_richfilemanager)
|
|
{
|
|
@((MarkupString)" ")
|
|
<button type="button" class="btn btn-secondary" @onclick="CloseRichFileManager">@Localizer["Close"]</button>
|
|
}
|
|
</div>
|
|
<div class="row">
|
|
<div class="col">
|
|
<div @ref="@_toolBar">
|
|
@if (ToolbarContent != null)
|
|
{
|
|
@ToolbarContent
|
|
}
|
|
else
|
|
{
|
|
<select class="ql-header">
|
|
<option selected=""></option>
|
|
<option value="1"></option>
|
|
<option value="2"></option>
|
|
<option value="3"></option>
|
|
<option value="4"></option>
|
|
<option value="5"></option>
|
|
</select>
|
|
<span class="ql-formats">
|
|
<button class="ql-bold"></button>
|
|
<button class="ql-italic"></button>
|
|
<button class="ql-underline"></button>
|
|
<button class="ql-strike"></button>
|
|
</span>
|
|
<span class="ql-formats">
|
|
<select class="ql-color"></select>
|
|
<select class="ql-background"></select>
|
|
</span>
|
|
<span class="ql-formats">
|
|
<button class="ql-list" value="ordered"></button>
|
|
<button class="ql-list" value="bullet"></button>
|
|
</span>
|
|
<span class="ql-formats">
|
|
<button class="ql-link"></button>
|
|
</span>
|
|
}
|
|
</div>
|
|
<div @ref="@_editorElement">
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</TabPanel>
|
|
@if (AllowRawHtml)
|
|
{
|
|
<TabPanel Name="Raw" Heading="Raw HTML Editor" ResourceKey="HtmlEditor">
|
|
@if (_rawfilemanager)
|
|
{
|
|
<FileManager @ref="_fileManager" Filter="@Constants.ImageFiles" />
|
|
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
|
|
<br />
|
|
}
|
|
<div class="d-flex justify-content-center mb-2">
|
|
<button type="button" class="btn btn-secondary" @onclick="RefreshRawHtml">@Localizer["SynchronizeContent"]</button>
|
|
@if (AllowFileManagement)
|
|
{
|
|
<button type="button" class="btn btn-primary" @onclick="InsertRawImage">@Localizer["InsertImage"]</button>
|
|
}
|
|
@if (_rawfilemanager)
|
|
{
|
|
@((MarkupString)" ")
|
|
<button type="button" class="btn btn-secondary" @onclick="CloseRawFileManager">@Localizer["Close"]</button>
|
|
}
|
|
</div>
|
|
@if (ReadOnly)
|
|
{
|
|
<textarea id="rawhtmleditor" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10" readonly></textarea>
|
|
}
|
|
else
|
|
{
|
|
<textarea id="rawhtmleditor" class="form-control" placeholder="@Placeholder" @bind="@_rawhtml" rows="10"></textarea>
|
|
}
|
|
</TabPanel>
|
|
}
|
|
</TabStrip>
|
|
</div>
|
|
</div>
|
|
|
|
@code {
|
|
private ElementReference _editorElement;
|
|
private ElementReference _toolBar;
|
|
private bool _richfilemanager = false;
|
|
private FileManager _fileManager;
|
|
private string _richhtml = string.Empty;
|
|
private string _originalrichhtml = string.Empty;
|
|
private bool _rawfilemanager = false;
|
|
private string _rawhtml = string.Empty;
|
|
private string _originalrawhtml = string.Empty;
|
|
private string _message = string.Empty;
|
|
|
|
[Parameter]
|
|
public string Content { get; set; }
|
|
|
|
[Parameter]
|
|
public bool ReadOnly { get; set; } = false;
|
|
|
|
[Parameter]
|
|
public string Placeholder { get; set; } = "Enter Your Content...";
|
|
|
|
[Parameter]
|
|
public bool AllowFileManagement { get; set; } = true;
|
|
|
|
[Parameter]
|
|
public bool AllowRawHtml { get; set; } = true;
|
|
|
|
// parameters only applicable to rich text editor
|
|
[Parameter]
|
|
public RenderFragment ToolbarContent { get; set; }
|
|
|
|
[Parameter]
|
|
public string Theme { get; set; } = "snow";
|
|
|
|
[Parameter]
|
|
public string DebugLevel { get; set; } = "info";
|
|
|
|
public override List<Resource> Resources => new List<Resource>()
|
|
{
|
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js" },
|
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-blot-formatter.min.js" },
|
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js" }
|
|
};
|
|
|
|
protected override void OnParametersSet()
|
|
{
|
|
_richhtml = Content;
|
|
_rawhtml = Content;
|
|
_originalrawhtml = _rawhtml; // preserve for comparison later
|
|
}
|
|
|
|
protected override async Task OnAfterRenderAsync(bool firstRender)
|
|
{
|
|
await base.OnAfterRenderAsync(firstRender);
|
|
|
|
var interop = new RichTextEditorInterop(JSRuntime);
|
|
|
|
if (firstRender)
|
|
{
|
|
await interop.CreateEditor(
|
|
_editorElement,
|
|
_toolBar,
|
|
ReadOnly,
|
|
Placeholder,
|
|
Theme,
|
|
DebugLevel);
|
|
|
|
await interop.LoadEditorContent(_editorElement, _richhtml);
|
|
|
|
// preserve a copy of the rich text content (Quill sanitizes content so we need to retrieve it from the editor)
|
|
_originalrichhtml = await interop.GetHtml(_editorElement);
|
|
}
|
|
}
|
|
|
|
public void CloseRichFileManager()
|
|
{
|
|
_richfilemanager = false;
|
|
_message = string.Empty;
|
|
StateHasChanged();
|
|
}
|
|
|
|
public void CloseRawFileManager()
|
|
{
|
|
_rawfilemanager = false;
|
|
_message = string.Empty;
|
|
StateHasChanged();
|
|
}
|
|
|
|
public void RefreshRichText()
|
|
{
|
|
_richhtml = _rawhtml;
|
|
StateHasChanged();
|
|
}
|
|
|
|
public async Task RefreshRawHtml()
|
|
{
|
|
var interop = new RichTextEditorInterop(JSRuntime);
|
|
_rawhtml = await interop.GetHtml(_editorElement);
|
|
StateHasChanged();
|
|
}
|
|
|
|
public async Task<string> GetHtml()
|
|
{
|
|
// evaluate raw html content as first priority
|
|
if (_rawhtml != _originalrawhtml)
|
|
{
|
|
return _rawhtml;
|
|
}
|
|
else
|
|
{
|
|
// return rich text content if it has changed
|
|
var interop = new RichTextEditorInterop(JSRuntime);
|
|
var richhtml = await interop.GetHtml(_editorElement);
|
|
if (richhtml != _originalrichhtml)
|
|
{
|
|
return richhtml;
|
|
}
|
|
else
|
|
{
|
|
// return original raw html content
|
|
return _originalrawhtml;
|
|
}
|
|
}
|
|
}
|
|
|
|
public async Task InsertRichImage()
|
|
{
|
|
_message = string.Empty;
|
|
if (_richfilemanager)
|
|
{
|
|
var file = _fileManager.GetFile();
|
|
if (file != null)
|
|
{
|
|
var interop = new RichTextEditorInterop(JSRuntime);
|
|
await interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name));
|
|
_richfilemanager = false;
|
|
}
|
|
else
|
|
{
|
|
_message = Localizer["Message.Require.Image"];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_richfilemanager = true;
|
|
}
|
|
StateHasChanged();
|
|
}
|
|
|
|
public async Task InsertRawImage()
|
|
{
|
|
_message = string.Empty;
|
|
if (_rawfilemanager)
|
|
{
|
|
var file = _fileManager.GetFile();
|
|
if (file != null)
|
|
{
|
|
var interop = new Interop(JSRuntime);
|
|
int pos = await interop.GetCaretPosition("rawhtmleditor");
|
|
var image = "<img src=\"" + file.Url + "\" alt=\"" + ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name) + "\" class=\"img-fluid\">";
|
|
_rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos);
|
|
_rawfilemanager = false;
|
|
}
|
|
else
|
|
{
|
|
_message = Localizer["Message.Require.Image"];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_rawfilemanager = true;
|
|
}
|
|
StateHasChanged();
|
|
}
|
|
}
|