2
2
// Elasticsearch B.V licenses this file to you under the Apache 2.0 License.
3
3
// See the LICENSE file in the project root for more information
4
4
5
+ using System . Reflection ;
5
6
using System . Text ;
7
+ using System . Text . Encodings . Web ;
8
+ using Elastic . Documentation . Extensions ;
6
9
7
10
namespace Elastic . Documentation . Site ;
8
11
12
+ public static class UrlHelper
13
+ {
14
+ private static readonly KeyValuePair < string , string ? > [ ] VersionParameters = [ new ( "v" , Htmx . VersionHash ) ] ;
15
+
16
+ public static string AddVersionParameters ( string uri ) => AddQueryString ( uri , VersionParameters ) ;
17
+
18
+ /// <summary>
19
+ /// Append the given query keys and values to the URI.
20
+ /// </summary>
21
+ /// <param name="uri">The base URI.</param>
22
+ /// <param name="queryString">A collection of name value query pairs to append.</param>
23
+ /// <returns>The combined result.</returns>
24
+ /// <exception cref="ArgumentNullException"><paramref name="uri"/> is <c>null</c>.</exception>
25
+ /// <exception cref="ArgumentNullException"><paramref name="queryString"/> is <c>null</c>.</exception>
26
+ public static string AddQueryString (
27
+ string uri ,
28
+ IEnumerable < KeyValuePair < string , string ? > > queryString )
29
+ {
30
+ ArgumentNullException . ThrowIfNull ( uri ) ;
31
+ ArgumentNullException . ThrowIfNull ( queryString ) ;
32
+
33
+ var anchorIndex = uri . IndexOf ( '#' ) ;
34
+ var uriToBeAppended = uri . AsSpan ( ) ;
35
+ var anchorText = ReadOnlySpan < char > . Empty ;
36
+ // If there is an anchor, then the query string must be inserted before its first occurrence.
37
+ if ( anchorIndex != - 1 )
38
+ {
39
+ anchorText = uriToBeAppended . Slice ( anchorIndex ) ;
40
+ uriToBeAppended = uriToBeAppended . Slice ( 0 , anchorIndex ) ;
41
+ }
42
+
43
+ var queryIndex = uriToBeAppended . IndexOf ( '?' ) ;
44
+ var hasQuery = queryIndex != - 1 ;
45
+
46
+ var sb = new StringBuilder ( ) ;
47
+ _ = sb . Append ( uriToBeAppended ) ;
48
+ foreach ( var parameter in queryString )
49
+ {
50
+ if ( parameter . Value == null )
51
+ continue ;
52
+
53
+ _ = sb . Append ( hasQuery ? '&' : '?' )
54
+ . Append ( UrlEncoder . Default . Encode ( parameter . Key ) )
55
+ . Append ( '=' )
56
+ . Append ( UrlEncoder . Default . Encode ( parameter . Value ) ) ;
57
+ hasQuery = true ;
58
+ }
59
+
60
+ _ = sb . Append ( anchorText ) ;
61
+ return sb . ToString ( ) ;
62
+ }
63
+ }
64
+
9
65
public static class Htmx
10
66
{
67
+ private static readonly string Version =
68
+ Assembly . GetExecutingAssembly ( ) . GetCustomAttributes < AssemblyInformationalVersionAttribute > ( )
69
+ . FirstOrDefault ( ) ? . InformationalVersion ?? "0.0.0" ;
70
+
71
+ public static readonly string VersionHash = ShortId . Create ( Version ) ;
72
+
11
73
public static string GetHxSelectOob ( bool hasSameTopLevelGroup ) => hasSameTopLevelGroup ? "#content-container,#toc-nav" : "#main-container" ;
12
74
public const string Preload = "mousedown" ;
13
75
public const string HxSwap = "none" ;
@@ -24,8 +86,10 @@ public static string GetHxAttributes(
24
86
string ? hxIndicator = HxIndicator
25
87
)
26
88
{
89
+ var hxGetUrl = UrlHelper . AddVersionParameters ( targetUrl ) ;
90
+
27
91
var attributes = new StringBuilder ( ) ;
28
- _ = attributes . Append ( $ " hx-get={ targetUrl } ") ;
92
+ _ = attributes . Append ( $ " hx-get={ hxGetUrl } ") ;
29
93
_ = attributes . Append ( $ " hx-select-oob={ hxSwapOob ?? GetHxSelectOob ( hasSameTopLevelGroup ) } ") ;
30
94
_ = attributes . Append ( $ " hx-swap={ hxSwap } ") ;
31
95
_ = attributes . Append ( $ " hx-push-url={ hxPushUrl } ") ;
0 commit comments