Merge pull request #4374 from zyhfish/task/fix-issue-4358
Fix #4358: RichTextEditor Provider Abstraction.
This commit is contained in:
commit
2f3978deed
|
@ -1,6 +1,7 @@
|
||||||
@namespace Oqtane.Modules.Admin.Site
|
@namespace Oqtane.Modules.Admin.Site
|
||||||
@inherits ModuleBase
|
@inherits ModuleBase
|
||||||
@using System.Text.RegularExpressions
|
@using System.Text.RegularExpressions
|
||||||
|
@using Microsoft.Extensions.DependencyInjection
|
||||||
@inject NavigationManager NavigationManager
|
@inject NavigationManager NavigationManager
|
||||||
@inject ISiteService SiteService
|
@inject ISiteService SiteService
|
||||||
@inject ITenantService TenantService
|
@inject ITenantService TenantService
|
||||||
|
@ -8,6 +9,7 @@
|
||||||
@inject IAliasService AliasService
|
@inject IAliasService AliasService
|
||||||
@inject IThemeService ThemeService
|
@inject IThemeService ThemeService
|
||||||
@inject ISettingService SettingService
|
@inject ISettingService SettingService
|
||||||
|
@inject IServiceProvider ServiceProvider
|
||||||
@inject IStringLocalizer<Index> Localizer
|
@inject IStringLocalizer<Index> Localizer
|
||||||
@inject INotificationService NotificationService
|
@inject INotificationService NotificationService
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
@ -123,6 +125,20 @@
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="textEditorProvider" HelpText="Select the text editor provider for the site" ResourceKey="TextEditorProvider">Text Editor Provider: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="textEditorProvider" class="form-select" @bind="@_textEditorProvider" required>
|
||||||
|
@if (_textEditorProviders != null)
|
||||||
|
{
|
||||||
|
@foreach (var provider in _textEditorProviders)
|
||||||
|
{
|
||||||
|
<option value="@provider.EditorType">@provider.Name</option>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</Section>
|
||||||
<Section Name="FileExtensions" Heading="File Extensions" ResourceKey="FileExtensions">
|
<Section Name="FileExtensions" Heading="File Extensions" ResourceKey="FileExtensions">
|
||||||
|
@ -438,6 +454,8 @@
|
||||||
private string _tenant = string.Empty;
|
private string _tenant = string.Empty;
|
||||||
private string _database = string.Empty;
|
private string _database = string.Empty;
|
||||||
private string _connectionstring = string.Empty;
|
private string _connectionstring = string.Empty;
|
||||||
|
private string _textEditorProvider = "";
|
||||||
|
private IEnumerable<ITextEditorProvider> _textEditorProviders;
|
||||||
private string _createdby;
|
private string _createdby;
|
||||||
private DateTime _createdon;
|
private DateTime _createdon;
|
||||||
private string _modifiedby;
|
private string _modifiedby;
|
||||||
|
@ -479,6 +497,7 @@
|
||||||
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
_containers = ThemeService.GetContainerControls(PageState.Site.Themes, _themetype);
|
||||||
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
_containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer;
|
||||||
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
_admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer;
|
||||||
|
_textEditorProviders = ServiceProvider.GetServices<ITextEditorProvider>();
|
||||||
|
|
||||||
// page content
|
// page content
|
||||||
_headcontent = site.HeadContent;
|
_headcontent = site.HeadContent;
|
||||||
|
@ -517,6 +536,9 @@
|
||||||
// aliases
|
// aliases
|
||||||
await GetAliases();
|
await GetAliases();
|
||||||
|
|
||||||
|
//text editor
|
||||||
|
_textEditorProvider = SettingService.GetSetting(settings, "TextEditorProvider", Constants.DefaultTextEditorProvider);
|
||||||
|
|
||||||
// hosting model
|
// hosting model
|
||||||
_rendermode = site.RenderMode;
|
_rendermode = site.RenderMode;
|
||||||
_runtime = site.Runtime;
|
_runtime = site.Runtime;
|
||||||
|
@ -673,17 +695,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
site = await SiteService.UpdateSiteAsync(site);
|
site = await SiteService.UpdateSiteAsync(site);
|
||||||
|
|
||||||
// SMTP
|
// SMTP
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(site.SiteId);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true);
|
||||||
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true);
|
||||||
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true);
|
||||||
|
@ -692,141 +714,144 @@
|
||||||
settings = SettingService.SetSetting(settings, "ImageFiles", (_ImageFiles != Constants.ImageFiles) ? _ImageFiles.Replace(" ", "") : "", false);
|
settings = SettingService.SetSetting(settings, "ImageFiles", (_ImageFiles != Constants.ImageFiles) ? _ImageFiles.Replace(" ", "") : "", false);
|
||||||
settings = SettingService.SetSetting(settings, "UploadableFiles", (_UploadableFiles != Constants.UploadableFiles) ? _UploadableFiles.Replace(" ", "") : "", false);
|
settings = SettingService.SetSetting(settings, "UploadableFiles", (_UploadableFiles != Constants.UploadableFiles) ? _UploadableFiles.Replace(" ", "") : "", false);
|
||||||
|
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
//text editor
|
||||||
|
settings = SettingService.SetSetting(settings, "TextEditorProvider", _textEditorProvider);
|
||||||
|
|
||||||
await logger.LogInformation("Site Settings Saved {Site}", site);
|
await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId);
|
||||||
|
|
||||||
NavigationManager.NavigateTo(NavigateUrl(), true); // reload
|
await logger.LogInformation("Site Settings Saved {Site}", site);
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.Required.SiteName"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Saving Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.SaveSite"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task DeleteSite()
|
NavigationManager.NavigateTo(NavigateUrl(), true); // reload
|
||||||
{
|
}
|
||||||
try
|
}
|
||||||
{
|
else
|
||||||
var aliases = await AliasService.GetAliasesAsync();
|
{
|
||||||
if (aliases.Any(item => item.SiteId != PageState.Site.SiteId || item.TenantId != PageState.Site.TenantId))
|
AddModuleMessage(Localizer["Message.Required.SiteName"], MessageType.Warning);
|
||||||
{
|
}
|
||||||
await SiteService.DeleteSiteAsync(PageState.Site.SiteId);
|
}
|
||||||
await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId);
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
await logger.LogError(ex, "Error Saving Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||||
|
AddModuleMessage(Localizer["Error.SaveSite"], MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AddModuleMessage(SharedLocalizer["Message.InfoRequired"], MessageType.Warning);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
foreach (Alias alias in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId))
|
private async Task DeleteSite()
|
||||||
{
|
{
|
||||||
await AliasService.DeleteAliasAsync(alias.AliasId);
|
try
|
||||||
}
|
{
|
||||||
|
var aliases = await AliasService.GetAliasesAsync();
|
||||||
|
if (aliases.Any(item => item.SiteId != PageState.Site.SiteId || item.TenantId != PageState.Site.TenantId))
|
||||||
|
{
|
||||||
|
await SiteService.DeleteSiteAsync(PageState.Site.SiteId);
|
||||||
|
await logger.LogInformation("Site Deleted {SiteId}", PageState.Site.SiteId);
|
||||||
|
|
||||||
var redirect = aliases.First(item => item.SiteId != PageState.Site.SiteId || item.TenantId != PageState.Site.TenantId);
|
foreach (Alias alias in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId))
|
||||||
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + redirect.Name, true);
|
{
|
||||||
}
|
await AliasService.DeleteAliasAsync(alias.AliasId);
|
||||||
else
|
}
|
||||||
{
|
|
||||||
AddModuleMessage(Localizer["Message.FailAuth.DeleteSite"], MessageType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
await logger.LogError(ex, "Error Deleting Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
|
||||||
AddModuleMessage(Localizer["Error.DeleteSite"], MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task SendEmail()
|
var redirect = aliases.First(item => item.SiteId != PageState.Site.SiteId || item.TenantId != PageState.Site.TenantId);
|
||||||
{
|
NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + redirect.Name, true);
|
||||||
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")
|
}
|
||||||
{
|
else
|
||||||
try
|
{
|
||||||
{
|
AddModuleMessage(Localizer["Message.FailAuth.DeleteSite"], MessageType.Warning);
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
}
|
||||||
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
}
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
catch (Exception ex)
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
{
|
||||||
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
await logger.LogError(ex, "Error Deleting Site {SiteId} {Error}", PageState.Site.SiteId, ex.Message);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
AddModuleMessage(Localizer["Error.DeleteSite"], MessageType.Error);
|
||||||
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
}
|
||||||
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
}
|
||||||
await logger.LogInformation("Site SMTP Settings Saved");
|
|
||||||
|
|
||||||
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
private async Task SendEmail()
|
||||||
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
{
|
||||||
|
if (_smtphost != "" && _smtpport != "" && _smtpsender != "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPHost", _smtphost, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPPort", _smtpport, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPSSL", _smtpssl, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPUsername", _smtpusername, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPPassword", _smtppassword, true);
|
||||||
|
settings = SettingService.SetSetting(settings, "SMTPSender", _smtpsender, true);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
await logger.LogInformation("Site SMTP Settings Saved");
|
||||||
|
|
||||||
|
await NotificationService.AddNotificationAsync(new Notification(PageState.Site.SiteId, PageState.User, PageState.Site.Name + " SMTP Configuration Test", "SMTP Server Is Configured Correctly."));
|
||||||
|
AddModuleMessage(Localizer["Info.Smtp.SaveSettings"], MessageType.Info);
|
||||||
await ScrollToPageTop();
|
await ScrollToPageTop();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
await logger.LogError(ex, "Error Testing SMTP Configuration");
|
await logger.LogError(ex, "Error Testing SMTP Configuration");
|
||||||
AddModuleMessage(Localizer["Error.Smtp.TestConfig"], MessageType.Error);
|
AddModuleMessage(Localizer["Error.Smtp.TestConfig"], MessageType.Error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AddModuleMessage(Localizer["Message.Required.Smtp"], MessageType.Warning);
|
AddModuleMessage(Localizer["Message.Required.Smtp"], MessageType.Warning);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ToggleSMTPPassword()
|
private void ToggleSMTPPassword()
|
||||||
{
|
{
|
||||||
if (_smtppasswordtype == "password")
|
if (_smtppasswordtype == "password")
|
||||||
{
|
{
|
||||||
_smtppasswordtype = "text";
|
_smtppasswordtype = "text";
|
||||||
_togglesmtppassword = SharedLocalizer["HidePassword"];
|
_togglesmtppassword = SharedLocalizer["HidePassword"];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_smtppasswordtype = "password";
|
_smtppasswordtype = "password";
|
||||||
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
_togglesmtppassword = SharedLocalizer["ShowPassword"];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task GetAliases()
|
private async Task GetAliases()
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
_aliases = await AliasService.GetAliasesAsync();
|
_aliases = await AliasService.GetAliasesAsync();
|
||||||
_aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).OrderBy(item => item.AliasId).ToList();
|
_aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).OrderBy(item => item.AliasId).ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddAlias()
|
private void AddAlias()
|
||||||
{
|
{
|
||||||
_aliases.Add(new Alias { AliasId = 0, Name = "", IsDefault = false });
|
_aliases.Add(new Alias { AliasId = 0, Name = "", IsDefault = false });
|
||||||
_aliasid = 0;
|
_aliasid = 0;
|
||||||
_aliasname = "";
|
_aliasname = "";
|
||||||
_defaultalias = "False";
|
_defaultalias = "False";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void EditAlias(Alias alias)
|
private void EditAlias(Alias alias)
|
||||||
{
|
{
|
||||||
_aliasid = alias.AliasId;
|
_aliasid = alias.AliasId;
|
||||||
_aliasname = alias.Name;
|
_aliasname = alias.Name;
|
||||||
_defaultalias = alias.IsDefault.ToString();
|
_defaultalias = alias.IsDefault.ToString();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task DeleteAlias(Alias alias)
|
private async Task DeleteAlias(Alias alias)
|
||||||
{
|
{
|
||||||
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host))
|
||||||
{
|
{
|
||||||
await AliasService.DeleteAliasAsync(alias.AliasId);
|
await AliasService.DeleteAliasAsync(alias.AliasId);
|
||||||
await GetAliases();
|
await GetAliases();
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task SaveAlias()
|
private async Task SaveAlias()
|
||||||
{
|
{
|
||||||
|
@ -878,11 +903,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task CancelAlias()
|
private async Task CancelAlias()
|
||||||
{
|
{
|
||||||
await GetAliases();
|
await GetAliases();
|
||||||
_aliasid = -1;
|
_aliasid = -1;
|
||||||
_aliasname = "";
|
_aliasname = "";
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
@namespace Oqtane.Modules.Controls
|
@namespace Oqtane.Modules.Controls
|
||||||
@inherits ModuleControlBase
|
@inherits ModuleControlBase
|
||||||
@implements ITextEditor
|
@implements ITextEditor
|
||||||
@inject IStringLocalizer<QuillTextEditor> Localizer
|
@inject ISettingService SettingService
|
||||||
|
@inject NavigationManager NavigationManager
|
||||||
|
@inject IStringLocalizer<QuillJSTextEditor> Localizer
|
||||||
|
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
||||||
|
|
||||||
<div class="quill-text-editor">
|
<div class="quill-text-editor @(_settingsVisible ? "d-none" : "d-block")">
|
||||||
<TabStrip ActiveTab="@_activetab">
|
<TabStrip ActiveTab="@_activetab">
|
||||||
@if (AllowRichText)
|
@if (_allowRichText)
|
||||||
{
|
{
|
||||||
<TabPanel Name="Rich" Heading="Rich Text Editor" ResourceKey="RichTextEditor">
|
<TabPanel Name="Rich" Heading="Rich Text Editor" ResourceKey="RichTextEditor">
|
||||||
@if (_richfilemanager)
|
@if (_richfilemanager)
|
||||||
|
@ -15,7 +18,7 @@
|
||||||
<br />
|
<br />
|
||||||
}
|
}
|
||||||
<div class="d-flex justify-content-center mb-2">
|
<div class="d-flex justify-content-center mb-2">
|
||||||
@if (AllowFileManagement)
|
@if (_allowFileManagement)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-primary" @onclick="InsertRichImage">@Localizer["InsertImage"]</button>
|
<button type="button" class="btn btn-primary" @onclick="InsertRichImage">@Localizer["InsertImage"]</button>
|
||||||
}
|
}
|
||||||
|
@ -28,9 +31,9 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<div @ref="@_toolBar">
|
<div @ref="@_toolBar">
|
||||||
@if (ToolbarContent != null)
|
@if (!string.IsNullOrEmpty(_toolbarContent))
|
||||||
{
|
{
|
||||||
@ToolbarContent
|
@((MarkupString)_toolbarContent)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -60,13 +63,19 @@
|
||||||
<button class="ql-link"></button>
|
<button class="ql-link"></button>
|
||||||
</span>
|
</span>
|
||||||
}
|
}
|
||||||
|
@if (_hasAdminPermission)
|
||||||
|
{
|
||||||
|
<span class="ql-formats">
|
||||||
|
<button class="ql-settings" @onclick="OpenSettings"></button>
|
||||||
|
</span>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
<div @ref="@_editorElement"></div>
|
<div @ref="@_editorElement"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
}
|
}
|
||||||
@if (AllowRawHtml)
|
@if (_allowRawHtml)
|
||||||
{
|
{
|
||||||
<TabPanel Name="Raw" Heading="Raw HTML Editor" ResourceKey="HtmlEditor">
|
<TabPanel Name="Raw" Heading="Raw HTML Editor" ResourceKey="HtmlEditor">
|
||||||
@if (_rawfilemanager)
|
@if (_rawfilemanager)
|
||||||
|
@ -76,7 +85,7 @@
|
||||||
<br />
|
<br />
|
||||||
}
|
}
|
||||||
<div class="d-flex justify-content-center mb-2">
|
<div class="d-flex justify-content-center mb-2">
|
||||||
@if (AllowFileManagement)
|
@if (_allowFileManagement)
|
||||||
{
|
{
|
||||||
<button type="button" class="btn btn-primary" @onclick="InsertRawImage">@Localizer["InsertImage"]</button>
|
<button type="button" class="btn btn-primary" @onclick="InsertRawImage">@Localizer["InsertImage"]</button>
|
||||||
}
|
}
|
||||||
|
@ -85,6 +94,10 @@
|
||||||
@((MarkupString)" ")
|
@((MarkupString)" ")
|
||||||
<button type="button" class="btn btn-secondary" @onclick="CloseRawFileManager">@Localizer["Close"]</button>
|
<button type="button" class="btn btn-secondary" @onclick="CloseRawFileManager">@Localizer["Close"]</button>
|
||||||
}
|
}
|
||||||
|
else if(_hasAdminPermission)
|
||||||
|
{
|
||||||
|
<button type="button" class="btn btn-primary ms-1" @onclick="OpenSettings">@Localizer["Settings"]</button>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
@if (ReadOnly)
|
@if (ReadOnly)
|
||||||
{
|
{
|
||||||
|
@ -98,13 +111,82 @@
|
||||||
}
|
}
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="quill-text-editor-settings @(_settingsVisible ? "d-block" : "d-none")">
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="AllowFileManagement" ResourceKey="AllowFileManagement" ResourceType="@resourceType" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="checkbox" id="AllowFileManagement" class="form-check-input" @bind="_allowFileManagementSetting" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="AllowRawHtml" ResourceKey="AllowRawHtml" ResourceType="@resourceType" HelpText="Specify If Editors Can Enter Raw HTML">Allow Raw HTML: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="checkbox" id="AllowRawHtml" class="form-check-input" @bind="_allowRawHtmlSetting" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="AllowRichText" ResourceKey="AllowRichText" ResourceType="@resourceType" HelpText="Specify If Editors Can Use Rich Text Editor">Allow Rich Text: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="checkbox" id="AllowRichText" class="form-check-input" @bind="_allowRichTextSetting" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="Theme" ResourceKey="Theme" ResourceType="@resourceType" HelpText="Specify the Rich Text Editor's Theme">Theme: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<input type="text" id="Theme" class="form-control" @bind="_themeSetting" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="DebugLevel" ResourceKey="DebugLevel" ResourceType="@resourceType" HelpText="Specify the Debug Level">Debug Level: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<select id="DebugLevel" class="form-select" @bind="_debugLevelSetting">
|
||||||
|
@foreach (var level in _debugLevels)
|
||||||
|
{
|
||||||
|
<option value="@level">@level</option>
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<Label Class="col-sm-3" For="ToolbarContent" ResourceKey="ToolbarContent" ResourceType="@resourceType" HelpText="Specify the Toolbar Content">Toolbar Content: </Label>
|
||||||
|
<div class="col-sm-9">
|
||||||
|
<textarea id="ToolbarContent" class="form-control" @bind="_toolbarContentSetting" rows="5" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row mb-1 align-items-center">
|
||||||
|
<div class="col-sm-9 offset-sm-3">
|
||||||
|
<button type="button" class="btn btn-success" @onclick="@(async () => await UpdateSettings())">@SharedLocalizer["Save"]</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
|
private string resourceType = "Oqtane.Modules.Controls.QuillJSTextEditor, Oqtane.Client";
|
||||||
|
|
||||||
private bool _initialized = false;
|
private bool _initialized = false;
|
||||||
|
|
||||||
private QuillEditorInterop interop;
|
private QuillEditorInterop interop;
|
||||||
private FileManager _fileManager;
|
private FileManager _fileManager;
|
||||||
private string _activetab = "Rich";
|
private string _activetab = "Rich";
|
||||||
|
private bool _hasAdminPermission;
|
||||||
|
|
||||||
|
private bool _allowFileManagement = false;
|
||||||
|
private bool _allowRawHtml = false;
|
||||||
|
private bool _allowRichText = false;
|
||||||
|
private string _theme = "snow";
|
||||||
|
private string _debugLevel = "info";
|
||||||
|
private string _toolbarContent = string.Empty;
|
||||||
|
|
||||||
|
//adjust settings variables won't affect UI
|
||||||
|
private bool _allowFileManagementSetting = false;
|
||||||
|
private bool _allowRawHtmlSetting = false;
|
||||||
|
private bool _allowRichTextSetting = false;
|
||||||
|
private string _themeSetting = "snow";
|
||||||
|
private string _debugLevelSetting = "info";
|
||||||
|
private string _toolbarContentSetting = string.Empty;
|
||||||
|
private bool _settingsVisible;
|
||||||
|
|
||||||
|
private bool _settingsLoaded;
|
||||||
|
|
||||||
private ElementReference _editorElement;
|
private ElementReference _editorElement;
|
||||||
private ElementReference _toolBar;
|
private ElementReference _toolBar;
|
||||||
|
@ -121,14 +203,7 @@
|
||||||
private bool _contentchanged = false;
|
private bool _contentchanged = false;
|
||||||
private int _editorIndex;
|
private int _editorIndex;
|
||||||
|
|
||||||
[Parameter]
|
private List<string> _debugLevels = new List<string> { "info", "log", "warn", "error" };
|
||||||
public bool AllowFileManagement{ get; set; }
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public bool AllowRichText { get; set; } = true;
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public bool AllowRawHtml { get; set; } = true;
|
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool ReadOnly { get; set; }
|
public bool ReadOnly { get; set; }
|
||||||
|
@ -136,15 +211,6 @@
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public string Placeholder { get; set; }
|
public string Placeholder { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string Theme { get; set; } = "snow";
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string DebugLevel { get; set; } = "info";
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public RenderFragment ToolbarContent { get; set; }
|
|
||||||
|
|
||||||
public override List<Resource> Resources { get; set; } = new List<Resource>()
|
public override List<Resource> Resources { get; set; } = new List<Resource>()
|
||||||
{
|
{
|
||||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js", Location = ResourceLocation.Body },
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill.min.js", Location = ResourceLocation.Body },
|
||||||
|
@ -152,7 +218,7 @@
|
||||||
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body }
|
new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body }
|
||||||
};
|
};
|
||||||
|
|
||||||
protected override void OnInitialized()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
interop = new QuillEditorInterop(JSRuntime);
|
interop = new QuillEditorInterop(JSRuntime);
|
||||||
|
|
||||||
|
@ -160,11 +226,13 @@
|
||||||
{
|
{
|
||||||
Placeholder = Localizer["Placeholder"];
|
Placeholder = Localizer["Placeholder"];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await LoadSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
{
|
{
|
||||||
if (!AllowRichText)
|
if (!_allowRichText)
|
||||||
{
|
{
|
||||||
_activetab = "Raw";
|
_activetab = "Raw";
|
||||||
}
|
}
|
||||||
|
@ -174,7 +242,8 @@
|
||||||
{
|
{
|
||||||
await base.OnAfterRenderAsync(firstRender);
|
await base.OnAfterRenderAsync(firstRender);
|
||||||
|
|
||||||
if (AllowRichText)
|
await LoadSettings();
|
||||||
|
if (_allowRichText)
|
||||||
{
|
{
|
||||||
if (firstRender)
|
if (firstRender)
|
||||||
{
|
{
|
||||||
|
@ -183,8 +252,8 @@
|
||||||
_toolBar,
|
_toolBar,
|
||||||
ReadOnly,
|
ReadOnly,
|
||||||
Placeholder,
|
Placeholder,
|
||||||
Theme,
|
_theme,
|
||||||
DebugLevel);
|
_debugLevel);
|
||||||
|
|
||||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||||
|
|
||||||
|
@ -202,6 +271,8 @@
|
||||||
// reload editor if Content passed to component has changed
|
// reload editor if Content passed to component has changed
|
||||||
await interop.LoadEditorContent(_editorElement, _richhtml);
|
await interop.LoadEditorContent(_editorElement, _richhtml);
|
||||||
_originalrichhtml = await interop.GetHtml(_editorElement);
|
_originalrichhtml = await interop.GetHtml(_editorElement);
|
||||||
|
|
||||||
|
_contentchanged = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -215,8 +286,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_contentchanged = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,10 +293,14 @@
|
||||||
{
|
{
|
||||||
_richhtml = content;
|
_richhtml = content;
|
||||||
_rawhtml = content;
|
_rawhtml = content;
|
||||||
_originalrawhtml = _rawhtml; // preserve for comparison later
|
|
||||||
_originalrichhtml = "";
|
_originalrichhtml = "";
|
||||||
_richhtml = content;
|
_richhtml = content;
|
||||||
_contentchanged = content != _originalrawhtml;
|
if (!_contentchanged)
|
||||||
|
{
|
||||||
|
_contentchanged = content != _originalrawhtml;
|
||||||
|
}
|
||||||
|
|
||||||
|
_originalrawhtml = _rawhtml; // preserve for comparison later
|
||||||
|
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
@ -243,7 +316,7 @@
|
||||||
{
|
{
|
||||||
var richhtml = "";
|
var richhtml = "";
|
||||||
|
|
||||||
if (AllowRichText)
|
if (_allowRichText)
|
||||||
{
|
{
|
||||||
richhtml = await interop.GetHtml(_editorElement);
|
richhtml = await interop.GetHtml(_editorElement);
|
||||||
}
|
}
|
||||||
|
@ -290,7 +363,7 @@
|
||||||
{
|
{
|
||||||
var richhtml = "";
|
var richhtml = "";
|
||||||
|
|
||||||
if (AllowRichText)
|
if (_allowRichText)
|
||||||
{
|
{
|
||||||
richhtml = await interop.GetHtml(_editorElement);
|
richhtml = await interop.GetHtml(_editorElement);
|
||||||
}
|
}
|
||||||
|
@ -362,4 +435,56 @@
|
||||||
}
|
}
|
||||||
StateHasChanged();
|
StateHasChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OpenSettings()
|
||||||
|
{
|
||||||
|
_settingsVisible = true;
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task LoadSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (!_settingsLoaded)
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
_allowFileManagementSetting = _allowFileManagement = SettingService.GetSetting(settings, "QuillTextEditor_AllowFileManagement", "true") == "true";
|
||||||
|
_allowRawHtmlSetting = _allowRawHtml = SettingService.GetSetting(settings, "QuillTextEditor_AllowRawHtml", "true") == "true";
|
||||||
|
_allowRichTextSetting = _allowRichText = SettingService.GetSetting(settings, "QuillTextEditor_AllowRichText", "true") == "true";
|
||||||
|
_themeSetting = _theme = SettingService.GetSetting(settings, "QuillTextEditor_Theme", "snow");
|
||||||
|
_debugLevelSetting = _debugLevel = SettingService.GetSetting(settings, "QuillTextEditor_DebugLevel", "info");
|
||||||
|
_toolbarContentSetting = _toolbarContent = SettingService.GetSetting(settings, "QuillTextEditor_ToolbarContent", string.Empty);
|
||||||
|
|
||||||
|
_hasAdminPermission = UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin);
|
||||||
|
|
||||||
|
_settingsLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task UpdateSettings()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowFileManagement", _allowFileManagementSetting.ToString().ToLower());
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRawHtml", _allowRawHtmlSetting.ToString().ToLower());
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_AllowRichText", _allowRichTextSetting.ToString().ToLower());
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_Theme", _themeSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_DebugLevel", _debugLevelSetting);
|
||||||
|
settings = SettingService.SetSetting(settings, "QuillTextEditor_ToolbarContent", _toolbarContentSetting);
|
||||||
|
await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId);
|
||||||
|
|
||||||
|
NavigationManager.NavigateTo(NavigationManager.Uri, true);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
AddModuleMessage(ex.Message, MessageType.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -14,7 +14,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
private ITextEditorProvider _textEditorProvider;
|
private string _textEditorProvider;
|
||||||
private RenderFragment _textEditorComponent;
|
private RenderFragment _textEditorComponent;
|
||||||
private ITextEditor _textEditor;
|
private ITextEditor _textEditor;
|
||||||
|
|
||||||
|
@ -28,29 +28,14 @@
|
||||||
public string Placeholder { get; set; }
|
public string Placeholder { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter]
|
||||||
public bool AllowFileManagement { get; set; } = true;
|
public string Provider { get; set; }
|
||||||
|
|
||||||
[Parameter]
|
[Parameter(CaptureUnmatchedValues = true)]
|
||||||
public bool AllowRichText { get; set; } = true;
|
public Dictionary<string, object> AdditionalAttributes { get; set; } = new Dictionary<string, object>();
|
||||||
|
|
||||||
[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; }
|
|
||||||
|
|
||||||
[Parameter]
|
|
||||||
public string DebugLevel { get; set; }
|
|
||||||
|
|
||||||
public override List<Resource> Resources { get; set; } = new List<Resource>();
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
_textEditorProvider = await GetTextEditorProvider();
|
_textEditorProvider = await GetTextEditorType();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnParametersSet()
|
protected override void OnParametersSet()
|
||||||
|
@ -78,37 +63,32 @@
|
||||||
|
|
||||||
private void CreateTextEditor(RenderTreeBuilder builder)
|
private void CreateTextEditor(RenderTreeBuilder builder)
|
||||||
{
|
{
|
||||||
if(_textEditorProvider != null)
|
if(!string.IsNullOrEmpty(_textEditorProvider))
|
||||||
{
|
{
|
||||||
var editorType = Type.GetType(_textEditorProvider.EditorType);
|
var editorType = Type.GetType(_textEditorProvider);
|
||||||
if (editorType != null)
|
if (editorType != null)
|
||||||
{
|
{
|
||||||
builder.OpenComponent(0, editorType);
|
builder.OpenComponent(0, editorType);
|
||||||
|
|
||||||
//set editor parameters if available.
|
|
||||||
var attributes = new Dictionary<string, object>
|
var attributes = new Dictionary<string, object>
|
||||||
{
|
{
|
||||||
{ "AllowFileManagement", AllowFileManagement },
|
{ "Placeholder", Placeholder },
|
||||||
{ "AllowRichText", AllowRichText },
|
|
||||||
{ "AllowRawHtml", AllowRawHtml },
|
|
||||||
{ "ReadOnly", ReadOnly }
|
{ "ReadOnly", ReadOnly }
|
||||||
};
|
};
|
||||||
|
|
||||||
if(!string.IsNullOrEmpty(Theme))
|
if (AdditionalAttributes != null)
|
||||||
{
|
{
|
||||||
attributes.Add("Theme", Theme);
|
foreach(var key in AdditionalAttributes.Keys)
|
||||||
}
|
{
|
||||||
if (!string.IsNullOrEmpty(DebugLevel))
|
if(!attributes.ContainsKey(key))
|
||||||
{
|
{
|
||||||
attributes.Add("DebugLevel", DebugLevel);
|
attributes.Add(key, AdditionalAttributes[key]);
|
||||||
}
|
}
|
||||||
if (!string.IsNullOrEmpty(Placeholder))
|
else
|
||||||
{
|
{
|
||||||
attributes.Add("Placeholder", Placeholder);
|
attributes[key] = AdditionalAttributes[key];
|
||||||
}
|
}
|
||||||
if(ToolbarContent != null)
|
}
|
||||||
{
|
|
||||||
attributes.Add("ToolbarContent", ToolbarContent);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var index = 1;
|
var index = 1;
|
||||||
|
@ -129,26 +109,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<ITextEditorProvider> GetTextEditorProvider()
|
private async Task<string> GetTextEditorType()
|
||||||
{
|
{
|
||||||
const string DefaultEditorName = "Quill";
|
const string EditorSettingName = "TextEditorProvider";
|
||||||
|
|
||||||
var editorName = await GetTextEditorName(DefaultEditorName);
|
if(!string.IsNullOrEmpty(Provider))
|
||||||
var editorProviders = ServiceProvider.GetServices<ITextEditorProvider>();
|
|
||||||
var editorProvider = editorProviders.FirstOrDefault(i => i.Name == editorName);
|
|
||||||
if(editorProvider == null)
|
|
||||||
{
|
{
|
||||||
editorProvider = editorProviders.FirstOrDefault(i => i.Name == DefaultEditorName);
|
var provider = ServiceProvider.GetServices<ITextEditorProvider>().FirstOrDefault(i => i.Name.Equals(Provider, StringComparison.OrdinalIgnoreCase));
|
||||||
|
if(provider != null)
|
||||||
|
{
|
||||||
|
return provider.EditorType;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return editorProvider;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task<string> GetTextEditorName(string defaultName)
|
|
||||||
{
|
|
||||||
const string EditorSettingName = "TextEditor";
|
|
||||||
|
|
||||||
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId);
|
||||||
return SettingService.GetSetting(settings, EditorSettingName, defaultName);
|
return SettingService.GetSetting(settings, EditorSettingName, Constants.DefaultTextEditorProvider);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
31
Oqtane.Client/Modules/Controls/TextAreaTextEditor.razor
Normal file
31
Oqtane.Client/Modules/Controls/TextAreaTextEditor.razor
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
@namespace Oqtane.Modules.Controls
|
||||||
|
@inherits ModuleControlBase
|
||||||
|
@implements ITextEditor
|
||||||
|
|
||||||
|
<div class="text-area-editor">
|
||||||
|
<textarea @bind="_content" @ref="_editor" placeholder="@Placeholder" readonly="@ReadOnly" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
@code {
|
||||||
|
private ElementReference _editor;
|
||||||
|
private string _content;
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public bool ReadOnly { get; set; }
|
||||||
|
|
||||||
|
[Parameter]
|
||||||
|
public string Placeholder { get; set; }
|
||||||
|
|
||||||
|
public void Initialize(string content)
|
||||||
|
{
|
||||||
|
_content = content;
|
||||||
|
|
||||||
|
StateHasChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string> GetContent()
|
||||||
|
{
|
||||||
|
await Task.CompletedTask;
|
||||||
|
return _content;
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,7 +13,7 @@
|
||||||
<TabPanel Name="Edit" Heading="Edit" ResourceKey="Edit">
|
<TabPanel Name="Edit" Heading="Edit" ResourceKey="Edit">
|
||||||
@if (_content != null)
|
@if (_content != null)
|
||||||
{
|
{
|
||||||
<RichTextEditor Content="@_content" AllowFileManagement="@_allowfilemanagement" AllowRawHtml="@_allowrawhtml" @ref="@RichTextEditorHtml"></RichTextEditor>
|
<RichTextEditor Content="@_content" @ref="@RichTextEditorHtml"></RichTextEditor>
|
||||||
<br />
|
<br />
|
||||||
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
<button type="button" class="btn btn-success" @onclick="SaveContent">@SharedLocalizer["Save"]</button>
|
||||||
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
<NavLink class="btn btn-secondary" href="@NavigateUrl()">@SharedLocalizer["Cancel"]</NavLink>
|
||||||
|
@ -47,44 +47,40 @@
|
||||||
</TabStrip>
|
</TabStrip>
|
||||||
|
|
||||||
@code {
|
@code {
|
||||||
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Edit;
|
||||||
|
|
||||||
public override string Title => "Edit Html/Text";
|
public override string Title => "Edit Html/Text";
|
||||||
|
|
||||||
public override List<Resource> Resources => new List<Resource>()
|
public override List<Resource> Resources => new List<Resource>()
|
||||||
{
|
{
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" },
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.bubble.css" },
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "css/quill/quill.snow.css" }
|
||||||
};
|
};
|
||||||
|
|
||||||
private RichTextEditor RichTextEditorHtml;
|
private RichTextEditor RichTextEditorHtml;
|
||||||
private bool _allowfilemanagement;
|
private string _content = null;
|
||||||
private bool _allowrawhtml;
|
private string _createdby;
|
||||||
private string _content = null;
|
private DateTime _createdon;
|
||||||
private string _createdby;
|
private string _modifiedby;
|
||||||
private DateTime _createdon;
|
private DateTime _modifiedon;
|
||||||
private string _modifiedby;
|
private List<Models.HtmlText> _htmltexts;
|
||||||
private DateTime _modifiedon;
|
private string _view = "";
|
||||||
private List<Models.HtmlText> _htmltexts;
|
|
||||||
private string _view = "";
|
|
||||||
|
|
||||||
protected override async Task OnInitializedAsync()
|
protected override async Task OnInitializedAsync()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
_allowfilemanagement = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true"));
|
await LoadContent();
|
||||||
_allowrawhtml = bool.Parse(SettingService.GetSetting(ModuleState.Settings, "AllowRawHtml", "true"));
|
}
|
||||||
await LoadContent();
|
catch (Exception ex)
|
||||||
}
|
{
|
||||||
catch (Exception ex)
|
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
||||||
{
|
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
||||||
await logger.LogError(ex, "Error Loading Content {Error}", ex.Message);
|
}
|
||||||
AddModuleMessage(Localizer["Error.Content.Load"], MessageType.Error);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task LoadContent()
|
private async Task LoadContent()
|
||||||
{
|
{
|
||||||
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
var htmltext = await HtmlTextService.GetHtmlTextAsync(ModuleState.ModuleId);
|
||||||
if (htmltext != null)
|
if (htmltext != null)
|
||||||
{
|
{
|
||||||
|
|
|
@ -15,7 +15,7 @@ namespace Oqtane.Modules.HtmlText
|
||||||
Version = "1.0.1",
|
Version = "1.0.1",
|
||||||
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
|
ServerManagerType = "Oqtane.Modules.HtmlText.Manager.HtmlTextManager, Oqtane.Server",
|
||||||
ReleaseVersions = "1.0.0,1.0.1",
|
ReleaseVersions = "1.0.0,1.0.1",
|
||||||
SettingsType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client",
|
SettingsType = string.Empty,
|
||||||
Resources = new List<Resource>()
|
Resources = new List<Resource>()
|
||||||
{
|
{
|
||||||
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Module.css" }
|
new Resource { ResourceType = ResourceType.Stylesheet, Url = "~/Module.css" }
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
@namespace Oqtane.Modules.HtmlText
|
|
||||||
@inherits ModuleBase
|
|
||||||
@inject ISettingService SettingService
|
|
||||||
@implements Oqtane.Interfaces.ISettingsControl
|
|
||||||
@inject IStringLocalizer<Settings> Localizer
|
|
||||||
@inject IStringLocalizer<SharedResources> SharedLocalizer
|
|
||||||
|
|
||||||
<div class="container">
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="files" ResourceKey="AllowFileManagement" ResourceType="@resourceType" HelpText="Specify If Editors Can Upload and Select Files">Allow File Management: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="files" class="form-select" @bind="@_allowfilemanagement">
|
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="row mb-1 align-items-center">
|
|
||||||
<Label Class="col-sm-3" For="files" ResourceKey="AllowRawHtml" ResourceType="@resourceType" HelpText="Specify If Editors Can Enter Raw HTML">Allow Raw HTML: </Label>
|
|
||||||
<div class="col-sm-9">
|
|
||||||
<select id="files" class="form-select" @bind="@_allowrawhtml">
|
|
||||||
<option value="true">@SharedLocalizer["Yes"]</option>
|
|
||||||
<option value="false">@SharedLocalizer["No"]</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
@code {
|
|
||||||
private string resourceType = "Oqtane.Modules.HtmlText.Settings, Oqtane.Client"; // for localization
|
|
||||||
private string _allowfilemanagement;
|
|
||||||
private string _allowrawhtml;
|
|
||||||
|
|
||||||
protected override void OnInitialized()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_allowfilemanagement = SettingService.GetSetting(ModuleState.Settings, "AllowFileManagement", "true");
|
|
||||||
_allowrawhtml = SettingService.GetSetting(ModuleState.Settings, "AllowRawHtml", "true");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateSettings()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId);
|
|
||||||
settings = SettingService.SetSetting(settings, "AllowFileManagement", _allowfilemanagement);
|
|
||||||
settings = SettingService.SetSetting(settings, "AllowRawHtml", _allowrawhtml);
|
|
||||||
await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
AddModuleMessage(ex.Message, MessageType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
11
Oqtane.Client/Providers/QuillJSTextEditorProvider.cs
Normal file
11
Oqtane.Client/Providers/QuillJSTextEditorProvider.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using Oqtane.Interfaces;
|
||||||
|
|
||||||
|
namespace Oqtane.Providers
|
||||||
|
{
|
||||||
|
public class QuillJSTextEditorProvider : ITextEditorProvider
|
||||||
|
{
|
||||||
|
public string Name => "QuillJS";
|
||||||
|
|
||||||
|
public string EditorType => "Oqtane.Modules.Controls.QuillJSTextEditor, Oqtane.Client";
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +0,0 @@
|
||||||
using Oqtane.Interfaces;
|
|
||||||
|
|
||||||
namespace Oqtane.Providers
|
|
||||||
{
|
|
||||||
public class QuillTextEditorProvider : ITextEditorProvider
|
|
||||||
{
|
|
||||||
public string Name => "Quill";
|
|
||||||
|
|
||||||
public string EditorType => "Oqtane.Modules.Controls.QuillTextEditor, Oqtane.Client";
|
|
||||||
}
|
|
||||||
}
|
|
11
Oqtane.Client/Providers/TextAreaTextEditorProvider.cs
Normal file
11
Oqtane.Client/Providers/TextAreaTextEditorProvider.cs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
using Oqtane.Interfaces;
|
||||||
|
|
||||||
|
namespace Oqtane.Providers
|
||||||
|
{
|
||||||
|
public class TextAreaTextEditorProvider : ITextEditorProvider
|
||||||
|
{
|
||||||
|
public string Name => "TextArea";
|
||||||
|
|
||||||
|
public string EditorType => "Oqtane.Modules.Controls.TextAreaTextEditor, Oqtane.Client";
|
||||||
|
}
|
||||||
|
}
|
|
@ -429,4 +429,10 @@
|
||||||
<data name="Runtime.Text" xml:space="preserve">
|
<data name="Runtime.Text" xml:space="preserve">
|
||||||
<value>Interactivity:</value>
|
<value>Interactivity:</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="TextEditorProvider.HelpText" xml:space="preserve">
|
||||||
|
<value>Select the text editor provider for the site</value>
|
||||||
|
</data>
|
||||||
|
<data name="TextEditorProvider.Text" xml:space="preserve">
|
||||||
|
<value>Text Editor Provider:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -117,9 +117,33 @@
|
||||||
<resheader name="writer">
|
<resheader name="writer">
|
||||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
</resheader>
|
</resheader>
|
||||||
|
<data name="AllowFileManagement.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify If Editors Can Upload and Select Files</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowFileManagement.Text" xml:space="preserve">
|
||||||
|
<value>Allow File Management:</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowRawHtml.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify If Editors Can Enter Raw HTML</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowRawHtml.Text" xml:space="preserve">
|
||||||
|
<value>Allow Raw HTML:</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowRichText.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify If Editors Can Use Rich Text Editor</value>
|
||||||
|
</data>
|
||||||
|
<data name="AllowRichText.Text" xml:space="preserve">
|
||||||
|
<value>Allow Rich Text: </value>
|
||||||
|
</data>
|
||||||
<data name="Close" xml:space="preserve">
|
<data name="Close" xml:space="preserve">
|
||||||
<value>Close</value>
|
<value>Close</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="DebugLevel.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the Debug Level</value>
|
||||||
|
</data>
|
||||||
|
<data name="DebugLevel.Text" xml:space="preserve">
|
||||||
|
<value>Debug Level:</value>
|
||||||
|
</data>
|
||||||
<data name="InsertImage" xml:space="preserve">
|
<data name="InsertImage" xml:space="preserve">
|
||||||
<value>Insert Image</value>
|
<value>Insert Image</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -129,4 +153,19 @@
|
||||||
<data name="Placeholder" xml:space="preserve">
|
<data name="Placeholder" xml:space="preserve">
|
||||||
<value>Enter Your Content...</value>
|
<value>Enter Your Content...</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Settings" xml:space="preserve">
|
||||||
|
<value>Settings</value>
|
||||||
|
</data>
|
||||||
|
<data name="Theme.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the Rich Text Editor's Theme</value>
|
||||||
|
</data>
|
||||||
|
<data name="Theme.Text" xml:space="preserve">
|
||||||
|
<value>Theme:</value>
|
||||||
|
</data>
|
||||||
|
<data name="ToolbarContent.HelpText" xml:space="preserve">
|
||||||
|
<value>Specify the Toolbar Content</value>
|
||||||
|
</data>
|
||||||
|
<data name="ToolbarContent.Text" xml:space="preserve">
|
||||||
|
<value>Toolbar Content:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
|
@ -151,7 +151,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||||
services.AddTransient<IUserManager, UserManager>();
|
services.AddTransient<IUserManager, UserManager>();
|
||||||
|
|
||||||
// providers
|
// providers
|
||||||
services.AddTransient<ITextEditorProvider, QuillTextEditorProvider>();
|
services.AddTransient<ITextEditorProvider, QuillJSTextEditorProvider>();
|
||||||
|
services.AddTransient<ITextEditorProvider, TextAreaTextEditorProvider>();
|
||||||
|
|
||||||
// obsolete - replaced by ITenantManager
|
// obsolete - replaced by ITenantManager
|
||||||
services.AddTransient<ITenantResolver, TenantResolver>();
|
services.AddTransient<ITenantResolver, TenantResolver>();
|
||||||
|
|
|
@ -248,4 +248,10 @@ app {
|
||||||
}
|
}
|
||||||
.app-search input + button .oi{
|
.app-search input + button .oi{
|
||||||
top: 0;
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text Editor */
|
||||||
|
.text-area-editor > textarea {
|
||||||
|
width: 100%;
|
||||||
|
min-height: 250px;
|
||||||
}
|
}
|
|
@ -19,6 +19,11 @@ Oqtane.RichTextEditor = {
|
||||||
};
|
};
|
||||||
|
|
||||||
new Quill(quillElement, options);
|
new Quill(quillElement, options);
|
||||||
|
|
||||||
|
var settingsButton = document.querySelector('.ql-toolbar button.ql-settings');
|
||||||
|
if (settingsButton !== null) {
|
||||||
|
settingsButton.innerHTML = '<svg viewBox="0 0 46 46"><g><path class="ql-stroke" d="M43.454,18.443h-2.437c-0.453-1.766-1.16-3.42-2.082-4.933l1.752-1.756c0.473-0.473,0.733-1.104,0.733-1.774 c0-0.669-0.262-1.301-0.733-1.773l-2.92-2.917c-0.947-0.948-2.602-0.947-3.545-0.001l-1.826,1.815 C30.9,6.232,29.296,5.56,27.529,5.128V2.52c0-1.383-1.105-2.52-2.488-2.52h-4.128c-1.383,0-2.471,1.137-2.471,2.52v2.607 c-1.766,0.431-3.38,1.104-4.878,1.977l-1.825-1.815c-0.946-0.948-2.602-0.947-3.551-0.001L5.27,8.205 C4.802,8.672,4.535,9.318,4.535,9.978c0,0.669,0.259,1.299,0.733,1.772l1.752,1.76c-0.921,1.513-1.629,3.167-2.081,4.933H2.501 C1.117,18.443,0,19.555,0,20.935v4.125c0,1.384,1.117,2.471,2.501,2.471h2.438c0.452,1.766,1.159,3.43,2.079,4.943l-1.752,1.763 c-0.474,0.473-0.734,1.106-0.734,1.776s0.261,1.303,0.734,1.776l2.92,2.919c0.474,0.473,1.103,0.733,1.772,0.733 s1.299-0.261,1.773-0.733l1.833-1.816c1.498,0.873,3.112,1.545,4.878,1.978v2.604c0,1.383,1.088,2.498,2.471,2.498h4.128 c1.383,0,2.488-1.115,2.488-2.498v-2.605c1.767-0.432,3.371-1.104,4.869-1.977l1.817,1.812c0.474,0.475,1.104,0.735,1.775,0.735 c0.67,0,1.301-0.261,1.774-0.733l2.92-2.917c0.473-0.472,0.732-1.103,0.734-1.772c0-0.67-0.262-1.299-0.734-1.773l-1.75-1.77 c0.92-1.514,1.627-3.179,2.08-4.943h2.438c1.383,0,2.52-1.087,2.52-2.471v-4.125C45.973,19.555,44.837,18.443,43.454,18.443z M22.976,30.85c-4.378,0-7.928-3.517-7.928-7.852c0-4.338,3.55-7.85,7.928-7.85c4.379,0,7.931,3.512,7.931,7.85 C30.906,27.334,27.355,30.85,22.976,30.85z" /></g></svg>';
|
||||||
|
}
|
||||||
},
|
},
|
||||||
getQuillContent: function (editorElement) {
|
getQuillContent: function (editorElement) {
|
||||||
return JSON.stringify(editorElement.__quill.getContents());
|
return JSON.stringify(editorElement.__quill.getContents());
|
||||||
|
|
|
@ -83,6 +83,7 @@ namespace Oqtane.Shared
|
||||||
public const string SearchModuleIdPropertyName = "ModuleId";
|
public const string SearchModuleIdPropertyName = "ModuleId";
|
||||||
|
|
||||||
public static readonly string[] InternalPagePaths = { "login", "register", "reset", "404" };
|
public static readonly string[] InternalPagePaths = { "login", "register", "reset", "404" };
|
||||||
|
public const string DefaultTextEditorProvider = "Oqtane.Modules.Controls.QuillJSTextEditor, Oqtane.Client";
|
||||||
|
|
||||||
// Obsolete constants
|
// Obsolete constants
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user