diff --git a/src/Common/Common.fs b/src/Common/Common.fs index 73245f8..854d0b7 100644 --- a/src/Common/Common.fs +++ b/src/Common/Common.fs @@ -44,7 +44,7 @@ module HxSwap = /// Morph the outer HTML of the target to the new content [] - let OuterMorph = "innerMorph" + let OuterMorph = "outerMorph" /// Replace the text content of the target without parsing the response as HTML [] diff --git a/src/Htmx/Htmx.fs b/src/Htmx/Htmx.fs index 99b9d6d..2b3d312 100644 --- a/src/Htmx/Htmx.fs +++ b/src/Htmx/Htmx.fs @@ -4,6 +4,14 @@ open Microsoft.AspNetCore.Http open Microsoft.Extensions.Primitives open System +/// The request types which may be set in the HX-Request header +type HxRequestTypes = + /// A request targeting the body tag or using an hx-select attribute + | HxFullRequest + + /// A request for partial content + | HxPartialRequest + /// Determine if the given header is present let private hdr (headers : IHeaderDictionary) hdr = match headers[hdr] with it when it = StringValues.Empty -> None | it -> Some it[0] @@ -32,6 +40,16 @@ type IHeaderDictionary with member this.HxRequest with get () = hdr this "HX-Request" |> Option.map bool.Parse + /// The request type sent by htmx + /// + member this.HxRequestType + with get () = + match hdr this "HX-Request-Type" with + | Some typ when typ = "full" -> Some HxFullRequest + | Some typ when typ = "partial" -> Some HxPartialRequest + | Some _ -> None + | None -> None + /// The tag name (fst) and id attribute (snd) of the element triggering this request member this.HxSource with get () = @@ -45,8 +63,23 @@ type IHeaderDictionary with | None -> None /// The id attribute of the target element if it exists + /// + /// In v4, this changed to tag name (fst) and id (snd); to resolve build errors, and restore the prior + /// behavior of [id] option, replace + /// ctx.HxTarget + /// with + /// ctx.HxTarget |> Option.iter snd + /// member this.HxTarget - with get () = hdr this "HX-Target" + with get () = + match hdr this "HX-Target" with + | Some src -> + let parts = src.Split "#" + if parts.Length = 1 then + Some (parts[0], None) + else + Some (parts[0], if parts[1] <> "" then Some parts[1] else None) + | None -> None /// The id attribute of the triggered element if it exists [] @@ -162,29 +195,33 @@ module Handlers = /// The call to the event that should be triggered /// An HTTP handler with the HX-Trigger-After-Settle header set /// Documentation + [] let withHxTriggerAfterSettle (evt: string) : HttpHandler = - setHttpHeader "HX-Trigger-After-Settle" evt + setHttpHeader "HX-Trigger" evt /// Allows you to trigger multiple client side events after changes have settled /// The calls to events that should be triggered /// An HTTP handler with the HX-Trigger-After-Settle header set for all given events /// Documentation + [] let withHxTriggerManyAfterSettle evts : HttpHandler = - toJson evts |> setHttpHeader "HX-Trigger-After-Settle" + toJson evts |> setHttpHeader "HX-Trigger" /// Allows you to trigger a single client side event after DOM swapping occurs /// The call to the event that should be triggered /// An HTTP handler with the HX-Trigger-After-Swap header set /// Documentation + [] let withHxTriggerAfterSwap (evt: string) : HttpHandler = - setHttpHeader "HX-Trigger-After-Swap" evt + setHttpHeader "HX-Trigger" evt /// Allows you to trigger multiple client side events after DOM swapping occurs /// The calls to events that should be triggered /// An HTTP handler with the HX-Trigger-After-Swap header set for all given events /// Documentation + [] let withHxTriggerManyAfterSwap evts : HttpHandler = - toJson evts |> setHttpHeader "HX-Trigger-After-Swap" + toJson evts |> setHttpHeader "HX-Trigger" /// Load the package-provided version of the htmx script diff --git a/src/Tests/Common.fs b/src/Tests/Common.fs index c71b643..5f18b56 100644 --- a/src/Tests/Common.fs +++ b/src/Tests/Common.fs @@ -22,7 +22,7 @@ let swap = Expect.equal HxSwap.InnerMorph "innerMorph" "Inner Morph swap value incorrect" } test "OuterMorph is correct" { - Expect.equal HxSwap.OuterMorph "innerMorph" "Outer Morph swap value incorrect" + Expect.equal HxSwap.OuterMorph "outerMorph" "Outer Morph swap value incorrect" } test "TextContent is correct" { Expect.equal HxSwap.TextContent "textContent" "Text Content swap value incorrect" diff --git a/src/Tests/Htmx.fs b/src/Tests/Htmx.fs index e6733a3..5eeb409 100644 --- a/src/Tests/Htmx.fs +++ b/src/Tests/Htmx.fs @@ -96,6 +96,36 @@ let dictExtensions = Expect.isFalse ctx.Request.Headers.HxRequest.Value "The header should have been false" } ] + testList "HxRequestType" [ + test "succeeds when the header is not present" { + let ctx = Substitute.For() + ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore + Expect.isNone ctx.Request.Headers.HxRequestType "There should not have been a header returned" + } + test "succeeds when the header is invalid" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + dic.Add("HX-Request-Type", "relaxed") + ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore + Expect.isNone ctx.Request.Headers.HxRequestType "There should not have been a header returned" + } + test "succeeds for a full request" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + dic.Add("HX-Request-Type", "full") + ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore + Expect.isSome ctx.Request.Headers.HxRequestType "There have been a header returned" + Expect.equal ctx.Request.Headers.HxRequestType.Value HxFullRequest "The header value is incorrect" + } + test "succeeds for a partial request" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + dic.Add("HX-Request-Type", "partial") + ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore + Expect.isSome ctx.Request.Headers.HxRequestType "There have been a header returned" + Expect.equal ctx.Request.Headers.HxRequestType.Value HxPartialRequest "The header value is incorrect" + } + ] testList "HxSource" [ test "succeeds when the header is not present" { let ctx = Substitute.For() @@ -140,13 +170,36 @@ let dictExtensions = ctx.Request.Headers.ReturnsForAnyArgs(HeaderDictionary()) |> ignore Expect.isNone ctx.Request.Headers.HxTarget "There should not have been a header returned" } - test "succeeds when the header is present" { + test "succeeds when the header is present and both parts exist" { let ctx = Substitute.For() let dic = HeaderDictionary() - dic.Add("HX-Target", "#leItem") + dic.Add("HX-Target", "div#leItem") ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore - Expect.isSome ctx.Request.Headers.HxTarget "There should be a header present" - Expect.equal ctx.Request.Headers.HxTarget.Value "#leItem" "The header value was incorrect" + let hdr = ctx.Request.Headers.HxTarget + Expect.isSome hdr "There should be a header present" + Expect.equal (fst hdr.Value) "div" "The target tag was incorrect" + Expect.isSome (snd hdr.Value) "There should be a target ID present" + Expect.equal (snd hdr.Value).Value "leItem" "The header value was incorrect" + } + test "succeeds when the header is present and ID is blank" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + dic.Add("HX-Target", "span#") + ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore + let hdr = ctx.Request.Headers.HxTarget + Expect.isSome hdr "There should be a header present" + Expect.equal (fst hdr.Value) "span" "The target tag was incorrect" + Expect.isNone (snd hdr.Value) "There should not be a target ID present" + } + test "succeeds when the header is present and ID is missing" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + dic.Add("HX-Target", "aside") + ctx.Request.Headers.ReturnsForAnyArgs dic |> ignore + let hdr = ctx.Request.Headers.HxTarget + Expect.isSome hdr "There should be a header present" + Expect.equal (fst hdr.Value) "aside" "The target tag was incorrect" + Expect.isNone (snd hdr.Value) "There should not be a target ID present" } ] ] @@ -307,44 +360,6 @@ let handlers = Expect.equal dic["HX-Trigger"].[0] """{ "blah": "foo", "bleh": "bar" }""" "The HX-Trigger value was incorrect" } - testTask "withHxTriggerAfterSettle succeeds" { - let ctx = Substitute.For() - let dic = HeaderDictionary() - ctx.Response.Headers.ReturnsForAnyArgs dic |> ignore - let! _ = withHxTriggerAfterSettle "byTheWay" next ctx - Expect.isTrue - (dic.ContainsKey "HX-Trigger-After-Settle") "The HX-Trigger-After-Settle header should be present" - Expect.equal dic["HX-Trigger-After-Settle"].[0] "byTheWay" "The HX-Trigger-After-Settle value was incorrect" - } - testTask "withHxTriggerManyAfterSettle succeeds" { - let ctx = Substitute.For() - let dic = HeaderDictionary() - ctx.Response.Headers.ReturnsForAnyArgs dic |> ignore - let! _ = withHxTriggerManyAfterSettle [ "oof", "ouch"; "hmm", "uh" ] next ctx - Expect.isTrue - (dic.ContainsKey "HX-Trigger-After-Settle") "The HX-Trigger-After-Settle header should be present" - Expect.equal - dic["HX-Trigger-After-Settle"].[0] """{ "oof": "ouch", "hmm": "uh" }""" - "The HX-Trigger-After-Settle value was incorrect" - } - testTask "withHxTriggerAfterSwap succeeds" { - let ctx = Substitute.For() - let dic = HeaderDictionary() - ctx.Response.Headers.ReturnsForAnyArgs dic |> ignore - let! _ = withHxTriggerAfterSwap "justASec" next ctx - Expect.isTrue (dic.ContainsKey "HX-Trigger-After-Swap") "The HX-Trigger-After-Swap header should be present" - Expect.equal dic["HX-Trigger-After-Swap"].[0] "justASec" "The HX-Trigger-After-Swap value was incorrect" - } - testTask "withHxTriggerManyAfterSwap succeeds" { - let ctx = Substitute.For() - let dic = HeaderDictionary() - ctx.Response.Headers.ReturnsForAnyArgs dic |> ignore - let! _ = withHxTriggerManyAfterSwap [ "this", "1"; "that", "2" ] next ctx - Expect.isTrue (dic.ContainsKey "HX-Trigger-After-Swap") "The HX-Trigger-After-Swap header should be present" - Expect.equal - dic["HX-Trigger-After-Swap"].[0] """{ "this": "1", "that": "2" }""" - "The HX-Trigger-After-Swap value was incorrect" - } ] /// Tests for the HtmxScript module @@ -408,5 +423,41 @@ let dictExtensionsObs = ] ] +let handlerObs = + testList "Handler Tests (Obsolete)" [ + testTask "withHxTriggerAfterSettle succeeds" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + ctx.Response.Headers.ReturnsForAnyArgs dic |> ignore + let! _ = withHxTriggerAfterSettle "byTheWay" next ctx + Expect.isTrue (dic.ContainsKey "HX-Trigger") "The HX-Trigger header should be present" + Expect.equal dic["HX-Trigger"].[0] "byTheWay" "The HX-Trigger value was incorrect" + } + testTask "withHxTriggerManyAfterSettle succeeds" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + ctx.Response.Headers.ReturnsForAnyArgs dic |> ignore + let! _ = withHxTriggerManyAfterSettle [ "oof", "ouch"; "hmm", "uh" ] next ctx + Expect.isTrue (dic.ContainsKey "HX-Trigger") "The HX-Trigger header should be present" + Expect.equal dic["HX-Trigger"].[0] """{ "oof": "ouch", "hmm": "uh" }""" "The HX-Trigger value was incorrect" + } + testTask "withHxTriggerAfterSwap succeeds" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + ctx.Response.Headers.ReturnsForAnyArgs dic |> ignore + let! _ = withHxTriggerAfterSwap "justASec" next ctx + Expect.isTrue (dic.ContainsKey "HX-Trigger") "The HX-Trigger header should be present" + Expect.equal dic["HX-Trigger"].[0] "justASec" "The HX-Trigger value was incorrect" + } + testTask "withHxTriggerManyAfterSwap succeeds" { + let ctx = Substitute.For() + let dic = HeaderDictionary() + ctx.Response.Headers.ReturnsForAnyArgs dic |> ignore + let! _ = withHxTriggerManyAfterSwap [ "this", "1"; "that", "2" ] next ctx + Expect.isTrue (dic.ContainsKey "HX-Trigger") "The HX-Trigger header should be present" + Expect.equal dic["HX-Trigger"].[0] """{ "this": "1", "that": "2" }""" "The HX-Trigger value was incorrect" + } + ] + /// All tests for this module -let allTests = testList "Htmx" [ dictExtensions; reqExtensions; handlers; script; dictExtensionsObs ] +let allTests = testList "Htmx" [ dictExtensions; reqExtensions; handlers; script; dictExtensionsObs; handlerObs ] diff --git a/src/Tests/ViewEngine.fs b/src/Tests/ViewEngine.fs index 264c385..cedf42c 100644 --- a/src/Tests/ViewEngine.fs +++ b/src/Tests/ViewEngine.fs @@ -1,6 +1,7 @@ module ViewEngine open Expecto +open Giraffe.Htmx open Giraffe.ViewEngine open Giraffe.ViewEngine.Htmx @@ -129,6 +130,14 @@ let hxEvent = Expect.equal (AfterRequest.ToHxOnString()) "after:request" "AfterRequest hx-on event name not correct" } ] + testList "AfterSettle" [ + test "ToString succeeds" { + Expect.equal (string AfterSettle) "afterSettle" "AfterSettle event name not correct" + } + test "ToHxOnString succeeds" { + Expect.equal (AfterSettle.ToHxOnString()) "after:settle" "AfterSettle hx-on event name not correct" + } + ] testList "AfterSseMessage" [ test "ToString succeeds" { Expect.equal (string AfterSseMessage) "afterSseMessage" "AfterSseMessage event name not correct" @@ -184,6 +193,15 @@ let hxEvent = Expect.equal (BeforeInit.ToHxOnString()) "before:init" "BeforeInit hx-on event name not correct" } ] + testList "BeforeProcess" [ + test "ToString succeeds" { + Expect.equal (string BeforeProcess) "beforeProcess" "BeforeProcess event name not correct" + } + test "ToHxOnString succeeds" { + Expect.equal + (BeforeProcess.ToHxOnString()) "before:process" "BeforeProcess hx-on event name not correct" + } + ] testList "BeforeRestoreHistory" [ test "ToString succeeds" { Expect.equal @@ -205,6 +223,15 @@ let hxEvent = (BeforeRequest.ToHxOnString()) "before:request" "BeforeRequest hx-on event name not correct" } ] + testList "BeforeResponse" [ + test "ToString succeeds" { + Expect.equal (string BeforeResponse) "beforeResponse" "BeforeResponse event name not correct" + } + test "ToHxOnString succeeds" { + Expect.equal + (BeforeResponse.ToHxOnString()) "before:response" "BeforeResponse hx-on event name not correct" + } + ] testList "BeforeSseMessage" [ test "ToString succeeds" { Expect.equal (string BeforeSseMessage) "beforeSseMessage" "BeforeSseMessage event name not correct" @@ -279,6 +306,15 @@ let hxEvent = (FinallyRequest.ToHxOnString()) "finally:request" "FinallyRequest hx-on event name not correct" } ] + testList "ResponseError" [ + test "ToString succeeds" { + Expect.equal (string ResponseError) "responseError" "ResponseError event name not correct" + } + test "ToHxOnString succeeds" { + Expect.equal + (ResponseError.ToHxOnString()) "response:error" "ResponseError hx-on event name not correct" + } + ] ] /// Tests for the HxHeaders module @@ -572,7 +608,7 @@ let attributes = } test "_hxOnHxEvent succeeds" { strong [ _hxOnHxEvent BeforeSwap "changeStuff()" ] [] - |> shouldRender """""" + |> shouldRender """""" } test "_hxPatch succeeds" { div [ _hxPatch "/arrrgh" ] [] |> shouldRender """
""" @@ -598,6 +634,18 @@ let attributes = test "_hxSelectOob succeeds" { section [ _hxSelectOob "#oob" ] [] |> shouldRender """
""" } + testList "_hxStatus" [ + test "succeeds for a full code with no action" { + div [ _hxStatus "403" HxSwap.After "" ] [] |> shouldRender """
""" + } + test "succeeds for a two-digit range with action" { + span [ _hxStatus "41" HxSwap.Before "target:main" ] [] + |> shouldRender """""" + } + test "succeeds for a one-digit range with no action" { + p [ _hxStatus "5" HxSwap.None "" ] [] |> shouldRender """

""" + } + ] test "_hxSwap succeeds" { del [ _hxSwap "innerHTML" ] [] |> shouldRender """""" } @@ -864,15 +912,7 @@ let hxEventObs = } test "ToHxOnString succeeds" { Expect.equal - (AfterProcessNode.ToHxOnString()) "after:init" "AfterProcessNode hx-on event name not correct" - } - ] - testList "AfterSettle" [ - test "ToString succeeds" { - Expect.equal (string AfterSettle) "afterSettle" "AfterSettle event name not correct" - } - test "ToHxOnString succeeds" { - Expect.equal (AfterSettle.ToHxOnString()) "after:swap" "AfterSettle hx-on event name not correct" + (AfterProcessNode.ToHxOnString()) "after:process" "AfterProcessNode hx-on event name not correct" } ] testList "BeforeCleanupElement" [ @@ -912,7 +952,7 @@ let hxEventObs = } test "ToHxOnString succeeds" { Expect.equal - (BeforeProcessNode.ToHxOnString()) "before:init" "BeforeProcessNode hx-on event name not correct" + (BeforeProcessNode.ToHxOnString()) "before:process" "BeforeProcessNode hx-on event name not correct" } ] testList "BeforeSend" [ @@ -1049,14 +1089,6 @@ let hxEventObs = "PushedIntoHistory hx-on event name not correct" } ] - testList "ResponseError" [ - test "ToString succeeds" { - Expect.equal (string ResponseError) "responseError" "ResponseError event name not correct" - } - test "ToHxOnString succeeds" { - Expect.equal (ResponseError.ToHxOnString()) "error" "ResponseError hx-on event name not correct" - } - ] testList "SendError" [ test "ToString succeeds" { Expect.equal (string SendError) "sendError" "SendError event name not correct" @@ -1144,7 +1176,7 @@ let hxEventObs = Expect.equal (string XhrAbort) "xhr:abort" "XhrAbort event name not correct" } test "ToHxOnString succeeds" { - Expect.equal (XhrAbort.ToHxOnString()) "xhr:abort" "XhrAbort hx-on event name not correct" + Expect.equal (XhrAbort.ToHxOnString()) "error" "XhrAbort hx-on event name not correct" } ] testList "XhrLoadEnd" [ @@ -1152,7 +1184,7 @@ let hxEventObs = Expect.equal (string XhrLoadEnd) "xhr:loadend" "XhrLoadEnd event name not correct" } test "ToHxOnString succeeds" { - Expect.equal (XhrLoadEnd.ToHxOnString()) "xhr:loadend" "XhrLoadEnd hx-on event name not correct" + Expect.equal (XhrLoadEnd.ToHxOnString()) "finally:request" "XhrLoadEnd hx-on event name not correct" } ] testList "XhrLoadStart" [ diff --git a/src/ViewEngine.Htmx/Htmx.fs b/src/ViewEngine.Htmx/Htmx.fs index 6f160bf..ad7fd74 100644 --- a/src/ViewEngine.Htmx/Htmx.fs +++ b/src/ViewEngine.Htmx/Htmx.fs @@ -71,8 +71,11 @@ type HxEvent = /// Triggered after an AJAX request has completed processing a successful response | [] AfterOnLoad + /// Triggered after htmx has initialized a DOM node or subtree + | AfterProcess + /// Triggered after htmx has initialized a node - | [] AfterProcessNode + | [] AfterProcessNode /// Triggered after new content is saved to the history cache | AfterPushIntoHistory @@ -84,7 +87,7 @@ type HxEvent = | AfterRequest /// Triggered after the DOM has settled - | [] AfterSettle + | AfterSettle /// Triggered after a Server Sent Events (SSE) message is read | AfterSseMessage @@ -116,12 +119,18 @@ type HxEvent = /// Triggered before any response processing occurs | [] BeforeOnLoad + /// Triggered before htmx begins processing a DOM node or subtree + | BeforeProcess + /// Triggered before htmx initializes a node - | [] BeforeProcessNode + | [] BeforeProcessNode /// Triggered before an HTTP request is made | BeforeRequest + /// Triggered before an HTTP response is processed (cancelable) + | BeforeResponse + /// Triggered before a history restore request is made | BeforeRestoreHistory @@ -199,7 +208,7 @@ type HxEvent = | [] PushedIntoHistory /// Triggered when an HTTP response error (non-200 or 300 response code) occurs - | [] ResponseError + | ResponseError /// Triggered when a network error prevents an HTTP request from happening | [] SendError @@ -229,10 +238,10 @@ type HxEvent = | [] ValidationHalted /// Triggered when an ajax request aborts - | [] XhrAbort + | [] XhrAbort /// Triggered when an ajax request ends - | [] XhrLoadEnd + | [] XhrLoadEnd /// Triggered when an ajax request starts | [] XhrLoadStart @@ -247,11 +256,11 @@ type HxEvent = AfterHistoryUpdate, ("afterHistoryUpdate", "after:history:update") AfterInit, ("afterInit", "after:init") AfterOnLoad, ("afterOnLoad", "after:init") - AfterProcessNode, ("afterProcessNode", "after:init") + AfterProcessNode, ("afterProcessNode", "after:process") AfterPushIntoHistory, ("afterPushIntoHistory", "after:push:into:history") AfterReplaceIntoHistory, ("afterReplaceIntoHistory", "after:replace:into:history") AfterRequest, ("afterRequest", "after:request") - AfterSettle, ("afterSettle", "after:swap") + AfterSettle, ("afterSettle", "after:settle") AfterSseMessage, ("afterSseMessage", "after:sse:message") AfterSseStream, ("afterSseStream", "after:sse:stream") AfterSwap, ("afterSwap", "after:swap") @@ -262,9 +271,11 @@ type HxEvent = BeforeHistoryUpdate, ("beforeHistoryUpdate", "before:history:update") BeforeInit, ("beforeInit", "before:init") BeforeOnLoad, ("beforeOnLoad", "before:init") - BeforeProcessNode, ("beforeProcessNode", "before:init") - BeforeRestoreHistory, ("beforeRestoreHistory", "before:restore:history") + BeforeProcess, ("beforeProcess", "before:process") + BeforeProcessNode, ("beforeProcessNode", "before:process") BeforeRequest, ("beforeRequest", "before:request") + BeforeResponse, ("beforeResponse", "before:response") + BeforeRestoreHistory, ("beforeRestoreHistory", "before:restore:history") BeforeSend, ("beforeSend", "before:request") BeforeSseMessage, ("beforeSseMessage", "before:sse:message") BeforeSseReconnect, ("beforeSseReconnect", "before:sse:reconnect") @@ -288,7 +299,7 @@ type HxEvent = OobErrorNoTarget, ("oobErrorNoTarget", "error") Prompt, ("prompt", "prompt") PushedIntoHistory, ("pushedIntoHistory", "after:push:into:history") - ResponseError, ("responseError", "error") + ResponseError, ("responseError", "response:error") SendError, ("sendError", "error") SseError, ("sseError", "error") SseOpen, ("sseOpen", "sse-open") @@ -298,8 +309,8 @@ type HxEvent = ValidationValidate, ("validation:validate", "validation:validate") ValidationFailed, ("validation:failed", "validation:failed") ValidationHalted, ("validation:halted", "validation:halted") - XhrAbort, ("xhr:abort", "xhr:abort") - XhrLoadEnd, ("xhr:loadend", "xhr:loadend") + XhrAbort, ("xhr:abort", "error") + XhrLoadEnd, ("xhr:loadend", "finally:request") XhrLoadStart, ("xhr:loadstart", "xhr:loadstart") XhrProgress, ("xhr:progress", "xhr:progress") ] @@ -757,7 +768,7 @@ module HtmxAttrs = /// /// Documentation let _hxOnHxEvent (hxEvent: HxEvent) handler = - _hxOnEvent $":{hxEvent.ToHxOnString()}" handler + _hxOnEvent $"htmx:{hxEvent.ToHxOnString()}" handler /// Filters the parameters that will be submitted with a request /// The fields to include (use HxParams to generate this value) @@ -852,6 +863,31 @@ module HtmxAttrs = let _hxSelectOob selectors = attr "hx-select-oob" selectors + /// Define a response to an HTTP status code or code range + /// + /// The code or code range; for a code, pass the full code as a string (ex. 404), and for a range, pass a + /// string with one or two characters (ex. 5 for all 500s, 42 for 420-429) + /// + /// The swap style to use for this action(use HxSwap values) + /// + /// The action which should be taken for responses matching the status code; can be a combination of the following, + /// with each item separated by a space: + ///
    + ///
  • target: and a CSS selector for the swap target (overrides original hx-target)
  • + ///
  • select: and a CSS selector for the content to be swapped (overrides original hx-select)
  • + ///
  • push: and true, false, or a URL; false does not update URL history, true + /// updates with the current URL, and a string URL will be pushed into history as-is
  • + ///
  • replace: and true, false, or a URL; same as push:, but replaces in history + /// instead
  • + ///
  • transition: and true or false; whether to use view transitions
  • + ///
+ /// If only the type of swap is being changed, pass an empty string to this parameter. + /// + /// Documentation + let _hxStatus code swap action = + let range = $"%s{code}xx".Substring(0, 3) + attr $"hx-status:{range}" ($"swap:%s{swap} %s{action}".Trim()) + /// /// Controls how the response content is swapped into the DOM (e.g. outerHTML or beforeEnd) ///