@@ -82,17 +82,32 @@ public SiteNavigationV2(
8282 /// </summary>
8383 public NavigationSection ? GetSectionForUrl ( string ? pageUrl )
8484 {
85- if ( pageUrl is not null )
86- {
87- var normalized = pageUrl . TrimEnd ( '/' ) ;
88- if ( _urlToSection . TryGetValue ( normalized , out var section ) )
89- return section ;
90- if ( _urlToSection . TryGetValue ( normalized + "/" , out section ) )
91- return section ;
92- }
85+ if ( pageUrl is not null && TryGetSectionForUrl ( pageUrl , out var section ) )
86+ return section ;
9387 return Sections . FirstOrDefault ( s => ! s . Isolated ) ;
9488 }
9589
90+ private bool TryGetSectionForUrl ( string url , out NavigationSection section )
91+ {
92+ var normalized = url . TrimEnd ( '/' ) ;
93+ if ( _urlToSection . TryGetValue ( normalized , out section ! ) )
94+ return true ;
95+ if ( _urlToSection . TryGetValue ( normalized + "/" , out section ! ) )
96+ return true ;
97+
98+ var prefix = Url . TrimEnd ( '/' ) ;
99+ if ( ! string . IsNullOrEmpty ( prefix ) && normalized . StartsWith ( $ "{ prefix } /", StringComparison . OrdinalIgnoreCase ) )
100+ {
101+ var withoutPrefix = normalized [ prefix . Length ..] ;
102+ if ( _urlToSection . TryGetValue ( withoutPrefix , out section ! ) )
103+ return true ;
104+ if ( _urlToSection . TryGetValue ( withoutPrefix + "/" , out section ! ) )
105+ return true ;
106+ }
107+
108+ section = null ! ;
109+ return false ;
110+ }
96111 private static IReadOnlyList < NavigationSection > BuildSections ( IReadOnlyList < INavigationItem > items ) =>
97112 items
98113 . OfType < SectionNavigationNode > ( )
@@ -137,7 +152,10 @@ [.. islandNode.NavigationItems]
137152 private void BuildUrlToSectionLookup ( )
138153 {
139154 foreach ( var section in Sections )
155+ {
140156 CollectUrlsForSection ( section . NavigationItems , section ) ;
157+ AddUrlToSection ( section . Url , section , replaceExisting : true ) ;
158+ }
141159 }
142160
143161 private void CollectUrlsForSection ( IEnumerable < INavigationItem > items , NavigationSection section )
@@ -148,17 +166,40 @@ private void CollectUrlsForSection(IEnumerable<INavigationItem> items, Navigatio
148166 if ( item is IslandNavigationNode )
149167 continue ;
150168
151- if ( ! string . IsNullOrEmpty ( item . Url ) )
152- {
153- var normalized = item . Url . TrimEnd ( '/' ) ;
154- _ = _urlToSection . TryAdd ( normalized , section ) ;
155- }
169+ AddUrlToSection ( item . Url , section ) ;
156170
157171 if ( item is INodeNavigationItem < INavigationModel , INavigationItem > node )
158172 CollectUrlsForSection ( node . NavigationItems , section ) ;
159173 }
160174 }
161175
176+ private void AddUrlToSection ( string url , NavigationSection section , bool replaceExisting = false )
177+ {
178+ if ( string . IsNullOrEmpty ( url ) )
179+ return ;
180+ AddNormalizedUrlToSection ( url , section , replaceExisting ) ;
181+ if ( IsExternalUrl ( url ) )
182+ return ;
183+ var prefix = Url . TrimEnd ( '/' ) ;
184+ var path = url . TrimStart ( '/' ) ;
185+ var prefixed = string . IsNullOrEmpty ( path ) ? prefix : $ "{ prefix } /{ path } ";
186+ if ( ! url . Equals ( prefixed , StringComparison . OrdinalIgnoreCase ) )
187+ AddNormalizedUrlToSection ( prefixed , section , replaceExisting ) ;
188+ }
189+
190+ private void AddNormalizedUrlToSection ( string url , NavigationSection section , bool replaceExisting )
191+ {
192+ var normalized = url . TrimEnd ( '/' ) ;
193+ if ( replaceExisting )
194+ _urlToSection [ normalized ] = section ;
195+ else
196+ _ = _urlToSection . TryAdd ( normalized , section ) ;
197+ }
198+
199+ private static bool IsExternalUrl ( string url ) =>
200+ url . StartsWith ( "http://" , StringComparison . OrdinalIgnoreCase ) ||
201+ url . StartsWith ( "https://" , StringComparison . OrdinalIgnoreCase ) ;
202+
162203 private void BuildTocRootToIslandLookup ( )
163204 {
164205 foreach ( var island in Islands )
0 commit comments