Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public static class ServiceCollectionExtensions
/// <param name="services">The service collection.</param>
/// <param name="configure">An optional delegate used to configure HTMX Toolkit.</param>
/// <returns>
/// The same service collection.
/// The same <paramref name="services" /> collection.
/// </returns>
public static IServiceCollection AddHtmxToolkit(this IServiceCollection services, Action<HtmxToolkitOptions>? configure = null)
{
Expand Down
33 changes: 12 additions & 21 deletions src/Ramstack.HtmxToolkit/HtmxFieldValues.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,20 @@ public string this[int index]
}

/// <summary>
/// Gets the underlying storage: a string, a string array, or <see langword="null" />.
/// Gets the underlying storage: a <see langword="string" />, an array of <see langword="string" /> values,
/// or <see langword="null" />.
/// </summary>
internal object? Values => _values;

/// <summary>
/// Initializes a new instance of the <see cref="HtmxFieldValues" /> structure
/// with a single value.
/// Initializes a new instance of the <see cref="HtmxFieldValues" /> structure with a single value.
/// </summary>
/// <param name="value">The value to store, or <see langword="null" />
/// to represent no values.</param>
/// <param name="value">The value to store, or <see langword="null" /> to represent no values.</param>
public HtmxFieldValues(string? value) =>
_values = value;

/// <summary>
/// Initializes a new instance of the <see cref="HtmxFieldValues" /> structure
/// with the specified values.
/// Initializes a new instance of the <see cref="HtmxFieldValues" /> structure with the specified values.
/// </summary>
/// <remarks>The specified array is stored directly and is not copied.</remarks>
/// <param name="values">The values to store, or <see langword="null" />
Expand All @@ -95,7 +93,7 @@ public static HtmxFieldValues Create(ReadOnlySpan<string> values)
}

/// <summary>
/// Converts a string to an <see cref="HtmxFieldValues" />.
/// Converts a <see langword="string" /> to an <see cref="HtmxFieldValues" />.
/// </summary>
/// <param name="value">The value to convert, or <see langword="null" />
/// to represent no values.</param>
Expand All @@ -106,10 +104,9 @@ public static implicit operator HtmxFieldValues(string? value) =>
new(value);

/// <summary>
/// Converts an array of strings to an <see cref="HtmxFieldValues" />.
/// Converts an array of <see langword="string" /> values to an <see cref="HtmxFieldValues" />.
/// </summary>
/// <param name="values">The values to convert, or <see langword="null" />
/// to represent no values.</param>
/// <param name="values">The values to convert, or <see langword="null" /> to represent no values.</param>
/// <returns>
/// An <see cref="HtmxFieldValues" /> containing <paramref name="values" />.
/// </returns>
Expand Down Expand Up @@ -152,14 +149,8 @@ private static string OutOfBounds() =>
/// Copies the specified read-only span to a new array.
/// </summary>
/// <remarks>
/// <para>
/// The JIT compiler inlines the implementation of <see cref="ReadOnlySpan{T}.ToArray" />
/// into its caller, producing a disproportionately large amount of native code
/// at the call site.
/// </para>
/// <para>
/// This non-inlined wrapper keeps that implementation out of <see cref="Create" />.
/// </para>
/// This non-inlined wrapper keeps the implementation of <see cref="ReadOnlySpan{T}.ToArray" />
/// out of <see cref="Create" /> to limit native code growth at its call sites.
/// </remarks>
/// <param name="s">The values to copy.</param>
/// <returns>
Expand All @@ -172,7 +163,7 @@ private static string[] CreateArray(ReadOnlySpan<string> s) =>
#region Inner type: Enumerator

/// <summary>
/// Enumerates the strings represented by an <see cref="HtmxFieldValues" />.
/// Enumerates the string values represented by an <see cref="HtmxFieldValues" />.
/// </summary>
public struct Enumerator : IEnumerator<string>
{
Expand All @@ -186,7 +177,7 @@ public struct Enumerator : IEnumerator<string>
/// <summary>
/// Initializes a new enumerator for the specified <see cref="HtmxFieldValues" />.
/// </summary>
/// <param name="value">The value whose strings to enumerate.</param>
/// <param name="value">The value containing the strings to enumerate.</param>
public Enumerator(HtmxFieldValues value)
{
if (value.Values is string s)
Expand Down
30 changes: 22 additions & 8 deletions src/Ramstack.HtmxToolkit/HtmxLocationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@ public sealed class HtmxLocationOptions
public string? Path { get; internal set; }

/// <summary>
/// Gets or sets the source element that initiated the request.
/// Gets or sets the CSS selector for the element used as the source of the new request.
/// </summary>
/// <remarks>Supported in HTMX 1.9.x, HTMX 2.x, and HTMX 4.x.</remarks>
public string? Source { get; set; }

/// <summary>
/// Gets or sets the target element into which the response will be swapped.
/// Gets or sets the selector for the target element into which the response will be swapped.
/// </summary>
/// <remarks>Supported in HTMX 1.9.x, HTMX 2.x, and HTMX 4.x.</remarks>
public string? Target { get; set; }
Expand All @@ -37,14 +37,27 @@ public sealed class HtmxLocationOptions
/// <summary>
/// Gets or sets the form field values to submit with the request.
/// </summary>
/// <remarks>Supported in HTMX 1.9.x, HTMX 2.x, and HTMX 4.x.</remarks>
/// <remarks>
/// <para>Supported in HTMX 1.9.x, HTMX 2.x, and HTMX 4.x.</para>
/// <para>
/// HTMX 1.9.x and 2.x submit array values as repeated parameters.
/// HTMX 4.0.0 converts an array to a single comma-separated field value.
/// </para>
/// </remarks>
public IDictionary<string, HtmxFieldValues>? Values { get; set; }

/// <summary>
/// Gets or sets the headers to include with the request.
/// Header values must be strings. Pass complex data as a pre-serialized JSON string.
/// </summary>
/// <remarks>Supported in HTMX 1.9.x, HTMX 2.x, and HTMX 4.x.</remarks>
/// <remarks>
/// <para>
/// Supported in HTMX 1.9.x, HTMX 2.x, and HTMX 4.x.
/// </para>
/// <para>
/// Header values must be strings.
/// Pass complex data as a pre-serialized JSON string.
/// </para>
/// </remarks>
public IDictionary<string, string>? Headers { get; set; }

/// <summary>
Expand All @@ -54,17 +67,18 @@ public sealed class HtmxLocationOptions
public string? Select { get; set; }

/// <summary>
/// Gets or sets a selector used to select content for out-of-band swaps from the response.
/// Gets or sets a comma-separated list of selectors, optionally followed by swap styles,
/// used to select content for out-of-band swaps from the response.
/// </summary>
/// <remarks>Supported in HTMX 2.x and HTMX 4.x.</remarks>
/// <remarks>Supported in HTMX 2.0.8 and later 2.x releases, and in HTMX 4.x.</remarks>
[JsonPropertyName("selectOOB")]
public string? SelectOob { get; set; }

/// <summary>
/// Gets or sets the path to push into the browser history.
/// Set this property to <c>"false"</c> to prevent the URL from being pushed.
/// </summary>
/// <remarks>Supported in HTMX 2.x and HTMX 4.x.</remarks>
/// <remarks>Supported in HTMX 2.0.8 and later 2.x releases, and in HTMX 4.x.</remarks>
public string? Push { get; set; }

/// <summary>
Expand Down
29 changes: 20 additions & 9 deletions src/Ramstack.HtmxToolkit/HtmxRequestHeaderNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ namespace Ramstack.HtmxToolkit;
public static class HtmxRequestHeaderNames
{
/// <summary>
/// The <c>HX-Boosted</c> header indicates whether the request was made using AJAX
/// instead of a normal navigation.
/// The <c>HX-Boosted</c> header indicates that the request came from a link or form
/// enhanced with <c>hx-boost</c>.
/// </summary>
public const string Boosted = "HX-Boosted";

Expand All @@ -21,16 +21,21 @@ public static class HtmxRequestHeaderNames

/// <summary>
/// The <c>HX-History-Restore-Request</c> header indicates whether the request
/// is for history restoration after a miss in the local history cache.
/// fetches content for history restoration.
/// </summary>
/// <remarks>
/// HTMX 1.x and 2.x send this header after a history cache miss.
/// HTMX 4.x refetches history content by default; local caching requires an extension.
/// </remarks>
public const string HistoryRestoreRequest = "HX-History-Restore-Request";

/// <summary>
/// The <c>HX-Prompt</c> header contains the user's response to an <c>hx-prompt</c>.
/// </summary>
/// <remarks>
/// Supported only in HTMX 1.x and 2.x. HTMX 4.x removed <c>hx-prompt</c>
/// and does not send this header.
/// Supported natively in HTMX 1.x and 2.x. In HTMX 4.x, the
/// <see href="https://four.htmx.org/extensions/hx-prompt">hx-prompt extension</see>
/// restores this header.
/// </remarks>
public const string Prompt = "HX-Prompt";

Expand All @@ -54,7 +59,9 @@ public static class HtmxRequestHeaderNames
/// The <c>HX-Source</c> header identifies the element that triggered the request.
/// </summary>
/// <remarks>
/// Supported only in HTMX 4.x. The value is in <c>tag#id</c> format, for example <c>button#submit</c>.
/// Supported only in HTMX 4.x. The value contains the lowercase tag name and,
/// when the element has an ID, <c>#</c> followed by its URI-encoded ID.
/// Examples include <c>button#submit</c> and <c>button</c>.
/// </remarks>
public const string Source = "HX-Source";

Expand All @@ -63,20 +70,24 @@ public static class HtmxRequestHeaderNames
/// </summary>
/// <remarks>
/// <para>In HTMX 1.x and 2.x, the value is the ID of the target element.</para>
/// <para>In HTMX 4.x, the value is in <c>tag#id</c> format, for example <c>div#results</c>.</para>
/// <para>
/// In HTMX 4.x, the value contains the lowercase tag name and, when the element has an ID,
/// <c>#</c> followed by its URI-encoded ID. Examples include <c>div#results</c> and <c>body</c>.
/// </para>
/// </remarks>
public const string Target = "HX-Target";

/// <summary>
/// The <c>HX-Trigger-Name</c> header contains the name of the triggered element, if present.
/// The <c>HX-Trigger-Name</c> header contains the <c>name</c> attribute of the element
/// that issued the request, if present.
/// </summary>
/// <remarks>
/// Supported only in HTMX 1.x and 2.x. HTMX 4.x identifies the source element with <c>HX-Source</c> instead.
/// </remarks>
public const string TriggerName = "HX-Trigger-Name";

/// <summary>
/// The <c>HX-Trigger</c> header contains the ID of the triggered element, if present.
/// The <c>HX-Trigger</c> header contains the ID of the element that issued the request, if present.
/// </summary>
/// <remarks>
/// Supported only in HTMX 1.x and 2.x. HTMX 4.x identifies the source element with <c>HX-Source</c> instead.
Expand Down
43 changes: 27 additions & 16 deletions src/Ramstack.HtmxToolkit/HtmxRequestHeaders.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ internal HtmxRequestHeaders(HttpRequest request) =>
_headers = request.Headers;

/// <summary>
/// Gets a value indicating whether the request was made
/// using AJAX instead of a normal navigation.
/// Gets a value indicating whether the request came from a link
/// or form enhanced with <c>hx-boost</c>.
/// </summary>
/// <remarks>
/// The header name is <see cref="HtmxRequestHeaderNames.Boosted" />.
Expand All @@ -39,11 +39,14 @@ internal HtmxRequestHeaders(HttpRequest request) =>
public string? CurrentUrl => GetString(_headers, HtmxRequestHeaderNames.CurrentUrl);

/// <summary>
/// Gets a value indicating whether the request restores history
/// after a miss in the local history cache.
/// Gets a value indicating whether the request fetches content for history restoration.
/// </summary>
/// <remarks>
/// The header name is <see cref="HtmxRequestHeaderNames.HistoryRestoreRequest" />.
/// <para>The header name is <see cref="HtmxRequestHeaderNames.HistoryRestoreRequest" />.</para>
/// <para>
/// HTMX 1.x and 2.x send this header after a history cache miss.
/// HTMX 4.x refetches history content by default; local caching requires an extension.
/// </para>
/// </remarks>
public bool HistoryRestoreRequest => GetBoolean(_headers, HtmxRequestHeaderNames.HistoryRestoreRequest);

Expand All @@ -53,8 +56,9 @@ internal HtmxRequestHeaders(HttpRequest request) =>
/// <remarks>
/// <para>The header name is <see cref="HtmxRequestHeaderNames.Prompt" />.</para>
/// <para>
/// Supported only in HTMX 1.x and 2.x; HTMX 4.x removed <c>hx-prompt</c>
/// and does not send this header.
/// Supported natively in HTMX 1.x and 2.x. In HTMX 4.x, the
/// <see href="https://four.htmx.org/extensions/hx-prompt">hx-prompt extension</see>
/// restores this header.
/// </para>
/// </remarks>
public string? Prompt => GetString(_headers, HtmxRequestHeaderNames.Prompt);
Expand All @@ -79,7 +83,6 @@ internal HtmxRequestHeaders(HttpRequest request) =>
/// and <c>"full"</c> for body-level or <c>hx-select</c> requests.
/// </para>
/// <para>
/// Returns <see cref="HtmxRequestType.Unspecified" /> when the header is absent.
/// The request type is not inferred from boosted navigation.
/// </para>
/// </remarks>
Expand Down Expand Up @@ -111,7 +114,9 @@ static HtmxRequestType GetRequestType(IHeaderDictionary dictionary)
/// <remarks>
/// <para>The header name is <see cref="HtmxRequestHeaderNames.Source" />.</para>
/// <para>
/// Supported only in HTMX 4.x. The value is in <c>tag#id</c> format, for example <c>button#submit</c>.
/// Supported only in HTMX 4.x. The value contains the lowercase tag name and,
/// when the element has an ID, <c>#</c> followed by its URI-encoded ID.
/// Examples include <c>button#submit</c> and <c>button</c>.
/// </para>
/// </remarks>
public string? Source => GetString(_headers, HtmxRequestHeaderNames.Source);
Expand All @@ -122,12 +127,16 @@ static HtmxRequestType GetRequestType(IHeaderDictionary dictionary)
/// <remarks>
/// <para>The header name is <see cref="HtmxRequestHeaderNames.Target" />.</para>
/// <para>In HTMX 1.x and 2.x, the value is the ID of the target element.</para>
/// <para>In HTMX 4.x, the value is in <c>tag#id</c> format, for example <c>div#results</c>.</para>
/// <para>
/// In HTMX 4.x, the value contains the lowercase tag name and,
/// when the element has an ID, <c>#</c> followed by its URI-encoded ID.
/// Examples include <c>div#results</c> and <c>body</c>.
/// </para>
/// </remarks>
public string? Target => GetString(_headers, HtmxRequestHeaderNames.Target);

/// <summary>
/// Gets the name of the triggered element, if present.
/// Gets the <c>name</c> attribute of the element that issued the request, if present.
/// </summary>
/// <remarks>
/// <para>The header name is <see cref="HtmxRequestHeaderNames.TriggerName" />.</para>
Expand All @@ -139,12 +148,13 @@ static HtmxRequestType GetRequestType(IHeaderDictionary dictionary)
public string? TriggerName => GetString(_headers, HtmxRequestHeaderNames.TriggerName);

/// <summary>
/// Gets the ID of the triggered element, if present.
/// Gets the ID of the element that issued the request, if present.
/// </summary>
/// <remarks>
/// <para>The header name is <see cref="HtmxRequestHeaderNames.Trigger" />.</para>
/// <para>
/// Supported only in HTMX 1.x and 2.x; HTMX 4.x identifies the source element with <c>HX-Source</c> instead.
/// Supported only in HTMX 1.x and 2.x; HTMX 4.x identifies the source element
/// with <c>HX-Source</c> instead.
/// </para>
/// </remarks>
public string? Trigger => GetString(_headers, HtmxRequestHeaderNames.Trigger);
Expand All @@ -155,7 +165,8 @@ static HtmxRequestType GetRequestType(IHeaderDictionary dictionary)
/// <param name="dictionary">The header collection to inspect.</param>
/// <param name="key">The name of the header.</param>
/// <returns>
/// <see langword="true" /> if the header value is <c>"true"</c>; otherwise, <see langword="false" />.
/// <see langword="true" /> if the header value is <c>"true"</c>;
/// otherwise, <see langword="false" />.
/// </returns>
private static bool GetBoolean(IHeaderDictionary dictionary, string key) =>
dictionary.TryGetValue(key, out var value) && value is ["true"];
Expand Down Expand Up @@ -184,8 +195,8 @@ private static bool GetBoolean(IHeaderDictionary dictionary, string key) =>
private sealed class HtmxRequestHeadersDebugView(HtmxRequestHeaders headers)
{
/// <summary>
/// Gets the collection of all HTTP headers stored
/// in the associated <see cref="HtmxRequestHeaders"/> instance
/// Gets the collection of request headers whose names start with <c>HX-</c>
/// from the associated <see cref="HtmxRequestHeaders"/> instance
/// as an array of key-value pairs.
/// </summary>
[DebuggerBrowsable(DebuggerBrowsableState.RootHidden)]
Expand Down
7 changes: 4 additions & 3 deletions src/Ramstack.HtmxToolkit/HtmxResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public HtmxResponse PreventPushUrl() =>
SetHeader(this, HtmxResponseHeaderNames.PushUrl, "false");

/// <summary>
/// Sets the <c>HX-Redirect</c> header to perform a client-side redirect to a new location.
/// Sets the <c>HX-Redirect</c> header to perform a client-side redirect with a full-page reload.
/// </summary>
/// <param name="value">The header value to set.</param>
/// <returns>
Expand Down Expand Up @@ -243,7 +243,8 @@ static HtmxResponse TriggerEventImpl(HtmxResponse response, string eventName, ob
/// <typeparam name="T">The event detail type.</typeparam>
/// <param name="eventName">The event name to trigger.</param>
/// <param name="detail">The event detail.</param>
/// <param name="jsonTypeInfo">The source-generated JSON metadata for the event detail.</param>
/// <param name="jsonTypeInfo">The JSON metadata for the event detail.
/// Use source-generated metadata for trimming and Native AOT.</param>
/// <param name="timing">The event timing. Defaults to <see cref="HtmxTriggerTiming.Receive" />.</param>
/// <returns>
/// The current <see cref="HtmxResponse" /> instance.
Expand Down Expand Up @@ -306,7 +307,7 @@ private static HtmxResponse AddToPendingEvent(HtmxResponse response, string even
private sealed class HtmxResponseDebugView(HtmxResponse response)
{
/// <summary>
/// Gets the collection of HTTP response headers
/// Gets the collection of HTMX response headers
/// from the associated <see cref="HtmxResponse"/> instance
/// as an array of key-value pairs.
/// </summary>
Expand Down
2 changes: 1 addition & 1 deletion src/Ramstack.HtmxToolkit/HtmxResponseHeaderNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public static class HtmxResponseHeaderNames
public const string PushUrl = "HX-Push-Url";

/// <summary>
/// The <c>HX-Redirect</c> header performs a client-side redirect to a new location.
/// The <c>HX-Redirect</c> header performs a client-side redirect with a full-page reload.
/// </summary>
public const string Redirect = "HX-Redirect";

Expand Down
Loading
Loading