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
76 changes: 47 additions & 29 deletions src/Ramstack.HtmxToolkit/HtmxResponseHeaders.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Microsoft.AspNetCore.Http;

using Ramstack.HtmxToolkit.Internal;
Expand All @@ -25,9 +24,11 @@ internal HtmxResponseHeaders(HttpResponse response) =>
/// Gets or sets the value of the <c>HX-Location</c> header, which performs
/// a client-side redirect without a full-page reload.
/// </summary>
/// <remarks>Assigning <see langword="null" /> or an empty string removes the header.</remarks>
[MaybeNull]
public string Location
/// <remarks>
/// If the header is not present, the property returns <see langword="null" />.
/// Assigning <see langword="null" /> or an empty string removes the header.
/// </remarks>
public string? Location
{
get => GetHeader(_response.Headers, HtmxResponseHeaderNames.Location);
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.Location, value);
Expand All @@ -38,14 +39,16 @@ public string Location
/// onto the browser's history stack.
/// </summary>
/// <remarks>
/// <para>Assigning <see langword="null" /> or an empty string removes the header.</para>
/// <para>
/// Unlike <see cref="HtmxResponse.PushUrl" />, setting this property
/// does not remove the <c>HX-Replace-Url</c> header.
/// If the header is not present, the property returns <see langword="null" />.
/// Assigning <see langword="null" /> or an empty string removes the header.
/// </para>
/// <para>
/// Unlike <see cref="HtmxResponse.PushUrl" />, setting this property does not remove
/// the <c>HX-Replace-Url</c> header or the legacy <c>HX-Push</c> header.
/// </para>
/// </remarks>
[MaybeNull]
public string PushUrl
public string? PushUrl
{
get => GetHeader(_response.Headers, HtmxResponseHeaderNames.PushUrl);
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.PushUrl, value);
Expand All @@ -56,14 +59,16 @@ public string PushUrl
/// without pushing a new entry to the browser's history stack.
/// </summary>
/// <remarks>
/// <para>Assigning <see langword="null" /> or an empty string removes the header.</para>
/// <para>
/// Unlike <see cref="HtmxResponse.ReplaceUrl" />, setting this property
/// does not remove the <c>HX-Push-Url</c> header.
/// If the header is not present, the property returns <see langword="null" />.
/// Assigning <see langword="null" /> or an empty string removes the header.
/// </para>
/// <para>
/// Unlike <see cref="HtmxResponse.ReplaceUrl" />, setting this property does not remove
/// the <c>HX-Push-Url</c> header or the legacy <c>HX-Push</c> header.
/// </para>
/// </remarks>
[MaybeNull]
public string ReplaceUrl
public string? ReplaceUrl
{
get => GetHeader(_response.Headers, HtmxResponseHeaderNames.ReplaceUrl);
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.ReplaceUrl, value);
Expand All @@ -73,9 +78,11 @@ public string ReplaceUrl
/// Gets or sets the value of the <c>HX-Redirect</c> header, which performs
/// a client-side redirect with a full-page reload.
/// </summary>
/// <remarks>Assigning <see langword="null" /> or an empty string removes the header.</remarks>
[MaybeNull]
public string Redirect
/// <remarks>
/// If the header is not present, the property returns <see langword="null" />.
/// Assigning <see langword="null" /> or an empty string removes the header.
/// </remarks>
public string? Redirect
{
get => GetHeader(_response.Headers, HtmxResponseHeaderNames.Redirect);
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.Redirect, value);
Expand All @@ -84,6 +91,7 @@ public string Redirect
/// <summary>
/// Gets or sets a value indicating whether the <c>HX-Refresh</c> header requests a full-page refresh.
/// </summary>
/// <remarks>Assigning <see langword="false" /> removes the header.</remarks>
public bool Refresh
{
get => GetHeader(_response.Headers, HtmxResponseHeaderNames.Refresh) == "true";
Expand All @@ -93,19 +101,25 @@ public bool Refresh
/// <summary>
/// Gets or sets the swap style specified by the <c>HX-Reswap</c> header.
/// </summary>
[DisallowNull]
/// <remarks>
/// Reads the style from <see cref="ReswapExpression" />, or returns <see langword="null" />
/// if the header is not present or the style is not recognized. Assigning a style replaces
/// the complete header value, including any modifiers. Assigning <see langword="null" /> removes the header.
/// </remarks>
public HtmxSwap? Reswap
{
get => EnumHelper.ParseHtmxSwap(GetHeader(_response.Headers, HtmxResponseHeaderNames.Reswap));
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.Reswap, value.GetValueOrDefault().GetSwapValue());
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.Reswap, value?.GetSwapValue());
}

/// <summary>
/// Gets or sets the complete <c>HX-Reswap</c> header value, including any swap modifiers.
/// </summary>
/// <remarks>Assigning <see langword="null" /> or an empty string removes the header.</remarks>
[MaybeNull]
public string ReswapExpression
/// <remarks>
/// If the header is not present, the property returns <see langword="null" />.
/// Assigning <see langword="null" /> or an empty string removes the header.
/// </remarks>
public string? ReswapExpression
{
get => GetHeader(_response.Headers, HtmxResponseHeaderNames.Reswap);
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.Reswap, value);
Expand All @@ -115,9 +129,11 @@ public string ReswapExpression
/// Gets or sets the CSS selector specified by the <c>HX-Retarget</c> header
/// to change the target of the content update.
/// </summary>
/// <remarks>Assigning <see langword="null" /> or an empty string removes the header.</remarks>
[MaybeNull]
public string Retarget
/// <remarks>
/// If the header is not present, the property returns <see langword="null" />.
/// Assigning <see langword="null" /> or an empty string removes the header.
/// </remarks>
public string? Retarget
{
get => GetHeader(_response.Headers, HtmxResponseHeaderNames.Retarget);
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.Retarget, value);
Expand All @@ -127,9 +143,11 @@ public string Retarget
/// Gets or sets the CSS selector specified by the <c>HX-Reselect</c> header
/// to determine which part of the response is swapped in.
/// </summary>
/// <remarks>Assigning <see langword="null" /> or an empty string removes the header.</remarks>
[MaybeNull]
public string Reselect
/// <remarks>
/// If the header is not present, the property returns <see langword="null" />.
/// Assigning <see langword="null" /> or an empty string removes the header.
/// </remarks>
public string? Reselect
{
get => GetHeader(_response.Headers, HtmxResponseHeaderNames.Reselect);
set => SetHeader(_response.Headers, HtmxResponseHeaderNames.Reselect, value);
Expand All @@ -147,7 +165,7 @@ public string Reselect
/// the property returns <see langword="null" />.
/// </para>
/// <para>
/// HTMX 1.x and 2.x trigger these events when the response is received,
/// HTMX 1.9.x and 2.x trigger these events when the response is received,
/// whereas HTMX 4.x triggers them when the request completes
/// (after the swap and settle steps whenever a swap is performed).
/// In HTMX 4.x, the list also includes the events added with other timings,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ public void SettingNull_DoesNotAddHeader()
var context = TestHelper.CreateHttpContext();
var headers = context.Response.GetHtmxHeaders();

headers.Location = null!;
headers.Location = null;

Assert.That(context.Response.Headers.ContainsKey(HtmxResponseHeaderNames.Location), Is.False);
}
Expand Down
Loading