Exemple #1
0
        static List <RouteRequestBuilder> SearchForGlobalRoutes(
            string[] segments,
            Uri startingFrom,
            NodeLocation currentLocation,
            string[] routeKeys)
        {
            List <RouteRequestBuilder> pureGlobalRoutesMatch = new List <RouteRequestBuilder>();
            string        newPath                  = String.Join(_pathSeparator, segments);
            var           currentSegments          = RetrievePaths(startingFrom.OriginalString);
            var           newSegments              = CollapsePath(newPath, currentSegments, true).ToArray();
            List <string> fullRouteWithNewSegments = new List <string>(currentSegments);

            fullRouteWithNewSegments.AddRange(newSegments);

            // This is used to calculate if the global route matches
            RouteRequestBuilder routeRequestBuilder = new RouteRequestBuilder(fullRouteWithNewSegments.ToArray());

            // add shell element routes
            routeRequestBuilder.AddMatch(currentLocation);

            // add routes that are contributed by global routes
            for (var i = 0; i < currentSegments.Length; i++)
            {
                var currentSeg = currentSegments[i];
                if (routeRequestBuilder.FullSegments.Count <= i || currentSeg != routeRequestBuilder.FullSegments[i])
                {
                    routeRequestBuilder.AddGlobalRoute(currentSeg, currentSeg);
                }
            }

            var existingGlobalRoutes = routeRequestBuilder.GlobalRouteMatches.ToList();

            ExpandOutGlobalRoutes(new List <RouteRequestBuilder> {
                routeRequestBuilder
            }, routeKeys);
            if (routeRequestBuilder.IsFullMatch)
            {
                RouteRequestBuilder requestBuilderWithNewSegments = new RouteRequestBuilder(newSegments);

                var additionalRouteMatches = routeRequestBuilder.GlobalRouteMatches;
                for (int i = existingGlobalRoutes.Count; i < additionalRouteMatches.Count; i++)
                {
                    requestBuilderWithNewSegments.AddGlobalRoute(additionalRouteMatches[i], segments[i - existingGlobalRoutes.Count]);
                }

                pureGlobalRoutesMatch.Add(requestBuilderWithNewSegments);
            }

            return(pureGlobalRoutesMatch);
        }
Exemple #2
0
        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);
            }
        }
Exemple #3
0
        static bool FindAndAddSegmentMatch(RouteRequestBuilder possibleRoutePath, string[] routeKeys)
        {
            // First search by collapsing global routes if user is registering routes like "route1/route2/route3"
            foreach (var routeKey in routeKeys)
            {
                var collapsedRoutes = CollapsePath(routeKey, possibleRoutePath.SegmentsMatched, true);
                var collapsedRoute  = String.Join(_pathSeparator, collapsedRoutes);

                if (routeKey.StartsWith("//"))
                {
                    var routeKeyPaths =
                        routeKey.Split(_pathSeparators, StringSplitOptions.RemoveEmptyEntries);

                    if (routeKeyPaths[0] == collapsedRoutes[0])
                    {
                        collapsedRoute = "//" + collapsedRoute;
                    }
                }

                string collapsedMatch = possibleRoutePath.GetNextSegmentMatch(collapsedRoute);
                if (!String.IsNullOrWhiteSpace(collapsedMatch))
                {
                    possibleRoutePath.AddGlobalRoute(routeKey, collapsedMatch);
                    return(true);
                }

                // If the registered route is a combination of shell items and global routes then we might end up here
                // without the previous tree search finding the correct path
                if ((possibleRoutePath.Shell != null) &&
                    (possibleRoutePath.Item == null || possibleRoutePath.Section == null || possibleRoutePath.Content == null))
                {
                    var nextNode = possibleRoutePath.GetNodeLocation().WalkToNextNode();

                    while (nextNode != null)
                    {
                        // This means we've jumped to a branch that no longer corresponds with the route path we are searching
                        if ((possibleRoutePath.Item != null && nextNode.Item != possibleRoutePath.Item) ||
                            (possibleRoutePath.Section != null && nextNode.Section != possibleRoutePath.Section) ||
                            (possibleRoutePath.Content != null && nextNode.Content != possibleRoutePath.Content))
                        {
                            nextNode = nextNode.WalkToNextNode();
                            continue;
                        }

                        var leafSearch = new RouteRequestBuilder(possibleRoutePath);
                        if (!leafSearch.AddMatch(nextNode))
                        {
                            nextNode = nextNode.WalkToNextNode();
                            continue;
                        }

                        var collapsedLeafRoute = String.Join(_pathSeparator, CollapsePath(routeKey, leafSearch.SegmentsMatched, true));

                        if (routeKey.StartsWith("//"))
                        {
                            collapsedLeafRoute = "//" + collapsedLeafRoute;
                        }

                        string segmentMatch = leafSearch.GetNextSegmentMatch(collapsedLeafRoute);
                        if (!String.IsNullOrWhiteSpace(segmentMatch))
                        {
                            possibleRoutePath.AddMatch(nextNode);
                            possibleRoutePath.AddGlobalRoute(routeKey, segmentMatch);
                            return(true);
                        }

                        nextNode = nextNode.WalkToNextNode();
                    }
                }
            }

            // check for exact matches
            if (routeKeys.Contains(possibleRoutePath.NextSegment))
            {
                possibleRoutePath.AddGlobalRoute(possibleRoutePath.NextSegment, possibleRoutePath.NextSegment);
                return(true);
            }

            return(false);
        }
Exemple #4
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 = RetrievePaths(localPath);

            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);


                    if (currentLocation.Content != null && pureGlobalRoutesMatch.Count == 0)
                    {
                        string newPath         = $"{shell.CurrentState.Location.OriginalString}{_pathSeparator}{String.Join(_pathSeparator, segments)}";
                        var    currentSegments = RetrievePaths(shell.CurrentState.FullLocation.OriginalString);
                        var    newSegments     = RetrievePaths(newPath);

                        RouteRequestBuilder routeRequestBuilder           = new RouteRequestBuilder(newSegments);
                        RouteRequestBuilder requestBuilderWithNewSegments = new RouteRequestBuilder(segments);

                        // add shell element routes
                        routeRequestBuilder.AddMatch(currentLocation);

                        // add routes that are contributed by global routes
                        for (var i = 0; i < currentSegments.Length; i++)
                        {
                            var currentSeg = currentSegments[i];
                            if (routeRequestBuilder.FullSegments.Count <= i || currentSeg != routeRequestBuilder.FullSegments[i])
                            {
                                routeRequestBuilder.AddGlobalRoute(currentSeg, currentSeg);
                            }
                        }

                        var existingGlobalRoutes = routeRequestBuilder.GlobalRouteMatches.ToList();
                        ExpandOutGlobalRoutes(new List <RouteRequestBuilder> {
                            routeRequestBuilder
                        }, routeKeys);
                        if (routeRequestBuilder.IsFullMatch)
                        {
                            var additionalRouteMatches = routeRequestBuilder.GlobalRouteMatches;
                            for (int i = existingGlobalRoutes.Count; i < additionalRouteMatches.Count; i++)
                            {
                                requestBuilderWithNewSegments.AddGlobalRoute(additionalRouteMatches[i], segments[i - existingGlobalRoutes.Count]);
                            }

                            pureGlobalRoutesMatch.Add(requestBuilderWithNewSegments);
                        }
                    }

                    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 sudden starts creating routes

                        int shellElementsMatched =
                            pureGlobalRoutesMatch[0].SegmentsMatched.Count -
                            pureGlobalRoutesMatch[0].GlobalRouteMatches.Count;

                        if (!enableRelativeShellRoutes && shellElementsMatched > 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);
        }