Skip to content

Commit 0211780

Browse files
authored
HTMX: Add v-querystring through javascript (#1453)
* HTMX: Add v-querystring through javascript * Cleanup * Cleanup * Refactor and add comments * Prettier * Fix tests
1 parent f8d4641 commit 0211780

File tree

13 files changed

+44
-97
lines changed

13 files changed

+44
-97
lines changed

src/Elastic.ApiExplorer/ApiViewModel.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
using Elastic.Documentation.Configuration;
77
using Elastic.Documentation.Configuration.Assembler;
88
using Elastic.Documentation.Configuration.Builder;
9+
using Elastic.Documentation.Extensions;
910
using Elastic.Documentation.Site;
1011
using Elastic.Documentation.Site.FileProviders;
1112
using Elastic.Documentation.Site.Navigation;
@@ -29,6 +30,7 @@ public HtmlString RenderMarkdown(string? markdown) =>
2930
public GlobalLayoutViewModel CreateGlobalLayoutModel() =>
3031
new()
3132
{
33+
DocsBuilderVersion = ShortId.Create(BuildContext.Version),
3234
DocSetName = "Api Explorer",
3335
Description = "",
3436
CurrentNavigationItem = CurrentNavigationItem,

src/Elastic.Documentation.Configuration/BuildContext.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information
44

55
using System.IO.Abstractions;
6+
using System.Reflection;
67
using Elastic.Documentation.Configuration.Assembler;
78
using Elastic.Documentation.Configuration.Builder;
89
using Elastic.Documentation.Diagnostics;
@@ -11,6 +12,8 @@ namespace Elastic.Documentation.Configuration;
1112

1213
public record BuildContext : IDocumentationContext
1314
{
15+
public static string Version { get; } = Assembly.GetExecutingAssembly().GetCustomAttributes<AssemblyInformationalVersionAttribute>()
16+
.FirstOrDefault()?.InformationalVersion ?? "0.0.0";
1417
public IFileSystem ReadFileSystem { get; }
1518
public IFileSystem WriteFileSystem { get; }
1619

src/Elastic.Documentation.Site/Assets/main.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,27 @@ document.body.addEventListener('htmx:responseError', function (event) {
9191
window.location.assign(event.detail.pathInfo.requestPath)
9292
}
9393
})
94+
95+
// We add a query string to the get request to make sure the requested page is up to date
96+
const docsBuilderVersion = $('body').dataset.docsBuilderVersion
97+
document.body.addEventListener('htmx:configRequest', function (event) {
98+
if (event.detail.verb === 'get') {
99+
event.detail.parameters['v'] = docsBuilderVersion
100+
}
101+
})
102+
103+
// Here we need to strip the v parameter from the URL so
104+
// that the browser doesn't show the v parameter in the address bar
105+
document.body.addEventListener('htmx:beforeHistoryUpdate', function (event) {
106+
const params = new URLSearchParams(
107+
event.detail.history.path.split('?')[1] ?? ''
108+
)
109+
params.delete('v')
110+
const pathWithoutQueryString = event.detail.history.path.split('?')[0]
111+
if (params.size === 0) {
112+
event.detail.history.path = pathWithoutQueryString
113+
} else {
114+
event.detail.history.path =
115+
pathWithoutQueryString + '?' + params.toString()
116+
}
117+
})

src/Elastic.Documentation.Site/Htmx.cs

Lines changed: 1 addition & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -9,91 +9,19 @@
99

1010
namespace Elastic.Documentation.Site;
1111

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-
6512
public static class Htmx
6613
{
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-
7314
public static string GetHxSelectOob(bool hasSameTopLevelGroup) => hasSameTopLevelGroup ? "#content-container,#toc-nav" : "#main-container";
7415
public const string Preload = "mousedown";
75-
public const string HxSwap = "none";
76-
public const string HxPushUrl = "true";
77-
public const string HxIndicator = "#htmx-indicator";
7816

7917
public static string GetHxAttributes(
80-
string targetUrl,
8118
bool hasSameTopLevelGroup = false,
8219
string? preload = Preload,
83-
string? hxSwapOob = null,
84-
string? hxSwap = HxSwap,
85-
string? hxPushUrl = HxPushUrl,
86-
string? hxIndicator = HxIndicator
20+
string? hxSwapOob = null
8721
)
8822
{
89-
var hxGetUrl = UrlHelper.AddVersionParameters(targetUrl);
90-
9123
var attributes = new StringBuilder();
92-
_ = attributes.Append($" hx-get={hxGetUrl}");
9324
_ = attributes.Append($" hx-select-oob={hxSwapOob ?? GetHxSelectOob(hasSameTopLevelGroup)}");
94-
_ = attributes.Append($" hx-swap={hxSwap}");
95-
_ = attributes.Append($" hx-push-url={hxPushUrl}");
96-
_ = attributes.Append($" hx-indicator={hxIndicator}");
9725
_ = attributes.Append($" preload={preload}");
9826
return attributes.ToString();
9927
}

src/Elastic.Documentation.Site/Layout/_SecondaryNav.cshtml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
<a
2020
href="@Model.Link("/release-notes/")"
2121
@Htmx.GetHxAttributes(
22-
targetUrl: Model.Link("/release-notes/"),
2322
hxSwapOob: "#main-container,#secondary-nav"
2423
)
2524
>
@@ -30,7 +29,6 @@
3029
<a
3130
href="@Model.Link("/troubleshoot/")"
3231
@Htmx.GetHxAttributes(
33-
targetUrl: Model.Link("/troubleshoot/"),
3432
hxSwapOob: "#main-container,#secondary-nav"
3533
)
3634
>
@@ -41,7 +39,6 @@
4139
<a
4240
href="@Model.Link("/reference/")"
4341
@Htmx.GetHxAttributes(
44-
Model.Link("/reference/"),
4542
hxSwapOob: "#main-container,#secondary-nav"
4643
)
4744
>

src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@using Elastic.Documentation.Site.Navigation
22
@inherits RazorSlice<Elastic.Documentation.Site.Navigation.NavigationViewModel>
3-
<div class="pb-20 font-body" hx-boost="true" hx-swap="none" hx-push-url="true" hx-indicator="#htmx-indicator">
3+
<div class="pb-20 font-body">
44
@{
55
var currentTopLevelItem = Model.TopLevelItems.FirstOrDefault(i => i.Id == Model.Tree.Id) ?? Model.Tree;
66
}

src/Elastic.Documentation.Site/_GlobalLayout.cshtml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
<body
1010
class="group/body text-ink has-[#primary-nav-hamburger:checked]:overflow-hidden"
1111
hx-ext="preload, head-support"
12-
data-root-path="@Model.Link("/")">
12+
data-docs-builder-version="@Model.DocsBuilderVersion"
13+
data-root-path="@Model.Link("/")"
14+
hx-boost="true" hx-swap="none" hx-push-url="true" hx-indicator="#htmx-indicator"
15+
>
1316
@if (Model.GoogleTagManager.Enabled)
1417
{
1518
<noscript><iframe src="https://www.googletagmanager.com/ns.html?id=@(Model.GoogleTagManager.Id)@(new HtmlString(Model.GoogleTagManager.QueryString()))"

src/Elastic.Documentation.Site/_ViewModels.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public static class GlobalSections
1717

1818
public record GlobalLayoutViewModel
1919
{
20+
public required string DocsBuilderVersion { get; init; }
2021
public required string DocSetName { get; init; }
2122
public string Title { get; set; } = "Elastic Documentation";
2223
public required string Description { get; init; }

src/Elastic.Markdown/Layout/_Breadcrumbs.cshtml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<a
1919
itemprop="item"
2020
href="@firstCrumb.Url"
21-
@Htmx.GetHxAttributes(firstCrumb.Url, Model.CurrentNavigationItem?.NavigationRoot.Id == firstCrumb.NavigationRoot.Id)
21+
@Htmx.GetHxAttributes( Model.CurrentNavigationItem?.NavigationRoot.Id == firstCrumb.NavigationRoot.Id)
2222
>
2323
<span itemprop="name" class="hover:text-black">@firstCrumb.NavigationTitle</span>
2424
</a>
@@ -41,7 +41,7 @@
4141
<a
4242
itemprop="item"
4343
href="@item.Url"
44-
@Htmx.GetHxAttributes(item.Url, Model.CurrentNavigationItem?.NavigationRoot.Id == item.NavigationRoot.Id)
44+
@Htmx.GetHxAttributes(Model.CurrentNavigationItem?.NavigationRoot.Id == item.NavigationRoot.Id)
4545
>
4646
<span itemprop="name" class="hover:text-black">@item.NavigationTitle</span>
4747
</a>

src/Elastic.Markdown/Layout/_PrevNextNav.cshtml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
{
77
<a
88
href="@Model.Previous.Url"
9-
@Htmx.GetHxAttributes(Model.Previous.Url, Model.CurrentNavigationItem?.NavigationRoot.Id == Model.Previous.NavigationRoot.Id)
9+
@Htmx.GetHxAttributes(Model.CurrentNavigationItem?.NavigationRoot.Id == Model.Previous.NavigationRoot.Id)
1010
class="flex h-full items-center text-ink-light hover:black border-1 border-grey-20 hover:border-grey-80 rounded-lg p-6 shadow-md"
1111
>
1212
<svg class="size-6 mr-2" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
@@ -24,7 +24,7 @@
2424
{
2525
<a
2626
href="@Model.Next.Url"
27-
@Htmx.GetHxAttributes(Model.Next.Url, Model.CurrentNavigationItem?.NavigationRoot.Id == Model.Next.NavigationRoot.Id)
27+
@Htmx.GetHxAttributes(Model.CurrentNavigationItem?.NavigationRoot.Id == Model.Next.NavigationRoot.Id)
2828
class="flex h-full items-center justify-end text-ink-light hover:black border-1 border-grey-20 hover:border-grey-80 rounded-lg p-6 shadow-md text-right"
2929
>
3030
<div>

0 commit comments

Comments
 (0)