diff --git a/Oqtane.Client/UI/PageState.cs b/Oqtane.Client/UI/PageState.cs index 14b15bbc..7bc56ed8 100644 --- a/Oqtane.Client/UI/PageState.cs +++ b/Oqtane.Client/UI/PageState.cs @@ -14,7 +14,8 @@ namespace Oqtane.UI public List Modules { get; set; } public Uri Uri { get; set; } public Dictionary QueryString { get; set; } - public Dictionary PageVariables { get; set; } + public string UrlParameters { get; set; } + public string Anchor { get; set; } public int ModuleId { get; set; } public string Action { get; set; } public bool EditMode { get; set; } diff --git a/Oqtane.Client/UI/SiteRouter.razor b/Oqtane.Client/UI/SiteRouter.razor index 3503cb77..d7f8b931 100644 --- a/Oqtane.Client/UI/SiteRouter.razor +++ b/Oqtane.Client/UI/SiteRouter.razor @@ -75,9 +75,10 @@ Page page; User user = null; List modules; - Dictionary pageVariables = new Dictionary(); var moduleid = -1; - var action = ""; + var action = string.Empty; + var urlparameters = string.Empty; + var anchor = string.Empty; var editmode = false; var reload = Reload.None; var lastsyncdate = DateTime.UtcNow; @@ -88,6 +89,12 @@ // get path var path = uri.LocalPath.Substring(1); + //set anchor + if (uri.Fragment.StartsWith('#')) + { + anchor = uri.Fragment.Remove(0, 1); + } + // parse querystring var querystring = ParseQueryString(uri.Query); @@ -182,18 +189,29 @@ int result; int modIdPos = 0; + int actionPos = 0; + int ulrParametersPos = 0; for (int i = 0; i < segments.Length; i++) { - if (segments[i] == Constants.ModuleSegment) + + if (segments[i] == Constants.UrlParametersDelimiter) { - modIdPos = i + 1; + ulrParametersPos = i + 1; } - if (i > modIdPos && modIdPos != 0) + if (i >= ulrParametersPos && ulrParametersPos != 0) { - action += segments[i] + "/"; + urlparameters += "/" + segments[i]; } + + if (segments[i] == Constants.ModuleDelimiter) + { + modIdPos = i + 1; + actionPos = modIdPos + 1; + action = segments[actionPos]; + } + } // check if path has moduleid and action specification ie. pagename/moduleid/action/ @@ -201,11 +219,14 @@ { int.TryParse(segments[modIdPos], out result); moduleid = result; - path = path.Replace(segments[modIdPos - 1] + "/" + segments[modIdPos] + "/" + action, ""); + path = path.Replace("/" + segments[modIdPos - 1] + "/" + segments[modIdPos] + "/" + segments[actionPos], ""); } - if (action.EndsWith("/")) action = action.Substring(0, action.Length - 1); + if (ulrParametersPos > 0) + { + path = path.Replace("/" + segments[ulrParametersPos - 1] + urlparameters, ""); + } // remove trailing slash so it can be used as a key for Pages if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1); @@ -257,7 +278,7 @@ if (PageState == null || reload >= Reload.Page) { modules = await ModuleService.GetModulesAsync(site.SiteId); - (page, modules, pageVariables) = ProcessModules(page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType); + (page, modules) = ProcessModules(page, modules, moduleid, action, (!string.IsNullOrEmpty(page.DefaultContainerType)) ? page.DefaultContainerType : site.DefaultContainerType); } else { @@ -274,7 +295,8 @@ Modules = modules, Uri = new Uri(_absoluteUri, UriKind.Absolute), QueryString = querystring, - PageVariables = pageVariables, + UrlParameters = urlparameters, + Anchor = anchor, ModuleId = moduleid, Action = action, EditMode = editmode, @@ -326,12 +348,9 @@ return Task.CompletedTask; } - private Dictionary - ParseQueryString(string query) + private Dictionary ParseQueryString(string query) { - Dictionary - querystring = new Dictionary - (); + Dictionary querystring = new Dictionary(); if (!string.IsNullOrEmpty(query)) { query = query.Substring(1); // ignore "?" @@ -354,8 +373,7 @@ return querystring; } - private async Task - ProcessPage(Page page, Site site, User user) + private async Task ProcessPage(Page page, Site site, User user) { try { @@ -371,10 +389,8 @@ page.LayoutType = site.DefaultLayoutType; } - page.Panes = new List - (); - page.Resources = new List - (); + page.Panes = new List(); + page.Resources = new List(); string panes = ""; Type themetype = Type.GetType(page.ThemeType); @@ -411,12 +427,9 @@ return page; } - private (Page Page, List - Modules, Dictionary PageVariables) ProcessModules(Page page, List - modules, int moduleid, string action, string defaultcontainertype) + private (Page Page, List Modules) ProcessModules(Page page, List modules, int moduleid, string action, string defaultcontainertype) { var paneindex = new Dictionary(); - var pageVariables = new Dictionary(); foreach (Module module in modules) { if (module.PageId == page.PageId || module.ModuleId == moduleid) @@ -431,52 +444,17 @@ typename = Constants.ErrorModule; } - var pages = action.Split('/', StringSplitOptions.RemoveEmptyEntries); - if (module.ModuleId == moduleid && action != "") { // check if the module defines custom routes if (module.ModuleDefinition.ControlTypeRoutes != "") { - var controlTypeRoutes = module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); - foreach (string route in controlTypeRoutes) + foreach (string route in module.ModuleDefinition.ControlTypeRoutes.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)) { - var pageAction = route.Split('=')[0]; - - var routes = pageAction.Split('/', StringSplitOptions.RemoveEmptyEntries); - var newRoute = ""; - if (pages.Length == routes.Length) + if (route.StartsWith(action + "=")) { - for (int i = 0; i < pages.Length; i++) - { - if (pages.Length > i) - { - if (routes[i] == pages[i]) - { - newRoute += pages[i] + "/"; - } - else if (routes[i].StartsWith("[") && routes[i].EndsWith("]")) - { - newRoute += pages[i] + "/"; - var key = routes[i].Replace("[", ""); - key = key.Replace("]", ""); - pageVariables.TryAdd(key, pages[i]); - } - else - { - i = pages.Length; - newRoute = ""; - } - - } - } - - if (newRoute != "") - { - typename = route.Replace(pageAction + "=", ""); - } + typename = route.Replace(action + "=", ""); } - } } module.ModuleType = typename.Replace(Constants.ActionToken, action); @@ -545,13 +523,10 @@ module.PaneModuleCount = paneindex[module.Pane.ToLower()] + 1; } - return (page, modules, pageVariables); + return (page, modules); } - private List - ManagePageResources(List - pageresources, List - resources) + private List ManagePageResources(List pageresources, List resources) { if (resources != null) { @@ -568,7 +543,7 @@ } private Runtime GetRuntime() - => RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")) - ? Runtime.WebAssembly - : Runtime.Server; +=> RuntimeInformation.IsOSPlatform(OSPlatform.Create("BROWSER")) + ? Runtime.WebAssembly + : Runtime.Server; } \ No newline at end of file diff --git a/Oqtane.Server/appsettings.json b/Oqtane.Server/appsettings.json index 4b88e95c..0ab499f0 100644 --- a/Oqtane.Server/appsettings.json +++ b/Oqtane.Server/appsettings.json @@ -1,6 +1,6 @@ { "ConnectionStrings": { - "DefaultConnection": "Data Source=(LocalDb)\\MSSQLLocalDB;AttachDbFilename=|DataDirectory|\\Oqtane.mdf;Initial Catalog=Oqtane;Integrated Security=SSPI;" + "DefaultConnection": "" }, "Runtime": "Server", "Installation": { diff --git a/Oqtane.Shared/Shared/Constants.cs b/Oqtane.Shared/Shared/Constants.cs index 3e02a938..77f7dc68 100644 --- a/Oqtane.Shared/Shared/Constants.cs +++ b/Oqtane.Shared/Shared/Constants.cs @@ -19,7 +19,8 @@ namespace Oqtane.Shared public const string ActionToken = "{Action}"; public const string DefaultAction = "Index"; public const string AdminPane = "Admin"; - public const string ModuleSegment = "module"; + public const string ModuleDelimiter = "*"; + public const string UrlParametersDelimiter = "!"; // Default Module Actions are reserved and should not be used by modules public static readonly string[] DefaultModuleActions = new[] { "Settings", "Import", "Export" }; diff --git a/Oqtane.Shared/Shared/Utilities.cs b/Oqtane.Shared/Shared/Utilities.cs index 5efe5c38..ce5255a3 100644 --- a/Oqtane.Shared/Shared/Utilities.cs +++ b/Oqtane.Shared/Shared/Utilities.cs @@ -20,8 +20,53 @@ namespace Oqtane.Shared return $"{type.Namespace}, {assemblyName}"; } + public static (string UrlParameters, string Querystring, string Anchor) ParseParameters(string parameters) + { + // /urlparameters /urlparameters?Id=1 /urlparameters#5 /urlparameters?Id=1#5 /urlparameters?reload#5 + + // Id=1 Id=1#5 reload#5 reload + + // #5 + + var urlparameters = string.Empty; + var querystring = string.Empty; + var anchor = string.Empty; + + if (parameters.Contains('#')) + { + anchor = parameters.Split('#').Last(); + parameters = parameters.Replace("#" + anchor, ""); + } + + if (parameters.Contains('?')) + { + urlparameters = parameters.Split('?').First(); + querystring = parameters.Replace(urlparameters + "?", ""); + } + else if (parameters.Contains('/')) + { + urlparameters = parameters; + } + else + { + querystring = parameters; + } + + return (urlparameters, querystring, anchor); + } + public static string NavigateUrl(string alias, string path, string parameters) { + string urlparameters; + string querystring; + string anchor; + (urlparameters, querystring, anchor) = ParseParameters(parameters); + + if (!string.IsNullOrEmpty(urlparameters)) + { + if (urlparameters.StartsWith("/")) urlparameters = urlparameters.Remove(0, 1); + path += $"/{Constants.UrlParametersDelimiter}/{urlparameters}"; + } var uriBuilder = new UriBuilder { Path = !string.IsNullOrEmpty(alias) @@ -29,17 +74,18 @@ namespace Oqtane.Shared ? $"{alias}/{path}" : $"{alias}" : $"{path}", - Query = parameters + Query = querystring, }; - return uriBuilder.Uri.PathAndQuery; + var navigateUrl = uriBuilder.Uri.PathAndQuery + "#" + anchor; + return navigateUrl; } public static string EditUrl(string alias, string path, int moduleid, string action, string parameters) { if (moduleid != -1) { - path += $"/{Constants.ModuleSegment}/{moduleid}"; + path += $"/{Constants.ModuleDelimiter}/{moduleid}"; if (!string.IsNullOrEmpty(action)) { path += $"/{action}";