diff --git a/src/Elastic.ApiExplorer/ApiViewModel.cs b/src/Elastic.ApiExplorer/ApiViewModel.cs index 4d53d79d9..6541365c4 100644 --- a/src/Elastic.ApiExplorer/ApiViewModel.cs +++ b/src/Elastic.ApiExplorer/ApiViewModel.cs @@ -6,6 +6,7 @@ using Elastic.Documentation.Configuration; using Elastic.Documentation.Configuration.Assembler; using Elastic.Documentation.Configuration.Builder; +using Elastic.Documentation.Extensions; using Elastic.Documentation.Site; using Elastic.Documentation.Site.FileProviders; using Elastic.Documentation.Site.Navigation; @@ -29,6 +30,7 @@ public HtmlString RenderMarkdown(string? markdown) => public GlobalLayoutViewModel CreateGlobalLayoutModel() => new() { + DocsBuilderVersion = ShortId.Create(BuildContext.Version), DocSetName = "Api Explorer", Description = "", CurrentNavigationItem = CurrentNavigationItem, diff --git a/src/Elastic.Documentation.Configuration/BuildContext.cs b/src/Elastic.Documentation.Configuration/BuildContext.cs index 2cdce4a08..5265aa171 100644 --- a/src/Elastic.Documentation.Configuration/BuildContext.cs +++ b/src/Elastic.Documentation.Configuration/BuildContext.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information using System.IO.Abstractions; +using System.Reflection; using Elastic.Documentation.Configuration.Assembler; using Elastic.Documentation.Configuration.Builder; using Elastic.Documentation.Diagnostics; @@ -11,6 +12,8 @@ namespace Elastic.Documentation.Configuration; public record BuildContext : IDocumentationContext { + public static string Version { get; } = Assembly.GetExecutingAssembly().GetCustomAttributes() + .FirstOrDefault()?.InformationalVersion ?? "0.0.0"; public IFileSystem ReadFileSystem { get; } public IFileSystem WriteFileSystem { get; } diff --git a/src/Elastic.Documentation.Site/Assets/main.ts b/src/Elastic.Documentation.Site/Assets/main.ts index c475d8799..de8404f8c 100644 --- a/src/Elastic.Documentation.Site/Assets/main.ts +++ b/src/Elastic.Documentation.Site/Assets/main.ts @@ -91,3 +91,27 @@ document.body.addEventListener('htmx:responseError', function (event) { window.location.assign(event.detail.pathInfo.requestPath) } }) + +// We add a query string to the get request to make sure the requested page is up to date +const docsBuilderVersion = $('body').dataset.docsBuilderVersion +document.body.addEventListener('htmx:configRequest', function (event) { + if (event.detail.verb === 'get') { + event.detail.parameters['v'] = docsBuilderVersion + } +}) + +// Here we need to strip the v parameter from the URL so +// that the browser doesn't show the v parameter in the address bar +document.body.addEventListener('htmx:beforeHistoryUpdate', function (event) { + const params = new URLSearchParams( + event.detail.history.path.split('?')[1] ?? '' + ) + params.delete('v') + const pathWithoutQueryString = event.detail.history.path.split('?')[0] + if (params.size === 0) { + event.detail.history.path = pathWithoutQueryString + } else { + event.detail.history.path = + pathWithoutQueryString + '?' + params.toString() + } +}) diff --git a/src/Elastic.Documentation.Site/Htmx.cs b/src/Elastic.Documentation.Site/Htmx.cs index c10140132..ff340d363 100644 --- a/src/Elastic.Documentation.Site/Htmx.cs +++ b/src/Elastic.Documentation.Site/Htmx.cs @@ -9,91 +9,19 @@ namespace Elastic.Documentation.Site; -public static class UrlHelper -{ - private static readonly KeyValuePair[] VersionParameters = [new("v", Htmx.VersionHash)]; - - public static string AddVersionParameters(string uri) => AddQueryString(uri, VersionParameters); - - /// - /// Append the given query keys and values to the URI. - /// - /// The base URI. - /// A collection of name value query pairs to append. - /// The combined result. - /// is null. - /// is null. - public static string AddQueryString( - string uri, - IEnumerable> queryString) - { - ArgumentNullException.ThrowIfNull(uri); - ArgumentNullException.ThrowIfNull(queryString); - - var anchorIndex = uri.IndexOf('#'); - var uriToBeAppended = uri.AsSpan(); - var anchorText = ReadOnlySpan.Empty; - // If there is an anchor, then the query string must be inserted before its first occurrence. - if (anchorIndex != -1) - { - anchorText = uriToBeAppended.Slice(anchorIndex); - uriToBeAppended = uriToBeAppended.Slice(0, anchorIndex); - } - - var queryIndex = uriToBeAppended.IndexOf('?'); - var hasQuery = queryIndex != -1; - - var sb = new StringBuilder(); - _ = sb.Append(uriToBeAppended); - foreach (var parameter in queryString) - { - if (parameter.Value == null) - continue; - - _ = sb.Append(hasQuery ? '&' : '?') - .Append(UrlEncoder.Default.Encode(parameter.Key)) - .Append('=') - .Append(UrlEncoder.Default.Encode(parameter.Value)); - hasQuery = true; - } - - _ = sb.Append(anchorText); - return sb.ToString(); - } -} - public static class Htmx { - private static readonly string Version = - Assembly.GetExecutingAssembly().GetCustomAttributes() - .FirstOrDefault()?.InformationalVersion ?? "0.0.0"; - - public static readonly string VersionHash = ShortId.Create(Version); - public static string GetHxSelectOob(bool hasSameTopLevelGroup) => hasSameTopLevelGroup ? "#content-container,#toc-nav" : "#main-container"; public const string Preload = "mousedown"; - public const string HxSwap = "none"; - public const string HxPushUrl = "true"; - public const string HxIndicator = "#htmx-indicator"; public static string GetHxAttributes( - string targetUrl, bool hasSameTopLevelGroup = false, string? preload = Preload, - string? hxSwapOob = null, - string? hxSwap = HxSwap, - string? hxPushUrl = HxPushUrl, - string? hxIndicator = HxIndicator + string? hxSwapOob = null ) { - var hxGetUrl = UrlHelper.AddVersionParameters(targetUrl); - var attributes = new StringBuilder(); - _ = attributes.Append($" hx-get={hxGetUrl}"); _ = attributes.Append($" hx-select-oob={hxSwapOob ?? GetHxSelectOob(hasSameTopLevelGroup)}"); - _ = attributes.Append($" hx-swap={hxSwap}"); - _ = attributes.Append($" hx-push-url={hxPushUrl}"); - _ = attributes.Append($" hx-indicator={hxIndicator}"); _ = attributes.Append($" preload={preload}"); return attributes.ToString(); } diff --git a/src/Elastic.Documentation.Site/Layout/_SecondaryNav.cshtml b/src/Elastic.Documentation.Site/Layout/_SecondaryNav.cshtml index f4bd99a58..085a5d12b 100644 --- a/src/Elastic.Documentation.Site/Layout/_SecondaryNav.cshtml +++ b/src/Elastic.Documentation.Site/Layout/_SecondaryNav.cshtml @@ -19,7 +19,6 @@ @@ -30,7 +29,6 @@ @@ -41,7 +39,6 @@ diff --git a/src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml b/src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml index 3c2527e94..fc8b2c12d 100644 --- a/src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml +++ b/src/Elastic.Documentation.Site/Navigation/_TocTree.cshtml @@ -1,6 +1,6 @@ @using Elastic.Documentation.Site.Navigation @inherits RazorSlice -
+
@{ var currentTopLevelItem = Model.TopLevelItems.FirstOrDefault(i => i.Id == Model.Tree.Id) ?? Model.Tree; } diff --git a/src/Elastic.Documentation.Site/_GlobalLayout.cshtml b/src/Elastic.Documentation.Site/_GlobalLayout.cshtml index a396783cf..afbdfcc6b 100644 --- a/src/Elastic.Documentation.Site/_GlobalLayout.cshtml +++ b/src/Elastic.Documentation.Site/_GlobalLayout.cshtml @@ -9,7 +9,10 @@ + data-docs-builder-version="@Model.DocsBuilderVersion" + data-root-path="@Model.Link("/")" + hx-boost="true" hx-swap="none" hx-push-url="true" hx-indicator="#htmx-indicator" + > @if (Model.GoogleTagManager.Enabled) {