diff --git a/Oqtane.Client/Modules/Admin/Pages/Edit.razor b/Oqtane.Client/Modules/Admin/Pages/Edit.razor
index 5f2a8536..d2edd289 100644
--- a/Oqtane.Client/Modules/Admin/Pages/Edit.razor
+++ b/Oqtane.Client/Modules/Admin/Pages/Edit.razor
@@ -384,21 +384,24 @@
private void ThemeSettings()
{
_themeSettingsType = null;
- var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
- if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
- {
- _themeSettingsType = Type.GetType(theme.ThemeSettingsType);
- if (_themeSettingsType != null)
- {
- ThemeSettingsComponent = builder =>
- {
- builder.OpenComponent(0, _themeSettingsType);
- builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
- builder.CloseComponent();
- };
- }
- _refresh = true;
- }
+ if (PageState.QueryString.ContainsKey("cp")) // can only be displayed if invoked from Control Panel
+ {
+ var theme = _themeList.FirstOrDefault(item => item.Themes.Any(themecontrol => themecontrol.TypeName.Equals(_themetype)));
+ if (theme != null && !string.IsNullOrEmpty(theme.ThemeSettingsType))
+ {
+ _themeSettingsType = Type.GetType(theme.ThemeSettingsType);
+ if (_themeSettingsType != null)
+ {
+ ThemeSettingsComponent = builder =>
+ {
+ builder.OpenComponent(0, _themeSettingsType);
+ builder.AddComponentReferenceCapture(1, inst => { _themeSettings = Convert.ChangeType(inst, _themeSettingsType); });
+ builder.CloseComponent();
+ };
+ }
+ _refresh = true;
+ }
+ }
}
private async Task SavePage()
diff --git a/Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor b/Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor
index 24a5da86..a2d9ba7c 100644
--- a/Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor
+++ b/Oqtane.Client/Themes/Controls/Container/ModuleTitle.razor
@@ -3,7 +3,9 @@
@attribute [OqtaneIgnore]
- @((MarkupString)title)
+
+ @((MarkupString)title)
+
@code {
diff --git a/Oqtane.Client/UI/Interop.cs b/Oqtane.Client/UI/Interop.cs
index 28b72307..43325047 100644
--- a/Oqtane.Client/UI/Interop.cs
+++ b/Oqtane.Client/UI/Interop.cs
@@ -279,5 +279,19 @@ namespace Oqtane.UI
}
}
+ public Task ScrollToId(string id)
+ {
+ try
+ {
+ _jsRuntime.InvokeVoidAsync(
+ "Oqtane.Interop.scrollToId",
+ id);
+ return Task.CompletedTask;
+ }
+ catch
+ {
+ return Task.CompletedTask;
+ }
+ }
}
}
diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor
index 360ff6a1..ad520fb5 100644
--- a/Oqtane.Client/UI/SiteRouter.razor
+++ b/Oqtane.Client/UI/SiteRouter.razor
@@ -11,6 +11,7 @@
@inject IModuleService ModuleService
@inject IUrlMappingService UrlMappingService
@inject ILogService LogService
+@inject IJSRuntime JSRuntime
@implements IHandleAfterRender
@DynamicComponent
@@ -234,6 +235,7 @@
};
OnStateChange?.Invoke(_pagestate);
+ await ScrollToFragment(_pagestate.Uri);
}
}
else // page not found
@@ -242,7 +244,7 @@
var urlMapping = await UrlMappingService.GetUrlMappingAsync(site.SiteId, route.PagePath);
if (urlMapping != null && !string.IsNullOrEmpty(urlMapping.MappedUrl))
{
- var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl;
+ var url = (urlMapping.MappedUrl.StartsWith("http")) ? urlMapping.MappedUrl : route.SiteUrl + "/" + urlMapping.MappedUrl;
NavigationManager.NavigateTo(url, false);
}
else // not mapped
@@ -262,238 +264,259 @@
}
}
}
- }
+ }
+ }
+ else
+ {
+ // site does not exist
+ }
+ }
+
+ private async void LocationChanged(object sender, LocationChangedEventArgs args)
+ {
+ _absoluteUri = args.Location;
+ await Refresh();
+ }
+
+ Task IHandleAfterRender.OnAfterRenderAsync()
+ {
+ if (!_navigationInterceptionEnabled)
+ {
+ _navigationInterceptionEnabled = true;
+ return NavigationInterception.EnableNavigationInterceptionAsync();
+ }
+ return Task.CompletedTask;
+ }
+
+ private Dictionary ParseQueryString(string query)
+ {
+ Dictionary querystring = new Dictionary(StringComparer.OrdinalIgnoreCase); // case insensistive keys
+ if (!string.IsNullOrEmpty(query))
+ {
+ if (query.StartsWith("?"))
+ {
+ query = query.Substring(1); // ignore "?"
+ }
+ foreach (string kvp in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ if (kvp != "")
+ {
+ if (kvp.Contains("="))
+ {
+ string[] pair = kvp.Split('=');
+ querystring.Add(pair[0], pair[1]);
+ }
+ else
+ {
+ querystring.Add(kvp, "true"); // default parameter when no value is provided
+ }
+ }
+ }
+ }
+ return querystring;
+ }
+
+ private async Task ProcessPage(Page page, Site site, User user)
+ {
+ try
+ {
+ if (page.IsPersonalizable && user != null)
+ {
+ // load the personalized page
+ page = await PageService.GetPageAsync(page.PageId, user.UserId);
+ }
+
+ if (string.IsNullOrEmpty(page.ThemeType))
+ {
+ page.ThemeType = site.DefaultThemeType;
+ }
+
+ page.Panes = new List();
+ page.Resources = new List();
+
+ string panes = PaneNames.Admin;
+ Type themetype = Type.GetType(page.ThemeType);
+ if (themetype == null)
+ {
+ // fallback
+ page.ThemeType = Constants.DefaultTheme;
+ themetype = Type.GetType(Constants.DefaultTheme);
+ }
+ if (themetype != null)
+ {
+ var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
+ if (themeobject != null)
+ {
+ if (!string.IsNullOrEmpty(themeobject.Panes))
+ {
+ panes = themeobject.Panes;
+ }
+ page.Resources = ManagePageResources(page.Resources, themeobject.Resources);
+ }
+ }
+ page.Panes = panes.Replace(";", ",").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
+ }
+ catch
+ {
+ // error loading theme or layout
+ }
+
+ return page;
+ }
+
+ private (Page Page, List Modules) ProcessModules(Page page, List modules, int moduleid, string action, string defaultcontainertype)
+ {
+ var paneindex = new Dictionary();
+ foreach (Module module in modules)
+ {
+ // initialize module control properties
+ module.SecurityAccessLevel = SecurityAccessLevel.Host;
+ module.ControlTitle = "";
+ module.Actions = "";
+ module.UseAdminContainer = false;
+ module.PaneModuleIndex = -1;
+ module.PaneModuleCount = 0;
+
+ if ((module.PageId == page.PageId || module.ModuleId == moduleid))
+ {
+ var typename = Constants.ErrorModule;
+ if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime)))
+ {
+ typename = module.ModuleDefinition.ControlTypeTemplate;
+
+ // handle default action
+ if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
+ {
+ action = module.ModuleDefinition.DefaultAction;
+ }
+
+ // check if the module defines custom action routes
+ if (module.ModuleDefinition.ControlTypeRoutes != "")
+ {
+ foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
+ {
+ if (route.StartsWith(action + "="))
+ {
+ typename = route.Replace(action + "=", "");
+ }
+ }
+ }
+ }
+
+ // ensure component exists and implements IModuleControl
+ module.ModuleType = "";
+ if (Constants.DefaultModuleActions.Contains(action, StringComparer.OrdinalIgnoreCase))
+ {
+ typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, action);
+ }
+ else
+ {
+ typename = typename.Replace(Constants.ActionToken, action);
+ }
+ Type moduletype = Type.GetType(typename, false, true); // case insensitive
+ if (moduletype != null && moduletype.GetInterfaces().Contains(typeof(IModuleControl)))
+ {
+ module.ModuleType = Utilities.GetFullTypeName(moduletype.AssemblyQualifiedName); // get actual type name
+ }
+
+ // get additional metadata from IModuleControl interface
+ if (moduletype != null && module.ModuleType != "")
+ {
+ // retrieve module component resources
+ var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
+ page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
+ if (action.ToLower() == "settings" && module.ModuleDefinition != null)
+ {
+ // settings components are embedded within a framework settings module
+ moduletype = Type.GetType(module.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, action), false, true);
+ if (moduletype != null)
+ {
+ moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
+ page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
+ }
+ }
+
+ // additional metadata needed for admin components
+ if (module.ModuleId == moduleid && action != "")
+ {
+ module.SecurityAccessLevel = moduleobject.SecurityAccessLevel;
+ module.ControlTitle = moduleobject.Title;
+ module.Actions = moduleobject.Actions;
+ module.UseAdminContainer = moduleobject.UseAdminContainer;
+ }
+ }
+
+ // ensure module's pane exists in current page and if not, assign it to the Admin pane
+ if (page.Panes == null || page.Panes.FindIndex(item => item.Equals(module.Pane, StringComparison.OrdinalIgnoreCase)) == -1)
+ {
+ module.Pane = PaneNames.Admin;
+ }
+
+ // calculate module position within pane
+ if (paneindex.ContainsKey(module.Pane.ToLower()))
+ {
+ paneindex[module.Pane.ToLower()] += 1;
+ }
+ else
+ {
+ paneindex.Add(module.Pane.ToLower(), 0);
+ }
+
+ module.PaneModuleIndex = paneindex[module.Pane.ToLower()];
+
+ // container fallback
+ if (string.IsNullOrEmpty(module.ContainerType))
+ {
+ module.ContainerType = defaultcontainertype;
+ }
+ }
+ }
+
+ foreach (Module module in modules.Where(item => item.PageId == page.PageId))
+ {
+ if (paneindex.ContainsKey(module.Pane.ToLower()))
+ {
+ module.PaneModuleCount = paneindex[module.Pane.ToLower()] + 1;
+ }
+ }
+
+ return (page, modules);
+ }
+
+ private List ManagePageResources(List pageresources, List resources)
+ {
+ if (resources != null)
+ {
+ foreach (var resource in resources)
+ {
+ // ensure resource does not exist already
+ if (pageresources.Find(item => item.Url == resource.Url) == null)
+ {
+ pageresources.Add(resource);
+ }
+ }
+ }
+ return pageresources;
+ }
+
+ private async Task ScrollToFragment(Uri uri)
+ {
+ var fragment = uri.Fragment;
+ if (fragment.StartsWith('#'))
+ {
+ // handle text fragment (https://example.org/#test:~:text=foo)
+ var id = fragment.Substring(1);
+ var index = id.IndexOf(":~:", StringComparison.Ordinal);
+ if (index > 0)
+ {
+ id = id.Substring(0, index);
+ }
+
+ if (!string.IsNullOrEmpty(id))
+ {
+ var interop = new Interop(JSRuntime);
+ await interop.ScrollToId(id);
+ }
}
- else
- {
- // site does not exist
- }
- }
-
- private async void LocationChanged(object sender, LocationChangedEventArgs args)
- {
- _absoluteUri = args.Location;
- await Refresh();
- }
-
- Task IHandleAfterRender.OnAfterRenderAsync()
- {
- if (!_navigationInterceptionEnabled)
- {
- _navigationInterceptionEnabled = true;
- return NavigationInterception.EnableNavigationInterceptionAsync();
- }
- return Task.CompletedTask;
- }
-
- private Dictionary ParseQueryString(string query)
- {
- Dictionary querystring = new Dictionary(StringComparer.OrdinalIgnoreCase); // case insensistive keys
- if (!string.IsNullOrEmpty(query))
- {
- if (query.StartsWith("?"))
- {
- query = query.Substring(1); // ignore "?"
- }
- foreach (string kvp in query.Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
- {
- if (kvp != "")
- {
- if (kvp.Contains("="))
- {
- string[] pair = kvp.Split('=');
- querystring.Add(pair[0], pair[1]);
- }
- else
- {
- querystring.Add(kvp, "true"); // default parameter when no value is provided
- }
- }
- }
- }
- return querystring;
- }
-
- private async Task ProcessPage(Page page, Site site, User user)
- {
- try
- {
- if (page.IsPersonalizable && user != null)
- {
- // load the personalized page
- page = await PageService.GetPageAsync(page.PageId, user.UserId);
- }
-
- if (string.IsNullOrEmpty(page.ThemeType))
- {
- page.ThemeType = site.DefaultThemeType;
- }
-
- page.Panes = new List();
- page.Resources = new List();
-
- string panes = PaneNames.Admin;
- Type themetype = Type.GetType(page.ThemeType);
- if (themetype == null)
- {
- // fallback
- page.ThemeType = Constants.DefaultTheme;
- themetype = Type.GetType(Constants.DefaultTheme);
- }
- if (themetype != null)
- {
- var themeobject = Activator.CreateInstance(themetype) as IThemeControl;
- if (themeobject != null)
- {
- if (!string.IsNullOrEmpty(themeobject.Panes))
- {
- panes = themeobject.Panes;
- }
- page.Resources = ManagePageResources(page.Resources, themeobject.Resources);
- }
- }
- page.Panes = panes.Replace(";", ",").Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).ToList();
- }
- catch
- {
- // error loading theme or layout
- }
-
- return page;
- }
-
- private (Page Page, List Modules) ProcessModules(Page page, List modules, int moduleid, string action, string defaultcontainertype)
- {
- var paneindex = new Dictionary();
- foreach (Module module in modules)
- {
- // initialize module control properties
- module.SecurityAccessLevel = SecurityAccessLevel.Host;
- module.ControlTitle = "";
- module.Actions = "";
- module.UseAdminContainer = false;
- module.PaneModuleIndex = -1;
- module.PaneModuleCount = 0;
-
- if ((module.PageId == page.PageId || module.ModuleId == moduleid))
- {
- var typename = Constants.ErrorModule;
- if (module.ModuleDefinition != null && (module.ModuleDefinition.Runtimes == "" || module.ModuleDefinition.Runtimes.Contains(Runtime)))
- {
- typename = module.ModuleDefinition.ControlTypeTemplate;
-
- // handle default action
- if (action == Constants.DefaultAction && !string.IsNullOrEmpty(module.ModuleDefinition.DefaultAction))
- {
- action = module.ModuleDefinition.DefaultAction;
- }
-
- // check if the module defines custom action routes
- if (module.ModuleDefinition.ControlTypeRoutes != "")
- {
- foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
- {
- if (route.StartsWith(action + "="))
- {
- typename = route.Replace(action + "=", "");
- }
- }
- }
- }
-
- // ensure component exists and implements IModuleControl
- module.ModuleType = "";
- if (Constants.DefaultModuleActions.Contains(action, StringComparer.OrdinalIgnoreCase))
- {
- typename = Constants.DefaultModuleActionsTemplate.Replace(Constants.ActionToken, action);
- }
- else
- {
- typename = typename.Replace(Constants.ActionToken, action);
- }
- Type moduletype = Type.GetType(typename, false, true); // case insensitive
- if (moduletype != null && moduletype.GetInterfaces().Contains(typeof(IModuleControl)))
- {
- module.ModuleType = Utilities.GetFullTypeName(moduletype.AssemblyQualifiedName); // get actual type name
- }
-
- // get additional metadata from IModuleControl interface
- if (moduletype != null && module.ModuleType != "")
- {
- // retrieve module component resources
- var moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
- page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
- if (action.ToLower() == "settings" && module.ModuleDefinition != null)
- {
- // settings components are embedded within a framework settings module
- moduletype = Type.GetType(module.ModuleDefinition.ControlTypeTemplate.Replace(Constants.ActionToken, action), false, true);
- if (moduletype != null)
- {
- moduleobject = Activator.CreateInstance(moduletype) as IModuleControl;
- page.Resources = ManagePageResources(page.Resources, moduleobject.Resources);
- }
- }
-
- // additional metadata needed for admin components
- if (module.ModuleId == moduleid && action != "")
- {
- module.SecurityAccessLevel = moduleobject.SecurityAccessLevel;
- module.ControlTitle = moduleobject.Title;
- module.Actions = moduleobject.Actions;
- module.UseAdminContainer = moduleobject.UseAdminContainer;
- }
- }
-
- // ensure module's pane exists in current page and if not, assign it to the Admin pane
- if (page.Panes == null || page.Panes.FindIndex(item => item.Equals(module.Pane, StringComparison.OrdinalIgnoreCase)) == -1)
- {
- module.Pane = PaneNames.Admin;
- }
-
- // calculate module position within pane
- if (paneindex.ContainsKey(module.Pane.ToLower()))
- {
- paneindex[module.Pane.ToLower()] += 1;
- }
- else
- {
- paneindex.Add(module.Pane.ToLower(), 0);
- }
-
- module.PaneModuleIndex = paneindex[module.Pane.ToLower()];
-
- // container fallback
- if (string.IsNullOrEmpty(module.ContainerType))
- {
- module.ContainerType = defaultcontainertype;
- }
- }
- }
-
- foreach (Module module in modules.Where(item => item.PageId == page.PageId))
- {
- if (paneindex.ContainsKey(module.Pane.ToLower()))
- {
- module.PaneModuleCount = paneindex[module.Pane.ToLower()] + 1;
- }
- }
-
- return (page, modules);
- }
-
- private List ManagePageResources(List pageresources, List resources)
- {
- if (resources != null)
- {
- foreach (var resource in resources)
- {
- // ensure resource does not exist already
- if (pageresources.Find(item => item.Url == resource.Url) == null)
- {
- pageresources.Add(resource);
- }
- }
- }
- return pageresources;
}
}
diff --git a/Oqtane.Server/Pages/_Host.cshtml b/Oqtane.Server/Pages/_Host.cshtml
index 9d562067..0185a5c2 100644
--- a/Oqtane.Server/Pages/_Host.cshtml
+++ b/Oqtane.Server/Pages/_Host.cshtml
@@ -3,7 +3,7 @@
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@model Oqtane.Pages.HostModel
-
+
diff --git a/Oqtane.Server/Pages/_Host.cshtml.cs b/Oqtane.Server/Pages/_Host.cshtml.cs
index 1d9004de..1a882402 100644
--- a/Oqtane.Server/Pages/_Host.cshtml.cs
+++ b/Oqtane.Server/Pages/_Host.cshtml.cs
@@ -52,6 +52,7 @@ namespace Oqtane.Pages
_settings = settings;
}
+ public string Language = "en";
public string AntiForgeryToken = "";
public string Runtime = "Server";
public RenderMode RenderMode = RenderMode.Server;
@@ -174,19 +175,29 @@ namespace Oqtane.Pages
}
// set culture if not specified
- if (HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName] == null)
+ string culture = HttpContext.Request.Cookies[CookieRequestCultureProvider.DefaultCookieName];
+ if (culture == null)
{
- // set default language for site if the culture is not supported
+ // get default language for site
var languages = _languages.GetLanguages(alias.SiteId);
- if (languages.Any() && languages.All(l => l.Code != CultureInfo.CurrentUICulture.Name))
+ if (languages.Any())
{
- var defaultLanguage = languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First();
- SetLocalizationCookie(defaultLanguage.Code);
+ // use default language if specified otherwise use first language in collection
+ culture = (languages.Where(l => l.IsDefault).SingleOrDefault() ?? languages.First()).Code;
}
else
{
- SetLocalizationCookie(_localizationManager.GetDefaultCulture());
+ culture = _localizationManager.GetDefaultCulture();
}
+ SetLocalizationCookie(culture);
+ }
+
+ // set language for page
+ if (!string.IsNullOrEmpty(culture))
+ {
+ // localization cookie value in form of c=en|uic=en
+ Language = culture.Split('|')[0];
+ Language = Language.Replace("c=", "");
}
}
}
diff --git a/Oqtane.Server/Repository/ThemeRepository.cs b/Oqtane.Server/Repository/ThemeRepository.cs
index 1b3b4e77..7f72eb9c 100644
--- a/Oqtane.Server/Repository/ThemeRepository.cs
+++ b/Oqtane.Server/Repository/ThemeRepository.cs
@@ -125,15 +125,18 @@ namespace Oqtane.Repository
foreach (Type containertype in containertypes)
{
var containerobject = Activator.CreateInstance(containertype) as IThemeControl;
- theme.Containers.Add(
- new ThemeControl
- {
- TypeName = containertype.FullName + ", " + themeControlType.Assembly.GetName().Name,
- Name = (string.IsNullOrEmpty(containerobject.Name)) ? Utilities.GetTypeNameLastSegment(containertype.FullName, 0) : containerobject.Name,
- Thumbnail = containerobject.Thumbnail,
- Panes = ""
- }
- );
+ if (theme.Containers.FirstOrDefault(item => item.TypeName == containertype.FullName + ", " + themeControlType.Assembly.GetName().Name) == null)
+ {
+ theme.Containers.Add(
+ new ThemeControl
+ {
+ TypeName = containertype.FullName + ", " + themeControlType.Assembly.GetName().Name,
+ Name = (string.IsNullOrEmpty(containerobject.Name)) ? Utilities.GetTypeNameLastSegment(containertype.FullName, 0) : containerobject.Name,
+ Thumbnail = containerobject.Thumbnail,
+ Panes = ""
+ }
+ );
+ }
}
themes[index] = theme;
diff --git a/Oqtane.Server/wwwroot/css/app.css b/Oqtane.Server/wwwroot/css/app.css
index a3559989..5da25ceb 100644
--- a/Oqtane.Server/wwwroot/css/app.css
+++ b/Oqtane.Server/wwwroot/css/app.css
@@ -126,6 +126,10 @@ app {
margin-bottom: 15px;
}
+.app-moduletitle a {
+ scroll-margin-top: 7rem;
+}
+
/* Tooltips */
.app-tooltip {
cursor: help;
diff --git a/Oqtane.Server/wwwroot/js/interop.js b/Oqtane.Server/wwwroot/js/interop.js
index e4e07e8e..dcecde3c 100644
--- a/Oqtane.Server/wwwroot/js/interop.js
+++ b/Oqtane.Server/wwwroot/js/interop.js
@@ -376,5 +376,14 @@ Oqtane.Interop = {
left: left,
behavior: behavior
});
+ },
+ scrollToId: function (id) {
+ var element = document.getElementById(id);
+ if (element instanceof HTMLElement) {
+ element.scrollIntoView({
+ behavior: "smooth",
+ block: "start",
+ inline: "nearest"
+ });
}
-};
+}};
diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs
index 0085b45f..aa70e703 100644
--- a/Oqtane.Shared/Shared/Constants.cs
+++ b/Oqtane.Shared/Shared/Constants.cs
@@ -62,7 +62,7 @@ namespace Oqtane.Shared {
[Obsolete(RoleObsoleteMessage)]
public const string RegisteredRole = RoleNames.Registered;
- public const string ImageFiles = "jpg,jpeg,jpe,gif,bmp,png,ico";
+ public const string ImageFiles = "jpg,jpeg,jpe,gif,bmp,png,ico,webp";
public const string UploadableFiles = ImageFiles + ",mov,wmv,avi,mp4,mp3,doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,nupkg,csv";
public const string ReservedDevices = "CON,NUL,PRN,COM0,COM1,COM2,COM3,COM4,COM5,COM6,COM7,COM8,COM9,LPT0,LPT1,LPT2,LPT3,LPT4,LPT5,LPT6,LPT7,LPT8,LPT9,CONIN$,CONOUT$";