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
10 changes: 5 additions & 5 deletions src/Ramstack.HtmxToolkit/HtmxResponse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ public HtmxResponse Reselect(string value) =>
/// See <see href="https://github.com/bigskysoftware/htmx/pull/3900">PR #3900</see>.
/// </remarks>
public HtmxResponse TriggerEvent(string eventName, HtmxTriggerTiming trigger = HtmxTriggerTiming.Receive) =>
QueueEvent(this, eventName, "{}", trigger);
AddToPendingEvent(this, eventName, "{}", trigger);

/// <summary>
/// Adds a client-side event and its detail to the response header selected by
Expand Down Expand Up @@ -274,10 +274,10 @@ private static HtmxResponse SetHeader(HtmxResponse response, string key, string
[RequiresDynamicCode("Event details are serialized using reflection.")]
[RequiresUnreferencedCode("Event details are serialized using reflection.")]
private static HtmxResponse TriggerEventCore(HtmxResponse response, string eventName, object detail, HtmxTriggerTiming timing) =>
QueueEvent(response, eventName, JsonSerializer.Serialize(detail, JsonOptions.CamelCase), timing);
AddToPendingEvent(response, eventName, JsonSerializer.Serialize(detail, JsonOptions.CamelCase), timing);

private static HtmxResponse TriggerEventCore<T>(HtmxResponse response, string eventName, T detail, JsonTypeInfo<T> jsonTypeInfo, HtmxTriggerTiming timing) =>
QueueEvent(response, eventName, SerializeEventDetail(detail, jsonTypeInfo), timing);
AddToPendingEvent(response, eventName, SerializeEventDetail(detail, jsonTypeInfo), timing);

private static string SerializeEventDetail<T>(T detail, JsonTypeInfo<T> jsonTypeInfo)
{
Expand All @@ -290,9 +290,9 @@ private static string SerializeEventDetail<T>(T detail, JsonTypeInfo<T> jsonType
return Encoding.UTF8.GetString(buffer.WrittenSpan);
}

private static HtmxResponse QueueEvent(HtmxResponse response, string eventName, string detail, HtmxTriggerTiming timing)
private static HtmxResponse AddToPendingEvent(HtmxResponse response, string eventName, string detailJson, HtmxTriggerTiming timing)
{
PendingEvents.GetOrCreate(response._response).AddEvent(timing, eventName, detail);
PendingEvents.GetOrCreate(response._response).AddEvent(timing, eventName, detailJson);
return response;
}

Expand Down
18 changes: 8 additions & 10 deletions src/Ramstack.HtmxToolkit/PendingEvents.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,22 +41,20 @@ private PendingEvents(HttpResponse response) =>
/// </summary>
/// <param name="timing">The time at which to trigger the events.</param>
/// <param name="eventName">The event name.</param>
/// <param name="detail">The event detail.</param>
public void AddEvent(HtmxTriggerTiming timing, string eventName, string? detail)
/// <param name="detailJson">The event detail as JSON.</param>
public void AddEvent(HtmxTriggerTiming timing, string eventName, string detailJson)
{
ArgumentNullException.ThrowIfNull(eventName);

if (string.IsNullOrWhiteSpace(eventName))
throw new ArgumentException("Event name cannot be empty.", nameof(eventName));
throw new ArgumentException("Event name cannot be null or whitespace.", nameof(eventName));

if (string.IsNullOrWhiteSpace(detailJson))
throw new ArgumentException("Event detail JSON cannot be null or whitespace.", nameof(detailJson));

if (eventName == ProxyEventName)
throw new ArgumentException(
$"The event name '{ProxyEventName}' is reserved.",
nameof(eventName));

if (string.IsNullOrWhiteSpace(detail))
detail = "{}";

timing = NormalizeTiming(timing);

var current = timing switch
Expand All @@ -66,7 +64,7 @@ public void AddEvent(HtmxTriggerTiming timing, string eventName, string? detail)
_ => _afterSettle ??= new SmallDictionary<string, object>(StringComparer.Ordinal)
};

if (!current.TryAdd(eventName, detail))
if (!current.TryAdd(eventName, detailJson))
{
if (!current.TryGetValue(ProxyEventName, out var value)
|| value is not List<KeyValuePair<string, string>> collection)
Expand All @@ -75,7 +73,7 @@ public void AddEvent(HtmxTriggerTiming timing, string eventName, string? detail)
current[ProxyEventName] = collection;
}

collection.Add(new KeyValuePair<string, string>(eventName, detail));
collection.Add(new KeyValuePair<string, string>(eventName, detailJson));
}
}

Expand Down
24 changes: 7 additions & 17 deletions tests/Ramstack.HtmxToolkit.Tests/PendingEventsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -204,37 +204,27 @@ public void Flush_SerializesNullEventDetail_AsNull()
[TestCase(null)]
[TestCase("")]
[TestCase(" ")]
public void AddEvent_NullOrWhitespaceDetail_NormalizesToEmptyObject(string? detail)
public void AddEvent_NullOrWhitespaceDetail_ThrowsArgumentException(string? detail)
{
var context = TestHelper.CreateHttpContext();
var pending = PendingEvents.GetOrCreate(context.Response);

pending.AddEvent(HtmxTriggerTiming.Receive, "e", detail);
pending.Flush();

var header = context.Response.Headers[HtmxResponseHeaderNames.Trigger].ToString();
Assert.That(header, Is.EqualTo("{\"e\":{}}"));
}

[Test]
public void AddEvent_NullEventName_ThrowsArgumentNullException()
{
var context = TestHelper.CreateHttpContext();
var pending = PendingEvents.GetOrCreate(context.Response);
var exception = Assert.Throws<ArgumentException>(() =>
pending.AddEvent(HtmxTriggerTiming.Receive, "e", detail!));

Assert.Throws<ArgumentNullException>(() =>
pending.AddEvent(HtmxTriggerTiming.Receive, null!, "1"));
Assert.That(exception?.ParamName, Is.EqualTo("detailJson"));
}

[TestCase(null)]
[TestCase("")]
[TestCase(" ")]
public void AddEvent_EmptyOrWhitespaceEventName_ThrowsArgumentException(string eventName)
public void AddEvent_NullOrWhitespaceEventName_ThrowsArgumentException(string? eventName)
{
var context = TestHelper.CreateHttpContext();
var pending = PendingEvents.GetOrCreate(context.Response);

var exception = Assert.Throws<ArgumentException>(() =>
pending.AddEvent(HtmxTriggerTiming.Receive, eventName, "1"));
pending.AddEvent(HtmxTriggerTiming.Receive, eventName!, "1"));

Assert.That(exception?.ParamName, Is.EqualTo("eventName"));
}
Expand Down