static IEnumerable GetItems(object node) { IEnumerable results = null; switch (node) { case IShellController shell: results = shell.GetItems(); break; case IShellItemController item: results = item.GetItems(); break; case IShellSectionController section: results = section.GetItems(); break; case ShellContent content: results = new object[0]; break; case GlobalRouteItem routeITem: results = routeITem.Items; break; } if (results == null) throw new ArgumentException($"{node}", nameof(node)); foreach (var result in results) yield return result; if (node is GlobalRouteItem) yield break; var keys = Routing.GetRouteKeys(); string route = GetRoute(node); for (var i = 0; i < keys.Length; i++) { var key = FormatUri(keys[i]); if (key.StartsWith(_pathSeparator, StringComparison.Ordinal) && !(node is Shell)) continue; var segments = key.Split(_pathSeparator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (segments[0] == route) { yield return new GlobalRouteItem(key, key); } } }
internal static List <RouteRequestBuilder> GenerateRoutePaths(Shell shell, Uri request, Uri originalRequest, bool enableRelativeShellRoutes) { var routeKeys = Routing.GetRouteKeys(); for (int i = 0; i < routeKeys.Length; i++) { routeKeys[i] = FormatUri(routeKeys[i]); } request = FormatUri(request, shell); originalRequest = FormatUri(originalRequest, shell); List <RouteRequestBuilder> possibleRoutePaths = new List <RouteRequestBuilder>(); if (!request.IsAbsoluteUri) { request = ConvertToStandardFormat(shell, request); } string localPath = request.LocalPath; bool relativeMatch = false; if (!originalRequest.IsAbsoluteUri && !originalRequest.OriginalString.StartsWith("//", StringComparison.Ordinal)) { relativeMatch = true; } var segments = RetrievePaths(localPath); var depthStart = 0; if (segments[0] == shell?.Route) { segments = segments.Skip(1).ToArray(); depthStart = 1; } else { depthStart = 0; } if (relativeMatch && shell?.CurrentItem != null) { var result = ProcessRelativeRoute(shell, routeKeys, segments, enableRelativeShellRoutes, originalRequest); if (result.Count > 0) { return(result); } } possibleRoutePaths.Clear(); SearchPath(shell, null, segments, possibleRoutePaths, depthStart); var bestMatches = GetBestMatches(possibleRoutePaths); if (bestMatches.Count > 0) { return(bestMatches); } bestMatches.Clear(); ExpandOutGlobalRoutes(possibleRoutePaths, routeKeys); foreach (var possibleRoutePath in possibleRoutePaths) { if (possibleRoutePath.IsFullMatch) { continue; } var url = possibleRoutePath.PathFull; var globalRouteMatches = SearchForGlobalRoutes( possibleRoutePath.RemainingSegments, new ShellNavigationState(url, false).FullLocation, possibleRoutePath.GetNodeLocation(), routeKeys); if (globalRouteMatches.Count != 1) { continue; } var globalRouteMatch = globalRouteMatches[0]; while (possibleRoutePath.NextSegment != null) { var matchIndex = globalRouteMatch.SegmentsMatched.IndexOf(possibleRoutePath.NextSegment); if (matchIndex < 0) { break; } possibleRoutePath.AddGlobalRoute( globalRouteMatch.GlobalRouteMatches[matchIndex], globalRouteMatch.SegmentsMatched[matchIndex]); } } possibleRoutePaths = GetBestMatches(possibleRoutePaths); if (possibleRoutePaths.Count == 0) { foreach (var routeKey in routeKeys) { if (routeKey == originalRequest.OriginalString) { var builder = new RouteRequestBuilder(routeKey, routeKey, null, new string[] { routeKey }); return(new List <RouteRequestBuilder> { builder }); } } if (!relativeMatch) { for (int i = 0; i < routeKeys.Length; i++) { var route = routeKeys[i]; var uri = ConvertToStandardFormat(shell, CreateUri(route)); if (uri.Equals(request)) { throw new Exception($"Global routes currently cannot be the only page on the stack, so absolute routing to global routes is not supported. For now, just navigate to: {originalRequest.OriginalString.Replace("//", "")}"); } } } } return(possibleRoutePaths); }
internal static List <RouteRequestBuilder> GenerateRoutePaths(Shell shell, Uri request, Uri originalRequest, bool enableRelativeShellRoutes) { var routeKeys = Routing.GetRouteKeys(); for (int i = 0; i < routeKeys.Length; i++) { if (routeKeys[i] == originalRequest.OriginalString) { var builder = new RouteRequestBuilder(routeKeys[i], routeKeys[i], null, new string[] { routeKeys[i] }); return(new List <RouteRequestBuilder> { builder }); } routeKeys[i] = FormatUri(routeKeys[i]); } request = FormatUri(request, shell); originalRequest = FormatUri(originalRequest, shell); List <RouteRequestBuilder> possibleRoutePaths = new List <RouteRequestBuilder>(); if (!request.IsAbsoluteUri) { request = ConvertToStandardFormat(shell, request); } string localPath = request.LocalPath; bool relativeMatch = false; if (!originalRequest.IsAbsoluteUri && !originalRequest.OriginalString.StartsWith("//", StringComparison.Ordinal)) { relativeMatch = true; } var segments = localPath.Split(_pathSeparator.ToCharArray(), StringSplitOptions.RemoveEmptyEntries); if (!relativeMatch) { for (int i = 0; i < routeKeys.Length; i++) { var route = routeKeys[i]; var uri = ConvertToStandardFormat(shell, CreateUri(route)); if (uri.Equals(request)) { throw new Exception($"Global routes currently cannot be the only page on the stack, so absolute routing to global routes is not supported. For now, just navigate to: {originalRequest.OriginalString.Replace("//", "")}"); //var builder = new RouteRequestBuilder(route, route, null, segments); //return new List<RouteRequestBuilder> { builder }; } } } var depthStart = 0; if (segments[0] == shell?.Route) { segments = segments.Skip(1).ToArray(); depthStart = 1; } else { depthStart = 0; } if (relativeMatch && shell?.CurrentItem != null) { // retrieve current location var currentLocation = NodeLocation.Create(shell); while (currentLocation.Shell != null) { var pureRoutesMatch = new List <RouteRequestBuilder>(); var pureGlobalRoutesMatch = new List <RouteRequestBuilder>(); //currently relative routes to shell routes isn't supported as we aren't creating navigation stacks if (enableRelativeShellRoutes) { SearchPath(currentLocation.LowestChild, null, segments, pureRoutesMatch, 0); ExpandOutGlobalRoutes(pureRoutesMatch, routeKeys); pureRoutesMatch = GetBestMatches(pureRoutesMatch); if (pureRoutesMatch.Count > 0) { return(pureRoutesMatch); } } SearchPath(currentLocation.LowestChild, null, segments, pureGlobalRoutesMatch, 0, ignoreGlobalRoutes: false); ExpandOutGlobalRoutes(pureGlobalRoutesMatch, routeKeys); pureGlobalRoutesMatch = GetBestMatches(pureGlobalRoutesMatch); if (pureGlobalRoutesMatch.Count > 0) { // currently relative routes to shell routes isn't supported as we aren't creating navigation stacks // So right now we will just throw an exception so that once this is implemented // GotoAsync doesn't start acting inconsistently and all of a suddent starts creating routes if (!enableRelativeShellRoutes && pureGlobalRoutesMatch[0].SegmentsMatched.Count > 0) { throw new Exception($"Relative routing to shell elements is currently not supported. Try prefixing your uri with ///: ///{originalRequest}"); } return(pureGlobalRoutesMatch); } currentLocation.Pop(); } string searchPath = String.Join(_pathSeparator, segments); if (routeKeys.Contains(searchPath)) { return(new List <RouteRequestBuilder> { new RouteRequestBuilder(searchPath, searchPath, null, segments) }); } RouteRequestBuilder builder = null; foreach (var segment in segments) { if (routeKeys.Contains(segment)) { if (builder == null) { builder = new RouteRequestBuilder(segment, segment, null, segments); } else { builder.AddGlobalRoute(segment, segment); } } } if (builder != null && builder.IsFullMatch) { return new List <RouteRequestBuilder> { builder } } ; } else { possibleRoutePaths.Clear(); SearchPath(shell, null, segments, possibleRoutePaths, depthStart); var bestMatches = GetBestMatches(possibleRoutePaths); if (bestMatches.Count > 0) { return(bestMatches); } bestMatches.Clear(); ExpandOutGlobalRoutes(possibleRoutePaths, routeKeys); } possibleRoutePaths = GetBestMatches(possibleRoutePaths); return(possibleRoutePaths); }
internal static List <RouteRequestBuilder> GenerateRoutePaths(Shell shell, Uri request, Uri originalRequest) { request = FormatUri(request); originalRequest = FormatUri(originalRequest); var routeKeys = Routing.GetRouteKeys(); for (int i = 0; i < routeKeys.Length; i++) { routeKeys[i] = FormatUri(routeKeys[i]); } List <RouteRequestBuilder> possibleRoutePaths = new List <RouteRequestBuilder>(); if (!request.IsAbsoluteUri) { request = ConvertToStandardFormat(shell, request); } string localPath = request.LocalPath; bool relativeMatch = false; if (!originalRequest.IsAbsoluteUri && !originalRequest.OriginalString.StartsWith("/") && !originalRequest.OriginalString.StartsWith("\\")) { relativeMatch = true; } var segments = localPath.Split(_pathSeparator, StringSplitOptions.RemoveEmptyEntries); if (!relativeMatch) { for (int i = 0; i < routeKeys.Length; i++) { var route = routeKeys[i]; var uri = ConvertToStandardFormat(shell, new Uri(route, UriKind.RelativeOrAbsolute)); // Todo is this supported? if (uri.Equals(request)) { var builder = new RouteRequestBuilder(route, route, null, segments); return(new List <RouteRequestBuilder> { builder }); } } } var depthStart = 0; if (segments[0] == shell.Route) { segments = segments.Skip(1).ToArray(); depthStart = 1; } else { depthStart = 0; } if (relativeMatch && shell?.CurrentItem != null) { // retrieve current location var currentLocation = NodeLocation.Create(shell); while (currentLocation.Shell != null) { List <RouteRequestBuilder> pureRoutesMatch = new List <RouteRequestBuilder>(); List <RouteRequestBuilder> pureGlobalRoutesMatch = new List <RouteRequestBuilder>(); SearchPath(currentLocation.LowestChild, null, segments, pureRoutesMatch, 0); SearchPath(currentLocation.LowestChild, null, segments, pureGlobalRoutesMatch, 0, ignoreGlobalRoutes: false); pureRoutesMatch = GetBestMatches(pureRoutesMatch); pureGlobalRoutesMatch = GetBestMatches(pureGlobalRoutesMatch); if (pureRoutesMatch.Count > 0) { return(pureRoutesMatch); } if (pureGlobalRoutesMatch.Count > 0) { return(pureGlobalRoutesMatch); } currentLocation.Pop(); } string searchPath = String.Join("/", segments); if (routeKeys.Contains(searchPath)) { return(new List <RouteRequestBuilder> { new RouteRequestBuilder(searchPath, searchPath, null, segments) }); } RouteRequestBuilder builder = null; foreach (var segment in segments) { if (routeKeys.Contains(segment)) { if (builder == null) { builder = new RouteRequestBuilder(segment, segment, null, segments); } else { builder.AddGlobalRoute(segment, segment); } } } if (builder != null && builder.IsFullMatch) { return new List <RouteRequestBuilder> { builder } } ; } else { possibleRoutePaths.Clear(); SearchPath(shell, null, segments, possibleRoutePaths, depthStart); var bestMatches = GetBestMatches(possibleRoutePaths); if (bestMatches.Count > 0) { return(bestMatches); } bestMatches.Clear(); foreach (var possibleRoutePath in possibleRoutePaths) { while (routeKeys.Contains(possibleRoutePath.NextSegment) || routeKeys.Contains(possibleRoutePath.RemainingPath)) { if (routeKeys.Contains(possibleRoutePath.NextSegment)) { possibleRoutePath.AddGlobalRoute(possibleRoutePath.NextSegment, possibleRoutePath.NextSegment); } else { possibleRoutePath.AddGlobalRoute(possibleRoutePath.RemainingPath, possibleRoutePath.RemainingPath); } } while (!possibleRoutePath.IsFullMatch) { NodeLocation nodeLocation = new NodeLocation(); nodeLocation.SetNode(possibleRoutePath.LowestChild); List <RouteRequestBuilder> pureGlobalRoutesMatch = new List <RouteRequestBuilder>(); while (nodeLocation.Shell != null && pureGlobalRoutesMatch.Count == 0) { SearchPath(nodeLocation.LowestChild, null, possibleRoutePath.RemainingSegments, pureGlobalRoutesMatch, 0, ignoreGlobalRoutes: false); nodeLocation.Pop(); } // nothing found or too many things found if (pureGlobalRoutesMatch.Count != 1) { break; } for (var i = 0; i < pureGlobalRoutesMatch[0].GlobalRouteMatches.Count; i++) { var match = pureGlobalRoutesMatch[0]; possibleRoutePath.AddGlobalRoute(match.GlobalRouteMatches[i], match.SegmentsMatched[i]); } } } } possibleRoutePaths = GetBestMatches(possibleRoutePaths); return(possibleRoutePaths); }