diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index db59fd4f..882835e9 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -101,8 +101,8 @@ _error = ""; Route route = new Route(_absoluteUri, SiteState.Alias.Path); - int moduleid = (int.TryParse(route.ModuleId, out moduleid)) ? moduleid : -1; - var action = (!string.IsNullOrEmpty(route.Action)) ? route.Action : Constants.DefaultAction; + int moduleid = int.Parse(route.ModuleId); + var action = route.Action; var querystring = Utilities.ParseQueryString(route.Query); var returnurl = ""; diff --git a/Oqtane.Client/UI/ThemeBuilder.razor b/Oqtane.Client/UI/ThemeBuilder.razor index 8bb4fe47..3f4669e8 100644 --- a/Oqtane.Client/UI/ThemeBuilder.razor +++ b/Oqtane.Client/UI/ThemeBuilder.razor @@ -53,15 +53,6 @@ { headcontent = AddHeadContent(headcontent, PageState.Page.HeadContent); } - - // stylesheets and scripts on static rendering - if (PageState.RenderMode == RenderModes.Static) - { - headcontent = AddHeadContent(headcontent, ManageStyleSheets(PageState.Page.Resources, PageState.Alias)); - headcontent = AddHeadContent(headcontent, ManageScripts(PageState.Page.Resources, PageState.Alias)); - } - - // send to Head component SiteState.Properties.HeadContent = headcontent; DynamicComponent = builder => diff --git a/Oqtane.Server/Components/App.razor b/Oqtane.Server/Components/App.razor index 7326e179..c8603059 100644 --- a/Oqtane.Server/Components/App.razor +++ b/Oqtane.Server/Components/App.razor @@ -168,13 +168,15 @@ CreateJwtToken(alias); } - // initial stylesheets (to prevent FOUC in interactive rendering) - if (_renderMode == RenderModes.Interactive) - { - ManageStyleSheets(alias, site, page); - } + // include stylesheets to prevent FOUC + var resources = GetPageResources(alias, site, page, int.Parse(route.ModuleId), route.Action); + ManageStyleSheets(resources); // scripts + if (_renderMode == RenderModes.Static) + { + ManageScripts(resources, alias); + } if (_renderMode == RenderModes.Interactive && _runtime == Runtimes.Server) { _reconnectScript = CreateReconnectScript(); @@ -548,56 +550,108 @@ CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture))); } - private void ManageStyleSheets(Alias alias, Site site, Page page) + private List GetPageResources(Alias alias, Site site, Page page, int moduleid, string action) { + var resources = new List(); + var themeType = (string.IsNullOrEmpty(page.ThemeType)) ? site.DefaultThemeType : page.ThemeType; var theme = site.Themes.FirstOrDefault(item => item.Themes.Any(item => item.TypeName == themeType)); - var resources = GetStyleSheetResources(page, theme); + if (theme != null) + { + resources = AddResources(resources, theme.Resources, ResourceLevel.Page, alias, "Themes", Utilities.GetTypeName(theme.ThemeName)); + } + var type = Type.GetType(themeType); + if (type != null) + { + var obj = Activator.CreateInstance(type) as IThemeControl; + if (obj != null) + { + resources = AddResources(resources, obj.Resources, ResourceLevel.Page, alias, "Themes", type.Namespace); + } + } + foreach (Module module in site.Modules) + { + if (module.PageId == page.PageId || module.ModuleId == moduleid) + { + var typename = ""; + if (module.ModuleDefinition != null) + { + typename = module.ModuleDefinition.ControlTypeTemplate; + resources = AddResources(resources, module.ModuleDefinition.Resources, ResourceLevel.Module, alias, "Modules", Utilities.GetTypeName(module.ModuleDefinition.ModuleDefinitionName)); + } + 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 + } + if (moduletype != null && module.ModuleType != "") + { + var obj = Activator.CreateInstance(moduletype) as IModuleControl; + if (obj != null) + { + resources = AddResources(resources, obj.Resources, ResourceLevel.Module, alias, "Modules", type.Namespace); + } + } + } + } + + return resources; + } + + private List AddResources(List pageresources, List resources, ResourceLevel level, Alias alias, string type, string name) + { + if (resources != null) + { + foreach (var resource in resources) + { + if (resource.Level != ResourceLevel.Site) + { + if (resource.Url.StartsWith("~")) + { + resource.Url = resource.Url.Replace("~", "/" + type + "/" + name + "/").Replace("//", "/"); + } + if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl)) + { + resource.Url = alias.BaseUrl + resource.Url; + } + + // ensure resource does not exist already + if (!pageresources.Exists(item => item.Url.ToLower() == resource.Url.ToLower())) + { + resource.Level = level; + resource.Namespace = name; + pageresources.Add(resource); + } + } + } + } + return pageresources; + } + + private void ManageStyleSheets(List resources) + { if (resources != null) { string batch = DateTime.UtcNow.ToString("yyyyMMddHHmmssfff"); int count = 0; foreach (var resource in resources.Where(item => item.ResourceType == ResourceType.Stylesheet)) { - if (resource.Url.StartsWith("~")) - { - resource.Url = resource.Url.Replace("~", "/Themes/" + Utilities.GetTypeName(theme.ThemeName) + "/").Replace("//", "/"); - } - if (!resource.Url.Contains("://") && alias.BaseUrl != "" && !resource.Url.StartsWith(alias.BaseUrl)) - { - resource.Url = alias.BaseUrl + resource.Url; - } - - if (!_styleSheets.Contains(resource.Url, StringComparison.OrdinalIgnoreCase)) - { - count++; - string id = "id=\"app-stylesheet-" + ResourceLevel.Page.ToString().ToLower() + "-" + batch + "-" + count.ToString("00") + "\" "; - _styleSheets += "" + Environment.NewLine; - } + count++; + string id = "id=\"app-stylesheet-" + ResourceLevel.Page.ToString().ToLower() + "-" + batch + "-" + count.ToString("00") + "\" "; + _styleSheets += "" + Environment.NewLine; } } } - private List GetStyleSheetResources(Page page, Theme theme) - { - var resources = new List(); - if (theme?.Resources != null) - { - resources.AddRange(theme.Resources); - } - var type = Type.GetType(page.ThemeType); - if (type != null) - { - var obj = Activator.CreateInstance(type) as IThemeControl; - if (obj?.Resources != null) - { - resources.AddRange(obj.Resources); - } - } - return resources; - } - private void ManageScripts(List resources, Alias alias) { if (resources != null) diff --git a/Oqtane.Shared/Models/Route.cs b/Oqtane.Shared/Models/Route.cs index 56dcc3b1..73d648fa 100644 --- a/Oqtane.Shared/Models/Route.cs +++ b/Oqtane.Shared/Models/Route.cs @@ -32,8 +32,8 @@ namespace Oqtane.Models PathAndQuery = uri.PathAndQuery; AliasPath = aliaspath; PagePath = AbsolutePath; - ModuleId = ""; - Action = ""; + ModuleId = "-1"; + Action = Constants.DefaultAction; UrlParameters = ""; if (AliasPath.Length != 0 && PagePath.StartsWith("/" + AliasPath)) @@ -50,6 +50,7 @@ namespace Oqtane.Models if (pos != -1) { ModuleId = PagePath.Substring(pos + 3); + ModuleId = (int.TryParse(ModuleId, out _)) ? ModuleId : "-1"; PagePath = PagePath.Substring(0, pos); } if (ModuleId.Length != 0) @@ -57,8 +58,10 @@ namespace Oqtane.Models pos = ModuleId.IndexOf("/"); if (pos != -1) { - Action = ModuleId.Substring(pos + 1); + Action = ModuleId.Substring(pos + 1); + Action = (!string.IsNullOrEmpty(Action)) ? Action : Constants.DefaultAction; ModuleId = ModuleId.Substring(0, pos); + ModuleId = (int.TryParse(ModuleId, out _)) ? ModuleId : "-1"; } } if (PagePath.StartsWith("/"))