static void SearchPath( object node, RouteRequestBuilder currentMatchedPath, string[] segments, List <RouteRequestBuilder> possibleRoutePaths, int depthToStart, int myDepth = -1, NodeLocation currentLocation = null, bool ignoreGlobalRoutes = true) { if (node is GlobalRouteItem && ignoreGlobalRoutes) { return; } ++myDepth; currentLocation = currentLocation ?? new NodeLocation(); currentLocation.SetNode(node); IEnumerable items = null; if (depthToStart > myDepth) { items = GetItems(node); if (items == null) { return; } foreach (var nextNode in items) { SearchPath(nextNode, null, segments, possibleRoutePaths, depthToStart, myDepth, currentLocation, ignoreGlobalRoutes); } return; } string shellSegment = GetRoute(node); string userSegment = null; if (currentMatchedPath == null) { userSegment = segments[0]; } else { userSegment = currentMatchedPath.NextSegment; } if (userSegment == null) { return; } RouteRequestBuilder builder = null; if (shellSegment == userSegment || Routing.IsImplicit(shellSegment)) { if (currentMatchedPath == null) { builder = new RouteRequestBuilder(shellSegment, userSegment, node, segments); } else { builder = new RouteRequestBuilder(currentMatchedPath); builder.AddMatch(shellSegment, userSegment, node); } if (!Routing.IsImplicit(shellSegment) || shellSegment == userSegment) { possibleRoutePaths.Add(builder); } } items = GetItems(node); if (items == null) { return; } foreach (var nextNode in items) { SearchPath(nextNode, builder, segments, possibleRoutePaths, depthToStart, myDepth, currentLocation, ignoreGlobalRoutes); } }
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++) { 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); }