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)
///