diff --git a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs index 7dcb2575..8facf91f 100644 --- a/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs +++ b/Oqtane.Client/Extensions/OqtaneServiceCollectionExtensions.cs @@ -1,4 +1,5 @@ using Microsoft.AspNetCore.Components.Authorization; +using Oqtane.Interfaces; using Oqtane.Providers; using Oqtane.Services; using Oqtane.Shared; @@ -51,6 +52,10 @@ namespace Microsoft.Extensions.DependencyInjection services.AddScoped(); services.AddScoped(); + // providers + services.AddScoped(); + services.AddScoped(); + return services; } } diff --git a/Oqtane.Client/Modules/Admin/Files/ModuleInfo.cs b/Oqtane.Client/Modules/Admin/Files/ModuleInfo.cs new file mode 100644 index 00000000..880d6d14 --- /dev/null +++ b/Oqtane.Client/Modules/Admin/Files/ModuleInfo.cs @@ -0,0 +1,19 @@ +using Oqtane.Documentation; +using Oqtane.Models; +using Oqtane.Shared; + +namespace Oqtane.Modules.Admin.Files +{ + [PrivateApi("Mark this as private, since it's not very useful in the public docs")] + public class ModuleInfo : IModule + { + public ModuleDefinition ModuleDefinition => new ModuleDefinition + { + Name = "File Management", + Description = "File Management", + Version = Constants.Version, + Categories = "Admin", + ServerManagerType = "Oqtane.Modules.Admin.Files.Manager.FileManager, Oqtane.Server" + }; + } +} diff --git a/Oqtane.Client/Modules/Admin/Jobs/Index.razor b/Oqtane.Client/Modules/Admin/Jobs/Index.razor index ce5f2b55..81c36430 100644 --- a/Oqtane.Client/Modules/Admin/Jobs/Index.razor +++ b/Oqtane.Client/Modules/Admin/Jobs/Index.razor @@ -10,9 +10,7 @@ } else { - - -
+
@@ -44,21 +42,29 @@ else + +
+ } @code { private List _jobs; - public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } } - + public override SecurityAccessLevel SecurityAccessLevel { get { return SecurityAccessLevel.Host; } } + protected override async Task OnInitializedAsync() { - _jobs = await JobService.GetJobsAsync(); + await GetJobs(); if (_jobs.Count == 0) { AddModuleMessage(string.Format(Localizer["Message.NoJobs"], NavigateUrl("admin/system")), MessageType.Warning); } - } + } + + private async Task GetJobs() + { + _jobs = await JobService.GetJobsAsync(); + } private string DisplayStatus(bool isEnabled, bool isExecuting) { @@ -146,7 +152,7 @@ else private async Task Refresh() { - _jobs = await JobService.GetJobsAsync(); + await GetJobs(); StateHasChanged(); } } diff --git a/Oqtane.Client/Modules/Admin/Jobs/Log.razor b/Oqtane.Client/Modules/Admin/Jobs/Log.razor index 23b605c2..e82ea9ae 100644 --- a/Oqtane.Client/Modules/Admin/Jobs/Log.razor +++ b/Oqtane.Client/Modules/Admin/Jobs/Log.razor @@ -10,6 +10,9 @@ } else { + +

+
@SharedLocalizer["Name"] @@ -35,6 +38,11 @@ else public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Host; protected override async Task OnParametersSetAsync() + { + await GetJobLogs(); + } + + private async Task GetJobLogs() { _jobLogs = await JobLogService.GetJobLogsAsync(); @@ -67,4 +75,10 @@ else return status; } + + private async Task Refresh() + { + await GetJobLogs(); + StateHasChanged(); + } } diff --git a/Oqtane.Client/Modules/Admin/Login/Index.razor b/Oqtane.Client/Modules/Admin/Login/Index.razor index 8ce6ea86..9b4f059b 100644 --- a/Oqtane.Client/Modules/Admin/Login/Index.razor +++ b/Oqtane.Client/Modules/Admin/Login/Index.razor @@ -93,6 +93,7 @@ private string _code = string.Empty; public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Anonymous; + public override bool? Prerender => true; public override List Resources => new List() { diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor index 9aa03a1f..f94f8997 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Add.razor @@ -125,7 +125,7 @@
- +
diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor index 0081e3e8..ffa2f1e3 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Edit.razor @@ -10,6 +10,7 @@ @inject IStringLocalizer SharedLocalizer @inject IPageModuleService PageModuleService @inject IModuleService ModuleService +@inject IPageService PageService @if (_initialized) { @@ -307,13 +308,15 @@ } // get distinct pages where module exists - var distinctPageIds = PageState.Modules + var modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId); + var distinctPageIds = modules .Where(md => md.ModuleDefinition?.ModuleDefinitionId == _moduleDefinitionId && md.IsDeleted == false) .Select(md => md.PageId) .Distinct(); - // Filter and retrieve the corresponding pages - _pagesWithModules = PageState.Pages + // retrieve the pages which contain the module + var pages = await PageService.GetPagesAsync(PageState.Site.SiteId); + _pagesWithModules = pages .Where(pg => distinctPageIds.Contains(pg.PageId) && pg.IsDeleted == false) .ToList(); diff --git a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor index 485f027f..89b10381 100644 --- a/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor +++ b/Oqtane.Client/Modules/Admin/ModuleDefinitions/Index.razor @@ -1,6 +1,7 @@ @namespace Oqtane.Modules.Admin.ModuleDefinitions @inherits ModuleBase @inject NavigationManager NavigationManager +@inject IModuleService ModuleService @inject IModuleDefinitionService ModuleDefinitionService @inject IPackageService PackageService @inject IStringLocalizer Localizer @@ -70,7 +71,7 @@ else } - @if (context.AssemblyName == Constants.ClientId || PageState.Modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null) + @if (context.AssemblyName == Constants.ClientId || _modules.Where(m => m.ModuleDefinition?.ModuleDefinitionId == context.ModuleDefinitionId).FirstOrDefault() != null) { @SharedLocalizer["Yes"] } @@ -99,6 +100,7 @@ else } @code { + private List _modules; private List _allModuleDefinitions; private List _moduleDefinitions; private List _packages; @@ -111,6 +113,7 @@ else { try { + _modules = await ModuleService.GetModulesAsync(PageState.Site.SiteId); _allModuleDefinitions = await ModuleDefinitionService.GetModuleDefinitionsAsync(PageState.Site.SiteId); _categories = _allModuleDefinitions.SelectMany(m => m.Categories.Split(',')).Distinct().ToList(); await LoadModuleDefinitions(); diff --git a/Oqtane.Client/Modules/Admin/Modules/Settings.razor b/Oqtane.Client/Modules/Admin/Modules/Settings.razor index 277f223b..ffe021d9 100644 --- a/Oqtane.Client/Modules/Admin/Modules/Settings.razor +++ b/Oqtane.Client/Modules/Admin/Modules/Settings.razor @@ -3,6 +3,7 @@ @inherits ModuleBase @inject NavigationManager NavigationManager @inject IThemeService ThemeService +@inject IPageService PageService @inject IModuleService ModuleService @inject IPageModuleService PageModuleService @inject IStringLocalizer Localizer @@ -79,14 +80,16 @@ } else { - foreach (Page p in PageState.Pages) + if (_pages != null) { - if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList)) + foreach (Page p in _pages) { - + if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.Edit, p.PermissionList)) + { + + } } } - }
@@ -154,10 +157,12 @@ private DateTime modifiedon; private DateTime? _effectivedate = null; private DateTime? _expirydate = null; + private List _pages; - protected override void OnInitialized() + protected override async Task OnInitializedAsync() { SetModuleTitle(Localizer["ModuleSettings.Title"]); + _module = ModuleState.ModuleDefinition.Name; _title = ModuleState.Title; _moduleSettingsTitle = Localizer["ModuleSettings.Heading"]; @@ -173,8 +178,8 @@ modifiedon = ModuleState.ModifiedOn; _effectivedate = Utilities.UtcAsLocalDate(ModuleState.EffectiveDate); _expirydate = Utilities.UtcAsLocalDate(ModuleState.ExpiryDate); - - + _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); + if (ModuleState.ModuleDefinition != null) { _permissionNames = ModuleState.ModuleDefinition?.PermissionNames; diff --git a/Oqtane.Client/Modules/Admin/Pages/Add.razor b/Oqtane.Client/Modules/Admin/Pages/Add.razor index b4bc912e..cc78ffab 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Add.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Add.razor @@ -26,7 +26,7 @@
- @foreach (Page page in PageState.Pages) + @foreach (Page page in _pages) { if (UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, page.PermissionList) && page.PageId != _pageId) { @@ -302,6 +302,7 @@ private bool validated = false; private List _themes = new List(); private List _containers = new List(); + private List _pages; private int _pageId; private string _name; private string _currentparentid; @@ -345,6 +346,7 @@ { try { + _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); _pageId = Int32.Parse(PageState.QueryString["id"]); _page = await PageService.GetPageAsync(_pageId); _icons = await SystemService.GetIconsAsync(); @@ -360,10 +362,10 @@ else { _parentid = _page.ParentId.ToString(); - _parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId); + _parent = _pages.FirstOrDefault(item => item.PageId == _page.ParentId); } _children = new List(); - foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture)))) + foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid, CultureInfo.InvariantCulture)))) { if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) { @@ -415,7 +417,7 @@ _permissions = _page.PermissionList; // page modules - _pageModules = PageState.Modules.Where(m => m.PageId == _page.PageId).ToList(); + _pageModules = PageState.Modules; // audit _createdby = _page.CreatedBy; @@ -447,8 +449,8 @@ { _parentid = (string)e.Value; _children = new List(); - foreach (Page p in PageState.Pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid)))) - { + foreach (Page p in _pages.Where(item => (_parentid == "-1" && item.ParentId == null) || (item.ParentId == int.Parse(_parentid)))) + { if (p.PageId != _pageId && UserSecurity.IsAuthorized(PageState.User, PermissionNames.View, p.PermissionList)) { _children.Add(p); @@ -549,7 +551,7 @@ } else { - Page parent = PageState.Pages.FirstOrDefault(item => item.PageId == _page.ParentId); + Page parent = _pages.FirstOrDefault(item => item.PageId == _page.ParentId); if (parent.Path == string.Empty) { _page.Path = Utilities.GetFriendlyUrl(parent.Name) + "/" + Utilities.GetFriendlyUrl(_path); @@ -560,7 +562,6 @@ } } - var _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); if (_pages.Any(item => item.Path == _page.Path && item.PageId != _page.PageId)) { AddModuleMessage(string.Format(Localizer["Mesage.Page.PathExists"], _path), MessageType.Warning); @@ -582,11 +583,11 @@ _page.Order = 0; break; case "<": - child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid); + child = _pages.FirstOrDefault(item => item.PageId == _childid); if (child != null) _page.Order = child.Order - 1; break; case ">": - child = PageState.Pages.FirstOrDefault(item => item.PageId == _childid); + child = _pages.FirstOrDefault(item => item.PageId == _childid); if (child != null) _page.Order = child.Order + 1; break; case ">>": diff --git a/Oqtane.Client/Modules/Admin/Pages/Index.razor b/Oqtane.Client/Modules/Admin/Pages/Index.razor index 391c6c42..6ce41c5b 100644 --- a/Oqtane.Client/Modules/Admin/Pages/Index.razor +++ b/Oqtane.Client/Modules/Admin/Pages/Index.razor @@ -5,11 +5,11 @@ @inject IStringLocalizer Localizer @inject IStringLocalizer SharedLocalizer -@if (PageState.Pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) +@if (_pages != null && UserSecurity.IsAuthorized(PageState.User, RoleNames.Admin)) { - +
    @@ -28,6 +28,21 @@ @code { public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; + private List _pages; + + protected override async Task OnInitializedAsync() + { + try + { + _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Loading Pages {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Page.Load"], MessageType.Error); + } + } + private async Task DeletePage(Page page) { try diff --git a/Oqtane.Client/Modules/Admin/Search/Index.razor b/Oqtane.Client/Modules/Admin/Search/Index.razor new file mode 100644 index 00000000..c76a594e --- /dev/null +++ b/Oqtane.Client/Modules/Admin/Search/Index.razor @@ -0,0 +1,102 @@ +@namespace Oqtane.Modules.Admin.Search +@inherits ModuleBase +@inject ISettingService SettingService +@inject IStringLocalizer Localizer +@inject IStringLocalizer SharedLocalizer + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+

+ +

+ +@code { + public override SecurityAccessLevel SecurityAccessLevel => SecurityAccessLevel.Admin; + + private string _searchProvider; + private string _enabled; + private string _lastIndexedOn; + private string _ignorePages; + private string _ignoreEntities; + private string _minimumWordLength; + private string _ignoreWords; + + protected override async Task OnInitializedAsync() + { + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + _searchProvider = SettingService.GetSetting(settings, "Search_SearchProvider", Constants.DefaultSearchProviderName); + _enabled = SettingService.GetSetting(settings, "Search_Enabled", "True"); + _lastIndexedOn = SettingService.GetSetting(settings, "Search_LastIndexedOn", ""); + _ignorePages = SettingService.GetSetting(settings, "Search_IgnorePages", ""); + _ignoreEntities = SettingService.GetSetting(settings, "Search_IgnoreEntities", ""); + _minimumWordLength = SettingService.GetSetting(settings, "Search_MininumWordLength", "3"); + _ignoreWords = SettingService.GetSetting(settings, "Search_IgnoreWords", ""); + } + + private async Task Save() + { + try + { + var settings = await SettingService.GetSiteSettingsAsync(PageState.Site.SiteId); + settings = SettingService.SetSetting(settings, "Search_SearchProvider", _searchProvider); + settings = SettingService.SetSetting(settings, "Search_Enabled", _enabled, true); + settings = SettingService.SetSetting(settings, "Search_LastIndexedOn", _lastIndexedOn, true); + settings = SettingService.SetSetting(settings, "Search_IgnorePages", _ignorePages, true); + settings = SettingService.SetSetting(settings, "Search_IgnoreEntities", _ignoreEntities, true); + settings = SettingService.SetSetting(settings, "Search_MininumWordLength", _minimumWordLength, true); + settings = SettingService.SetSetting(settings, "Search_IgnoreWords", _ignoreWords, true); + await SettingService.UpdateSiteSettingsAsync(settings, PageState.Site.SiteId); + AddModuleMessage(Localizer["Success.Save"], MessageType.Success); + } + catch (Exception ex) + { + await logger.LogError(ex, "Error Saving Search Settings {Error}", ex.Message); + AddModuleMessage(Localizer["Error.Save"], MessageType.Error); + } + } +} \ No newline at end of file diff --git a/Oqtane.Client/Modules/Admin/SearchResults/Index.razor b/Oqtane.Client/Modules/Admin/SearchResults/Index.razor new file mode 100644 index 00000000..4043761a --- /dev/null +++ b/Oqtane.Client/Modules/Admin/SearchResults/Index.razor @@ -0,0 +1,141 @@ +@using Oqtane.Services +@using System.Net +@namespace Oqtane.Modules.Admin.SearchResults +@inherits ModuleBase +@inject NavigationManager NavigationManager +@inject ISearchResultsService SearchResultsService +@inject ISettingService SettingService +@inject IStringLocalizer Localizer +@inject IStringLocalizer SharedLocalizer + +
+
+
+
+
+ @Localizer["SearchLabel"] + + + + @SharedLocalizer["Reset"] +
+
+
+
+
+
+ @if (_loading) + { +
+ } + else + { + @if (_searchResults != null && _searchResults.Results != null) + { + if (_searchResults.Results.Any()) + { + + +
+

@context.Title

+

@((MarkupString)context.Snippet)

+
+
+
+ } + else + { + + } + } +
+ } +
+
+
+ +@code { + public override string RenderMode => RenderModes.Static; + + private string _includeEntities; + private string _excludeEntities; + private string _fromDate; + private string _toDate; + private string _pageSize; + private string _sortField; + private string _sortOrder; + private string _bodyLength; + + private string _keywords; + private SearchResults _searchResults; + private bool _loading; + + [SupplyParameterFromForm(FormName = "SearchResultsForm")] + public string KeyWords { get => ""; set => _keywords = value; } + + protected override async Task OnInitializedAsync() + { + _includeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_IncludeEntities", ""); + _excludeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ExcludeEntities", ""); + _fromDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_FromDate", DateTime.MinValue.ToString()); + _toDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ToDate", DateTime.MaxValue.ToString()); + _pageSize = SettingService.GetSetting(ModuleState.Settings, "SearchResults_PageSize", int.MaxValue.ToString()); + _sortField = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortField", "Relevance"); + _sortOrder = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortOrder", "Descending"); + _bodyLength = SettingService.GetSetting(ModuleState.Settings, "SearchResults_BodyLength", "255"); + + if (_keywords == null && PageState.QueryString.ContainsKey("q")) + { + _keywords = WebUtility.UrlDecode(PageState.QueryString["q"]); + await PerformSearch(); + } + } + + private void Search() + { + NavigationManager.NavigateTo(NavigateUrl(PageState.Page.Path, $"page=1&q={_keywords}")); + } + + private async Task PerformSearch() + { + _loading = true; + StateHasChanged(); + + if (!string.IsNullOrEmpty(_keywords)) + { + var searchQuery = new SearchQuery + { + SiteId = PageState.Site.SiteId, + Alias = PageState.Alias, + Keywords = _keywords, + IncludeEntities = _includeEntities, + ExcludeEntities = _excludeEntities, + FromDate = (!string.IsNullOrEmpty(_fromDate)) ? DateTime.Parse(_fromDate) : DateTime.MinValue, + ToDate = (!string.IsNullOrEmpty(_toDate)) ? DateTime.Parse(_toDate) : DateTime.MaxValue, + PageSize = (!string.IsNullOrEmpty(_pageSize)) ? int.Parse(_pageSize) : int.MaxValue, + PageIndex = 0, + SortField = (!string.IsNullOrEmpty(_sortField)) ? (SearchSortField)Enum.Parse(typeof(SearchSortField), _sortField) : SearchSortField.Relevance, + SortOrder = (!string.IsNullOrEmpty(_sortOrder)) ? (SearchSortOrder)Enum.Parse(typeof(SearchSortOrder), _sortOrder) : SearchSortOrder.Descending, + BodyLength = (!string.IsNullOrEmpty(_bodyLength)) ? int.Parse(_bodyLength) : 255 + }; + + _searchResults = await SearchResultsService.GetSearchResultsAsync(searchQuery); + } + else + { + AddModuleMessage(Localizer["NoCriteria"], MessageType.Info, "bottom"); + } + + _loading = false; + StateHasChanged(); + } +} \ No newline at end of file diff --git a/Oqtane.Client/Modules/Admin/SearchResults/ModuleInfo.cs b/Oqtane.Client/Modules/Admin/SearchResults/ModuleInfo.cs new file mode 100644 index 00000000..e848f845 --- /dev/null +++ b/Oqtane.Client/Modules/Admin/SearchResults/ModuleInfo.cs @@ -0,0 +1,19 @@ +using Oqtane.Documentation; +using Oqtane.Models; +using Oqtane.Shared; + +namespace Oqtane.Modules.Admin.SearchResults +{ + [PrivateApi("Mark this as private, since it's not very useful in the public docs")] + public class ModuleInfo : IModule + { + public ModuleDefinition ModuleDefinition => new ModuleDefinition + { + Name = "Search Results", + Description = "Search Results", + Categories = "Admin", + Version = Constants.Version, + SettingsType = "Oqtane.Modules.Admin.SearchResults.Settings, Oqtane.Client" + }; + } +} diff --git a/Oqtane.Client/Modules/Admin/SearchResults/Settings.razor b/Oqtane.Client/Modules/Admin/SearchResults/Settings.razor new file mode 100644 index 00000000..161210cc --- /dev/null +++ b/Oqtane.Client/Modules/Admin/SearchResults/Settings.razor @@ -0,0 +1,123 @@ +@namespace Oqtane.Modules.Admin.SearchResults +@inherits ModuleBase +@inject ISettingService SettingService +@implements Oqtane.Interfaces.ISettingsControl +@inject IStringLocalizer Localizer +@inject IStringLocalizer SharedLocalizer + +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
+ + @Localizer["To"] + +
+
+
+
+ +
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+
+ +@code { + private string resourceType = "Oqtane.Modules.Admin.SearchResults.Settings, Oqtane.Client"; // for localization + + private ElementReference form; + private bool validated = false; + + private string _includeEntities; + private string _excludeEntities; + private DateTime? _fromDate = null; + private DateTime? _toDate = null; + private string _pageSize; + private string _sortField; + private string _sortOrder; + private string _bodyLength; + + protected override void OnInitialized() + { + try + { + _includeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_IncludeEntities", ""); + _excludeEntities = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ExcludeEntities", ""); + var fromDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_FromDate", ""); + _fromDate = (string.IsNullOrEmpty(fromDate)) ? null : DateTime.Parse(fromDate); + var toDate = SettingService.GetSetting(ModuleState.Settings, "SearchResults_ToDate", ""); + _toDate = (string.IsNullOrEmpty(toDate)) ? null : DateTime.Parse(toDate); + _pageSize = SettingService.GetSetting(ModuleState.Settings, "SearchResults_PageSize", ""); + _sortField = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortField", "Relevance"); + _sortOrder = SettingService.GetSetting(ModuleState.Settings, "SearchResults_SortOrder", "Descending"); + _bodyLength = SettingService.GetSetting(ModuleState.Settings, "SearchResults_BodyLength", "255"); + } + catch (Exception ex) + { + AddModuleMessage(ex.Message, MessageType.Error); + } + } + + public async Task UpdateSettings() + { + try + { + var settings = await SettingService.GetModuleSettingsAsync(ModuleState.ModuleId); + settings = SettingService.SetSetting(settings, "SearchResults_IncludeEntities", _includeEntities); + settings = SettingService.SetSetting(settings, "SearchResults_ExcludeEntities", _excludeEntities); + settings = SettingService.SetSetting(settings, "SearchResults_From", _fromDate.ToString()); + settings = SettingService.SetSetting(settings, "SearchResults_To", _toDate.ToString()); + settings = SettingService.SetSetting(settings, "SearchResults_PageSize", _pageSize); + settings = SettingService.SetSetting(settings, "SearchResults_SortField", _sortField); + settings = SettingService.SetSetting(settings, "SearchResults_SortOrder", _sortOrder); + settings = SettingService.SetSetting(settings, "SearchResults_BodyLength", _bodyLength); + await SettingService.UpdateModuleSettingsAsync(settings, ModuleState.ModuleId); + } + catch (Exception ex) + { + AddModuleMessage(ex.Message, MessageType.Error); + } + } +} diff --git a/Oqtane.Client/Modules/Admin/Site/Index.razor b/Oqtane.Client/Modules/Admin/Site/Index.razor index a5626a5d..b708149c 100644 --- a/Oqtane.Client/Modules/Admin/Site/Index.razor +++ b/Oqtane.Client/Modules/Admin/Site/Index.razor @@ -1,13 +1,16 @@ @namespace Oqtane.Modules.Admin.Site @inherits ModuleBase @using System.Text.RegularExpressions +@using Microsoft.Extensions.DependencyInjection @inject NavigationManager NavigationManager @inject ISiteService SiteService +@inject IPageService PageService @inject ITenantService TenantService @inject IDatabaseService DatabaseService @inject IAliasService AliasService @inject IThemeService ThemeService @inject ISettingService SettingService +@inject IServiceProvider ServiceProvider @inject IStringLocalizer Localizer @inject INotificationService NotificationService @inject IStringLocalizer SharedLocalizer @@ -27,7 +30,7 @@
+ @if (_textEditors != null) + { + @foreach (var textEditor in _textEditors) + { + + } + } + +
+
- +
- +
@@ -394,12 +411,15 @@ private bool _initialized = false; private List _themes = new List(); private List _containers = new List(); + private List _pages; + private string _name = string.Empty; private string _homepageid = "-"; private string _isdeleted; private string _sitemap = ""; private string _siteguid = ""; private string _version = ""; + private int _logofileid = -1; private FileManager _logofilemanager; private int _faviconfileid = -1; @@ -407,8 +427,15 @@ private string _themetype = ""; private string _containertype = ""; private string _admincontainertype = ""; + + private Dictionary _textEditors = new Dictionary(); + private string _textEditor = ""; + private string _imageFiles = string.Empty; + private string _uploadableFiles = string.Empty; + private string _headcontent = string.Empty; private string _bodycontent = string.Empty; + private string _smtphost = string.Empty; private string _smtpport = string.Empty; private string _smtpssl = "False"; @@ -419,25 +446,28 @@ private string _smtpsender = string.Empty; private string _smtprelay = "False"; private string _smtpenabled = "True"; - private string _ImageFiles = string.Empty; - private string _UploadableFiles = string.Empty; private int _retention = 30; + private string _pwaisenabled; private int _pwaappiconfileid = -1; private FileManager _pwaappiconfilemanager; private int _pwasplashiconfileid = -1; private FileManager _pwasplashiconfilemanager; + private List _aliases; private int _aliasid = -1; private string _aliasname; private string _defaultalias; + private string _rendermode = RenderModes.Interactive; private string _runtime = Runtimes.Server; private string _prerender = "True"; private string _hybrid = "False"; + private string _tenant = string.Empty; private string _database = string.Empty; private string _connectionstring = string.Empty; + private string _createdby; private DateTime _createdon; private string _modifiedby; @@ -454,6 +484,10 @@ Site site = await SiteService.GetSiteAsync(PageState.Site.SiteId); if (site != null) { + var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); + + _pages = await PageService.GetPagesAsync(PageState.Site.SiteId); + _name = site.Name; if (site.HomePageId != null) { @@ -480,23 +514,23 @@ _containertype = (!string.IsNullOrEmpty(site.DefaultContainerType)) ? site.DefaultContainerType : Constants.DefaultContainer; _admincontainertype = (!string.IsNullOrEmpty(site.AdminContainerType)) ? site.AdminContainerType : Constants.DefaultAdminContainer; + // functionality + var textEditors = ServiceProvider.GetServices(); + foreach (var textEditor in textEditors) + { + _textEditors.Add(textEditor.Name, Utilities.GetFullTypeName(textEditor.GetType().AssemblyQualifiedName)); + } + _textEditor = SettingService.GetSetting(settings, "TextEditor", Constants.DefaultTextEditor); + _imageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles); + _imageFiles = (string.IsNullOrEmpty(_imageFiles)) ? Constants.ImageFiles : _imageFiles; + _uploadableFiles = SettingService.GetSetting(settings, "UploadableFiles", Constants.UploadableFiles); + _uploadableFiles = (string.IsNullOrEmpty(_uploadableFiles)) ? Constants.UploadableFiles : _uploadableFiles; + // page content _headcontent = site.HeadContent; _bodycontent = site.BodyContent; - // PWA - _pwaisenabled = site.PwaIsEnabled.ToString(); - if (site.PwaAppIconFileId != null) - { - _pwaappiconfileid = site.PwaAppIconFileId.Value; - } - if (site.PwaSplashIconFileId != null) - { - _pwasplashiconfileid = site.PwaSplashIconFileId.Value; - } - // SMTP - var settings = await SettingService.GetSiteSettingsAsync(site.SiteId); _smtphost = SettingService.GetSetting(settings, "SMTPHost", string.Empty); _smtpport = SettingService.GetSetting(settings, "SMTPPort", string.Empty); _smtpssl = SettingService.GetSetting(settings, "SMTPSSL", "False"); @@ -508,11 +542,16 @@ _smtpenabled = SettingService.GetSetting(settings, "SMTPEnabled", "True"); _retention = int.Parse(SettingService.GetSetting(settings, "NotificationRetention", "30")); - // file extensions - _ImageFiles = SettingService.GetSetting(settings, "ImageFiles", Constants.ImageFiles); - _ImageFiles = (string.IsNullOrEmpty(_ImageFiles)) ? Constants.ImageFiles : _ImageFiles; - _UploadableFiles = SettingService.GetSetting(settings, "UploadableFiles", Constants.UploadableFiles); - _UploadableFiles = (string.IsNullOrEmpty(_UploadableFiles)) ? Constants.UploadableFiles : _UploadableFiles; + // PWA + _pwaisenabled = site.PwaIsEnabled.ToString(); + if (site.PwaAppIconFileId != null) + { + _pwaappiconfileid = site.PwaAppIconFileId.Value; + } + if (site.PwaSplashIconFileId != null) + { + _pwasplashiconfileid = site.PwaSplashIconFileId.Value; + } // aliases await GetAliases(); @@ -673,160 +712,161 @@ } } - site = await SiteService.UpdateSiteAsync(site); + site = await SiteService.UpdateSiteAsync(site); // 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, "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); - settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, 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); + settings = SettingService.SetSetting(settings, "SMTPRelay", _smtprelay, true); settings = SettingService.SetSetting(settings, "SMTPEnabled", _smtpenabled, true); settings = SettingService.SetSetting(settings, "SiteGuid", _siteguid, true); settings = SettingService.SetSetting(settings, "NotificationRetention", _retention.ToString(), true); - // file extensions - settings = SettingService.SetSetting(settings, "ImageFiles", (_ImageFiles != Constants.ImageFiles) ? _ImageFiles.Replace(" ", "") : "", false); - settings = SettingService.SetSetting(settings, "UploadableFiles", (_UploadableFiles != Constants.UploadableFiles) ? _UploadableFiles.Replace(" ", "") : "", false); + // functionality + settings = SettingService.SetSetting(settings, "TextEditor", _textEditor); + settings = SettingService.SetSetting(settings, "ImageFiles", (_imageFiles != Constants.ImageFiles) ? _imageFiles.Replace(" ", "") : "", false); + settings = SettingService.SetSetting(settings, "UploadableFiles", (_uploadableFiles != Constants.UploadableFiles) ? _uploadableFiles.Replace(" ", "") : "", false); - await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); + await SettingService.UpdateSiteSettingsAsync(settings, site.SiteId); - await logger.LogInformation("Site Settings Saved {Site}", site); + await logger.LogInformation("Site Settings Saved {Site}", site); - NavigationManager.NavigateTo(NavigateUrl(), true); // reload - } - } - 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); - } - } + NavigationManager.NavigateTo(NavigateUrl(), true); // reload + } + } + 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() - { - 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); + private async Task DeleteSite() + { + 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); - foreach (Alias alias in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId)) - { - await AliasService.DeleteAliasAsync(alias.AliasId); - } + foreach (Alias alias in aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId)) + { + await AliasService.DeleteAliasAsync(alias.AliasId); + } - var redirect = aliases.First(item => item.SiteId != PageState.Site.SiteId || item.TenantId != PageState.Site.TenantId); - NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + redirect.Name, true); - } - 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); - } - } + var redirect = aliases.First(item => item.SiteId != PageState.Site.SiteId || item.TenantId != PageState.Site.TenantId); + NavigationManager.NavigateTo(PageState.Uri.Scheme + "://" + redirect.Name, true); + } + 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() - { - 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"); + private async Task SendEmail() + { + 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 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(); } - catch (Exception ex) - { - await logger.LogError(ex, "Error Testing SMTP Configuration"); - AddModuleMessage(Localizer["Error.Smtp.TestConfig"], MessageType.Error); - } - } - else - { - AddModuleMessage(Localizer["Message.Required.Smtp"], MessageType.Warning); - } - } + catch (Exception ex) + { + await logger.LogError(ex, "Error Testing SMTP Configuration"); + AddModuleMessage(Localizer["Error.Smtp.TestConfig"], MessageType.Error); + } + } + else + { + AddModuleMessage(Localizer["Message.Required.Smtp"], MessageType.Warning); + } + } - private void ToggleSMTPPassword() - { - if (_smtppasswordtype == "password") - { - _smtppasswordtype = "text"; - _togglesmtppassword = SharedLocalizer["HidePassword"]; - } - else - { - _smtppasswordtype = "password"; - _togglesmtppassword = SharedLocalizer["ShowPassword"]; - } - } + private void ToggleSMTPPassword() + { + if (_smtppasswordtype == "password") + { + _smtppasswordtype = "text"; + _togglesmtppassword = SharedLocalizer["HidePassword"]; + } + else + { + _smtppasswordtype = "password"; + _togglesmtppassword = SharedLocalizer["ShowPassword"]; + } + } - private async Task GetAliases() - { - if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) - { - _aliases = await AliasService.GetAliasesAsync(); - _aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).OrderBy(item => item.AliasId).ToList(); - } - } + private async Task GetAliases() + { + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + _aliases = await AliasService.GetAliasesAsync(); + _aliases = _aliases.Where(item => item.SiteId == PageState.Site.SiteId && item.TenantId == PageState.Site.TenantId).OrderBy(item => item.AliasId).ToList(); + } + } - private void AddAlias() - { - _aliases.Add(new Alias { AliasId = 0, Name = "", IsDefault = false }); - _aliasid = 0; - _aliasname = ""; - _defaultalias = "False"; - StateHasChanged(); - } + private void AddAlias() + { + _aliases.Add(new Alias { AliasId = 0, Name = "", IsDefault = false }); + _aliasid = 0; + _aliasname = ""; + _defaultalias = "False"; + StateHasChanged(); + } - private void EditAlias(Alias alias) - { - _aliasid = alias.AliasId; - _aliasname = alias.Name; - _defaultalias = alias.IsDefault.ToString(); - StateHasChanged(); - } + private void EditAlias(Alias alias) + { + _aliasid = alias.AliasId; + _aliasname = alias.Name; + _defaultalias = alias.IsDefault.ToString(); + StateHasChanged(); + } - private async Task DeleteAlias(Alias alias) - { - if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) - { - await AliasService.DeleteAliasAsync(alias.AliasId); - await GetAliases(); - StateHasChanged(); - } - } + private async Task DeleteAlias(Alias alias) + { + if (UserSecurity.IsAuthorized(PageState.User, RoleNames.Host)) + { + await AliasService.DeleteAliasAsync(alias.AliasId); + await GetAliases(); + StateHasChanged(); + } + } private async Task SaveAlias() { @@ -878,11 +918,11 @@ } } - private async Task CancelAlias() - { - await GetAliases(); - _aliasid = -1; - _aliasname = ""; - StateHasChanged(); - } + private async Task CancelAlias() + { + await GetAliases(); + _aliasid = -1; + _aliasname = ""; + StateHasChanged(); + } } diff --git a/Oqtane.Client/Modules/Admin/Themes/Add.razor b/Oqtane.Client/Modules/Admin/Themes/Add.razor index a7be5907..d8937984 100644 --- a/Oqtane.Client/Modules/Admin/Themes/Add.razor +++ b/Oqtane.Client/Modules/Admin/Themes/Add.razor @@ -125,7 +125,7 @@
- +
diff --git a/Oqtane.Client/Modules/Controls/ActionDialog.razor b/Oqtane.Client/Modules/Controls/ActionDialog.razor index defb520d..be192a6a 100644 --- a/Oqtane.Client/Modules/Controls/ActionDialog.razor +++ b/Oqtane.Client/Modules/Controls/ActionDialog.razor @@ -162,7 +162,6 @@ else { Text = Action; } - _openText = Text; if (string.IsNullOrEmpty(Class)) { @@ -181,7 +180,10 @@ else _openText = string.Empty; } - if (!IconName.Contains(" ")) + // Check if IconName starts with "oi oi-" + bool startsWithOiOi = IconName.StartsWith("oi oi-"); + + if (!startsWithOiOi && !IconName.Contains(" ")) { IconName = "oi oi-" + IconName; } @@ -193,6 +195,7 @@ else Header = Localize(nameof(Header), Header); Message = Localize(nameof(Message), Message); + _openText = Text; _permissions = (PermissionList == null) ? ModuleState.PermissionList : PermissionList; _authorized = IsAuthorized(); diff --git a/Oqtane.Client/Modules/Controls/ActionLink.razor b/Oqtane.Client/Modules/Controls/ActionLink.razor index 9517e275..545dca5c 100644 --- a/Oqtane.Client/Modules/Controls/ActionLink.razor +++ b/Oqtane.Client/Modules/Controls/ActionLink.razor @@ -145,7 +145,10 @@ if (!string.IsNullOrEmpty(IconName)) { - if (!IconName.Contains(" ")) + // Check if IconName starts with "oi oi-" + bool startsWithOiOi = IconName.StartsWith("oi oi-"); + + if (!startsWithOiOi && !IconName.Contains(" ")) { IconName = "oi oi-" + IconName; } diff --git a/Oqtane.Client/Modules/Controls/InputList.razor b/Oqtane.Client/Modules/Controls/InputList.razor index 25de9fda..e187479b 100644 --- a/Oqtane.Client/Modules/Controls/InputList.razor +++ b/Oqtane.Client/Modules/Controls/InputList.razor @@ -38,13 +38,10 @@ protected void OnChange(ChangeEventArgs e) { - if (!string.IsNullOrEmpty(e.Value.ToString())) + Value = e.Value.ToString(); + if (ValueChanged.HasDelegate) { - Value = e.Value.ToString(); - if (ValueChanged.HasDelegate) - { - ValueChanged.InvokeAsync(Value); - } + ValueChanged.InvokeAsync(Value); } } } \ No newline at end of file diff --git a/Oqtane.Client/Modules/Controls/Pager.razor b/Oqtane.Client/Modules/Controls/Pager.razor index 8e643f17..ce14eed6 100644 --- a/Oqtane.Client/Modules/Controls/Pager.razor +++ b/Oqtane.Client/Modules/Controls/Pager.razor @@ -11,7 +11,7 @@ @if (!string.IsNullOrEmpty(SearchProperties)) {
-
+
@@ -74,7 +74,7 @@ { -
+
@SharedLocalizer["Reset"] @@ -359,6 +359,9 @@ [Parameter] public string SearchProperties { get; set; } // comma delimited list of property names to include in search + [Parameter] + public string SearchBoxClass { get; set; } // class for Search box + [Parameter] public string Parameters { get; set; } // optional - querystring parameters in the form of "id=x&name=y" used in static render mode diff --git a/Oqtane.Client/Modules/Controls/RichTextEditorInterop.cs b/Oqtane.Client/Modules/Controls/QuillEditorInterop.cs similarity index 97% rename from Oqtane.Client/Modules/Controls/RichTextEditorInterop.cs rename to Oqtane.Client/Modules/Controls/QuillEditorInterop.cs index 338f240a..ed53c4e7 100644 --- a/Oqtane.Client/Modules/Controls/RichTextEditorInterop.cs +++ b/Oqtane.Client/Modules/Controls/QuillEditorInterop.cs @@ -4,11 +4,11 @@ using System.Threading.Tasks; namespace Oqtane.Modules.Controls { - public class RichTextEditorInterop + public class QuillEditorInterop { private readonly IJSRuntime _jsRuntime; - public RichTextEditorInterop(IJSRuntime jsRuntime) + public QuillEditorInterop(IJSRuntime jsRuntime) { _jsRuntime = jsRuntime; } diff --git a/Oqtane.Client/Modules/Controls/QuillJSTextEditor.razor b/Oqtane.Client/Modules/Controls/QuillJSTextEditor.razor new file mode 100644 index 00000000..d6542a08 --- /dev/null +++ b/Oqtane.Client/Modules/Controls/QuillJSTextEditor.razor @@ -0,0 +1,578 @@ +@namespace Oqtane.Modules.Controls +@inherits ModuleControlBase +@implements ITextEditor +@inject ISettingService SettingService +@inject NavigationManager NavigationManager +@inject IStringLocalizer Localizer +@inject IStringLocalizer SharedLocalizer + +
+ + @if (_allowRichText) + { + + @if (_richfilemanager) + { + + +
+ } +
+ @if (_allowFileManagement) + { + + } + @if (_richfilemanager) + { + @((MarkupString)"  ") + + } +
+
+
+
+ @if (!string.IsNullOrEmpty(_toolbarContent)) + { + @((MarkupString)_toolbarContent) + } + else + { + + + + + + + + + + + + + + + + + + + } +
+
+
+
+
+ } + @if (_allowRawHtml) + { + + @if (_rawfilemanager) + { + + +
+ } +
+ @if (_allowFileManagement) + { + + } + @if (_rawfilemanager) + { + @((MarkupString)"  ") + + } +
+ @if (ReadOnly) + { + + } + else + { + + } +
+ } + @if (_allowSettings) + { + +
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ - } - else - { - - } - - } - + @_textEditorComponent
@code { - private bool _initialized = false; - - private RichTextEditorInterop interop; - private FileManager _fileManager; - private string _activetab = "Rich"; - - private ElementReference _editorElement; - private ElementReference _toolBar; - private bool _richfilemanager = false; - private string _richhtml = string.Empty; - private string _originalrichhtml = string.Empty; - - private bool _rawfilemanager = false; - private string _rawhtmlid = "RawHtmlEditor_" + Guid.NewGuid().ToString("N"); - private string _rawhtml = string.Empty; - private string _originalrawhtml = string.Empty; - - private string _message = string.Empty; - private bool _contentchanged = false; - private int _editorIndex; + private string _textEditorType; + private RenderFragment _textEditorComponent; + private ITextEditor _textEditor; [Parameter] public string Content { get; set; } @@ -134,203 +28,100 @@ public string Placeholder { get; set; } [Parameter] - public bool AllowFileManagement { get; set; } = true; + public string Provider { get; set; } - [Parameter] - public bool AllowRichText { 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 Resources => new List() - { - 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-blot-formatter.min.js", Location = ResourceLocation.Body }, - new Resource { ResourceType = ResourceType.Script, Bundle = "Quill", Url = "js/quill-interop.js", Location = ResourceLocation.Body } - }; + [Parameter(CaptureUnmatchedValues = true)] + public Dictionary AdditionalAttributes { get; set; } = new Dictionary(); protected override void OnInitialized() { - interop = new RichTextEditorInterop(JSRuntime); - if (string.IsNullOrEmpty(Placeholder)) - { - Placeholder = Localizer["Placeholder"]; - } + _textEditorType = GetTextEditorType(); } protected override void OnParametersSet() { - _richhtml = Content; - _rawhtml = Content; - _originalrawhtml = _rawhtml; // preserve for comparison later - _originalrichhtml = ""; - - if (Content != _originalrawhtml) + _textEditorComponent = (builder) => { - _contentchanged = true; // identifies when Content parameter has changed - } - - if (!AllowRichText) - { - _activetab = "Raw"; - } + CreateTextEditor(builder); + }; } protected override async Task OnAfterRenderAsync(bool firstRender) { - await base.OnAfterRenderAsync(firstRender); - - if (AllowRichText) + if(_textEditor != null) { - if (firstRender) - { - await interop.CreateEditor( - _editorElement, - _toolBar, - ReadOnly, - Placeholder, - Theme, - DebugLevel); - - await interop.LoadEditorContent(_editorElement, _richhtml); - - // preserve a copy of the content (Quill sanitizes content so we need to retrieve it from the editor as it may have been modified) - _originalrichhtml = await interop.GetHtml(_editorElement); - - _initialized = true; - } - else - { - if (_initialized) - { - if (_contentchanged) - { - // reload editor if Content passed to component has changed - await interop.LoadEditorContent(_editorElement, _richhtml); - _originalrichhtml = await interop.GetHtml(_editorElement); - } - else - { - // preserve changed content on re-render event - var richhtml = await interop.GetHtml(_editorElement); - if (richhtml != _richhtml) - { - _richhtml = richhtml; - await interop.LoadEditorContent(_editorElement, _richhtml); - } - } - } - } - - _contentchanged = false; + _textEditor.Initialize(Content); } - } - public void CloseRichFileManager() - { - _richfilemanager = false; - _message = string.Empty; - StateHasChanged(); - } - - public void CloseRawFileManager() - { - _rawfilemanager = false; - _message = string.Empty; - StateHasChanged(); + await base.OnAfterRenderAsync(firstRender); } public async Task GetHtml() { - // evaluate raw html content as first priority - if (_rawhtml != _originalrawhtml) - { - return _rawhtml; - } - else - { - var richhtml = ""; + return await _textEditor.GetContent(); + } - if (AllowRichText) + private void CreateTextEditor(RenderTreeBuilder builder) + { + if(!string.IsNullOrEmpty(_textEditorType)) + { + var editorType = Type.GetType(_textEditorType); + if (editorType != null) { - richhtml = await interop.GetHtml(_editorElement); - } + builder.OpenComponent(0, editorType); - if (richhtml != _originalrichhtml && !string.IsNullOrEmpty(richhtml)) - { - // convert Quill's empty content to empty string - if (richhtml == "


") + var attributes = new Dictionary { - richhtml = string.Empty; + { "Placeholder", Placeholder }, + { "ReadOnly", ReadOnly } + }; + + if (AdditionalAttributes != null) + { + foreach(var key in AdditionalAttributes.Keys) + { + if(!attributes.ContainsKey(key)) + { + attributes.Add(key, AdditionalAttributes[key]); + } + else + { + attributes[key] = AdditionalAttributes[key]; + } + } } - return richhtml; - } - else - { - // return original raw html content - return _originalrawhtml; + + var index = 1; + foreach(var name in attributes.Keys) + { + if (editorType.GetProperty(name) != null) + { + builder.AddAttribute(index++, name, attributes[name]); + } + } + + builder.AddComponentReferenceCapture(index, (c) => + { + _textEditor = (ITextEditor)c; + }); + builder.CloseComponent(); } } } - public async Task InsertRichImage() + private string GetTextEditorType() { - _message = string.Empty; - if (_richfilemanager) - { - var file = _fileManager.GetFile(); - if (file != null) - { - await interop.InsertImage(_editorElement, file.Url, ((!string.IsNullOrEmpty(file.Description)) ? file.Description : file.Name), _editorIndex); - _richhtml = await interop.GetHtml(_editorElement); - _richfilemanager = false; - } - else - { - _message = Localizer["Message.Require.Image"]; - } - } - else - { - _editorIndex = await interop.GetCurrentCursor(_editorElement); - _richfilemanager = true; - } - StateHasChanged(); - } + const string EditorSettingName = "TextEditor"; - 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(_rawhtmlid); - var image = "\"""; - _rawhtml = _rawhtml.Substring(0, pos) + image + _rawhtml.Substring(pos); - _rawfilemanager = false; - } - else - { - _message = Localizer["Message.Require.Image"]; - } - } - else - { - _rawfilemanager = true; - } - StateHasChanged(); - } + if(!string.IsNullOrEmpty(Provider)) + { + var provider = ServiceProvider.GetServices().FirstOrDefault(i => i.Name.Equals(Provider, StringComparison.OrdinalIgnoreCase)); + if(provider != null) + { + return Utilities.GetFullTypeName(provider.GetType().AssemblyQualifiedName); + } + } + + return SettingService.GetSetting(PageState.Site.Settings, EditorSettingName, Constants.DefaultTextEditor); + } } diff --git a/Oqtane.Client/Modules/Controls/TabStrip.razor b/Oqtane.Client/Modules/Controls/TabStrip.razor index 90b3948a..e2a3c0f1 100644 --- a/Oqtane.Client/Modules/Controls/TabStrip.razor +++ b/Oqtane.Client/Modules/Controls/TabStrip.razor @@ -23,7 +23,7 @@ } -
+

@ChildContent
@@ -47,6 +47,9 @@ [Parameter] public string Id { get; set; } // optional - used to uniquely identify an instance of a tab strip component (will be set automatically if no value provided) + [Parameter] + public string TabContentClass { get; set; } // optional - to extend the TabContent div. + protected override void OnInitialized() { if (string.IsNullOrEmpty(Id)) diff --git a/Oqtane.Client/Modules/Controls/TextAreaTextEditor.razor b/Oqtane.Client/Modules/Controls/TextAreaTextEditor.razor new file mode 100644 index 00000000..f8bb9565 --- /dev/null +++ b/Oqtane.Client/Modules/Controls/TextAreaTextEditor.razor @@ -0,0 +1,33 @@ +@namespace Oqtane.Modules.Controls +@inherits ModuleControlBase +@implements ITextEditor + +
+