Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
17
Directory.Build.props
Normal file
17
Directory.Build.props
Normal file
@@ -0,0 +1,17 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>6.2.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
<Description>CMS and Application Framework for Blazor and .NET MAUI</Description>
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -329,6 +329,15 @@ else
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mb-1 align-items-center">
|
||||
<Label Class="col-sm-3" For="singlelogout" HelpText="Specify if users should be logged out of both the application and provider (the default is false indicating they will only be logged out of the application)" ResourceKey="SingleLogout">Use Single Logout?</Label>
|
||||
<div class="col-sm-9">
|
||||
<select id="singlelogout" class="form-select" @bind="@_singlelogout" required>
|
||||
<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="scopes" HelpText="A list of Scopes to request from the provider (separated by commas). If none are specified, standard Scopes will be used by default." ResourceKey="Scopes">Scopes:</Label>
|
||||
@@ -560,6 +569,7 @@ else
|
||||
private string _toggleclientsecret = string.Empty;
|
||||
private string _authresponsetype;
|
||||
private string _requirenonce;
|
||||
private string _singlelogout;
|
||||
private string _scopes;
|
||||
private string _parameters;
|
||||
private string _pkce;
|
||||
@@ -648,6 +658,7 @@ else
|
||||
_toggleclientsecret = SharedLocalizer["ShowPassword"];
|
||||
_authresponsetype = SettingService.GetSetting(settings, "ExternalLogin:AuthResponseType", "code");
|
||||
_requirenonce = SettingService.GetSetting(settings, "ExternalLogin:RequireNonce", "true");
|
||||
_singlelogout = SettingService.GetSetting(settings, "ExternalLogin:SingleLogout", "false");
|
||||
_scopes = SettingService.GetSetting(settings, "ExternalLogin:Scopes", "");
|
||||
_parameters = SettingService.GetSetting(settings, "ExternalLogin:Parameters", "");
|
||||
_pkce = SettingService.GetSetting(settings, "ExternalLogin:PKCE", "false");
|
||||
@@ -771,6 +782,7 @@ else
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:ClientSecret", _clientsecret, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:AuthResponseType", _authresponsetype, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:RequireNonce", _requirenonce, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:SingleLogout", _singlelogout, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Scopes", _scopes, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:Parameters", _parameters, true);
|
||||
settings = SettingService.SetSetting(settings, "ExternalLogin:PKCE", _pkce, true);
|
||||
|
||||
@@ -1,19 +1,23 @@
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@using System.IO
|
||||
@using Radzen
|
||||
@using Radzen.Blazor
|
||||
@inject DialogService DialogService
|
||||
@inject IStringLocalizer<Oqtane.Modules.Controls.RadzenTextEditor> Localizer
|
||||
|
||||
<div class="d-flex">
|
||||
@if (!string.IsNullOrEmpty(_message))
|
||||
{
|
||||
<div class="rz-html-editor-dialog-item">
|
||||
<div class="alert alert-warning alert-dismissible fade show mb-3" role="alert">
|
||||
@((MarkupString)_message)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="rz-html-editor-dialog-item">
|
||||
<FileManager @ref="_fileManager" Filter="@Filters" />
|
||||
</div>
|
||||
<div class="d-flex">
|
||||
<ModuleMessage Message="@_message" Type="MessageType.Warning"></ModuleMessage>
|
||||
</div>
|
||||
<div class="mt-1 text-end">
|
||||
<RadzenButton Text="OK" Click=@OnOkClick />
|
||||
<RadzenButton Text="Cancel" Click=@OnCancelClick ButtonStyle="ButtonStyle.Secondary" />
|
||||
<div class="rz-html-editor-dialog-buttons">
|
||||
<RadzenButton Text="@Localizer["InsertImage"]" Click="InsertImage" />
|
||||
<RadzenButton Text="@Localizer["Cancel"]" Click="() => DialogService.Close()" ButtonStyle="ButtonStyle.Secondary" />
|
||||
</div>
|
||||
@code {
|
||||
private FileManager _fileManager;
|
||||
@@ -22,12 +26,7 @@
|
||||
[Parameter]
|
||||
public string Filters { get; set; }
|
||||
|
||||
private void OnCancelClick()
|
||||
{
|
||||
DialogService.Close(null);
|
||||
}
|
||||
|
||||
private void OnOkClick()
|
||||
private void InsertImage()
|
||||
{
|
||||
_message = string.Empty;
|
||||
var file = _fileManager.GetFile();
|
||||
|
||||
@@ -0,0 +1,148 @@
|
||||
@namespace Oqtane.Modules.Controls
|
||||
@using Radzen
|
||||
@using Radzen.Blazor
|
||||
@using System.Text
|
||||
@inject DialogService DialogService
|
||||
@inject IStringLocalizer<Oqtane.Modules.Controls.RadzenTextEditor> Localizer
|
||||
|
||||
@if (_linkAttributes != null)
|
||||
{
|
||||
@if (!string.IsNullOrWhiteSpace(_message))
|
||||
{
|
||||
<div class="rz-html-editor-dialog-item">
|
||||
<div class="alert alert-warning alert-dismissible fade show mb-3" role="alert">
|
||||
@((MarkupString)_message)
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
<div class="rz-html-editor-dialog-item">
|
||||
<RadzenDropDown TValue="int" class="form-control" PopupStyle="color: var(--rz-input-value-color);" @bind-Value="_linkType" Data="_linkTypes" TextProperty="Value" ValueProperty="Key" />
|
||||
</div>
|
||||
@if (_linkType == 0)
|
||||
{
|
||||
<div class="rz-html-editor-dialog-item">
|
||||
<RadzenTextBox class="form-control" @bind-Value="@_linkAttributes.Href" Placeholder="@Localizer["WebAddress"]" />
|
||||
</div>
|
||||
}
|
||||
else
|
||||
{
|
||||
<div class="rz-html-editor-dialog-item">
|
||||
<FileManager @ref="_fileManager" OnSelectFile="SelectFile" OnSelectFolder="SelectFile" />
|
||||
</div>
|
||||
}
|
||||
@if (_linkTextEditable)
|
||||
{
|
||||
<div class="rz-html-editor-dialog-item">
|
||||
<RadzenTextBox class="form-control" @bind-Value="@_linkAttributes.InnerText" Placeholder="@Localizer["LinkText"]" />
|
||||
</div>
|
||||
}
|
||||
<div class="rz-html-editor-dialog-item">
|
||||
<RadzenDropDown TValue="bool" class="form-control" PopupStyle="color: var(--rz-input-value-color);" @bind-Value="_blank" Data="_linkTargets" TextProperty="Value" ValueProperty="Key" />
|
||||
</div>
|
||||
}
|
||||
<div class="rz-html-editor-dialog-buttons">
|
||||
<RadzenButton Text=@Localizer["InsertLink"] Click="InsertLink" />
|
||||
<RadzenButton Text=@Localizer["Cancel"] Click="() => DialogService.Close()" ButtonStyle="ButtonStyle.Secondary" />
|
||||
</div>
|
||||
|
||||
@code {
|
||||
class LinkAttributes
|
||||
{
|
||||
public string InnerText { get; set; }
|
||||
public string InnerHtml { get; set; }
|
||||
public string Href { get; set; }
|
||||
public string Target { get; set; }
|
||||
}
|
||||
|
||||
[Parameter]
|
||||
public RadzenHtmlEditor Editor { get; set; }
|
||||
|
||||
private IDictionary<int, string> _linkTypes;
|
||||
private IDictionary<bool, string> _linkTargets;
|
||||
private LinkAttributes _linkAttributes;
|
||||
private bool _blank;
|
||||
private int _linkType;
|
||||
private string _message;
|
||||
private bool _linkTextEditable;
|
||||
private FileManager _fileManager;
|
||||
private File _previousFile;
|
||||
|
||||
protected override async Task OnInitializedAsync()
|
||||
{
|
||||
await base.OnInitializedAsync();
|
||||
_linkAttributes = await Editor.GetSelectionAttributes<LinkAttributes>("a", new[] { "innerText", "href", "target" });
|
||||
if (_linkAttributes.Target == "_blank")
|
||||
{
|
||||
_blank = true;
|
||||
}
|
||||
|
||||
_linkTextEditable = string.IsNullOrWhiteSpace(_linkAttributes.InnerHtml) || _linkAttributes.InnerHtml == "<br>";
|
||||
|
||||
_linkTypes = new Dictionary<int, string>
|
||||
{
|
||||
{ 0, Localizer["WebLink"] },
|
||||
{ 1, Localizer["FileLink"] }
|
||||
};
|
||||
|
||||
_linkTargets = new Dictionary<bool, string>
|
||||
{
|
||||
{ false, Localizer["OpenInCurrentWindow"] },
|
||||
{ true, Localizer["OpenInNewWindow"] }
|
||||
};
|
||||
}
|
||||
|
||||
private void SelectFile()
|
||||
{
|
||||
var file = _fileManager.GetFile();
|
||||
if(file != null)
|
||||
{
|
||||
_linkAttributes.Href = file.Url;
|
||||
if ((string.IsNullOrWhiteSpace(_linkAttributes.InnerText) || _linkAttributes.InnerText == _previousFile?.Name) && _linkTextEditable)
|
||||
{
|
||||
_linkAttributes.InnerText = file.Name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_linkAttributes.Href = string.Empty;
|
||||
if (_linkAttributes.InnerText == _previousFile?.Name)
|
||||
{
|
||||
_linkAttributes.InnerText = string.Empty;
|
||||
}
|
||||
}
|
||||
_previousFile = file;
|
||||
|
||||
StateHasChanged();
|
||||
}
|
||||
|
||||
private void InsertLink()
|
||||
{
|
||||
_message = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(_linkAttributes.Href))
|
||||
{
|
||||
_message = _linkType == 1 ? Localizer["Message.Require.File"] : Localizer["Message.Require.WebAddress"];
|
||||
}
|
||||
else if (string.IsNullOrWhiteSpace(_linkAttributes.InnerText) && _linkTextEditable)
|
||||
{
|
||||
_message = Localizer["Message.Require.LinkText"];
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(_message))
|
||||
{
|
||||
var html = new StringBuilder();
|
||||
html.AppendFormat("<a href=\"{0}\"", _linkAttributes.Href);
|
||||
if (_blank)
|
||||
{
|
||||
html.Append(" target=\"_blank\"");
|
||||
}
|
||||
|
||||
html.AppendFormat(">{0}</a>", string.IsNullOrWhiteSpace(_linkAttributes.InnerText) ? _linkAttributes.InnerHtml : _linkAttributes.InnerText);
|
||||
|
||||
DialogService.Close(html.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
StateHasChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,13 +147,17 @@
|
||||
|
||||
private async Task OnExecute(HtmlEditorExecuteEventArgs args)
|
||||
{
|
||||
if (args.CommandName == "InsertImage")
|
||||
switch(args.CommandName)
|
||||
{
|
||||
await InsertImage(args.Editor);
|
||||
}
|
||||
else if (args.CommandName == "Settings")
|
||||
{
|
||||
await UpdateSettings(args.Editor);
|
||||
case "InsertImage":
|
||||
await InsertImage(args.Editor);
|
||||
break;
|
||||
case "InsertLink":
|
||||
await InsertLink(args.Editor);
|
||||
break;
|
||||
case "Settings":
|
||||
await UpdateSettings(args.Editor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +168,24 @@
|
||||
var result = await DialogService.OpenAsync<RadzenFileManagerDialog>(Localizer["DialogTitle.SelectImage"], new Dictionary<string, object>
|
||||
{
|
||||
{ "Filters", PageState.Site.ImageFiles }
|
||||
});
|
||||
}, new DialogOptions { CssClass = "rz-text-editor-dialog" });
|
||||
|
||||
await editor.RestoreSelectionAsync();
|
||||
|
||||
if (result != null)
|
||||
{
|
||||
await editor.ExecuteCommandAsync(HtmlEditorCommands.InsertHtml, result);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task InsertLink(RadzenHtmlEditor editor)
|
||||
{
|
||||
await editor.SaveSelectionAsync();
|
||||
|
||||
var result = await DialogService.OpenAsync<RadzenInsertLinkDialog>(Localizer["DialogTitle.InsertLink"], new Dictionary<string, object>
|
||||
{
|
||||
{ "Editor", editor }
|
||||
}, new DialogOptions { CssClass = "rz-text-editor-dialog" });
|
||||
|
||||
await editor.RestoreSelectionAsync();
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace Oqtane.Modules.Controls
|
||||
{ "InsertImage", (builder, sequence) => CreateFragment(builder, sequence, "InsertImage", "RadzenHtmlEditorCustomTool", "InsertImage", "image") },
|
||||
{ "Italic", (builder, sequence) => CreateFragment(builder, sequence, "Italic", "RadzenHtmlEditorItalic") },
|
||||
{ "Justify", (builder, sequence) => CreateFragment(builder, sequence, "Justify", "RadzenHtmlEditorJustify") },
|
||||
{ "Link", (builder, sequence) => CreateFragment(builder, sequence, "Link", "RadzenHtmlEditorLink") },
|
||||
{ "Link", (builder, sequence) => CreateFragment(builder, sequence, "InsertLink", "RadzenHtmlEditorCustomTool", "InsertLink", "insert_link") },
|
||||
{ "OrderedList", (builder, sequence) => CreateFragment(builder, sequence, "OrderedList", "RadzenHtmlEditorOrderedList") },
|
||||
{ "Outdent", (builder, sequence) => CreateFragment(builder, sequence, "Outdent", "RadzenHtmlEditorOutdent") },
|
||||
{ "Redo", (builder, sequence) => CreateFragment(builder, sequence, "Redo", "RadzenHtmlEditorRedo") },
|
||||
|
||||
@@ -1,22 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>6.2.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
<Description>CMS and Application Framework for Blazor and .NET MAUI</Description>
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
<IsPackable>true</IsPackable>
|
||||
<BlazorWebAssemblyLoadAllGlobalizationData>true</BlazorWebAssemblyLoadAllGlobalizationData>
|
||||
<StaticWebAssetProjectMode>Default</StaticWebAssetProjectMode>
|
||||
</PropertyGroup>
|
||||
@@ -26,7 +12,7 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Authentication" Version="9.0.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Localization" Version="9.0.9" />
|
||||
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.9" />
|
||||
<PackageReference Include="Radzen.Blazor" Version="7.3.5" />
|
||||
<PackageReference Include="Radzen.Blazor" Version="7.4.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -181,9 +181,9 @@
|
||||
<value>View License</value>
|
||||
</data>
|
||||
<data name="Theme.Heading" xml:space="preserve">
|
||||
<value>Themex</value>
|
||||
<value>Theme</value>
|
||||
</data>
|
||||
<data name="Permissions.Heading" xml:space="preserve">
|
||||
<value>Permissionsx</value>
|
||||
<value>Permissions</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -555,4 +555,10 @@
|
||||
<data name="CookieDomain.HelpText" xml:space="preserve">
|
||||
<value>If you would like to share cookies across subdomains you will need to specify a root domain with a leading dot (ie. '.example.com')</value>
|
||||
</data>
|
||||
<data name="SingleLogout.Text" xml:space="preserve">
|
||||
<value>Allow Single Logout?</value>
|
||||
</data>
|
||||
<data name="SingleLogout.HelpText" xml:space="preserve">
|
||||
<value>Specify if users should be logged out of both the application and provider (the default is false indicating they will only be logged out of the application)</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -216,4 +216,37 @@
|
||||
<data name="Reset" xml:space="preserve">
|
||||
<value>Reset</value>
|
||||
</data>
|
||||
<data name="InsertLink" xml:space="preserve">
|
||||
<value>Insert Link</value>
|
||||
</data>
|
||||
<data name="DialogTitle.InsertLink" xml:space="preserve">
|
||||
<value>Insert Link</value>
|
||||
</data>
|
||||
<data name="WebAddress" xml:space="preserve">
|
||||
<value>Enter Web Address</value>
|
||||
</data>
|
||||
<data name="LinkText" xml:space="preserve">
|
||||
<value>Enter Link Text</value>
|
||||
</data>
|
||||
<data name="OpenInNewWindow" xml:space="preserve">
|
||||
<value>Open In New Window</value>
|
||||
</data>
|
||||
<data name="WebLink" xml:space="preserve">
|
||||
<value>Web Link</value>
|
||||
</data>
|
||||
<data name="FileLink" xml:space="preserve">
|
||||
<value>File Link</value>
|
||||
</data>
|
||||
<data name="OpenInCurrentWindow" xml:space="preserve">
|
||||
<value>Open In Current Window</value>
|
||||
</data>
|
||||
<data name="Message.Require.WebAddress" xml:space="preserve">
|
||||
<value>The Web Address is Empty</value>
|
||||
</data>
|
||||
<data name="Message.Require.LinkText" xml:space="preserve">
|
||||
<value>The Link Text is Empty</value>
|
||||
</data>
|
||||
<data name="Message.Require.File" xml:space="preserve">
|
||||
<value>You Must Select a File</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -6,17 +6,6 @@
|
||||
<!-- <TargetFrameworks>net9.0-android;net9.0-ios;net9.0-maccatalyst</TargetFrameworks> -->
|
||||
<!-- <TargetFrameworks>$(TargetFrameworks);net9.0-tizen</TargetFrameworks> -->
|
||||
<OutputType>Exe</OutputType>
|
||||
<Version>6.2.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
<Description>Modular Application Framework for Blazor and MAUI</Description>
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane.Maui</RootNamespace>
|
||||
<UseMaui>true</UseMaui>
|
||||
<SingleProject>true</SingleProject>
|
||||
|
||||
@@ -286,3 +286,34 @@ app {
|
||||
top: 0;
|
||||
right: 5px;
|
||||
}
|
||||
|
||||
.app-modulemessage-toast {
|
||||
position: fixed;
|
||||
width: 350px;
|
||||
z-index: 1000;
|
||||
animation: slide-in 0.5s ease-out, slide-out 0.5s ease-in 5s forwards;
|
||||
}
|
||||
|
||||
@keyframes slide-in {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-out {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
1173
Oqtane.Maui/wwwroot/css/texteditors/quilljs/quill.bubble.css
Normal file
1173
Oqtane.Maui/wwwroot/css/texteditors/quilljs/quill.bubble.css
Normal file
File diff suppressed because it is too large
Load Diff
1170
Oqtane.Maui/wwwroot/css/texteditors/quilljs/quill.snow.css
Normal file
1170
Oqtane.Maui/wwwroot/css/texteditors/quilljs/quill.snow.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,42 @@
|
||||
.rz-text-editor {
|
||||
outline: none !important;
|
||||
}
|
||||
|
||||
.rz-html-editor-dropdown-items,
|
||||
.rz-popup,
|
||||
.rz-editor-dialog-wrapper {
|
||||
z-index: 9999 !important;
|
||||
}
|
||||
|
||||
.rz-html-editor-dropdown-items .rz-html-editor-dropdown-item,
|
||||
.rz-html-editor-dropdown-items .rz-html-editor-dropdown-item > * {
|
||||
color: var(--rz-editor-button-color);
|
||||
}
|
||||
.rz-text-editor .rz-html-editor-dropdown .rz-html-editor-dropdown-value,
|
||||
.rz-text-editor .rz-html-editor-dropdown .rz-html-editor-dropdown-trigger,
|
||||
.rz-text-editor .rz-html-editor-colorpicker .rz-html-editor-color {
|
||||
color: var(--rz-editor-button-color);
|
||||
}
|
||||
.rz-text-editor .rz-colorpicker.rz-state-disabled {
|
||||
border: none !important;
|
||||
}
|
||||
.rz-text-editor-dialog .rz-html-editor-dialog-item select{
|
||||
border: var(--rz-input-border);
|
||||
border-block-end: var(--rz-input-border-block-end);
|
||||
border-radius: var(--rz-input-border-radius);
|
||||
box-shadow: var(--rz-input-shadow);
|
||||
background-color: var(--rz-input-background-color);
|
||||
padding-block: var(--rz-input-padding-block);
|
||||
padding-inline: var(--rz-input-padding-inline);
|
||||
font-size: var(--rz-input-font-size);
|
||||
color: var(--rz-input-value-color);
|
||||
}
|
||||
.rz-text-editor-dialog .rz-html-editor-dialog-item select:hover, .rz-text-edit-dialog .rz-html-editor-dialog-item select:active {
|
||||
box-shadow: var(--rz-input-hover-shadow);
|
||||
background-color: var(--rz-input-hover-background-color);
|
||||
border: var(--rz-input-hover-border);
|
||||
border-block-end: var(--rz-input-hover-border-block-end);
|
||||
}
|
||||
.rz-text-editor-dialog .alert form{
|
||||
display: none;
|
||||
}
|
||||
BIN
Oqtane.Maui/wwwroot/images/disabled.png
Normal file
BIN
Oqtane.Maui/wwwroot/images/disabled.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 875 B |
1
Oqtane.Maui/wwwroot/js/texteditors/quilljs/quill-blot-formatter.min.js
vendored
Normal file
1
Oqtane.Maui/wwwroot/js/texteditors/quilljs/quill-blot-formatter.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
54
Oqtane.Maui/wwwroot/js/texteditors/quilljs/quill-interop.js
Normal file
54
Oqtane.Maui/wwwroot/js/texteditors/quilljs/quill-interop.js
Normal file
@@ -0,0 +1,54 @@
|
||||
var Oqtane = Oqtane || {};
|
||||
|
||||
Oqtane.RichTextEditor = {
|
||||
createQuill: async function (
|
||||
quillElement, toolBar, readOnly,
|
||||
placeholder, theme, debugLevel) {
|
||||
|
||||
Quill.register('modules/blotFormatter', QuillBlotFormatter.default);
|
||||
|
||||
var options = {
|
||||
debug: debugLevel,
|
||||
modules: {
|
||||
toolbar: toolBar,
|
||||
blotFormatter: {}
|
||||
},
|
||||
placeholder: placeholder,
|
||||
readOnly: readOnly,
|
||||
theme: theme
|
||||
};
|
||||
|
||||
new Quill(quillElement, options);
|
||||
},
|
||||
getQuillContent: function (editorElement) {
|
||||
return JSON.stringify(editorElement.__quill.getContents());
|
||||
},
|
||||
getQuillText: function (editorElement) {
|
||||
return editorElement.__quill.getText();
|
||||
},
|
||||
getQuillHTML: function (editorElement) {
|
||||
return editorElement.__quill.root.innerHTML;
|
||||
},
|
||||
loadQuillContent: function (editorElement, editorContent) {
|
||||
return editorElement.__quill.root.innerHTML = editorContent;
|
||||
},
|
||||
enableQuillEditor: function (editorElement, mode) {
|
||||
editorElement.__quill.enable(mode);
|
||||
},
|
||||
getCurrentCursor: function (quillElement) {
|
||||
var editorIndex = 0;
|
||||
if (quillElement.__quill.getSelection() !== null) {
|
||||
editorIndex = quillElement.__quill.getSelection().index;
|
||||
}
|
||||
return editorIndex;
|
||||
},
|
||||
insertQuillImage: function (quillElement, imageURL, altText, editorIndex) {
|
||||
var Delta = Quill.import('delta');
|
||||
|
||||
return quillElement.__quill.updateContents(
|
||||
new Delta()
|
||||
.retain(editorIndex)
|
||||
.insert({ image: imageURL },
|
||||
{ alt: altText }));
|
||||
}
|
||||
};
|
||||
8
Oqtane.Maui/wwwroot/js/texteditors/quilljs/quill.min.js
vendored
Normal file
8
Oqtane.Maui/wwwroot/js/texteditors/quilljs/quill.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
47
Oqtane.Maui/wwwroot/js/texteditors/radzen/radzen-interop.js
Normal file
47
Oqtane.Maui/wwwroot/js/texteditors/radzen/radzen-interop.js
Normal file
@@ -0,0 +1,47 @@
|
||||
var Oqtane = Oqtane || {};
|
||||
|
||||
Oqtane.RadzenTextEditor = {
|
||||
initialize: function (editor) {
|
||||
if (typeof Radzen.openPopup === "function" && Radzen.openPopup !== Oqtane.RadzenTextEditor.openPopup) {
|
||||
Oqtane.RadzenTextEditor.radzenOpenPopup = Radzen.openPopup;
|
||||
Radzen.openPopup = Oqtane.RadzenTextEditor.openPopup;
|
||||
}
|
||||
},
|
||||
openPopup: function () {
|
||||
Oqtane.RadzenTextEditor.radzenOpenPopup.apply(this, arguments);
|
||||
var id = arguments[1];
|
||||
var popup = document.getElementById(id);
|
||||
if (popup) {
|
||||
Oqtane.RadzenTextEditor.updateButtonStyles(popup);
|
||||
}
|
||||
},
|
||||
setBackgroundColor: function (editor, color) {
|
||||
editor.getElementsByClassName("rz-html-editor-content")[0].style.backgroundColor = color;
|
||||
},
|
||||
updateDialogLayout: function (editor) {
|
||||
var dialogs = editor.parentElement.getElementsByClassName('rz-dialog-wrapper');
|
||||
for (var dialog of dialogs) {
|
||||
document.body.appendChild(dialog);
|
||||
dialog.classList.add('rz-editor-dialog-wrapper', 'text-dark');
|
||||
|
||||
this.updateButtonStyles(dialog);
|
||||
}
|
||||
},
|
||||
updateButtonStyles: function (parent) {
|
||||
var primaryBtns = parent.getElementsByClassName('rz-primary');
|
||||
if (primaryBtns) {
|
||||
for (var btn of primaryBtns) {
|
||||
btn.classList.remove('rz-button', 'rz-primary');
|
||||
btn.classList.add('btn', 'btn-primary');
|
||||
}
|
||||
}
|
||||
|
||||
var secondaryBtns = parent.getElementsByClassName('rz-secondary');
|
||||
if (secondaryBtns) {
|
||||
for (var btn of secondaryBtns) {
|
||||
btn.classList.remove('rz-button', 'rz-secondary');
|
||||
btn.classList.add('btn', 'btn-secondary');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 72 KiB |
@@ -1,3 +0,0 @@
|
||||
nuget.exe pack ..\Oqtane.Application\Oqtane.Application.Template.nuspec -NoDefaultExcludes
|
||||
pause
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<dependency id="Microsoft.AspNetCore.Components.WebAssembly.Authentication" version="9.0.9" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.Extensions.Http" version="9.0.9" exclude="Build,Analyzers" />
|
||||
<dependency id="Microsoft.Extensions.Localization" version="9.0.9" exclude="Build,Analyzers" />
|
||||
<dependency id="Radzen.Blazor" version="7.3.5" exclude="Build,Analyzers" />
|
||||
<dependency id="Radzen.Blazor" version="7.4.3" exclude="Build,Analyzers" />
|
||||
</group>
|
||||
</dependencies>
|
||||
</metadata>
|
||||
|
||||
@@ -28,8 +28,8 @@
|
||||
<dependency id="Microsoft.AspNetCore.Authentication.OpenIdConnect" version="9.0.9" exclude="Build,Analyzers" />
|
||||
<dependency id="SixLabors.ImageSharp" version="3.1.11" exclude="Build,Analyzers" />
|
||||
<dependency id="HtmlAgilityPack" version="1.12.3" exclude="Build,Analyzers" />
|
||||
<dependency id="Swashbuckle.AspNetCore" version="9.0.4" exclude="Build,Analyzers" />
|
||||
<dependency id="MailKit" version="4.13.0" exclude="Build,Analyzers" />
|
||||
<dependency id="Swashbuckle.AspNetCore" version="9.0.5" exclude="Build,Analyzers" />
|
||||
<dependency id="MailKit" version="4.14.0" exclude="Build,Analyzers" />
|
||||
<dependency id="MySql.Data" version="9.4.0" exclude="Build,Analyzers" />
|
||||
<dependency id="Pomelo.EntityFrameworkCore.MySql" version="9.0.0" exclude="Build,Analyzers" />
|
||||
<dependency id="EFCore.NamingConventions" version="9.0.0" exclude="Build,Analyzers" />
|
||||
@@ -55,7 +55,7 @@
|
||||
<file src="..\Oqtane.Server\obj\Release\net9.0\staticwebassets\msbuild.build.Oqtane.Server.props" target="build\Oqtane.Server.props" />
|
||||
<file src="..\Oqtane.Server\obj\Release\net9.0\staticwebassets\msbuild.buildMultiTargeting.Oqtane.Server.props" target="buildMultiTargeting\Oqtane.Server.props" />
|
||||
<file src="..\Oqtane.Server\obj\Release\net9.0\staticwebassets\msbuild.buildTransitive.Oqtane.Server.props" target="buildTransitive\Oqtane.Server.props" />
|
||||
<file src="..\Oqtane.Server\wwwroot\**\*" target="staticwebassets" />
|
||||
<file src="..\Oqtane.Server\wwwroot\**\*" exclude="..\Oqtane.Server\wwwroot\Modules\Templates\**;..\Oqtane.Server\wwwroot\Themes\Templates\**" target="staticwebassets" />
|
||||
<file src="icon.png" target="" />
|
||||
<file src="readme.md" target="" />
|
||||
</files>
|
||||
|
||||
@@ -23,9 +23,9 @@ C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\install.ps1"
|
||||
del "..\Oqtane.Server\bin\Release\net9.0\publish\appsettings.json"
|
||||
del "..\Oqtane.Server\bin\Release\net9.0\publish\web.config"
|
||||
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe ".\upgrade.ps1"
|
||||
dotnet clean -c Release ..\Oqtane.Updater.sln
|
||||
dotnet build -c Release ..\Oqtane.Updater.sln
|
||||
dotnet publish ..\Oqtane.Updater\Oqtane.Updater.csproj /p:Configuration=Release
|
||||
nuget.exe pack Oqtane.Updater.nuspec
|
||||
nuget.exe pack ..\Oqtane.Application\Oqtane.Application.Template.nuspec -NoDefaultExcludes
|
||||
pause
|
||||
|
||||
|
||||
@@ -1,19 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>6.2.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
<Description>CMS and Application Framework for Blazor and .NET MAUI</Description>
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
<IsPackable>true</IsPackable>
|
||||
<DefineConstants>$(DefineConstants);OQTANE</DefineConstants>
|
||||
@@ -49,8 +36,8 @@
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.OpenIdConnect" Version="9.0.9" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.11" />
|
||||
<PackageReference Include="HtmlAgilityPack" Version="1.12.3" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.4" />
|
||||
<PackageReference Include="MailKit" Version="4.13.0" />
|
||||
<PackageReference Include="Swashbuckle.AspNetCore" Version="9.0.5" />
|
||||
<PackageReference Include="MailKit" Version="4.14.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
@@ -8,6 +11,7 @@ using Oqtane.Extensions;
|
||||
using Oqtane.Infrastructure;
|
||||
using Oqtane.Managers;
|
||||
using Oqtane.Shared;
|
||||
using Radzen.Blazor.Markdown;
|
||||
|
||||
namespace Oqtane.Pages
|
||||
{
|
||||
@@ -28,6 +32,9 @@ namespace Oqtane.Pages
|
||||
|
||||
public async Task<IActionResult> OnPostAsync(string returnurl, string everywhere)
|
||||
{
|
||||
returnurl = (returnurl == null) ? "/" : returnurl;
|
||||
returnurl = (!returnurl.StartsWith("/")) ? "/" + returnurl : returnurl;
|
||||
|
||||
if (HttpContext.User != null)
|
||||
{
|
||||
var alias = HttpContext.GetAlias();
|
||||
@@ -43,13 +50,25 @@ namespace Oqtane.Pages
|
||||
_logger.Log(LogLevel.Information, this, LogFunction.Security, "User Logout For Username {Username}", user.Username);
|
||||
}
|
||||
|
||||
await HttpContext.SignOutAsync(Constants.AuthenticationScheme);
|
||||
var authenticationProperties = new AuthenticationProperties
|
||||
{
|
||||
RedirectUri = returnurl
|
||||
};
|
||||
|
||||
var authenticationSchemes = new List<string>();
|
||||
authenticationSchemes.Add(Constants.AuthenticationScheme);
|
||||
if (HttpContext.GetSiteSettings().GetValue("ExternalLogin:ProviderType", "") == AuthenticationProviderTypes.OpenIDConnect &&
|
||||
HttpContext.GetSiteSettings().GetValue("ExternalLogin:SingleLogout", "false") == "true")
|
||||
{
|
||||
authenticationSchemes.Add(AuthenticationProviderTypes.OpenIDConnect);
|
||||
}
|
||||
|
||||
return SignOut(authenticationProperties, authenticationSchemes.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
return LocalRedirect(Url.Content("~" + returnurl));
|
||||
}
|
||||
|
||||
returnurl = (returnurl == null) ? "/" : returnurl;
|
||||
returnurl = (!returnurl.StartsWith("/")) ? "/" + returnurl : returnurl;
|
||||
|
||||
return LocalRedirect(Url.Content("~" + returnurl));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,4 +19,24 @@
|
||||
}
|
||||
.rz-text-editor .rz-colorpicker.rz-state-disabled {
|
||||
border: none !important;
|
||||
}
|
||||
.rz-text-editor-dialog .rz-html-editor-dialog-item select{
|
||||
border: var(--rz-input-border);
|
||||
border-block-end: var(--rz-input-border-block-end);
|
||||
border-radius: var(--rz-input-border-radius);
|
||||
box-shadow: var(--rz-input-shadow);
|
||||
background-color: var(--rz-input-background-color);
|
||||
padding-block: var(--rz-input-padding-block);
|
||||
padding-inline: var(--rz-input-padding-inline);
|
||||
font-size: var(--rz-input-font-size);
|
||||
color: var(--rz-input-value-color);
|
||||
}
|
||||
.rz-text-editor-dialog .rz-html-editor-dialog-item select:hover, .rz-text-edit-dialog .rz-html-editor-dialog-item select:active {
|
||||
box-shadow: var(--rz-input-hover-shadow);
|
||||
background-color: var(--rz-input-hover-background-color);
|
||||
border: var(--rz-input-hover-border);
|
||||
border-block-end: var(--rz-input-hover-border-block-end);
|
||||
}
|
||||
.rz-text-editor-dialog .alert form{
|
||||
display: none;
|
||||
}
|
||||
@@ -1,21 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Configurations>Debug;Release</Configurations>
|
||||
<Version>6.2.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
<Description>CMS and Application Framework for Blazor and .NET MAUI</Description>
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
<IsPackable>true</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<OutputType>Exe</OutputType>
|
||||
<Version>6.2.1</Version>
|
||||
<Product>Oqtane</Product>
|
||||
<Authors>Shaun Walker</Authors>
|
||||
<Company>.NET Foundation</Company>
|
||||
<Description>Modular Application Framework for Blazor and MAUI</Description>
|
||||
<Copyright>.NET Foundation</Copyright>
|
||||
<PackageProjectUrl>https://www.oqtane.org</PackageProjectUrl>
|
||||
<PackageLicenseUrl>https://github.com/oqtane/oqtane.framework/blob/dev/LICENSE</PackageLicenseUrl>
|
||||
<PackageReleaseNotes>https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1</PackageReleaseNotes>
|
||||
<RepositoryUrl>https://github.com/oqtane/oqtane.framework</RepositoryUrl>
|
||||
<RepositoryType>Git</RepositoryType>
|
||||
<RootNamespace>Oqtane</RootNamespace>
|
||||
<IsPackable>false</IsPackable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
11
README.md
11
README.md
@@ -12,7 +12,7 @@ Oqtane is being developed based on some fundamental principles which are outline
|
||||
|
||||
# Latest Release
|
||||
|
||||
[6.2.0](https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.0) was released on September 9, 2025 and is a major release including 57 pull requests by 4 different contributors, pushing the total number of project commits all-time over 7000. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
|
||||
[6.2.1](https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1) was released on September 29, 2025 and is a maintenance release including 65 pull requests by 6 different contributors, pushing the total number of project commits all-time over 7100. The Oqtane framework continues to evolve at a rapid pace to meet the needs of .NET developers.
|
||||
|
||||
# Try It Now!
|
||||
|
||||
@@ -35,20 +35,18 @@ cd Server
|
||||
dotnet run
|
||||
```
|
||||
|
||||
- Browse to http://localhost:5001 to run the application (the Install Wizard will be displayed the first time)
|
||||
- Browse to http://localhost:5001 to run the application (an Installation Wizard screen will be displayed the first time you run the application)
|
||||
- To develop/debug the application, open the MyCompany.MyProject.sln file in the root folder and hit F5
|
||||
|
||||
**Installing using source code from the Dev/Master branch:**
|
||||
|
||||
- Install **[.NET 9.0.9 SDK](https://dotnet.microsoft.com/en-us/download)**.
|
||||
- Install Latest **[.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download)**.
|
||||
|
||||
- Install the latest edition (v17.12 or higher) of [Visual Studio 2022](https://visualstudio.microsoft.com/downloads) with the **ASP.NET and web development** workload enabled. Oqtane works with ALL editions of Visual Studio from Community to Enterprise. If you wish to use LocalDB for development ( not a requirement as Oqtane supports SQLite, mySQL, and PostgreSQL ) you must also install the **Data storage and processing**.
|
||||
|
||||
- Clone (or download) the Oqtane Master or Dev branch source code to your local system.
|
||||
|
||||
- Open the **Oqtane.sln** solution file.
|
||||
|
||||
- **Important:** Rebuild the entire solution before running it (ie. Build / Rebuild Solution).
|
||||
|
||||
- Make sure you specify Oqtane.Server as the Startup Project.
|
||||
|
||||
@@ -106,6 +104,9 @@ Connect with other developers, get support, and share ideas by joining the Oqtan
|
||||
# Roadmap
|
||||
This project is open source, and therefore is a work in progress...
|
||||
|
||||
[6.2.1](https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.1) (Sep 29, 2025)
|
||||
- [x] Stabilization improvements
|
||||
|
||||
[6.2.0](https://github.com/oqtane/oqtane.framework/releases/tag/v6.2.0) (Sep 9, 2025)
|
||||
- [x] Oqtane Application Template
|
||||
- [x] Radzen Text Editor
|
||||
|
||||
@@ -220,7 +220,7 @@
|
||||
"apiVersion": "2024-04-01",
|
||||
"name": "[concat(parameters('BlazorWebsiteName'), '/ZipDeploy')]",
|
||||
"properties": {
|
||||
"packageUri": "https://github.com/oqtane/oqtane.framework/releases/download/v6.2.0/Oqtane.Framework.6.2.0.Install.zip"
|
||||
"packageUri": "https://github.com/oqtane/oqtane.framework/releases/download/v6.2.1/Oqtane.Framework.6.2.1.Install.zip"
|
||||
},
|
||||
"dependsOn": [
|
||||
"[resourceId('Microsoft.Web/sites', parameters('BlazorWebsiteName'))]"
|
||||
|
||||
Reference in New Issue
Block a user