diff --git a/src/Ramstack.HtmxToolkit/Internal/EnumHelper.cs b/src/Ramstack.HtmxToolkit/Internal/EnumHelper.cs
index 6ffbb0d..79f872d 100644
--- a/src/Ramstack.HtmxToolkit/Internal/EnumHelper.cs
+++ b/src/Ramstack.HtmxToolkit/Internal/EnumHelper.cs
@@ -178,25 +178,44 @@ or HtmxFetchMode.Cors
}
///
- /// Parses a string into a value.
+ /// Parses the swap style at the start of a swap expression into a value.
///
- /// The string to parse.
+ /// The swap expression to parse.
///
/// The parsed value if successful;
/// otherwise, .
///
+ ///
+ /// Like HTMX, ignores leading whitespace, treats any whitespace as the separator
+ /// before swap modifiers, and compares the style case-sensitively.
+ /// Only the values returned by are recognized.
+ ///
public static HtmxSwap? ParseHtmxSwap(string? expression)
{
- expression ??= "";
+ var s = expression.AsSpan().TrimStart();
- var index = expression.IndexOf(' ');
- if (index < 0)
- index = expression.Length;
+ var index = 0;
+ while ((uint)index < (uint)s.Length && !char.IsWhiteSpace(s[index]))
+ index++;
- var s = expression.AsSpan(0, index);
- if (Enum.TryParse(s, ignoreCase: true, out var value))
- return value;
+ if ((uint)index < (uint)s.Length)
+ s = s[..index];
- return null;
+ return s switch
+ {
+ "innerHTML" => HtmxSwap.InnerHtml,
+ "outerHTML" => HtmxSwap.OuterHtml,
+ "innerMorph" => HtmxSwap.InnerMorph,
+ "outerMorph" => HtmxSwap.OuterMorph,
+ "outerSync" => HtmxSwap.OuterSync,
+ "textContent" => HtmxSwap.TextContent,
+ "beforebegin" => HtmxSwap.BeforeBegin,
+ "afterbegin" => HtmxSwap.AfterBegin,
+ "beforeend" => HtmxSwap.BeforeEnd,
+ "afterend" => HtmxSwap.AfterEnd,
+ "delete" => HtmxSwap.Delete,
+ "none" => HtmxSwap.None,
+ _ => null
+ };
}
}
diff --git a/tests/Ramstack.HtmxToolkit.Tests/HtmxResponseHeadersTests.cs b/tests/Ramstack.HtmxToolkit.Tests/HtmxResponseHeadersTests.cs
index 9948c1d..95c4779 100644
--- a/tests/Ramstack.HtmxToolkit.Tests/HtmxResponseHeadersTests.cs
+++ b/tests/Ramstack.HtmxToolkit.Tests/HtmxResponseHeadersTests.cs
@@ -60,13 +60,15 @@ public void Reswap_IsNull_WhenHeaderAbsent()
Assert.That(headers.Reswap, Is.Null);
}
- [Test]
- public void Reswap_IsNull_WhenHeaderUnknown()
+ [TestCase("bogus")]
+ [TestCase("OuterHTML")]
+ [TestCase("1")]
+ public void Reswap_IsNull_WhenHeaderUnknown(string value)
{
var context = TestHelper.CreateHttpContext();
var headers = context.Response.GetHtmxHeaders();
- context.Response.Headers[HtmxResponseHeaderNames.Reswap] = "bogus";
+ context.Response.Headers[HtmxResponseHeaderNames.Reswap] = value;
Assert.That(headers.Reswap, Is.Null);
}
diff --git a/tests/Ramstack.HtmxToolkit.Tests/Internal/EnumHelperTests.cs b/tests/Ramstack.HtmxToolkit.Tests/Internal/EnumHelperTests.cs
index 3e1ee4a..e85d56f 100644
--- a/tests/Ramstack.HtmxToolkit.Tests/Internal/EnumHelperTests.cs
+++ b/tests/Ramstack.HtmxToolkit.Tests/Internal/EnumHelperTests.cs
@@ -42,21 +42,41 @@ public void GetSwapValue_ReturnsNull_ForNullValue()
public void ParseHtmxSwap_ParsesValue(string expression, HtmxSwap expected) =>
Assert.That(EnumHelper.ParseHtmxSwap(expression), Is.EqualTo(expected));
- [Test]
- public void ParseHtmxSwap_IgnoresModifiers() =>
- Assert.That(EnumHelper.ParseHtmxSwap("innerHTML show:#content"), Is.EqualTo(HtmxSwap.InnerHtml));
+ [TestCase("innerHTML show:#content", HtmxSwap.InnerHtml)]
+ [TestCase("outerHTML\tsettle:200ms", HtmxSwap.OuterHtml)]
+ [TestCase("beforeend\n swap:1s", HtmxSwap.BeforeEnd)]
+ public void ParseHtmxSwap_IgnoresModifiers(string expression, HtmxSwap expected) =>
+ Assert.That(EnumHelper.ParseHtmxSwap(expression), Is.EqualTo(expected));
- [Test]
- public void ParseHtmxSwap_IsCaseInsensitive() =>
- Assert.That(EnumHelper.ParseHtmxSwap("OuterHTML"), Is.EqualTo(HtmxSwap.OuterHtml));
+ [TestCase(" outerHTML", HtmxSwap.OuterHtml)]
+ [TestCase("\t outerHTML show:top", HtmxSwap.OuterHtml)]
+ public void ParseHtmxSwap_IgnoresLeadingWhitespace(string expression, HtmxSwap expected) =>
+ Assert.That(EnumHelper.ParseHtmxSwap(expression), Is.EqualTo(expected));
- [Test]
- public void ParseHtmxSwap_ReturnsNull_ForUnknownValue() =>
- Assert.That(EnumHelper.ParseHtmxSwap("bogus"), Is.Null);
+ [TestCase("OuterHTML")]
+ [TestCase("outerhtml")]
+ [TestCase("InnerHtml")]
+ [TestCase("BEFOREEND")]
+ public void ParseHtmxSwap_IsCaseSensitive(string expression) =>
+ Assert.That(EnumHelper.ParseHtmxSwap(expression), Is.Null);
- [Test]
- public void ParseHtmxSwap_ReturnsNull_ForNullExpression() =>
- Assert.That(EnumHelper.ParseHtmxSwap(null), Is.Null);
+ [TestCase("bogus")]
+ [TestCase("1")]
+ [TestCase("42")]
+ [TestCase("-1")]
+ [TestCase("innerHTML,outerHTML")]
+ [TestCase("before")]
+ [TestCase("append")]
+ public void ParseHtmxSwap_ReturnsNull_ForUnknownValue(string expression) =>
+ Assert.That(EnumHelper.ParseHtmxSwap(expression), Is.Null);
+
+ [TestCase(null)]
+ [TestCase("")]
+ [TestCase(" ")]
+ [TestCase("show:top")]
+ [TestCase("swap:1s settle:200ms")]
+ public void ParseHtmxSwap_ReturnsNull_WithoutStyle(string? expression) =>
+ Assert.That(EnumHelper.ParseHtmxSwap(expression), Is.Null);
[TestCase(HttpVerb.Get, "get")]
[TestCase(HttpVerb.Head, "head")]