Merge pull request #638 from PoisnFang/routing

Module Router Enhancement
This commit is contained in:
Shaun Walker 2020-06-30 16:15:27 -04:00 committed by GitHub
commit 568c283efd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 155 additions and 29 deletions

View File

@ -116,6 +116,38 @@ namespace Oqtane.Modules
return Utilities.ContentUrl(PageState.Alias, fileid); return Utilities.ContentUrl(PageState.Alias, fileid);
} }
public Dictionary<string, string> GetUrlParameters(string parameterTemplate)
{
var urlParameters = new Dictionary<string, string>();
var templateSegments = parameterTemplate.Split('/', StringSplitOptions.RemoveEmptyEntries);
var parameters = PageState.UrlParameters.Split('/', StringSplitOptions.RemoveEmptyEntries);
if (parameters.Length == templateSegments.Length)
{
for (int i = 0; i < parameters.Length; i++)
{
if (parameters.Length > i)
{
if (templateSegments[i] == parameters[i])
{
}
else if (templateSegments[i].StartsWith("{") && templateSegments[i].EndsWith("}"))
{
var key = templateSegments[i].Replace("{", "");
key = key.Replace("}", "");
urlParameters.TryAdd(key, parameters[i]);
}
else
{
i = parameters.Length;
}
}
}
}
return urlParameters;
}
// user feedback methods // user feedback methods
public void AddModuleMessage(string message, MessageType type) public void AddModuleMessage(string message, MessageType type)
{ {
@ -154,12 +186,15 @@ namespace Oqtane.Modules
case "add": case "add":
logFunction = LogFunction.Create; logFunction = LogFunction.Create;
break; break;
case "edit": case "edit":
logFunction = LogFunction.Update; logFunction = LogFunction.Update;
break; break;
case "delete": case "delete":
logFunction = LogFunction.Delete; logFunction = LogFunction.Delete;
break; break;
default: default:
logFunction = LogFunction.Read; logFunction = LogFunction.Read;
break; break;

View File

@ -14,6 +14,7 @@ namespace Oqtane.UI
public List<Module> Modules { get; set; } public List<Module> Modules { get; set; }
public Uri Uri { get; set; } public Uri Uri { get; set; }
public Dictionary<string, string> QueryString { get; set; } public Dictionary<string, string> QueryString { get; set; }
public string UrlParameters { get; set; }
public int ModuleId { get; set; } public int ModuleId { get; set; }
public string Action { get; set; } public string Action { get; set; }
public bool EditMode { get; set; } public bool EditMode { get; set; }

View File

@ -76,7 +76,8 @@
User user = null; User user = null;
List<Module> modules; List<Module> modules;
var moduleid = -1; var moduleid = -1;
var action = ""; var action = string.Empty;
var urlparameters = string.Empty;
var editmode = false; var editmode = false;
var reload = Reload.None; var reload = Reload.None;
var lastsyncdate = DateTime.UtcNow; var lastsyncdate = DateTime.UtcNow;
@ -179,23 +180,62 @@
// extract admin route elements from path // extract admin route elements from path
var segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); var segments = path.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
int result; int result;
// check if path has moduleid and action specification ie. pagename/moduleid/action/
if (segments.Length >= 2 && int.TryParse(segments[segments.Length - 2], out result)) int modIdPos = 0;
int actionPos = 0;
int urlParametersPos = 0;
for (int i = 0; i < segments.Length; i++)
{ {
action = segments[segments.Length - 1];
moduleid = result; if (segments[i] == Constants.UrlParametersDelimiter)
path = path.Replace(moduleid.ToString() + "/" + action + "/", ""); {
urlParametersPos = i + 1;
}
if (i >= urlParametersPos && urlParametersPos != 0)
{
urlparameters += "/" + segments[i];
}
if (segments[i] == Constants.ModuleDelimiter)
{
modIdPos = i + 1;
actionPos = modIdPos + 1;
if (actionPos > segments.Length - 1)
{
action = Constants.DefaultAction;
} }
else else
{ {
// check if path has moduleid specification ie. pagename/moduleid/ action = segments[actionPos];
if (segments.Length >= 1 && int.TryParse(segments[segments.Length - 1], out result))
{
moduleid = result;
path = path.Replace(moduleid.ToString() + "/", "");
} }
} }
}
// check if path has moduleid and action specification ie. pagename/moduleid/action/
if (modIdPos > 0)
{
int.TryParse(segments[modIdPos], out result);
moduleid = result;
if (actionPos > segments.Length - 1)
{
path = path.Replace("/" + segments[modIdPos - 1] + "/" + segments[modIdPos], "");
}
else
{
path = path.Replace("/" + segments[modIdPos - 1] + "/" + segments[modIdPos] + "/" + segments[actionPos], "");
}
}
if (urlParametersPos > 0)
{
path = path.Replace("/" + segments[urlParametersPos - 1] + urlparameters, "");
}
// remove trailing slash so it can be used as a key for Pages // remove trailing slash so it can be used as a key for Pages
if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1); if (path.EndsWith("/")) path = path.Substring(0, path.Length - 1);
@ -263,6 +303,7 @@
Modules = modules, Modules = modules,
Uri = new Uri(_absoluteUri, UriKind.Absolute), Uri = new Uri(_absoluteUri, UriKind.Absolute),
QueryString = querystring, QueryString = querystring,
UrlParameters = urlparameters,
ModuleId = moduleid, ModuleId = moduleid,
Action = action, Action = action,
EditMode = editmode, EditMode = editmode,

View File

@ -19,6 +19,8 @@ namespace Oqtane.Shared
public const string ActionToken = "{Action}"; public const string ActionToken = "{Action}";
public const string DefaultAction = "Index"; public const string DefaultAction = "Index";
public const string AdminPane = "Admin"; public const string AdminPane = "Admin";
public const string ModuleDelimiter = "*";
public const string UrlParametersDelimiter = "!";
// Default Module Actions are reserved and should not be used by modules // Default Module Actions are reserved and should not be used by modules
public static readonly string[] DefaultModuleActions = new[] { "Settings", "Import", "Export" }; public static readonly string[] DefaultModuleActions = new[] { "Settings", "Import", "Export" };
@ -46,6 +48,7 @@ namespace Oqtane.Shared
public const string ImageFiles = "jpg,jpeg,jpe,gif,bmp,png"; public const string ImageFiles = "jpg,jpeg,jpe,gif,bmp,png";
public const string UploadableFiles = "jpg,jpeg,jpe,gif,bmp,png,mov,wmv,avi,mp4,mp3,doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,nupkg"; public const string UploadableFiles = "jpg,jpeg,jpe,gif,bmp,png,mov,wmv,avi,mp4,mp3,doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,nupkg";
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$"; 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$";
public static readonly char[] InvalidFileNameChars = public static readonly char[] InvalidFileNameChars =
{ {
'\"', '<', '>', '|', '\0', (Char) 1, (Char) 2, (Char) 3, (Char) 4, (Char) 5, (Char) 6, (Char) 7, (Char) 8, '\"', '<', '>', '|', '\0', (Char) 1, (Char) 2, (Char) 3, (Char) 4, (Char) 5, (Char) 6, (Char) 7, (Char) 8,

View File

@ -20,8 +20,53 @@ namespace Oqtane.Shared
return $"{type.Namespace}, {assemblyName}"; 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) 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 var uriBuilder = new UriBuilder
{ {
Path = !string.IsNullOrEmpty(alias) Path = !string.IsNullOrEmpty(alias)
@ -29,17 +74,18 @@ namespace Oqtane.Shared
? $"{alias}/{path}" ? $"{alias}/{path}"
: $"{alias}" : $"{alias}"
: $"{path}", : $"{path}",
Query = parameters Query = querystring,
}; };
anchor = string.IsNullOrEmpty(anchor) ? "" : "#" + anchor;
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) public static string EditUrl(string alias, string path, int moduleid, string action, string parameters)
{ {
if (moduleid != -1) if (moduleid != -1)
{ {
path += $"/{moduleid}"; path += $"/{Constants.ModuleDelimiter}/{moduleid}";
if (!string.IsNullOrEmpty(action)) if (!string.IsNullOrEmpty(action))
{ {
path += $"/{action}"; path += $"/{action}";
@ -136,6 +182,7 @@ namespace Oqtane.Shared
stringBuilder.Append(RemapInternationalCharToAscii(c)); stringBuilder.Append(RemapInternationalCharToAscii(c));
prevdash = false; prevdash = false;
break; break;
case UnicodeCategory.SpaceSeparator: case UnicodeCategory.SpaceSeparator:
case UnicodeCategory.ConnectorPunctuation: case UnicodeCategory.ConnectorPunctuation:
case UnicodeCategory.DashPunctuation: case UnicodeCategory.DashPunctuation:
@ -250,7 +297,7 @@ namespace Oqtane.Shared
public static string PathCombine(params string[] segments) public static string PathCombine(params string[] segments)
{ {
var separators = new char[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}; var separators = new char[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar };
for (int i = 1; i < segments.Length; i++) for (int i = 1; i < segments.Length; i++)
{ {
@ -284,7 +331,6 @@ namespace Oqtane.Shared
!Constants.ReservedDevices.Split(',').Contains(name.ToUpper().Split('.')[0])); !Constants.ReservedDevices.Split(',').Contains(name.ToUpper().Split('.')[0]));
} }
public static bool TryGetQueryValue( public static bool TryGetQueryValue(
this Uri uri, this Uri uri,
string key, string key,
@ -304,7 +350,7 @@ namespace Oqtane.Shared
{ {
value = defaultValue; value = defaultValue;
string s; string s;
return uri.TryGetQueryValue(key, out s, (string) null) && int.TryParse(s, out value); return uri.TryGetQueryValue(key, out s, (string)null) && int.TryParse(s, out value);
} }
public static Dictionary<string, string> ParseQueryString(string query) public static Dictionary<string, string> ParseQueryString(string query)
@ -314,7 +360,7 @@ namespace Oqtane.Shared
{ {
query = query.Substring(1); query = query.Substring(1);
string str = query; string str = query;
char[] separator = new char[1] {'&'}; char[] separator = new char[1] { '&' };
foreach (string key in str.Split(separator, StringSplitOptions.RemoveEmptyEntries)) foreach (string key in str.Split(separator, StringSplitOptions.RemoveEmptyEntries))
{ {
if (key != "") if (key != "")