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);
				}
			}
		}
Example #2
0
        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);
        }
Example #3
0
        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);
        }