diff --git a/src/Ramstack.HtmxToolkit/HtmxBinaryTypeJsonConverter.cs b/src/Ramstack.HtmxToolkit/HtmxBinaryTypeJsonConverter.cs
index 5aa23c5..b1fbd5c 100644
--- a/src/Ramstack.HtmxToolkit/HtmxBinaryTypeJsonConverter.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxBinaryTypeJsonConverter.cs
@@ -17,13 +17,8 @@ internal sealed class HtmxBinaryTypeJsonConverter : JsonConverter
public override void Write(Utf8JsonWriter writer, HtmxBinaryType? value, JsonSerializerOptions options)
{
- if (value is null)
- {
- writer.WriteNullValue();
- }
- else
- {
- writer.WriteStringValue(value.GetValueOrDefault().GetWsBinaryTypeValue());
- }
+ // NOTE: value is never null here: null-valued properties are omitted
+ // by JsonIgnoreCondition.WhenWritingNull before this converter is invoked.
+ writer.WriteStringValue(value.GetValueOrDefault().GetWsBinaryTypeValue());
}
}
diff --git a/src/Ramstack.HtmxToolkit/HtmxConfig.cs b/src/Ramstack.HtmxToolkit/HtmxConfig.cs
index db12174..e467dc1 100644
--- a/src/Ramstack.HtmxToolkit/HtmxConfig.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxConfig.cs
@@ -1,5 +1,7 @@
using System.Text.Json.Serialization;
+using Microsoft.AspNetCore.Html;
+
namespace Ramstack.HtmxToolkit;
///
@@ -7,6 +9,8 @@ namespace Ramstack.HtmxToolkit;
///
public abstract class HtmxConfig
{
+ private HtmlString? _json;
+
///
/// Gets the configured HTMX major version.
///
@@ -23,10 +27,33 @@ internal HtmxConfig(HtmxTargetVersion version) =>
TargetVersion = version;
///
- /// Serializes this configuration to JSON.
+ /// Returns this configuration serialized as JSON,
+ /// cached and reused until the configuration changes.
+ ///
+ ///
+ /// An containing the configuration serialized as JSON.
+ ///
+ internal HtmlString ToJson() =>
+ _json ??= new HtmlString(Serialize());
+
+ ///
+ /// Serializes this configuration to a JSON string.
///
///
- /// A string containing this configuration serialized as JSON.
+ /// A JSON string representing this configuration.
///
- internal abstract string ToJson();
+ protected abstract string Serialize();
+
+ ///
+ /// Assigns to and invalidates
+ /// the cached JSON so it is regenerated on the next serialization.
+ ///
+ /// The type of the field.
+ /// The backing field to update.
+ /// The value to assign.
+ protected void SetField(ref T field, T value)
+ {
+ field = value;
+ _json = null;
+ }
}
diff --git a/src/Ramstack.HtmxToolkit/HtmxFetchModeJsonConverter.cs b/src/Ramstack.HtmxToolkit/HtmxFetchModeJsonConverter.cs
index 8b02b38..7ce7875 100644
--- a/src/Ramstack.HtmxToolkit/HtmxFetchModeJsonConverter.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxFetchModeJsonConverter.cs
@@ -17,13 +17,8 @@ internal sealed class HtmxFetchModeJsonConverter : JsonConverter
///
public override void Write(Utf8JsonWriter writer, HtmxFetchMode? value, JsonSerializerOptions options)
{
- if (value is null)
- {
- writer.WriteNullValue();
- }
- else
- {
- writer.WriteStringValue(value.GetValueOrDefault().GetFetchModeValue());
- }
+ // NOTE: value is never null here: null-valued properties are omitted
+ // by JsonIgnoreCondition.WhenWritingNull before this converter is invoked.
+ writer.WriteStringValue(value.GetValueOrDefault().GetFetchModeValue());
}
}
diff --git a/src/Ramstack.HtmxToolkit/HtmxHistoryModeJsonConverter.cs b/src/Ramstack.HtmxToolkit/HtmxHistoryModeJsonConverter.cs
index 553b0c0..881e684 100644
--- a/src/Ramstack.HtmxToolkit/HtmxHistoryModeJsonConverter.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxHistoryModeJsonConverter.cs
@@ -21,24 +21,19 @@ internal sealed class HtmxHistoryModeJsonConverter : JsonConverter
public override void Write(Utf8JsonWriter writer, HtmxHistoryMode? value, JsonSerializerOptions options)
{
- if (value is null)
+ // NOTE: value is never null here: null-valued properties are omitted
+ // by JsonIgnoreCondition.WhenWritingNull before this converter is invoked.
+ switch (value.GetValueOrDefault())
{
- writer.WriteNullValue();
- }
- else
- {
- switch (value.GetValueOrDefault())
- {
- case HtmxHistoryMode.Enabled:
- writer.WriteBooleanValue(true);
- break;
- case HtmxHistoryMode.Disabled:
- writer.WriteBooleanValue(false);
- break;
- default:
- writer.WriteStringValue(s_reload);
- break;
- }
+ case HtmxHistoryMode.Enabled:
+ writer.WriteBooleanValue(true);
+ break;
+ case HtmxHistoryMode.Disabled:
+ writer.WriteBooleanValue(false);
+ break;
+ default:
+ writer.WriteStringValue(s_reload);
+ break;
}
}
}
diff --git a/src/Ramstack.HtmxToolkit/HtmxScrollBehaviorJsonConverter.cs b/src/Ramstack.HtmxToolkit/HtmxScrollBehaviorJsonConverter.cs
index 775d159..aa4f63d 100644
--- a/src/Ramstack.HtmxToolkit/HtmxScrollBehaviorJsonConverter.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxScrollBehaviorJsonConverter.cs
@@ -17,13 +17,8 @@ internal sealed class HtmxScrollBehaviorJsonConverter : JsonConverter
public override void Write(Utf8JsonWriter writer, HtmxScrollBehavior? value, JsonSerializerOptions options)
{
- if (value is null)
- {
- writer.WriteNullValue();
- }
- else
- {
- writer.WriteStringValue(value.GetValueOrDefault().GetScrollBehaviorValue());
- }
+ // NOTE: value is never null here: null-valued properties are omitted
+ // by JsonIgnoreCondition.WhenWritingNull before this converter is invoked.
+ writer.WriteStringValue(value.GetValueOrDefault().GetScrollBehaviorValue());
}
}
diff --git a/src/Ramstack.HtmxToolkit/HtmxSwapJsonConverter.cs b/src/Ramstack.HtmxToolkit/HtmxSwapJsonConverter.cs
index 7babc0b..44878f2 100644
--- a/src/Ramstack.HtmxToolkit/HtmxSwapJsonConverter.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxSwapJsonConverter.cs
@@ -17,13 +17,8 @@ internal sealed class HtmxSwapJsonConverter : JsonConverter
///
public override void Write(Utf8JsonWriter writer, HtmxSwap? value, JsonSerializerOptions options)
{
- if (value is null)
- {
- writer.WriteNullValue();
- }
- else
- {
- writer.WriteStringValue(value.GetValueOrDefault().GetSwapValue());
- }
+ // NOTE: value is never null here: null-valued properties are omitted
+ // by JsonIgnoreCondition.WhenWritingNull before this converter is invoked.
+ writer.WriteStringValue(value.GetValueOrDefault().GetSwapValue());
}
}
diff --git a/src/Ramstack.HtmxToolkit/HtmxV1Config.cs b/src/Ramstack.HtmxToolkit/HtmxV1Config.cs
index 1dcf201..88753c3 100644
--- a/src/Ramstack.HtmxToolkit/HtmxV1Config.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxV1Config.cs
@@ -12,186 +12,306 @@ public sealed class HtmxV1Config() : HtmxConfig(HtmxTargetVersion.V1)
/// Gets or sets a value indicating whether HTMX history support is enabled.
/// The HTMX default is .
///
- public bool? HistoryEnabled { get; set; }
+ public bool? HistoryEnabled
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the size of the history cache.
/// The HTMX default is 10.
///
- public int? HistoryCacheSize { get; set; }
+ public int? HistoryCacheSize
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether a full-page refresh should be issued
/// on history misses rather than using an AJAX request.
/// The HTMX default is .
///
- public bool? RefreshOnHistoryMiss { get; set; }
+ public bool? RefreshOnHistoryMiss
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default swap style.
/// The HTMX default is .
///
[JsonConverter(typeof(HtmxSwapJsonConverter))]
- public HtmxSwap? DefaultSwapStyle { get; set; }
+ public HtmxSwap? DefaultSwapStyle
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default swap delay in milliseconds.
/// The HTMX default is 0.
///
- public int? DefaultSwapDelay { get; set; }
+ public int? DefaultSwapDelay
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default settle delay in milliseconds.
/// The HTMX default is 20.
///
- public int? DefaultSettleDelay { get; set; }
+ public int? DefaultSettleDelay
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the indicator styles are loaded.
/// The HTMX default is .
///
- public bool? IncludeIndicatorStyles { get; set; }
+ public bool? IncludeIndicatorStyles
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the indicator class.
/// The HTMX default is htmx-indicator.
///
- public string? IndicatorClass { get; set; }
+ public string? IndicatorClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the request class.
/// The HTMX default is htmx-request.
///
- public string? RequestClass { get; set; }
+ public string? RequestClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the added class.
/// The HTMX default is htmx-added.
///
- public string? AddedClass { get; set; }
+ public string? AddedClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the swapping class.
/// The HTMX default is htmx-swapping.
///
- public string? SwappingClass { get; set; }
+ public string? SwappingClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the settling class.
/// The HTMX default is htmx-settling.
///
- public string? SettlingClass { get; set; }
+ public string? SettlingClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the use of eval is allowed.
/// The HTMX default is .
///
- public bool? AllowEval { get; set; }
+ public bool? AllowEval
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether script tags should be processed in new content.
/// The HTMX default is .
///
- public bool? AllowScriptTags { get; set; }
+ public bool? AllowScriptTags
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the nonce added to inline scripts.
/// The HTMX default is an empty string.
///
- public string? InlineScriptNonce { get; set; }
+ public string? InlineScriptNonce
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the attributes to settle during the settling phase.
/// The HTMX default is ["class", "style", "width", "height"].
///
- public string[]? AttributesToSettle { get; set; }
+ public string[]? AttributesToSettle
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether HTML template tags are used to parse content.
/// The HTMX default is .
///
- public bool? UseTemplateFragments { get; set; }
+ public bool? UseTemplateFragments
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the WebSocket reconnection delay strategy.
/// The HTMX default is full-jitter.
///
- public string? WsReconnectDelay { get; set; }
+ public string? WsReconnectDelay
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the type of binary data received over WebSocket connections.
/// The HTMX default is .
///
[JsonConverter(typeof(HtmxBinaryTypeJsonConverter))]
- public HtmxBinaryType? WsBinaryType { get; set; }
+ public HtmxBinaryType? WsBinaryType
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the selector for elements that HTMX must not process.
/// The HTMX default is [disable-htmx], [data-disable-htmx].
///
- public string? DisableSelector { get; set; }
+ public string? DisableSelector
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether credentials are included in cross-origin requests.
/// The HTMX default is .
///
- public bool? WithCredentials { get; set; }
+ public bool? WithCredentials
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the request timeout, in milliseconds.
/// The HTMX default is 0.
///
- public int? Timeout { get; set; }
+ public int? Timeout
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether requests are restricted to the current origin.
/// The HTMX default is .
///
- public bool? SelfRequestsOnly { get; set; }
+ public bool? SelfRequestsOnly
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the scrolling behavior for boosted links.
/// The HTMX default is .
///
[JsonConverter(typeof(HtmxScrollBehaviorJsonConverter))]
- public HtmxScrollBehavior? ScrollBehavior { get; set; }
+ public HtmxScrollBehavior? ScrollBehavior
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the focused element should be scrolled into view.
/// The HTMX default is .
///
- public bool? DefaultFocusScroll { get; set; }
+ public bool? DefaultFocusScroll
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether GET requests use a cache-busting parameter.
/// The HTMX default is .
///
- public bool? GetCacheBusterParam { get; set; }
+ public bool? GetCacheBusterParam
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the View Transition API should be used for swaps.
/// The HTMX default is .
///
- public bool? GlobalViewTransitions { get; set; }
+ public bool? GlobalViewTransitions
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the HTTP methods that use URL parameters.
/// The HTMX default is ["get"].
///
[JsonConverter(typeof(HttpVerbArrayJsonConverter))]
- public HttpVerb[]? MethodsThatUseUrlParams { get; set; }
+ public HttpVerb[]? MethodsThatUseUrlParams
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether document titles found in new content are ignored.
/// The HTMX default is .
///
- public bool? IgnoreTitle { get; set; }
+ public bool? IgnoreTitle
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether boosted targets are scrolled into the viewport.
/// The HTMX default is .
///
- public bool? ScrollIntoViewOnBoost { get; set; }
+ public bool? ScrollIntoViewOnBoost
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether parsed trigger specifications use
@@ -199,9 +319,13 @@ public sealed class HtmxV1Config() : HtmxConfig(HtmxTargetVersion.V1)
///
[JsonPropertyName("triggerSpecsCache")]
[JsonConverter(typeof(HtmxTriggerSpecsCacheJsonConverter))]
- public bool? TriggerSpecsCacheEnabled { get; set; }
+ public bool? TriggerSpecsCacheEnabled
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
- internal override string ToJson() =>
+ protected override string Serialize() =>
JsonSerializer.Serialize(this, HtmxConfigJsonSerializerContext.Default.HtmxV1Config);
}
diff --git a/src/Ramstack.HtmxToolkit/HtmxV2Config.cs b/src/Ramstack.HtmxToolkit/HtmxV2Config.cs
index bdfab03..2f76af9 100644
--- a/src/Ramstack.HtmxToolkit/HtmxV2Config.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxV2Config.cs
@@ -14,192 +14,316 @@ public sealed class HtmxV2Config() : HtmxConfig(HtmxTargetVersion.V2)
/// Gets or sets a value indicating whether HTMX history support is enabled.
/// The HTMX default is .
///
- public bool? HistoryEnabled { get; set; }
+ public bool? HistoryEnabled
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the size of the history cache.
/// The HTMX default is 10.
///
- public int? HistoryCacheSize { get; set; }
+ public int? HistoryCacheSize
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether a history miss causes a full-page refresh
/// instead of an AJAX request.
/// The HTMX default is .
///
- public bool? RefreshOnHistoryMiss { get; set; }
+ public bool? RefreshOnHistoryMiss
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default swap style.
/// The HTMX default is .
///
[JsonConverter(typeof(HtmxSwapJsonConverter))]
- public HtmxSwap? DefaultSwapStyle { get; set; }
+ public HtmxSwap? DefaultSwapStyle
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default swap delay in milliseconds.
/// The HTMX default is 0.
///
- public int? DefaultSwapDelay { get; set; }
+ public int? DefaultSwapDelay
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default settle delay in milliseconds.
/// The HTMX default is 20.
///
- public int? DefaultSettleDelay { get; set; }
+ public int? DefaultSettleDelay
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the indicator styles are loaded.
/// The HTMX default is .
///
- public bool? IncludeIndicatorStyles { get; set; }
+ public bool? IncludeIndicatorStyles
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the indicator class.
/// The HTMX default is htmx-indicator.
///
- public string? IndicatorClass { get; set; }
+ public string? IndicatorClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the request class.
/// The HTMX default is htmx-request.
///
- public string? RequestClass { get; set; }
+ public string? RequestClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the added class.
/// The HTMX default is htmx-added.
///
- public string? AddedClass { get; set; }
+ public string? AddedClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the swapping class.
/// The HTMX default is htmx-swapping.
///
- public string? SwappingClass { get; set; }
+ public string? SwappingClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the settling class.
/// The HTMX default is htmx-settling.
///
- public string? SettlingClass { get; set; }
+ public string? SettlingClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the use of eval is allowed.
/// The HTMX default is .
///
- public bool? AllowEval { get; set; }
+ public bool? AllowEval
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether script tags should be processed in new content.
/// The HTMX default is .
///
- public bool? AllowScriptTags { get; set; }
+ public bool? AllowScriptTags
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the nonce added to inline scripts.
/// The HTMX default is an empty string.
///
- public string? InlineScriptNonce { get; set; }
+ public string? InlineScriptNonce
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the nonce added to inline styles.
/// The HTMX default is an empty string.
///
- public string? InlineStyleNonce { get; set; }
+ public string? InlineStyleNonce
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the attributes to settle during the settling phase.
/// The HTMX default is ["class", "style", "width", "height"].
///
- public string[]? AttributesToSettle { get; set; }
+ public string[]? AttributesToSettle
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the WebSocket reconnection delay strategy.
/// The HTMX default is full-jitter.
///
- public string? WsReconnectDelay { get; set; }
+ public string? WsReconnectDelay
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the type of binary data received over WebSocket connections.
/// The HTMX default is .
///
[JsonConverter(typeof(HtmxBinaryTypeJsonConverter))]
- public HtmxBinaryType? WsBinaryType { get; set; }
+ public HtmxBinaryType? WsBinaryType
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the selector for elements that HTMX must not process.
/// The HTMX default is [disable-htmx], [data-disable-htmx].
///
- public string? DisableSelector { get; set; }
+ public string? DisableSelector
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether credentials are included in cross-origin requests.
/// The HTMX default is .
///
- public bool? WithCredentials { get; set; }
+ public bool? WithCredentials
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether attribute inheritance is disabled.
/// The HTMX default is .
///
- public bool? DisableInheritance { get; set; }
+ public bool? DisableInheritance
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the request timeout, in milliseconds.
/// The HTMX default is 0.
///
- public int? Timeout { get; set; }
+ public int? Timeout
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether requests are restricted to the current origin.
/// The HTMX default is .
///
- public bool? SelfRequestsOnly { get; set; }
+ public bool? SelfRequestsOnly
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the scrolling behavior for boosted links.
/// The HTMX default is .
///
[JsonConverter(typeof(HtmxScrollBehaviorJsonConverter))]
- public HtmxScrollBehavior? ScrollBehavior { get; set; }
+ public HtmxScrollBehavior? ScrollBehavior
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the focused element should be scrolled into view.
/// The HTMX default is .
///
- public bool? DefaultFocusScroll { get; set; }
+ public bool? DefaultFocusScroll
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether GET requests use a cache-busting parameter.
/// The HTMX default is .
///
- public bool? GetCacheBusterParam { get; set; }
+ public bool? GetCacheBusterParam
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the View Transition API should be used for swaps.
/// The HTMX default is .
///
- public bool? GlobalViewTransitions { get; set; }
+ public bool? GlobalViewTransitions
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the HTTP methods that use URL parameters.
/// The HTMX default is ["get", "delete"].
///
[JsonConverter(typeof(HttpVerbArrayJsonConverter))]
- public HttpVerb[]? MethodsThatUseUrlParams { get; set; }
+ public HttpVerb[]? MethodsThatUseUrlParams
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether document titles found in new content are ignored.
/// The HTMX default is .
///
- public bool? IgnoreTitle { get; set; }
+ public bool? IgnoreTitle
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether boosted targets are scrolled into the viewport.
/// The HTMX default is .
///
- public bool? ScrollIntoViewOnBoost { get; set; }
+ public bool? ScrollIntoViewOnBoost
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether parsed trigger specifications use
@@ -207,35 +331,55 @@ public sealed class HtmxV2Config() : HtmxConfig(HtmxTargetVersion.V2)
///
[JsonConverter(typeof(HtmxTriggerSpecsCacheJsonConverter))]
[JsonPropertyName("triggerSpecsCache")]
- public bool? TriggerSpecsCacheEnabled { get; set; }
+ public bool? TriggerSpecsCacheEnabled
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the rules that determine how HTTP response status codes are handled.
///
- public IList? ResponseHandling { get; set; }
+ public IList? ResponseHandling
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether out-of-band swaps nested in the main
/// response are processed.
/// The HTMX default is .
///
- public bool? AllowNestedOobSwaps { get; set; }
+ public bool? AllowNestedOobSwaps
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether history cache-miss requests are marked
/// as HTMX requests.
/// The HTMX default is .
///
- public bool? HistoryRestoreAsHxRequest { get; set; }
+ public bool? HistoryRestoreAsHxRequest
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether form validity is reported before
/// a request is issued.
/// The HTMX default is .
///
- public bool? ReportValidityOfForms { get; set; }
+ public bool? ReportValidityOfForms
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
- internal override string ToJson() =>
+ protected override string Serialize() =>
JsonSerializer.Serialize(this, HtmxConfigJsonSerializerContext.Default.HtmxV2Config);
}
diff --git a/src/Ramstack.HtmxToolkit/HtmxV4Config.cs b/src/Ramstack.HtmxToolkit/HtmxV4Config.cs
index fd2ef2e..84653aa 100644
--- a/src/Ramstack.HtmxToolkit/HtmxV4Config.cs
+++ b/src/Ramstack.HtmxToolkit/HtmxV4Config.cs
@@ -12,102 +12,166 @@ public sealed class HtmxV4Config() : HtmxConfig(HtmxTargetVersion.V4)
/// Gets or sets a value indicating whether all HTMX events are logged to the console.
/// The HTMX default is .
///
- public bool? LogAll { get; set; }
+ public bool? LogAll
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the secondary attribute prefix recognized alongside hx-*.
/// The HTMX default is data-hx-.
///
- public string? Prefix { get; set; }
+ public string? Prefix
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the character used instead of : in attribute names.
/// The HTMX default is undefined.
///
- public string? MetaCharacter { get; set; }
+ public string? MetaCharacter
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets how HTMX history restoration is handled.
/// The HTMX default is .
///
[JsonConverter(typeof(HtmxHistoryModeJsonConverter))]
- public HtmxHistoryMode? History { get; set; }
+ public HtmxHistoryMode? History
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default swap style.
/// The HTMX default is .
///
[JsonConverter(typeof(HtmxSwapJsonConverter))]
- public HtmxSwap? DefaultSwap { get; set; }
+ public HtmxSwap? DefaultSwap
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether an empty response body replaces the main swap target.
/// The HTMX default is undefined.
///
- public bool? DefaultSwapEmpty { get; set; }
+ public bool? DefaultSwapEmpty
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default settle delay in milliseconds.
/// The HTMX default is 1.
///
- public int? DefaultSettleDelay { get; set; }
+ public int? DefaultSettleDelay
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the indicator styles are loaded.
/// The HTMX default is .
///
[JsonPropertyName("includeIndicatorCSS")]
- public bool? IncludeIndicatorCss { get; set; }
+ public bool? IncludeIndicatorCss
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the indicator class.
/// The HTMX default is htmx-indicator.
///
- public string? IndicatorClass { get; set; }
+ public string? IndicatorClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the request class.
/// The HTMX default is htmx-request.
///
- public string? RequestClass { get; set; }
+ public string? RequestClass
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the nonce added to inline scripts.
/// The HTMX default is undefined, which means that no nonce is added.
///
- public string? InlineScriptNonce { get; set; }
+ public string? InlineScriptNonce
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a comma-separated list of extensions that HTMX is allowed to load.
/// The HTMX default is an empty string.
///
- public string? Extensions { get; set; }
+ public string? Extensions
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether HTMX attributes are inherited implicitly.
/// The HTMX default is .
///
- public bool? ImplicitInheritance { get; set; }
+ public bool? ImplicitInheritance
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the default request timeout in milliseconds.
/// The HTMX default is 60000.
///
- public int? DefaultTimeout { get; set; }
+ public int? DefaultTimeout
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the request mode passed to the Fetch API.
/// The HTMX default is same-origin.
///
[JsonConverter(typeof(HtmxFetchModeJsonConverter))]
- public HtmxFetchMode? Mode { get; set; }
+ public HtmxFetchMode? Mode
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the focused element should be scrolled into view.
/// The HTMX default is and can be overridden
/// using the focus-scroll swap modifier.
///
- public bool? DefaultFocusScroll { get; set; }
+ public bool? DefaultFocusScroll
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets a value indicating whether the
@@ -115,31 +179,51 @@ public sealed class HtmxV4Config() : HtmxConfig(HtmxTargetVersion.V4)
/// should be used when swapping in new content.
/// The HTMX default is .
///
- public bool? Transitions { get; set; }
+ public bool? Transitions
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the attribute name prefixes to preserve during morphing.
/// The HTMX default is ["data-htmx-powered"].
///
- public string[]? MorphIgnore { get; set; }
+ public string[]? MorphIgnore
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the selector for elements to skip during morphing.
/// The HTMX default is [hx-morph-skip].
///
- public string? MorphSkip { get; set; }
+ public string? MorphSkip
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the selector for elements whose children should not be morphed.
/// The HTMX default is [hx-morph-skip-children].
///
- public string? MorphSkipChildren { get; set; }
+ public string? MorphSkipChildren
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the maximum number of siblings scanned while matching elements during morphing.
/// The HTMX default is 10.
///
- public int? MorphScanLimit { get; set; }
+ public int? MorphScanLimit
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
/// Gets or sets the response status codes or patterns for which HTMX does not perform a swap.
@@ -149,9 +233,13 @@ public sealed class HtmxV4Config() : HtmxConfig(HtmxTargetVersion.V4)
/// Although HTMX declares this option as a number array, it converts each entry to a string
/// at runtime and supports wildcard patterns such as "4xx" and "44x".
///
- public string[]? NoSwap { get; set; }
+ public string[]? NoSwap
+ {
+ get;
+ set => SetField(ref field, value);
+ }
///
- internal override string ToJson() =>
+ protected override string Serialize() =>
JsonSerializer.Serialize(this, HtmxConfigJsonSerializerContext.Default.HtmxV4Config);
}
diff --git a/src/Ramstack.HtmxToolkit/HttpVerbArrayJsonConverter.cs b/src/Ramstack.HtmxToolkit/HttpVerbArrayJsonConverter.cs
index bf93b71..fa00f8d 100644
--- a/src/Ramstack.HtmxToolkit/HttpVerbArrayJsonConverter.cs
+++ b/src/Ramstack.HtmxToolkit/HttpVerbArrayJsonConverter.cs
@@ -15,20 +15,15 @@ public override HttpVerb[] Read(ref Utf8JsonReader reader, Type typeToConvert, J
throw new NotSupportedException();
///
- public override void Write(Utf8JsonWriter writer, HttpVerb[]? value, JsonSerializerOptions options)
+ public override void Write(Utf8JsonWriter writer, HttpVerb[] value, JsonSerializerOptions options)
{
- if (value is null)
- {
- writer.WriteNullValue();
- }
- else
- {
- writer.WriteStartArray();
+ // NOTE: value is never null here: null-valued properties are omitted
+ // by JsonIgnoreCondition.WhenWritingNull before this converter is invoked.
+ writer.WriteStartArray();
- foreach (var verb in value)
- writer.WriteStringValue(verb.GetHttpVerbValue());
+ foreach (var verb in value)
+ writer.WriteStringValue(verb.GetHttpVerbValue());
- writer.WriteEndArray();
- }
+ writer.WriteEndArray();
}
}
diff --git a/src/Ramstack.HtmxToolkit/TagHelpers/HtmxConfigTagHelper.cs b/src/Ramstack.HtmxToolkit/TagHelpers/HtmxConfigTagHelper.cs
index 18a8865..cf2b5cd 100644
--- a/src/Ramstack.HtmxToolkit/TagHelpers/HtmxConfigTagHelper.cs
+++ b/src/Ramstack.HtmxToolkit/TagHelpers/HtmxConfigTagHelper.cs
@@ -40,7 +40,7 @@ public override Task ProcessAsync(TagHelperContext context, TagHelperOutput outp
var json = options.Value.HtmxConfig.ToJson();
output.Attributes.SetAttribute(
- new TagHelperAttribute("content", new HtmlString(json), HtmlAttributeValueStyle.SingleQuotes));
+ new TagHelperAttribute("content", json, HtmlAttributeValueStyle.SingleQuotes));
if (options.Value.IncludeAntiforgeryToken)
RenderAntiforgeryAttributes(output);